0 前言

近些年来,所谓的人工智能也就是AI。

在媒体的炒作下,变得神乎其神,但实际上,类似于图片识别的AI,其原理只不过是数学的应用。

线性代数,概率论,微积分(著名的反向传播算法)。

大家觉得这些东西离自己很远,没错!

这东西底层实在是很难,斯坦福公开课网站上(Coursera), 有吴恩达教授的机器学习课程,需要利用Matlab用向量化的编程方式完成线性回归,逻辑回归,甚至是神经网络,以及反向传播代码。这些内容无论在任何方面都是艰涩的难以理解的。

而这只能算是人工智能机器学习的入门课程。本人21年利用零碎时间将近3个月,拿到了这门课的证书,99分,到现今几乎忘的差不多了。再纯手写神经网络已经写不出来了。

但是时间在向前流动,一些所谓难以触及的东西也在普及化。汽车,电脑,飞机,智能电话...。

人工智能也不例外!如今随着技术的发展,以及抽象。我们有现成的框架,可以非常方便制作属于自己的AI。

这篇博文,会从数据搜集,模型训练,web应用来做一个可用的图片识别AI项目。(当然是缩减版本,有许多需要优化的地方。)

最终结果如下:

1 数据搜集

1.1 为什么需要数据?

数据对于AI程序来说非常重要,AI程序通过对数据的观察,来获取对于事物的“理解”。

举个例子:给Ai看10张猫咪的照片后,当AI看到新的猫咪后,会识别出这是一个猫咪。

这看似与人类很像,但实际上有非常大的不同!

总的来说,数据越多,AI程序识别的效果也会更好。近几十年中,神经网络的逆袭之路就是因为数据的爆发。

1.2 如何搜集数据?

  • 图片数据的搜集可以用手机来拍摄,之后让AI学习。这是可行的,但是是低效的。

  • 通过爬虫来进行图片的爬取。速度快,质量低。

这里我们使用一个百度图片搜索的爬虫,即将百度图片搜索到的图片爬取到本地上来。

1.3 百度图片爬取

前导条件:

  • Python3.7
  • requets
    • >>pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple 从清华那里把这个python组件给下载回来。
import os
import sys
import re
import requests class baidu_img_crawl(): def __init__(self):
# after ? we use the get method to transefer a request
self.target_url = "https://image.baidu.com/search/acjson?" # we use this to pretend we're a normal human being
self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"} # The name of the picture to be searched, using Baidu Image Search Engine
# self.keyword = input("Enter your food type:")
self.keyword = sys.argv[1] # One respones page equal to 30 images
# self.page_nums = int(input("Enter the number of pages you need:"))
self.page_nums = int(sys.argv[2]) # self.file_name = input("Enter the file name where you want to store:")
self.file_name = sys.argv[3] def generate_GET_params(self):
params = [] for page_num in range(1, self.page_nums+1):
# params from F12 network Fetch/XHR json payload:
# word = queryword := search keyword
# pn = 30*pageNum gsm = hex(pn)
params.append('tn=resultjson_com&logid=7230074900925652532&ipn=rj&ct=201326592&is=&fp=result&\
fr=&word={}&queryWord={}\
&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=undefined&ic=undefined&hd=undefined&latest=undefined&copyright=undefined&\
s=&se=&tab=&width=undefined&height=undefined&face=0&istype=2&qc=&nc=1&expermode=&nojc=&isAsync=&pn={}&rn=30&\
gsm={}&1657782304389='.format(self.keyword, self.keyword, 30*page_num, hex(30*page_num)[2:]))
return params def get_request_url_list(self, params):
request_urls = [] for param in params:
request_urls.append(self.target_url + param) return request_urls def get_image_url_list(self, request_urls):
image_urls = []
for request_url in request_urls:
#{"data":[{1,"thumb":"https:xxx.com"},{2},...,{30},{NULL}]}
json_txt = requests.get(request_url, headers=self.headers).text
image_urls += re.findall(r'"thumbURL":"(.*?)",', json_txt) return image_urls def download_image(self, image_urls):
store_path = r'../' + self.file_name if not os.path.exists(store_path):
os.makedirs(store_path) index = 0
for image_url in image_urls:
with open(os.path.join(store_path, str(index) + ".jpg"),"wb") as f: # with写文件不用关
f.write(requests.get(image_url, headers=self.headers).content)
index += 1
if index % 30 == 0:
print("Page {} is downloaded!".format(index/30)) # Python 类中一个非常特殊的实例方法,即 __call__()
# 该方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用。
def __call__(self):
params = self.generate_GET_params()
request_urls = self.get_request_url_list(params)
image_urls = self.get_image_url_list(request_urls)
self.download_image(image_urls) if __name__ == '__main__':
spider = baidu_img_crawl()
spider()

