【参考视频网址:】https://space.bilibili.com/45151802/video
(老师讲的特别好,良心推荐)
【dog数据集下载:】https://download.csdn.net/download/weixin_41874898/11434095
【github代码下载:】https://github.com/Seasea77/keras_small_project_19_07_26
文章目录
1 准备工作
1.1 文件目录
Raw_img存放收集的四种狗狗,分别放到不同的文件夹,每类180张。(事先创建好,并放好图片)
Resize_img存放Raw_img统一大小后的图片(不用创建,程序检测如果没有会自动创建)
test_img存放测试图片,用于测试训练模型(事先创建好,并放好图片(我放了4张))
dog.h5是生成的h5模型文件
keras_dog_cnn_train.py用于训练模型
keras_dog_cnn_train.py用于测试图片
1.2 continue
# image文件夹下面有:1.jpg 2.jpg 3.jpg 4.jpg 5.jpg
import os
for i in os.listdir("image"):
if i == "3.jpg":
continue # 如果进入循环,跳过下面的步骤
print(i)
# 1.jpg 2.jpg 4.jpg 5.jpg
1.3 读取和写入中文名图片
import cv2
import numpy as np
import os
# 写入中文名图片,路径和图片中只要包含中文都要用这个
def cv_imwrite(file_path, frame):
cv2.imencode('.jpg', frame)[1].tofile(file_path)
# 读取中文名图片
def cv_imread(filePath):
cv_img = cv2.imdecode(np.fromfile(filePath, dtype=np.uint8), -1)
return cv_img
# img = cv2.imread("4.jpg") # 读进来是None,文件有问题
# img = cv_imread("11_11_N_11_德国牧羊犬0.jpg") # 读中文使用这个cv_imread
# img = cv_imread("images/Dog20/Dog20\史宾格犬/7_7_N_7_史宾格犬168.jpg")
# img = cv_imread("images/Dog20/Dog20\史宾格犬\7_7_N_7_史宾格犬168.jpg")
# 这样写会报错,但是用os.path.join()生成的不会报错
i = os.path.join("images/Dog20/Dog20\史宾格犬", "7_7_N_7_史宾格犬168.jpg") # images\Dog20\Dog20\柯基犬\2_2_N_2_柯基犬125.jpg
img = cv_imread(i) # 读中文使用这个
img_resize = cv2.resize(img, (100, 100), cv2.INTER_LINEAR)
cv2.imshow("img", img_resize)
cv2.waitKey(0)
2 代码实现
2.1 keras_dog_cnn_train.py
功能:
- 对Raw_img文件里图片重命名
- 改变Raw_img里的图片大小尺寸,保存到Resize_img文件夹里面(没有子目录)
- 训练模型,生成dog.h5文件
import os
import numpy as np
from PIL import Image
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Convolution2D, Activation, MaxPool2D, Flatten, Dense
from keras.optimizers import Adam
import shutil
# 文件重命名
File_path = "Raw_img"
Width = 100
Height = 100
Save_path = "Resize_img"
Nb_class = 4
Nb_batch_size = 64
Nb_epochs = 20
class PreImage(object):
"""
File_path是未处理照片路径
Save_path是调整大小后导出照片路径
"""
def __init__(self, File_path, Save_path, Width=100, Height=100):
self.path = File_path
self.width = Width
self.height = Height
self.save_path = Save_path
# 1图片重命名
def ImageRename(self):
File_sub_path_list = os.listdir(self.path)
path_counter = 0
for File_sub_path in File_sub_path_list:
file_counter = 0
for image in os.listdir(os.path.join(self.path, File_sub_path)): #1****************************
os.rename(os.path.join(self.path, File_sub_path) + "/" + image,
os.path.join(self.path, File_sub_path) + "/" + str(path_counter) + "_" + str(file_counter) + ".jpg")
# 如果出现这次创建的文件名和rename之前的文件名名字相同,则会报错,提示文件已经存在无法创建该文件。
# os.rename(name1, name2)注意这个地方的name1是要到子root目录
file_counter = file_counter + 1
path_counter = path_counter + 1
print(">>>>>>>重命名成功>>>>>>>>")
# 2图片大小改变
def ImageResize(self):
# if os.path.exists(self.resized_path):
# shutil.rmtree(self.resized_path) # 删除文件夹,无论空不空
# # 不适用先删除文件夹指令也行,因为每一次会覆盖上一次5****************************
# # os.remove(path) # 删除文件
# # os.removedirs(path) # 删除空文件夹
# # shutil.rmtree(path) # 递归删除文件夹2****************************
for root, dirs, files in os.walk(self.path):
# root会变化,变化成图片所在的根目录,dirs是当前目录下包括的文件夹
for filename in files:
# print(os.path.join(root, filename))
image = Image.open(os.path.join(root, filename)) # 可以多路径join
image_RGB = image.convert("RGB")
image_Resize = image_RGB.resize((self.width, self.height), Image.BILINEAR)
if not os.path.exists(self.save_path):
os.mkdir(self.save_path)
# print(filename)
image_Resize.save(os.path.join(self.save_path, os.path.basename(filename)))
# 保存图片时,必须先对图片进行灰度化或者RGB化3****************************
print(">>>>>>>图片大小更改成功,保存到当前%s文件夹>>>>>>>>" % self.save_path)
class Training(object):
"""
File_path:待训练图片路径
图片输入大小固定100*100,图片种类数量可变.
"""
def __init__(self, Save_path, Nb_class, Nb_batch_size, Nb_epochs, Width=100, Height=100):
self.path = Save_path
self.nb_class = Nb_class
self.nb_batch_size = Nb_batch_size
self.nb_epochs = Nb_epochs
self.width = Width
self.height = Height
# 1提取图片矩阵
def Train(self):
# 类里面函数之间的调用,也是需要self.Train(),也是需要使用self来实现的.
Train_img_list = []
Train_label_list = []
for image in os.listdir(self.path):
img = Image.open(os.path.join(self.path, image))
image_array = np.array(img)
Train_img_list.append(image_array)
Train_label_list.append(int(image.split("_")[0])) # 此处加上一个int
Train_label_array = np.array(Train_label_list) # 网络需要传入的是numpy数组而不是list
Train_img_array = np.array(Train_img_list)
print(Train_label_array.shape)
print(Train_img_array.shape)
# Train_img_array = Train_img_array.reshape(-1, self.width, self.height, 1) # 这步骤多余.
Train_img_array = Train_img_array / 255.
print(type(Train_label_array))
Train_label_array = np_utils.to_categorical(Train_label_array, 4)
# IndexError: index 4 is out of bounds for axis 1 with size 4
# 类标号要从0开始.所以图片rename的时候应该是0开头
# 模型建立
model = Sequential()
model.add(Convolution2D(
input_shape=(100, 100, 3),
filters=32,
kernel_size=(5, 5),
padding="same"
))
model.add(Activation("relu"))
model.add(MaxPool2D(
pool_size=(2, 2),
strides=(2, 2),
padding="same"
))
model.add(Convolution2D(
filters=64,
kernel_size=(5, 5),
padding="same"
))
model.add(Activation("relu"))
model.add(MaxPool2D(
pool_size=(2, 2),
strides=(2, 2),
padding="same"
))
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation("relu"))
model.add(Dense(512))
model.add(Activation("relu"))
model.add(Dense(256))
model.add(Activation("relu"))
model.add(Dense(self.nb_class))
model.add(Activation("softmax"))
# 模型编译
adam = Adam(lr=0.001)
model.compile(
loss="categorical_crossentropy",
optimizer=adam,
metrics=["accuracy"]
)
# 模型启动
model.fit(
x=Train_img_array,
y=Train_label_array,
batch_size=self.nb_batch_size,
epochs=self.nb_epochs,
verbose=1
)
model.save("./dog.h5")
if __name__ == "__main__":
"""第一个类:预处理图片"""
DogProcess = PreImage(File_path, Save_path, Width, Height)
# # 图片重命名
DogProcess.ImageRename()
# # 图片大小尺寸改变
DogProcess.ImageResize()
"""第二个类:训练模型"""
DogTraining = Training(Save_path, Nb_class, Nb_batch_size, Nb_epochs)
DogTraining.Train()
2.2 keras_dog_cnn_predict.py
功能:加载模型,预测test_img的图片
from keras.models import load_model
from PIL import Image
import numpy as np
import os
class PredImage(object):
def __init__(self, Model_name, Test_image):
self.model_name = Model_name
self.test_image = Test_image
def Class_dog(self, prediction):
Final_prediction = np.argmax(prediction)
dog_name_list = ["哈士奇", "柯基犬", "藏獒", "金毛"]
for i in range(4):
if Final_prediction == i:
print("输出结果为:", dog_name_list[i])
def Predict(self):
model = load_model(self.model_name)
img = Image.open(self.test_image)
img_rgb = img.convert("RGB")
img_resize = img_rgb.resize((100, 100), Image.BILINEAR)
img_array = np.array(img_resize)
img_array = img_array / 255.
img_array = img_array.reshape(-1, 100, 100, 3)
prediction = model.predict(img_array)
print(prediction)
self.Class_dog(prediction)
test_dir = "./test_img"
for img in os.listdir(test_dir):
PredictImage = PredImage("dog.h5", os.path.join(test_dir, img))
PredictImage.Predict()
2.3 识别结果
(1)test_img内容为:
(2)测试结果为: