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)
humoments = cv2.HuMoments(moments)
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个不变矩的变化范围很大,为了便于比较,可利用取对数的方法进行数据压缩;
同时考虑到不变矩有可能出现负值的情况,因此,在取对数之前先取绝对值
经修正后的不变矩特征具有平移 、旋转和比例不变性
'''
row, col = img_gray.shape
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()
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)
print('Hu不变矩为:\n', sys_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.xlabel('Epoch')
plt.legend(['Train_acc', 'Val_acc', '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__':
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)
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]
train_data = x[0:240]
train_label = y[0:240]
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)
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的分享
如果这篇文章帮助到你了,那就点个赞,给个关注吧!
|