1.3.1 程序解释

web的基本原理:你访问一个链接url,会向web服务器发送一个关于这个url的请求,web服务器会根据这个url给你一个答复,浏览器会根据这个答复进行页面的构建。你的一次访问就成功了。

爬虫的基本原理:自动访问链接,获取答复,对于答复进行数据分离,并下载到本地。

百度的图片搜索引擎会根据你搜索的关键词,自动的生成url链接,并且向百度web服务器进行请求这个链接,而百度返回的答复里就有这些图片的资源。

我们的爬虫所要做的就是

  • 自动生成类似百度图片引擎的url链接

    • params = self.generate_GET_params()
    • request_urls = self.get_request_url_list(params)
  • 访问这些链接,并分离图片资源链接
    • image_urls = self.get_image_url_list(request_urls)
  • 我们把这些图片资源进本地下载
    • self.download_image(image_urls)

1.3.2 程序使用

将本程序保存为 spider.py

命令行中切换到此程序所在路径。

python .\spider.py 冰激淋 20 foodData/ice-cream

会在脚本的上级目录foodData下创建Ice-cream文件,并下载 600=20*30 张冰激淋的图片。

1.3.3 项目构建

  1. 首先创建项目文件夹: AI_FOOD

  2. 接着创建存放图片数据的子文件夹: AI_FOOD/food

  3. 在接着创建存放爬虫脚本的文件夹: AI_FOOD/food/food_script

  4. 把爬虫代码保存为:AI_FOOD/food/food_script/spyder.py

  5. 命令行使用爬虫爬取: python .\spider.py 冰激淋 20 foodData/ice-cream

完成下载之后:

接着我们再下载5个类别!每个类别600张

  • python .\spider.py 汉堡包 20 foodData/hamburger
  • python .\spider.py 蛋挞 20 foodData/tart
  • python .\spider.py 甜甜圈 20 foodData/donut
  • python .\spider.py 披萨 20 foodData/pizza
  • python .\spider.py 米饭 20 foodData/rice

注:图片中的演示只下载了60=2*30张,是为了好截图。实际操作按照上述代码进行操作!

2. AI模型训练

现在我们已经将数据搜集过来了。

接下来就是进行模型的训练。

在进行训练时,我们通常将所有数据分为三个部分

  • 训练集:拿这部分的数据进行模型的训练,就是拿这里的图片给 AI程序学习。

  • 交叉验证集:拿这部分的数据进行模型训练结果的验证,这部分给出了当前模型的效果,如果效果不好,可以在之后更换模型或者算法!

  • 测试集:交叉验证集评估出了不错的模型,我们将用此模型在测试集上观察实际效果。

2.1 数据划分

六个类别分别分到 训练集文件夹,交叉验证集文件夹,测试集文件夹,所以最后会出现 3*6 = 18个文件夹。

import os, shutil

def mkdirs(path):
if not os.path.exists(path):
os.makedirs(path) def split_data(src_dir, dst_dir, train_prop, val_prop, test_prop):
# 我们使用 kreas 一个文件夹代表一个种类 的 数据处理函数
src_classes = os.listdir(src_dir) data_sets = ['train', 'val', 'test'] for data_set in data_sets:
for src_class in src_classes:
mkdirs(os.path.join(dst_dir, data_set, src_class)) for src_class in src_classes:
class_images = os.listdir(os.path.join(src_dir, src_class))
num = len(class_images) train_class_images = class_images[:int(num * train_prop)]
val_class_images = class_images[int(num * train_prop): int(num * (train_prop + val_prop))]
test_class_images = class_images[int(num * (train_prop + val_prop)):] print("Copying class:{} to train set!".format(src_class))
for class_image in train_class_images:
src = os.path.join(src_dir, src_class, class_image)
dst = os.path.join(dst_dir, 'train' , src_class, class_image)
shutil.copyfile(src, dst) print("Copying class:{} to val set!".format(src_class))
for class_image in val_class_images:
src = os.path.join(src_dir, src_class, class_image)
dst = os.path.join(dst_dir, 'val' , src_class, class_image)
shutil.copyfile(src, dst) print("Copying class:{} to test set!".format(src_class))
for class_image in test_class_images:
src = os.path.join(src_dir, src_class, class_image)
dst = os.path.join(dst_dir, 'test' , src_class, class_image)
shutil.copyfile(src, dst) print("train_num:{}, val_num:{}, test_num:{}".format(len(train_class_images), len(val_class_images), len(test_class_images))) print('done!') if __name__ == '__main__':
src_dir = "foodData"
dst_dir = "foodData_cnn_split"
split_data(src_dir, dst_dir, 0.5, 0.25, 0.25)

