特征提取+BP神经网络,实现对图像的分类

1.前言

这里是使用“特征提取+BP神经网络,实现对图像的分类”,需要知道的是:1.对二维图像做完标签,制作数据集后,可以用CNN(一般输入是而惟独图片)来对图像做分类的。当前,在这之前要经过对模型的训练过程。2.也可以通过特征提取先把二维图片变成一位特征,输入到BP神经网络中,进行模型训练,然后做分类。

今天,讲到的,就是第2种方式。

2.数据集制作

这里使用的是对工业金属件表面缺陷图像(有三类缺陷图像,分别是:裂纹crack,夹杂inclusion,麻点pitted )。
在这里插入图片描述

使用Hu不变矩等方法手动提取特征(一维特征),然后输入BP神经网络中做分类。

首先,使用Hu不变矩对缺陷图像进行特征提取,每一副缺陷图像产生7个特征,再加上这副图像的类别标签,就形成了数据集中的一个样本。

我们选取了夹杂、裂纹和麻点三类缺陷各100副图像,制作数据集。使用Hu不变矩进行特征提取后,就有了300个样本的特征。
在这里插入图片描述

Hu矩特征提取的代码(opencv+python)

def sys_moments(img):
    '''
    opencv_python自带求矩以及不变矩的函数
    :param img: 灰度图像,对于二值图像来说就只有两个灰度0和255
    :return: 返回以10为底对数化后的hu不变矩
    '''
    moments = cv2.moments(img)  # 返回的是一个字典,三阶及以下的几何矩(mpq)、中心矩(mupq)和归一化的矩(nupq)
    humoments = cv2.HuMoments(moments)  # 根据几何矩(mpq)、中心矩(mupq)和归一化的矩(nupq)计算出hu不变矩
    # 因为直接计算出来的矩可能很小或者很大,因此取对数好比较,这里的对数底数为e,通过对数除法的性质将其转换为以10为底的对数
    humoment = (np.log(np.abs(humoments))) / np.log(10)
    return humoment


def def_moments(img_gray):
    '''
    自定义求矩函数,主要是根据公式将一个个参数求出
    :param img_gray:  灰度图像,对于二值图像来说就只有两个灰度0和255
    :return: 返回以10为底对数化后的hu不变矩
    '''
    '''
        由于7个不变矩的变化范围很大,为了便于比较,可利用取对数的方法进行数据压缩;
        同时考虑到不变矩有可能出现负值的情况,因此,在取对数之前先取绝对值
        经修正后的不变矩特征具有平移 、旋转和比例不变性
    '''
    # 标准矩定义为m_pq = sumsum(x^p * y^q * f(x, y))其中f(x,y)为像素点处的灰度值
    row, col = img_gray.shape
    # 计算图像的0阶几何矩
    m00 = img_gray.sum()
    ##初始化一到三阶几何矩
    # 计算一阶矩阵
    m10 = m01 = 0
    # 计算图像的二阶、三阶几何矩
    m11 = m20 = m02 = m12 = m21 = m30 = m03 = 0
    for i in range(row):
        m10 += (i * img_gray[i]).sum()  # sum表示将一行的灰度值进行相加
        m20 += (i ** 2 * img_gray[i]).sum()
        m30 += (i ** 3 * img_gray[i]).sum()
        for j in range(col):
            m11 += i * j * img_gray[i][j]
            m12 += i * j ** 2 * img_gray[i][j]
            m21 += i ** 2 * j * img_gray[i][j]
    for j in range(col):
        m01 += (j * img_gray[:, j]).sum()
        m02 += (j ** 2 * img_gray[:, j]).sum()
        m30 += (j ** 3 * img_gray[:, j]).sum()
    # 由标准矩我们可以得到图像的"重心"
    u10 = m10 / m00
    u01 = m01 / m00
    # 计算图像的二阶中心矩、三阶中心矩
    y00 = m00
    y10 = y01 = 0
    y11 = m11 - u01 * m10
    y20 = m20 - u10 * m10
    y02 = m02 - u01 * m01
    y30 = m30 - 3 * u10 * m20 + 2 * u10 ** 2 * m10
    y12 = m12 - 2 * u01 * m11 - u10 * m02 + 2 * u01 ** 2 * m10
    y21 = m21 - 2 * u10 * m11 - u01 * m20 + 2 * u10 ** 2 * m01
    y03 = m03 - 3 * u01 * m02 + 2 * u01 ** 2 * m01
    # 计算图像的归一化中心矩
    n20 = y20 / m00 ** 2
    n02 = y02 / m00 ** 2
    n11 = y11 / m00 ** 2
    n30 = y30 / m00 ** 2.5
    n03 = y03 / m00 ** 2.5
    n12 = y12 / m00 ** 2.5
    n21 = y21 / m00 ** 2.5
    # 计算图像的七个不变矩
    h1 = n20 + n02
    h2 = (n20 - n02) ** 2 + 4 * n11 ** 2
    h3 = (n30 - 3 * n12) ** 2 + (3 * n21 - n03) ** 2
    h4 = (n30 + n12) ** 2 + (n21 + n03) ** 2
    h5 = (n30 - 3 * n12) * (n30 + n12) * ((n30 + n12) ** 2 - 3 * (n21 + n03) ** 2) + (3 * n21 - n03) * (n21 + n03) \
         * (3 * (n30 + n12) ** 2 - (
            n21 + n03) ** 2)
    h6 = (n20 - n02) * ((n30 + n12) ** 2 - (n21 + n03) ** 2) + 4 * n11 * (n30 + n12) * (n21 + n03)
    h7 = (3 * n21 - n03) * (n30 + n12) * ((n30 + n12) ** 2 - 3 * (n21 + n03) ** 2) + (3 * n12 - n30) * (n21 + n03) \
         * (3 * (n30 + n12) ** 2 - (
            n21 + n03) ** 2)
    inv_m7 = [h1, h2, h3, h4, h5, h6, h7]
    humoments = np.log(np.abs(inv_m7))
    return humoments
def main():
    img = cv2.imread('3.png', 0)
    sys_humoments = sys_moments(img)
    #def_humoments = sys_moments(img)
    print('Hu不变矩为:\n', sys_humoments)
    #print('自定义函数:\n', def_humoments)


if __name__ == '__main__':
    main()

这里提供了两个Hu的实现,一个opencv中封装的,一个手动实现的。建议读者使用opencv中封装的。

为何Hu矩可以作为特征提取的一个方法,因为Hu矩具有不变性的特点(Hu不变矩,Hu.M.K在1962年证明了它们具有平移,尺度(缩放)和旋转不变性,参考论文:Visual pattern recognition by moment invariants)。既然具有不变性,就可以作为图像分类的依据。
在这里插入图片描述

从实验中,可以看出对一副图像做平移,尺度,旋转变换后,这7个值很接近。表明Hu矩的不变性。

3.使用tensortflow搭建BP网络

这里只附上代码,不做具体讲解,读者有疑问可评论区留言。

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import random
from sklearn.preprocessing import MinMaxScaler

from tensorflow.python.client import device_lib
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

Lables = {
    
    0: 'crack',
          1: 'inclusion',
          2: 'pitted'}


def print_history(history):
    # 绘制训练 & 验证的准确率值
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model accuracy&loss')
    # plt.title('Model loss')
    plt.xlabel('Epoch')
    plt.legend(['Train_acc', 'Val_acc', 'Train_loss', 'Val_loss'])
    # plt.legend(['Train_loss', 'Val_loss'])
    plt.show()


def BP1(lr):
    model = tf.keras.models.Sequential([
        tf.keras.layers.Dense(5, activation='sigmoid', input_shape=(7,)),
        tf.keras.layers.Dense(3, activation='softmax')
    ])
    model.build(input_shape=(None, 7))

    model.compile(loss='categorical_crossentropy',
                  optimizer=tf.keras.optimizers.Adam(lr),
                  metrics=['accuracy'])

    return model


if __name__ == '__main__':
    # 这里是数据和标签,数据的shape是7,标签one-hot,shape是3

    data = []
    # 读取数据
    raw = pd.read_csv('Hu.csv')
    raw_data = raw.values
    raw_feature = raw_data[:, 0:7]

    # 数据归一化
    scaler = MinMaxScaler()
    scaler.fit(raw_feature)
    scaler.data_max_
    raw_feature = scaler.transform(raw_feature)

    # 将最后一列的缺陷类别转成one-hot编码形式
    x = []
    y = []
    for i in range(len(raw_feature)):
        x.append(list(raw_feature[i]))
        if raw_data[i][9] == 'crack':
            y.append([1, 0, 0])
        elif raw_data[i][9] == 'inclusion':
            y.append([0, 1, 0])
        else:
            y.append([0, 0, 1])


    # 随机打乱数据
    x = np.array(x)
    y = np.array(y)
    permutation = np.random.permutation(len(x))
    x = x[permutation]
    y = y[permutation]
    # 选取打乱后的前240个数据作为训练数据和验证数据
    train_data = x[0:240]
    train_label = y[0:240]
    # 选取打乱后的后60个作为测试数据
    test_data = x[240:]
    test_label = y[240:]


    lr = 0.001  #学习率初值,可动态下降
    bp_model = BP1(lr=lr)

    bp_model.summary()

    #学子率动态衰减
    lr_reducer = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss',
                                                      factor=0.8, patience=5,
                                                      min_lr=0.5e-6)

    # 早停法,保存训练中的最优参数
    es = tf.keras.callbacks.EarlyStopping(monitor='val_loss', mode='min',
                                          verbose=0, patience=100, min_delta=0.0001,
                                          restore_best_weights='True')

    history = bp_model.fit(train_data, train_label, batch_size=10, epochs=10000, verbose=1,
                           callbacks=[lr_reducer, es], validation_split=0.25, shuffle=False)

    # 画出四条曲线(训练集和验证集的loss和accuracy缺陷)
    print_history(history)
    # 训练好的模型,在测试集上的准确率
    print('loss, acc:', bp_model.evaluate(test_data, test_label, batch_size=10, verbose=0))

这里数据集、验证集和测试集采用6:2:2的比例划分,总共300个样本

实现结果:
在这里插入图片描述
在这里插入图片描述

使用Early Stopping在训练集和验证集上accuracy和loss曲线

数据和代码:百度网盘
提取码:tian
–来自百度网盘超级会员V7的分享

如果这篇文章帮助到你了,那就点个赞,给个关注吧!

猜你喜欢

转载自blog.csdn.net/t18438605018/article/details/121664082