一、缺陷检测~使用深度学习1

这里研究工业ai, 在制造业中任何公司的主要目标都是为客户生产无缺陷产品。如果在产品开发过程中出现任何内部孔、凹坑、磨损或划痕(由于多种原因,从生产设备故障到恶劣的工作条件),其结果不仅是产品缺陷,而且导致客户满意度的损失。在本文中,您将了解可用于识别缺陷的各种深度学习方法,从而防止缺陷产品流入市场。

深度学习是如何工作的?

深度学习是一种机器学习,其特点是使用神经元或数据计算流经的节点。深度学习神经元之所以如此命名,是因为它们最初被建模为以类似于人脑中神经元的结构发送和接收信号。神经元接收一个或多个输入信号(要么来自原始数据,要么来自模型前一层的神经元),对这些输入信号进行一些计算,然后(通过突触)将输出信号发送到神经网络深处的神经元。通过这种方式,这些模型模仿了人类大脑如何学习检测、识别和分类周围环境中的项目,并做出非线性决策。最初的神经网络设计非常简单(或“肤浅”),但今天的架构已经变得极其复杂,现在被称为“深层”神经网络。

然而,深度神经网络不仅仅是一堆神经层。考虑一层作为单个神经元的外壳。这些层将始终以输入层开始(接收数据),以输出层结束(产生结果)。此外,在神经网络中,可以有零个或多个隐藏层堆叠在一起。层架构的类型包括但不限于密集(或完全连接)、卷积、反褶积和递归。然而,单独添加额外的层并不足以解决更复杂的问题,事实上可能会带来额外的挑战和潜在的错误。

必须根据需要解决的问题提出多种技术。存在不同形式的深度神经网络,每种网络都以不同的方式和不同的算法来解决问题。

图像分析-在分析图像时,更需要查看像素定义的事物层次,而不是单独查看每个像素。卷积网络使用称为卷积层的神经元的特定层,通常用于解释、编码或生成图片。由于许多卷积层的叠加,检测图片中更复杂的分层模式是可能的。卷积层越深,生成的特征图越抽象。

51c~缺陷检测~合集2_视觉

文本处理——文本分类、情感分析、自动翻译和语言建模概念是文本数据处理的一些最常见的深度学习用例。在某些情况下,例如分类,神经网络的表现几乎和人类一样好。然而,在某些工作中,神经网络仍然远远不能与人类进行比较,例如情绪分析等。 

51c~缺陷检测~合集2_视觉_02

自动编码器-自动编码器的目标是能够完全解构并重建输入数据。重建需要使用中间压缩表示,因此神经网络的表示必须具有足够的信息来进行此生成。自动编码器的压缩表示随后可用于各种任务,例如分类。

51c~缺陷检测~合集2_缺陷检测_03

生成对抗网络-它们已被有效地用于黑白照片的着色、增强图像分辨率和重建部分擦除的图像等。然而,GAN陡峭的学习曲线限制了他们的潜力,这似乎非常有前景。它主要用于医学图像,以提高图像性能,并使人们更容易发现疾病。

51c~缺陷检测~合集2_缺陷检测_04

深度学习缺陷检测技术

物体识别、智能机器人、显著性检测、停车场声音事件检测和无人机叶片问题诊断只是受益于深度学习技术的众多学科中的几个例子。有时,可以通过抽象表示或奇异特征(如边缘和梯度)更好地解释数据。深度学习模型结合了这些低级特征,以构建属性和特征的更抽象的高级表示,并提高模型的性能。利用这些核心概念,一些学者正在尝试将深度学习技术应用于产品缺陷的识别,以提高产品质量。

1.LeNet,卷积神经网络(CNN)

CNN代表“卷积神经网络”,是具有一个或多个卷积层的任何前馈神经网络,但也可能包含完全连接的层、池化层、ReLU校正层等。最初的卷积神经网络结构之一是LeNet框架,它可以识别手写字符。

在这里,我们将探讨使用LeNet模型结构原理来检测缺陷的两种方法。一种是创建复杂的多层CNN结构,使用不同的网络结构添加图像内容特征,并完成端到端训练以检测图像中的缺陷。

2.基于神经网络的产品缺陷检测工具

AutoEncoder网络的编码和解码阶段是最重要的。这是一种数据压缩技术,其中压缩和解压缩功能是从样本数据中自动学习的,而不是由人类编程的。在编码阶段将输入信号转换为用于特征提取的编码信号;特征信息在解码阶段被转换为重建信号,并且通过调整权重和偏置来最小化重建误差,以在解码阶段实现缺陷检测。

AutoEncoder网络与其他机器学习技术的区别在于,AutoEncode器网络的学习目标是特征学习,而不是分类。它还具有卓越的自学能力,能够进行极为非线性的映射。为了处理分割复杂背景和前景区域的挑战,它可以学习非线性度量函数。

3.深度残差神经网络产品故障检测技术

深度残差网络向卷积神经网络添加残差模块。残差网络具有简单的优化过程,并且可以通过增加网络深度来提高精度。生成对抗网络、CNN等。提取特征随着网络深度的增加而改善,然而,激活函数可能无法收敛。深度残差网络的目标是在增长网络结构的同时优化网络层的数量,使得残差单元中卷积层的输出和输入元素维度相同。

4.全卷积神经网络

当两个相邻层中的所有节点都连接时,该层称为密集层或完全连接层。由于完全连接的神经网络采用完全连接的操作,因此将有更多的权重值,这意味着网络将需要更多的内存和计算。在构建完全连接的神经网络期间,卷积层创建的特征图被映射为固定长度的特征向量。整个卷积神经网络可以拍摄任何大小的输入图片,通过用去卷积层对最后一个卷积层的特征图进行采样,可以恢复到与原始图像相同的大小。   

实 施

下面,我们实施图像处理技术,这些技术产生的输出类似于深度学习网络可能产生的卷积神经网络中的特征图。

import numpy as np
import cv2
import matplotlib.pyplot as plt

接下来,将创建一个函数,使用图像处理来检测缺陷,以显示不同形式的图像,如hsv、binay、dst、扩张等。

def fab_defect_detect(img):
   image = img.copy()    
   hsv = cv2.cvtColor(image,cv2.COLOR_BGR2HSV)    
   h = hsv[:,:,0]    
   s = hsv[:,:,1]    
   v = hsv[:,:,2]
   
   blr = cv2.blur(v,(16,16))    
   dst = cv2.fastNlMeansDenoising(blr,None,10,7,22)    
    _,binary = cv2.threshold(dst, 127,256,cv2.THRESH_BINARY+cv2.THRESH_OTSU)    kernel = np.ones((5,5),np.uint8)    
    erosion = cv2.erode(binary,kernel,iterations = 1)    
   dilation = cv2.dilate(binary,kernel,iterations = 1)    
   if(dilation==0).sum() >1:        
       print("Fabric has a defect")        
       contours,_=cv2.findContours(dilation,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
       for i in contours:
           if cv2.contourArea(i) < 261124.0:                
                cv2.drawContours(image, i, -1, (0,255,0), 3)             
             else:                  
                  print("There is No Defect in Fabric")      
       return img,hsv,v,blr,dst,binary,dilation,image

最后,使用以下命令生成输出。

input_img= cv2.imread('Fabric1.jpg')
image,hsv,v,blr,dst,binary,dilation,img = defect_detect(input_img)
fig, ax = plt.subplots(2,4,figsize=(16,12))
ax[0,0].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
ax[0,0].set_title('Original Image')
ax[0,1].imshow(cv2.cvtColor(hsv, cv2.COLOR_BGR2RGB))
ax[0,1].set_title('HSV Image')
ax[0,2].imshow(cv2.cvtColor(v, cv2.COLOR_BGR2RGB))
ax[0,2].set_title('V Image')
ax[0,3].imshow(cv2.cvtColor(blr, cv2.COLOR_BGR2RGB))
ax[0,3].set_title('Blur Image')
ax[1,0].imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
ax[1,0].set_title('Filter Image')ax[1,1].imshow(binary,cmap='gray')
ax[1,1].set_title('Binary Image')ax[1,2].imshow(dilation,cmap='gray')
ax[1,2].set_title('Dilation Image')
ax[1,3].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
ax[1,3].set_title('Output Image')fig.tight_layout()

输 出 

以下是以与第一张原始图像不同的格式生成的图像。

51c~缺陷检测~合集2_缺陷检测_05

结 论

在本文中,我们了解了什么是深度学习,它是如何工作的,以及我们可以使用什么技术来检测产品中的缺陷,同时学习了如何使用图像处理来检测图像中的缺陷。





二、缺陷检测~深度学习2


缺陷检测被广泛使用于布匹瑕疵检测、工件表面质量检测、航空航天领域等。传统的算法对规则缺陷以及场景比较简单的场合,能够很好工作,但是对特征不明显的、形状多样、场景比较混乱的场合,则不再适用。近年来,基于深度学习的识别算法越来越成熟,许多公司开始尝试把深度学习算法应用到工业场合中。

缺陷数据

如下图所示,这里以布匹数据作为案例,常见的有以下三种缺陷,磨损、白点、多线。

51c~缺陷检测~合集2_视觉_06

51c~缺陷检测~合集2_缺陷检测_07

 

51c~缺陷检测~合集2_视觉_08

 

如何制作训练数据呢?这里是在原图像上进行截取,截取到小图像,比如上述图像是512x512,这里我裁剪成64x64的小图像。这里以第一类缺陷为例,下面是制作数据的方法。

51c~缺陷检测~合集2_视觉_09

 

51c~缺陷检测~合集2_视觉_10

 

注意:在制作缺陷数据的时候,缺陷面积至少占截取图像的2/3,否则舍弃掉,不做为缺陷图像。

一般来说,缺陷数据都要比背景数据少很多,此外通过增强后的数据,缺陷:背景=1:1,每类在1000幅左右~~~

网络结构

具体使用的网络结构如下所示,输入大小就是64x64x3,采用的是截取的小图像的大小。每个Conv卷积层后都接BN层,具体层参数如下所示。

Conv1:64x3x3
Conv2:128x3x3
ResNetBlock和DenseNetBlock各两个,具体细节请参考残差网络和DenseNet。
Add:把残差模块输出的结果和DenseNetBlock输出的结果在对应feature map上进行相加,相加方式和残差模块相同。注意,其实这里是为了更好的提取特征,方式不一定就是残差模块+DenseNetBlock,也可以是inception,或者其它。
Conv3:128x3x3
Maxpool:stride=2,size=2x2
FC1:4096
Dropout1:0.5
FC2:1024
Dropout1:0.5
Softmax:对应的就是要分的类别,在这里我是二分类。

51c~缺陷检测~合集2_视觉_11

关于最后的损失函数,建议选择Focal Loss,这是何凯明大神的杰作,源码如下所示: 

51c~缺陷检测~合集2_缺陷检测_12

数据做好,就可以开始训练了~~~

整幅场景图像的缺陷检测

上述训练的网络,输入是64x64x3的,但是整幅场景图像却是512x512的,这个输入和模型的输入对不上号,这怎么办呢?其实,可以把训练好的模型参数提取出来,然后赋值到另外一个新的模型中,然后把新的模型的输入改成512x512就好,只是最后在conv3+maxpool层提取的feature map比较大,这个时候把feature map映射到原图,比如原模型在最后一个maxpool层后,输出的feature map尺寸是8x8x128,其中128是通道数。如果输入改成512x512,那输出的feature map就成了64x64x128,这里的每个8x8就对应原图上的64x64,这样就可以使用一个8x8的滑动窗口在64x64x128的feature map上进行滑动裁剪特征。然后把裁剪的特征进行fatten,送入到全连接层。具体如下图所示。

全连接层也需要重新建立一个模型,输入是flatten之后的输入,输出是softmax层的输出。这是一个简单的小模型。

51c~缺陷检测~合集2_缺陷检测_13

在这里提供一个把训练好的模型参数,读取到另外一个模型中的代码

#提取特征的大模型
def read_big_model(inputs):
   # 第一个卷积和最大池化层
   X = Conv2D(16, (3, 3), name="conv2d_1")(inputs)
   X = BatchNormalization(name="batch_normalization_1")(X)
   X = Activation('relu', name="activation_1")(X)
   X = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name="max_pooling2d_1")(X)
   # google_inception模块
   conv_1 = Conv2D(32, (1, 1), padding='same', name='conv2d_2')(X)
   conv_1 = BatchNormalization(name='batch_normalization_2')(conv_1)
   conv_1 = Activation('relu', name='activation_2')(conv_1)
   conv_2 = Conv2D(32, (3, 3), padding='same', name='conv2d_3')(X)
   conv_2 = BatchNormalization(name='batch_normalization_3')(conv_2)
   conv_2 = Activation('relu', name='activation_3')(conv_2)
   conv_3 = Conv2D(32, (5, 5), padding='same', name='conv2d_4')(X)
   conv_3 = BatchNormalization(name='batch_normalization_4')(conv_3)
   conv_3 = Activation('relu', name='activation_4')(conv_3)
   pooling_1 = MaxPooling2D(pool_size=(2, 2), strides=(1, 1), padding='same', name='max_pooling2d_2')(X)
   X = merge([conv_1, conv_2, conv_3, pooling_1], mode='concat', name='merge_1')
   X = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='max_pooling2d_3')(X)  # 这里的尺寸变成16x16x112
   X = Conv2D(64, (3, 3), kernel_regularizer=regularizers.l2(0.01), padding='same', name='conv2d_5')(X)
   X = BatchNormalization(name='batch_normalization_5')(X)
   X = Activation('relu', name='activation_5')(X)
   X = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='max_pooling2d_4')(X)  # 这里尺寸变成8x8x64
   X = Conv2D(128, (3, 3), padding='same', name='conv2d_6')(X)
   X = BatchNormalization(name='batch_normalization_6')(X)
   X = Activation('relu', name='activation_6')(X)
   X = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='same', name='max_pooling2d_5')(X)  # 这里尺寸变成4x4x128

return X

def read_big_model_classify(inputs_sec):
   X_ = Flatten(name='flatten_1')(inputs_sec)
   X_ = Dense(256, activation='relu', name="dense_1")(X_)
   X_ = Dropout(0.5, name="dropout_1")(X_)
   predictions = Dense(2, activation='softmax', name="dense_2")(X_)
   return predictions
#建立的小模型

inputs=Input(shape=(512,512,3))
X=read_big_model(inputs)#读取训练好模型的网络参数
#建立第一个model
model=Model(inputs=inputs, outputs=X)
model.load_weights('model_halcon.h5', by_name=True)
识别定位结果

上述的滑窗方式可以定位到原图像,8x8的滑窗定位到原图就是64x64,同样,在原图中根据滑窗方式不同(在这里选择的是左右和上下的步长为16个像素)识别定位到的缺陷位置也不止一个,这样就涉及到定位精度了。在这里选择投票的方式,其实就是对原图像上每个被标记的像素位置进行计数,当数字大于指定的阈值,就被判断为缺陷像素。

识别结果如下图所示:

51c~缺陷检测~合集2_缺陷检测_14

51c~缺陷检测~合集2_视觉_15

51c~缺陷检测~合集2_缺陷检测_16

 一些Trick

对上述案例来说,其实64x64大小的定位框不够准确,可以考虑训练一个32x32大小的模型,然后应用方式和64x64的模型相同,最后基于32x32的定位位置和64x64的定位位置进行投票,但是这会涉及到一个问题,就是时间上会增加很多,要慎用。

对背景和前景相差不大的时候,网络尽量不要太深,因为太深的网络到后面基本学到的东西都是相同的,没有很好的区分能力,这也是我在这里为什么不用object detection的原因,这些检测模型网络,深度动辄都是50+,效果反而不好,虽然有残差模块作为backbone。

但是对背景和前景相差很大的时候,可以选择较深的网络,这个时候,object detection方式就派上用场了。