此程序的运行需要指定:

  • src_dir: 为我们搜集到的数据的一级文件夹,里面存放这6个类别的图片!

  • dst_dir: 为我们对于src_dir里图片的划分的文件夹(会根据你所写的名字自动创建),里面存放这6个类别的图片!

  • train_prop: 为训练集的比例。300

  • val_prop: 为验证集的比例。150

  • test_prop: 为测试集的比例。150

2.2 项目构建

  1. 首先将上述代码保存为:split.py

  2. 接着将split.py放到: AI_FOOD/food/split.py 也就是与 foodData 文件夹同一级目录。

  3. 直接运行该文件即可!

Copying class:donut to train set!

Copying class:donut to val set!

Copying class:donut to test set!

Copying class:hamburger to train set!

Copying class:hamburger to val set!

Copying class:hamburger to test set!

Copying class:ice-cream to train set!

Copying class:ice-cream to val set!

Copying class:ice-cream to test set!

Copying class:pizza to train set!

Copying class:pizza to val set!

Copying class:pizza to test set!

Copying class:rice to train set!

Copying class:rice to val set!

Copying class:rice to test set!

Copying class:tart to train set!

Copying class:tart to val set!

Copying class:tart to test set!

done!

2.3 模型训练

Keras是一个由Python编写的开源人工神经网络库,可以作为Tensorflow、Microsoft-CNTK和Theano的高阶应用程序接口,进行深度学习模型的设计、调试、评估、应用和可视化。

将人工智能程序变得简单了许多!甚至是编程小白都可以熟练的使用。

构建一个AI只需要3个函数即可完成。

2.4 AI 是什么

这里对于图片分类CNN卷积神经网络AI进行一个解释。

我们知道,计算机里都是数字(二进制),无论是文本还是视频,还是图片,在计算机看来都是数字。

有数字就有函数。

数字 \(x\) 结果 \(y\)
1 2
2 3
3 4
4 5
\[y=x+1
\]

例如一个40*40的灰度手写体数字图片(0-9),既为1600个像素点,每一个像素点为一个数字,所以有1600个数字(特征)。每1600个数字对应10个数字(标签)。

我们把这1600个自变量输入到AI中,AI会自动找到匹配10个因变量的特定函数。

就是这么简单。

我们所要做的就是将图片还原为数字的形式。将自变量数字以及因变量数字输入到设定好的AI算法中(寻找函数的算法)。

寻找函数的过程称之为训练,使用的算法为反向传播,核心为微积分的链式求导法则。

普通算法为将1600个自变量送入AI进行训练,但这个计算量会非常大!

而CNN卷积神经网络的工作就是将1600个自变量变为更少数量的自变量(eg.512), 但是还可以保留原来自变量的特征!

2.5 keras CNN—AI模型 构建及训练

  • 首先下载 tensorflow

    • >>pip install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple 从清华那里把这个python组件给下载回来。
