关于这篇文章
最近,我在在线学习中学习了使用 python AI 进行图像识别,因此我正在尝试使用该知识对产品进行分类。
我仍然是 python 和 AI 的初学者,所以我的第一个目标是创建可以对两种类型的产品进行分类的东西。
在那之后,我想增加分类的类型并扩展功能。
目录
0.执行环境
1. 我做了什么
2. 图像数据的收集
3.数据预处理
4. 模型定义和训练
5. 任意图像分类
6.未来展望
0.执行环境
电脑:Windows 10 家庭版
Jupyter 实验室 3.3.2
谷歌合作实验室
1. 我做了什么
作为产品示例,我使用了来自游戏厅的奖品(盒子)。
拿着手头的图拍很多张图片,分类成训练数据和测试数据。
使用训练数据学习并使用测试数据验证准确性。
使用创建的模型,我们确认了可以对任意照片进行分类的准确度。
2.图像数据采集
深度学习需要大量的训练数据。
这一次,我决定用电脑的网络摄像头拍下手头的照片。
在 jupyter lab 上运行此代码并将其保存到延时/PC。将产品放置在转盘上,转身进行 360 度拍摄。
代码
import cv2
import os
import datetime
def save_frame_camera_key(device_num, dir_path, basename, ext='jpg', delay=1, window_name='frame'):
cap = cv2.VideoCapture(device_num)
if not cap.isOpened():
return
os.makedirs(dir_path, exist_ok=True)
base_path = os.path.join(dir_path, basename)
n = 0
while True:
ret, frame = cap.read()
cv2.imshow(window_name, frame)
key = cv2.waitKey(delay) & 0xFF
if key == ord('c'):
cv2.imwrite('{}_{}.{}'.format(base_path, n, ext), frame)
n += 1
elif key == ord('q'):
break
cv2.destroyWindow(window_name)
def save_frame_camera_cycle(device_num, dir_path, basename, cycle, ext='jpg', delay=1, window_name='frame'):
cap = cv2.VideoCapture(device_num)
if not cap.isOpened():
return
os.makedirs(dir_path, exist_ok=True)
base_path = os.path.join(dir_path, basename)
n = 0
while True:
ret, frame = cap.read()
cv2.imshow(window_name, frame)
if cv2.waitKey(delay) & 0xFF == ord('q'):
break
if n == cycle:
n = 0
cv2.imwrite('{}_{}.{}'.format(base_path, datetime.datetime.now().strftime('%Y%m%d%H%M%S%f'), ext), frame)
n += 1
cv2.destroyWindow(window_name)
#save_frame_camera_key(0, 'data/temp', 'camera_capture')
save_frame_camera_cycle(0, 'data/temp', '***', 15) #***は保存するファイルに着ける名前
美少女战士月野兔
Hiroaka Himiko Toga
我从各个角度拍摄的图像都是这样的。我以一种类型的200多张作为指导。
起初我以为我会用不同的美少女战士角色来做,但我认为它们很容易分类,因为头发的颜色和包装明显不同,所以我选择了包装颜色和设计相似的那些。 。 (因为美少女战士的性格差异,我还是把名字弄错了……)
3. 数据预处理
挂载谷歌驱动器
数据处理将由 Google Colaboratory 完成。原因是您可以使用 GPU 轻松学习并快速进行。
将图片上传到 Google Drive 并挂载 Google Drive
from google.colab import drive
drive.mount('/content/drive/')
图像数据缩减
这一次,我在 MyDrive 下创建了一个名为 AI_App 的文件夹,并将其作为我的工作目录。
我将原始图像保存在 ./temp/ 中,所以首先将它们复制到 ./sample_images/。
import cv2
import os, glob
import shutil
caractors = ["usagi", "togahimiko"]
work_DIR = "/content/drive/MyDrive/AI_App/"
os.chdir(work_DIR)
# temp/caractor/下の写真データを
# test_images/caractor/へコピー
for caractor in caractors:
# テストデータ保存ディレクトリの作成
os.makedirs("./sample_images/" + caractor, exist_ok=True)
files = glob.glob('./temp/' + caractor + '/*.jpg')
print(files)
for file in files:
shutil.copy(file, './sample_images/' + caractor)
减小图像大小,以便训练不会花费太长时间。这次尺寸是150x150。您可以在视觉上看到差异的感觉的大小。
拆分为训练数据和测试数据
随机抽取50张图片作为测试数据保存到./test_images/
import os, glob
import random
# 50枚をtest_imagesに移行
os.makedirs("./test_images", exist_ok=True)
for caractor in caractors:
files = glob.glob(os.path.join(work_DIR, "sample_images/" + caractor + "/resize_*.jpg"))
random.shuffle(files)
os.makedirs('./test_images/' + caractor, exist_ok=True)
for i in range(50):
shutil.move(str(files[i]), "./test_images/" + caractor)
膨胀训练数据
我们继续学习少于 200 个剩余图像。对于深度学习,最好每种类型都有数千张图像以确保准确性,但准备成本很高,因此图像被夸大了。图像翻转、旋转、模糊等
import os
import cv2
import numpy as np
def scratch_image(img, flip=True, blur=True, rotate=True):
methods = [flip, blur, rotate]
# filp は画像上下反転
# blur はぼかし
# rotate は画像回転
# 画像のサイズ(x, y)
size = np.array([img.shape[1], img.shape[0]])
# 画像の中心位置(x, y)
center = tuple([int(size[0]/2), int(size[1]/2)])
# 回転させる角度
angle = 30
# 拡大倍率
scale = 1.0
mat = cv2.getRotationMatrix2D(center, angle, scale)
# 画像処理をする手法をNumpy配列に格納
scratch = np.array([
lambda x: cv2.flip(x, 0), # flip
lambda x: cv2.GaussianBlur(x, (15, 15), 0), # blur
lambda x: cv2.warpAffine(x, mat, img.shape[::-1][1:3]) # rotate
])
# imagesにオリジナルの画像を配列として格納
images = [img]
# 関数と画像を引数に、加工した画像を元と合わせて水増しする関数
def doubling_images(func, images):
return images + [func(i) for i in images]
for func in scratch[methods]:
images = doubling_images(func, images)
return images
for caractor in caractors:
files = glob.glob(os.path.join(work_DIR, "sample_images/" + caractor + "/resize_*.jpg"))
print(files[0])
for index, file in enumerate(files):
caractor_image = cv2.imread(file)
data_aug_list = scratch_image(caractor_image)
# 拡張した画像を出力するディレクトリを作成
os.makedirs("train_images/{}".format(caractor), exist_ok=True)
output_dir = "train_images/{}".format(caractor)
# 保存
for j, img in enumerate(data_aug_list):
cv2.imwrite("{}/{}_{}.jpg".format(output_dir, str(index).zfill(3), str(j).zfill(2)), img)
4. 模型定义和训练
在这里,我们将使用 VGG16 进行迁移学习。
提前准备
首先,存储和转换预先准备好的训练数据和测试数据。
正确的标签由 one-hot 向量表示。
import os, glob
import random
import cv2
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.utils import to_categorical
from tensorflow.keras import Input, Sequential, Model
from tensorflow.keras.models import load_model, save_model
from tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.optimizers import SGD, Adam
from keras.callbacks import ModelCheckpoint, EarlyStopping
caractors = ["usagi", "togahimiko"]
work_DIR = "/content/drive/MyDrive/AI_App/"
os.chdir(work_DIR)
num_classes = len(caractors)
image_size = 150
IMAGE_DIR_TRAIN = "train_images"
IMAGE_DIR_TEST = "test_images"
# 訓練データとテストデータをわける
X_train = []
X_test = []
y_train = []
y_test = []
# 訓練データをリストに代入
for index, caractor in enumerate(caractors):
files = glob.glob(os.path.join(IMAGE_DIR_TRAIN, caractor + "/*.jpg"))
for file in files:
image = load_img(file)
image = image.resize((image_size, image_size))
image = img_to_array(image)
X_train.append(image)
y_train.append(index)
# テストデータをリストに代入
for index, caractor in enumerate(caractors):
files = glob.glob(os.path.join(IMAGE_DIR_TEST, caractor + "/*.jpg"))
for file in files:
image = load_img(file)
image = image.resize((image_size, image_size))
image = img_to_array(image)
X_test.append(image)
y_test.append(index)
# テストデータと訓練データをシャッフル
p = list(zip(X_train, y_train))
random.shuffle(p)
X_train, y_train = zip(*p)
q = list(zip(X_test, y_test))
random.shuffle(q)
X_test, y_test = zip(*q)
# Numpy配列に変換
X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)
# データの正規化
X_train = X_train / 255.0
X_test = X_test / 255.0
# One-hot表現
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)
模型定义
由于是迁移学习,VGG16有一个全连接层,dropout,和一个输出层的连接。
# VGG16のインスタンスの生成
input_tensor = Input(shape=(150, 150, 3))
vgg16 = VGG16(include_top=False, weights="imagenet", input_tensor=input_tensor)
# モデルの生成
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation="relu"))
top_model.add(Dropout(0.5))
top_model.add(Dense(128, activation="relu"))
top_model.add(Dropout(0.5))
top_model.add(Dense(num_classes, activation="softmax"))
# モデルの結合
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
# model.summary()
# 15層目までのパラメータを固定
for layer in model.layers[:15]:
layer.trainable = False
# モデルのコンパイル
optimizer = SGD(learning_rate=1e-4, momentum=0.9)
model.compile(optimizer=optimizer, loss="categorical_crossentropy", metrics=["accuracy"])
# モデルの学習
batch_size = 32
epochs = 30
# EaelyStoppingの設定
early_stopping = EarlyStopping(
monitor='val_loss',
min_delta=0.0,
patience=3,
)
history = model.fit(X_train,
y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(X_test, y_test),
callbacks=[early_stopping]
)
scores = model.evaluate(X_test, y_test, verbose=1)
学习
history = model.fit(X_train,
y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(X_test, y_test),
callbacks=[early_stopping]
)
scores = model.evaluate(X_test, y_test, verbose=1)
# モデルの保存
model.save("./model.h5")
确认学习结果
结果是...
# 可視化
fig = plt.figure(figsize=(15,5))
plt.subplots_adjust(wspace=0.4, hspace=0.6)
ax1 = fig.add_subplot(1, 2, 1)
ax1.plot(history.history["accuracy"], c="b", label="acc")
ax1.plot(history.history["val_accuracy"], c="r", label="val_acc")
ax1.set_xlabel("epochs")
ax1.set_ylabel("accuracy")
plt.legend(loc="best")
ax2 = fig.add_subplot(1, 2, 2)
ax2.plot(history.history["loss"], c="b", label="loss")
ax2.plot(history.history["val_loss"], c="r", label="val_loss")
ax2.set_xlabel("epochs")
ax2.set_ylabel("loss")
plt.legend(loc="best")
fig.show()
这是结果。
准确度很高,因为它都是在转盘上打开的所有相似图像。
5. 任意图像分类
所以,我试图看看它对智能手机拍摄的图像进行分类的能力如何。
我将尝试使用两种不同的背景,一种是普通的背景,一种是杂乱的背景,这似乎更准确。
8/8 适用于纯色背景,2/4 适用于杂乱背景。不是错误的答案做出了微妙的判断,所以背景特征值似乎受到了很大的影响。
六、未来展望
这一次,我做了两个最基本的分类。
未来增加种类数量时,能保证多少准确度?似乎也可以从轮廓中提取形状,所以如果可以的话,似乎可以进行不受背景影响的高精度分类。
之后,下一步就是让实时从视频中进行分类成为可能。而且我认为能够从许多产品的图像中找出哪些产品在哪里以及有多少是很好的。
我觉得这种东西在这附近已经用过并不奇怪,但是由于这是2022/08/08的文章,我还没有真正看到介绍案例,所以使用AI的方法还是有很多种的取决于想法。这似乎是可能的。
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308628938.html