一.项目描述
数据集来源于kaggle猫狗大战数据集。训练集有25000张,猫狗各占一半。测试集12500张。希望计算机可以从这些训练集图片中学习到猫狗的特征,从而使得计算机可以正确的对未曾见过的猫狗图片进行分类。这就是图像分类问题,计算机视觉研究领域之一,计算机通过学习图像本身的特征将不同类别的图像区分开来。
二.评价指标
二分类评价指标
binary_crossentropy:交叉熵
ŷ i是样本标签,yi样本输出。只有yi和ŷ i是相等时,loss才为0,否则loss就是为一个正数。而且,概率相差越大,loss就越大。这个度量概率距离的方式称为交叉熵。
二分类模型的最后一层的激活函数 是:sigmoid
二分类模型最后输出的是0到1的数。
应该使用numpy的四舍五入求取类别,并转换为整数
pred_y=int(np.round(predict_y))
多分类评价指标
categorical_crossentropy:分类交叉熵函数
ŷ i是样本标签,yi样本输出
多分类模型的最后一层的激活函数 是:softmax
softmax先把输出指数化,再归一化,得到各类概率。
假设一个问题是3分类,一个训练样本进来得到的softmax是[0.5,0.2,0.3]
假设这个正确样本类别为第一个类别。
则该样本分类交叉熵为:
多分类模型输出的是各个类别的概率,如2个样本的预测输出为:ypred=[[0.5,0.2,0.3],[0.4,0.1,0.5]]
应该使用numpy求取最大值索引
pred=np.argmax(ypred,axis=1)
得到[0,2]
三.算例实现
数据集
电脑垃圾啦,无法将全部图片都用上,跑不动。
于是猫和狗都选取原始数据集的一半左右。
猫的图片如下:
狗的图片如下:
各种各样的猫和狗,不容易找到统一的图片预处理方式,如处理成二值图像(但猫狗颜色不一样,二值处理有的把背景提取出来啦,毕竟二值处理需要把前景色处理成白色,为了达到此要求,有的图片得做反二值化处理)
就对图片不做任何处理吧,防止图片失真。
1数据集读取函数
注意:cv2.imread(name) 图片路径不能含有中文。
#个人喜好用OpenCV
需要对图片统一大小: cv2.resize(img, (100, 100))
import os
import numpy as np
import cv2
def ReFileName(dirPath):
"""
:param dirPath: 文件夹路径
:return:
"""
# 对目录下的文件进行遍历
x=[]
for file in os.listdir(dirPath):
# 判断是否是文件
if os.path.isfile(os.path.join(dirPath, file)) == True:
c= os.path.basename(file)
name = dirPath + '\\' + c
img = cv2.imread(name)
img = cv2.resize(img, (100, 100)) # 使尺寸大小一样
x.append(img)
return x
2数据集读取并处理
分别读取猫狗数据集,之前我将猫和狗放在两个文件夹啦。
对数据除以255,cnn模型对数值小的数处理得比较好。
转换数据格式,图像格式为np.uint8, 转换成float型,计算机可以计算。
标签处理,猫处理成1,狗处理成0
dirPathcat = r"catdog\cat"#文件路径
cat=ReFileName(dirPathcat)#调用函数
cat=np.array(cat)/255
cat=cat.astype(np.float64)
print('输入cat.shape',cat.shape)
biaoqiancat=[1 for i in range(len(cat))]#标签处理
biaoqiancat=np.array(biaoqiancat)#标签
dirPathdog = r"catdog\dog"#文件路径
dog=ReFileName(dirPathdog)#调用函数
dog=np.array(dog)/255#数据
dog=dog.astype(np.float64)
biaoqiandog=[0 for i in range(len(dog))]#标签处理
biaoqiandog=np.array(biaoqiandog)#标签
3.数据打乱
首先拼接数据集,然后打乱数据集特征和标签。
如果是多分类问题得在打乱数据前对y进行one-hot化,如:
y=keras.utils.to_categorical(y,4)#四分类
x=np.concatenate((cat,dog),axis=0)
y=np.concatenate((biaoqiancat,biaoqiandog),axis=0)
index = [i for i in range(len(y))] # test_data为测试数据
np.random.seed(1)
np.random.shuffle(index) # 打乱索引
train_data = x[index]
train_label = y[index]
4.定义模型
电脑不行,就用个普通模型跑吧。
如果是多分类问题
最后两行为
model.add(Dense(2, activation='softmax')) # 输出层
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
本文模型
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
import keras
import time
def define_model():
model = Sequential()
model.add(Conv2D(filters=16,
kernel_size=(5, 5),
padding='same',
input_shape=(100, 100, 3),
activation='relu')) # 卷积层1
model.add(MaxPooling2D(pool_size=(2, 2))) # 池化层2
model.add(Dropout(0.25))
model.add(Flatten()) # 平坦层
model.add(Dense(10,activation='relu')) # 隐藏层
model.add(Dense(1, activation='sigmoid')) # 输出层
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
model.summary()
return model
5.模型训练并保持
准确率0.7072,之前使用的是猫狗各3000多张,准确率为0.5。
现在使用的是各6000多张,准确率0.7。
原始数据集有各12000多张,原谅我,使用全部数据集电脑太卡,没服务器,学生党。
start_time = time.time()
model = define_model()
model.fit(train_data, train_label, epochs=2)
model.save('猫狗分类.h5')
end_time = time.time()
run_time = (end_time - start_time) / 60
print(run_time) #3.931485986709595
print('训练结束')
#0.7072
四.pyqt可视化结果
建立个简单版的qt猫狗预测系统吧。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: yudengwu
# @Date : 2020/7/18
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import cv2
import keras
from keras .models import load_model
import numpy as np
import re
class picture(QWidget):
def __init__(self):
super(picture, self).__init__()
self.resize(600, 400)
self.setWindowTitle("猫狗分类")
self.btn = QPushButton()
self.btn.setText("打开图片")
self.btn.clicked.connect(self.openimage)
self.label = QLabel()
self.label.setText('图片路径')
self.labelimage = QLabel()
self.labelimage.setText("显示图片")
#self.labelimage.setFixedSize(500, 400)#设置尺寸
self.labelimage.setStyleSheet("QLabel{background:white;}"
"QLabel{color:rgb(300,300,300,120);font-size:10px;font-weight:bold;font-family:宋体;}"
)
#预测按钮
self.btnclass=QPushButton()
self.btnclass.setText('点击预测分类')
self.btnclass.clicked.connect(self.fenlei)
self.labelclass=QLabel()
self.labelclass.setText('预测类别')
self.labelclass.setStyleSheet("font:16pt '楷体';border-width:2px;border-style: inset;border-color:gray")
layout1=QVBoxLayout()
layout1.addWidget(self.btn)
layout1.addWidget(self.label)
layout1.addWidget(self.labelimage)
layout2 = QVBoxLayout()
layout2.addWidget(self.btnclass)
layout2.addWidget(self.labelclass)
layout=QVBoxLayout()
layout.addLayout(layout1)
layout.addLayout(layout2)
self.setLayout(layout)
def openimage(self):
imgName, imgType = QFileDialog.getOpenFileName(self, "打开图片", "", "*.jpg;;*.png;;All Files(*)")
#jpg = QtGui.QPixmap(imgName).scaled(self.labelimage.width(), self.label.height())#适应labelimage尺寸,前提是label设置了尺寸
jpg = QtGui.QPixmap(imgName)
self.labelimage.setPixmap(jpg)
self.label.setText(str(imgName))
def fenlei(self):
biaoqian = {'1': '猫', '0': '狗'}
path=self.label.text()
newName = re.sub('(D:/机器学习/学习草稿/)','', path)
print(newName)
img = cv2.imread(str(newName))
img = cv2.resize(img, (100, 100)) # 使尺寸大小一样
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = np.array(img) / 255
img = img.astype(np.float64)
img = img.reshape(-1, 100, 100, 1)
model = load_model('猫狗分类.h5')
predict_y = model.predict(img)
pred_y = int(np.round(predict_y))
print(pred_y)
self.labelclass.setText(biaoqian[str(pred_y)])
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
my = picture()
my.show()
sys.exit(app.exec_())
说明:
newName = re.sub(’(D:/机器学习/学习草稿/)’,’’, path)
这是因为我图片放在了当前项目文件夹里,导致图片绝对路径含有中文,cv.imread()会出错,我去除掉中文部分,使模型读取相对路径
如果你要读取任意文件夹里的图片,要使图片绝对路径无中文。
可以固定图片显示尺寸;
#self.labelimage.setFixedSize(500, 400)#设置尺寸
#jpg = QtGui.QPixmap(imgName).scaled(self.labelimage.width(), self.label.height())#适应labelimage尺寸,前提是label设置了尺寸
结果
预测界面:
识别cat
识别dog
这个结果还不能让我满意,等我多学习下知识再来吧。
当然也可以调用摄像头,实现对摄像头下的猫狗进行实时识别。
可以参考博文然后自己修改程序。就是一个定时器作用,每隔多少时间识别下摄像头下的物体。
opencv进阶学习笔记1: 调用摄像头用法大全(打开摄像头,打开摄像头并实时不断截屏,读取视频并截图)