from keras import layers
from keras import models
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
from tensorflow import optimizers
import tensorflow as tf
import os # model build model = models.Sequential() model.add(layers.Conv2D(32, (3, 3), activation='relu',input_shape=(224, 224, 3)))
model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Flatten())
model.add(layers.Dropout(0.1))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(6, activation='softmax')) model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) model.summary() # Data preprocessing and Using data augmentation
train_dir = './foodData_cnn_split/train'
validation_dir = './foodData_cnn_split/val' train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest') test_datagen = ImageDataGenerator(rescale=1./255) train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(224, 224),
batch_size=30, # 每次找30张图片变换
# save_to_dir = './train_gen', 这个会把数据增强的图片保存下来
class_mode='categorical') validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(224, 224),
batch_size=30,
class_mode='categorical') if not os.path.exists('./train_gen'):
os.mkdir('./train_gen') print(train_generator.class_indices) # 输出对应的标签文件夹 # fit the model
history = model.fit(
train_generator,
steps_per_epoch=300*6//30, # 总计1800张图片,每次30张,所以需要60次可以遍历一遍
epochs=3,
validation_data=validation_generator,
validation_steps=150*6//30) # save the model
model.save('six_class_cnn.h5') # show train data acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss'] epochs = range(1, len(acc) + 1) plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend() plt.figure() plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend() plt.show()
  1. model = models.Sequential(): 进行AI模型的构建(寻找函数的方式)
  2. model.compile(): 进行AI模型的编译
  3. model.summary(): 输出AI模型的详细信息
  4. model.fit(): 进行模型的训练(函数寻找)
  5. model.save(): 将训练过后的模型保存(函数最终模式)

1800张训练图片,6个分类。遍历3遍(epoch=3)进行训练。最后输出训练过程的图片。

遍历次数越多,找到的模型预测结果越准确,但是如果数据或算法不好,预测的结果准确率会有上限。

  • 这里因为时间关系,就只遍历了3遍,遍历次数越多,时间越长!
  • 如果需要更好的效果,可以将 设置 epoch=50

2.6 项目构建

  1. 首先将上述代码保存为:train_cnn.py

  2. 接着将 train_cnn.py 放到: AI_FOOD/food/train_cnn.py 也就是与 foodData 文件夹同一级目录。

  3. 直接运行该文件即可!最后得到模型,之后直接拿这个模型预测即可!

3 Python Flask AI 上 web

Flask是一个Python的后端轻量框架,非常简单以及轻简。

3.1 Flask环境搭建以及文件结构

  • 首先下载 Flask

    • >>pip install Flask -i https://pypi.tuna.tsinghua.edu.cn/simple 从清华那里把这个python组件给下载回来。
  • 文件结构

AI_FOOD/web
|___static
|__Image:存放上传后的图片
|__CSS:存放bootstrap.min.css样式文件
|__templates
|__index.html:前端模板
|__six_class_cnn.h5:训练好的模型
|__predict.py:预测脚本
|__index.py:后端代码

3.2 后端代码

# index.py
import os
import urllib.request
import time
from flask import Flask, flash, request, redirect, url_for, render_template
from werkzeug.utils import secure_filename
from predict import predict app = Flask(__name__) app.config["SECRET_KEY"] = 'TPmi4aLWRbyVq8zu9v82dWYW1'
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif']) def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS @app.route('/')
def upload_form():
return render_template('index.html') @app.route('/', methods=['POST'])
def upload_image():
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No image selected for uploading')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = str(int(time.time())) + secure_filename(file.filename)
file.save(os.path.join("static/Image", filename))
# print('upload_image filename: ' + filename)
class_names = ['cat', 'dog', 'humberger', 'ice-cream', 'pizza', 'tart']
type_class, outputs = predict(os.path.join("static/Image", filename))
flash('Image successfully uploaded and displayed below')
return render_template('index.html', filename=filename, type_class=type_class, outputs=outputs, class_names=class_names)
else:
flash('Allowed image types are -> png, jpg, jpeg, gif')
return redirect(request.url) @app.route('/display/<filename>')
def display_image(filename):
print('display_image filename: ' + filename)
return redirect(url_for('static', filename='Image/'+filename), code=301) if __name__ == '__main__':
# 运行本项目,host=0.0.0.0可以让其他电脑也能访问到该网站,port指定访问的端口。默认的host是127.0.0.1,port为5000
app.run(host='0.0.0.0',port=9000)

3.3 前端代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="{{url_for('static', filename='CSS/'+'bootstrap.min.css')}}">
<title>Document</title>
</head>
<body> <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarColor01">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link active" href="#">Home
<span class="visually-hidden">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Dropdown</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Separated link</a>
</div>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-sm-2" type="text" placeholder="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</div>
</nav> <div class="container-fluid">
<div class="row">
<div class="col-md-4">
<!-- space -->
</div>
<div class="col-md-4">
<!-- space -->
<h2>Select a file to upload</h2>
<p>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</p>
{% if filename %}
<div>
<img src="{{ url_for('display_image', filename=filename) }}">
</div>
<div>
<h1>{{type_class}}</h1>
</div> <ul> {% for i in range(6) %}
<li>{{ class_names[i]}}:{{outputs[0][i]*100}}</li>
{% endfor %}
</ul>
{% endif %}
<!-- space -->
<form method="post" action="/" enctype="multipart/form-data">
<fieldset>
<div class="form-group">
<label for="formFile" class="form-label mt-4">Choose an Image!</label>
<input class="form-control" type="file" id="formFile" name="file" autocomplete="off" required> <p></p>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 75%;"></div>
</div>
<p></p>
<input type="submit" class="btn btn-primary">
</div>
</fieldset>
</form> <p></p> </div>
<div class="col-md-4">
<!-- space -->
</div>
</div>
</div> </body>
</html>

3.4 css样式代码

https://bootswatch.com/5/sketchy/bootstrap.min.css

保存并放置在相应文件夹。

3.5 预测代码

predict.py

import tensorflow as tf
from PIL import Image
import numpy as np def predict(filename):
model = tf.keras.models.load_model("six_class_cnn.h5") # {'donut': 0, 'hamburger': 1, 'ice-cream': 2, 'pizza': 3, 'rice': 4, 'tart': 5} class_names = ['donut', 'hamburger', 'ice-cream' ,'pizza', 'rice','tart']
img = Image.open(filename) # 读取图片
img = img.resize((224,224),Image.ANTIALIAS)
img = np.asarray(img) # 将图片转化为numpy的数组
outputs = model.predict(img.reshape(1, 224, 224, 3)) # 将图片输入模型得到结果
result_index = int(np.argmax(outputs))
result = class_names[result_index] # 获得对应的水果名称
acc = outputs[0][result_index]*100
print("The class is:{}, the acc is {}%".format(result, acc))
return "The class is:{}, the acc is {}%".format(result, acc), outputs if __name__ == '__main__':
predict("static/Image/16589928990.jpg")

4. 最终结果

无论如何,我们已经看到了,在当下搭建一个AI应用是多么简单,从零开始。经过数据搜集,模型训练,模型上web。1个小时足以发布到互联网。

我对深度学习特别乐观,因为即使未来十年没有进一步的技术进展,将现有算法部署到所有适用的问题上,就能够带来大多数行业的变革。深度学习就是一场革命,目前正以惊人的速度快速发展,这得益于在资源和人力上的指数式投资。从我的立场来看,未来很光明,尽管短期期望有些过于乐观。将深度学习部署到可能应用的所有领域需要超过十年的时间。__Keras 创始人

虽然现在制作非常简单。利用卷积神经网络,可以组建各个领域的图片识别应用,日常,医学影像。并以此创造出巨大的价值!

参考各大AI初创公司!几年时间,利用卷积神经网络算法,融资额度可以上达数十亿元人民币。

5. Refference

  1. 《Python 深度学习》

本文由Dba_sys创作,首发于博客园。2022.8.01

文章会随时改动,要到博客园里看偶。一些网站会爬取本文章,但是可能会有出入。

转载请注明出处哦( ̄︶ ̄)

https://www.cnblogs.com/asmurmur/

1个小时!从零制作一个! AI图片识别WEB应用!的更多相关文章

  1. ios学习-制作一个浏览图片的Demo

    一.项目要求:制作一个浏览图片的Demo,要求包含夜间模式,以及改变图片大小,能够显示不同的图片描述 二.开发步骤: 1.在storyboard上添加一个空白的View,然后添加”设置“按钮,添加im ...

  2. 制作一个顶部图片可以拉伸放大缩小效果的tableViewHeader

    最近负责公司项目个人中心的项目模块研发,首页是一个头部图片可以拉伸放大缩小效果的tableViewHeader,今天这个demo和教程我增加了模糊效果和头像缩小效果.具体效果如图: 如果这个效果是想要 ...

  3. ESP8266 鼓捣记 - 从零制作一个温湿度计

    一.前言 经过上一篇文章 <ESP8266 鼓捣记 - 入门(环境搭建) >搭建好环境后,肯定不会满足于 Hello World ,想快速做一个实际有用的东西出来,我认为温湿度计就非常合适 ...

  4. 从零构建一个简单的 Python Web框架

    为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...

  5. 一起学HTML基础-利用CSS和JavaScript制作一个切换图片的网页

    由于个人原因,不详细写步骤 思路: 一.布局 二.制作图片区和按钮区的div及颜色.边框.背景属性等 三.用PS将四张图片剪切到同一个尺寸,重叠放置在图片切换区,透明度设置为0 四.点击对应按钮时,将 ...

  6. HTML-利用CSS和JavaScript制作一个切换图片的网页

    由于个人原因,不详细写步骤 思路: 一.布局 二.制作图片区和按钮区的div及颜色.边框.背景属性等 三.用PS将四张图片剪切到同一个尺寸,重叠放置在图片切换区,透明度设置为0 四.点击对应按钮时,将 ...

  7. 百度AI图片识别

    官方文档:http://ai.baidu.com/tech/ocr/general

  8. JMeter AI图片识别接口并发量测试

    由于临时接到一个性能测试任务,测试8个独立接口在实验室环境的TPS.响应时间以及服务器性能监控如CPU.内存.IO等,没有明确具体的响应时间与并发数,需求较模糊. 1.软件.硬件环境信息:JMeter ...

  9. Android自定义view(一):制作一个最最最简单的自定义view

    转载:https://blog.csdn.net/wsyizmao/article/details/78491422 浅谈安卓自定义view(一):制作一个最最最简单的自定义view 对于安卓程序员来 ...

随机推荐

  1. 【mq】从零开始实现 mq-11-消费者消息回执添加分组信息 pull message ack groupName

    前景回顾 [mq]从零开始实现 mq-01-生产者.消费者启动 [mq]从零开始实现 mq-02-如何实现生产者调用消费者? [mq]从零开始实现 mq-03-引入 broker 中间人 [mq]从零 ...

  2. linux篇-centos7搭建apache服务器(亲测可用)

    1安装apache yum install httpd httpd-devel -y 2开启服务器 systemctl start httpd.service 3开机自启 systemctl enab ...

  3. unity---动画基础

    旧动画系统 using System.Collections; using System.Collections.Generic; using UnityEngine; public class Mo ...

  4. MUI+html5+javascript 点击事件触发页面间传值

    关于如何进行页面转跳,请看 https://www.cnblogs.com/JUNELITTLEPANDA/p/15956176.html,以下跳转方法是采用的其中一种 1-  仅适用于移动端,pc端 ...

  5. vue2升级vue3:vue2 vue-i18n 升级到vue3搭配VueI18n v9

    项目从vue2 升级vue3,VueI18n需要做适当的调整.主要是Vue I18n v8.x 到Vue I18n v9 or later 的变化,其中初始化: 具体可以参看:https://vue- ...

  6. node线上项目连接mysql出现 504 Gateway Time-Out

    var connection = mysql.createConnection({host : 'localhost',user : 'root',password : '123456',port: ...

  7. canvas简易画布

    今天学习了canvas,利用它做了一个简易版的画板,校验自己所学的知识,分享出来以供大家学习指教.先上效果图. 主要是使用了canvas的stroke和clearReact来实现画板的绘画和橡皮擦功能 ...

  8. linux shell的配置文件执行顺序

    shell配置文件的作用:初始化环境变量.设置命令提示符.指定系统命令路径等 shell配置文件分类: (1)系统级别配置文件: /etc下,比如/etc/profile./etc/bashrc (2 ...

  9. React技巧之表单提交获取input值

    正文从这开始~ 总览 在React中,通过表单提交获得input的值: 在state变量中存储输入控件的值. 在form表单上设置onSubmit属性. 在handleSubmit函数中访问输入控件的 ...

  10. 一个紧张刺激的聊天器,要不要进来看看(Python UDP网络模型)

    先来哔哔两句:(https://jq.qq.com/?_wv=1027&k=QgGWqAVF) 互联网的本质是什么?其实就是信息的交换.那么如何将自己的信息发送到其他人的电脑上呢?那就需要借助 ...