欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python +keras实现图像分类(入门级例子讲解)

程序员文章站 2022-04-08 21:49:15
一.项目描述数据集来源于kaggle猫狗大战数据集。训练集有25000张,猫狗各占一半。测试集12500张。希望计算机可以从这些训练集图片中学习到猫狗的特征,从而使得计算机可以正确的对未曾见过的猫狗图片进行分类。这就是图像分类问题,计算机视觉研究领域之一,计算机通过学习图像本身的特征将不同类别的图像区分开来。二.评价指标二分类评价指标binary_crossentropy:交叉熵只有yi和ŷ i是相等时,loss才为0,否则loss就是为一个正数。而且,概率相差越大,loss就越大。这个度量概...

一.项目描述

数据集来源于kaggle猫狗大战数据集。训练集有25000张,猫狗各占一半。测试集12500张。希望计算机可以从这些训练集图片中学习到猫狗的特征,从而使得计算机可以正确的对未曾见过的猫狗图片进行分类。这就是图像分类问题,计算机视觉研究领域之一,计算机通过学习图像本身的特征将不同类别的图像区分开来。

二.评价指标

二分类评价指标
binary_crossentropy:交叉熵
python +keras实现图像分类(入门级例子讲解)

ŷ i是样本标签,yi样本输出。只有yi和ŷ i是相等时,loss才为0,否则loss就是为一个正数。而且,概率相差越大,loss就越大。这个度量概率距离的方式称为交叉熵。
二分类模型的最后一层的激活函数 是:sigmoid
python +keras实现图像分类(入门级例子讲解)

二分类模型最后输出的是0到1的数。
应该使用numpy的四舍五入求取类别,并转换为整数
pred_y=int(np.round(predict_y))

多分类评价指标
categorical_crossentropy:分类交叉熵函数

python +keras实现图像分类(入门级例子讲解)
ŷ i是样本标签,yi样本输出
多分类模型的最后一层的激活函数 是:softmax

python +keras实现图像分类(入门级例子讲解)

softmax先把输出指数化,再归一化,得到各类概率。
假设一个问题是3分类,一个训练样本进来得到的softmax是[0.5,0.2,0.3]
假设这个正确样本类别为第一个类别。
则该样本分类交叉熵为:
python +keras实现图像分类(入门级例子讲解)

多分类模型输出的是各个类别的概率,如2个样本的预测输出为:ypred=[[0.5,0.2,0.3],[0.4,0.1,0.5]]
应该使用numpy求取最大值索引
pred=np.argmax(ypred,axis=1)
得到[0,2]

三.算例实现

数据集
电脑垃圾啦,无法将全部图片都用上,跑不动。
于是猫和狗都选取原始数据集的一半左右。
猫的图片如下:
python +keras实现图像分类(入门级例子讲解)
狗的图片如下:
python +keras实现图像分类(入门级例子讲解)

各种各样的猫和狗,不容易找到统一的图片预处理方式,如处理成二值图像(但猫狗颜色不一样,二值处理有的把背景提取出来啦,毕竟二值处理需要把前景色处理成白色,为了达到此要求,有的图片得做反二值化处理)
就对图片不做任何处理吧,防止图片失真。

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设置了尺寸

结果
预测界面:

python +keras实现图像分类(入门级例子讲解)

识别cat
python +keras实现图像分类(入门级例子讲解)
识别dog
python +keras实现图像分类(入门级例子讲解)

这个结果还不能让我满意,等我多学习下知识再来吧。

当然也可以调用摄像头,实现对摄像头下的猫狗进行实时识别。
可以参考博文然后自己修改程序。就是一个定时器作用,每隔多少时间识别下摄像头下的物体。
opencv进阶学习笔记1: 调用摄像头用法大全(打开摄像头,打开摄像头并实时不断截屏,读取视频并截图)

电气专业的计算机萌新,写博文不容易。如果你觉得本文对你有用,请点个赞再走,谢谢。

python +keras实现图像分类(入门级例子讲解)

本文地址:https://blog.csdn.net/kobeyu652453/article/details/107440224