使用計算機視覺在鋼鐵平面上檢測焊接缺陷
點擊上方“小白學視覺”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達
本文轉自:機器學習算法那些事
導讀
借助卷積神經網絡算法和U-Net結構,可以準確地檢測出鋼鐵平面的焊接故障,還能評估它的嚴重程度。本文即介紹了這一檢測方法,并給出了3個樣本結果。
焊接缺陷可以定義為焊縫表面出現(xiàn)的不規(guī)則、不連續(xù)性、缺陷或不一致性。焊接接頭的缺陷可能導致零件和組件的報廢、昂貴的維修費用、工作條件下性能的顯著降低,在極端情況下,還可能導致導致財產和生命損失的災難性故障。
此外,由于焊接工藝本身的缺陷和金屬本身的特性,在焊接過程中總會存在一定的缺陷。評估焊接質量是很重要的,因為由于固有的冶金幾何缺陷、機械性能的不均一性和殘余應力的存在,焊接接頭經常是裂紋萌生的位置。
在實踐中,幾乎不可能得到完美的焊接,而且在大多數情況下,也沒有必要提供所需的足夠的服務功能。然而,及早發(fā)現(xiàn)和隔離總是比發(fā)生事故更可取。
利用我們的算法,我們可以很容易地檢測出焊接故障的圖像,并準確地衡量每一個故障的嚴重程度。這將進一步幫助更快的圖像識別和避免不良情況的出現(xiàn)。
結果表明,采用卷積神經網絡算法和U-Net結構,可以大大提高處理效率。結果在工作結束時,準確率達到98.3%。
對機器學習有基本了解 卷積神經網絡的基本思想 理解卷積,最大池化和上采樣操作 了解U-Net的架構理念 對殘差塊中skip連接有基本了解(可選) 使用Python、TensorFlow和Keras庫操作ConvNets的知識(可選)
分割是將圖像分割成不同的區(qū)域,這些區(qū)域包含具有相似屬性的像素。為了對圖像分析和解釋有意義和有用,區(qū)域應該與描繪的物體或感興趣的特征有強烈的關聯(lián)。
圖像分析的成功與否取決于分割的可靠性,但圖像的精確分割通常是一個非常具有挑戰(zhàn)性的問題。

分割后的胸部x光片,心臟(紅色)、肺(綠色)和鎖骨(藍色)
圖像矩是圖像像素強度的某一特定加權平均值。圖像矩用于描述分割后的目標。
通過圖像矩發(fā)現(xiàn)的圖像的簡單屬性包括:
面積(或總強度) 重心 關于方向的信息
dataset包含兩個目錄。原始圖像存儲在‘images’目錄中,分割后的圖像存儲在‘labels’目錄中。
讓我們將數據可視化:

來自‘image’的原始圖像

來自‘labels’的二值圖像
這些來自“l(fā)abels”目錄的圖像是二進制圖像或ground truth標簽。這是我們的模型必須對給定的原始圖像做出的預測。在二進制圖像中,像素要么有一個“high”值,要么有一個“l(fā)ow”值。白色區(qū)域或“high”值表示缺陷區(qū)域,黑色區(qū)域或“l(fā)ow”值表示沒有缺陷。
我們在這個問題上使用的架構是U-Net。我們將通過三個步驟來檢測故障并測量這些焊接圖像的嚴重程度:
圖像分割 使用顏色表示嚴重程度 使用圖像矩度量嚴重程度
下面是我們用于模型的U-Net架構:

使用的U-Net結構
要注意的點:
每個藍框對應一個多通道特征圖
通道的數量在盒子的頂部表示
(x,y)維度顯示在盒子的左下邊緣
箭頭表示不同的操作
層的名稱在層的下面
C1 C2…C7是卷積操作后的輸出層
P1, P2, P3是最大池化操作的輸出層
U1, U2, U3是上采樣操作的輸出層
A1, A2, A3是跳躍連接
左側是收縮路徑,應用常規(guī)卷積和最大池操作
圖像的尺寸逐漸減小,而深度逐漸增加
右邊是展開路徑,在這里應用(上采樣)轉置卷積和常規(guī)卷積操作
在擴展路徑中,圖像的尺寸逐漸增大,深度逐漸減小
為了得到更精確的位置,在擴展路徑的每一步中,我們使用跳躍連接,將轉置卷積層的輸出與來自編碼器的相同級別的特征圖連接在一起:A1 = U1 + C3 A2 = U2 + C2 A3 = U3 + C1
在每次連接之后,我們再次應用常規(guī)卷積,以便模型能夠學習組裝出更精確的輸出。
import numpy as np
import cv2
import os
import random
import tensorflow as tf
h,w = 512,512
def create_model():
inputs = tf.keras.layers.Input(shape=(h,w,3))
conv1 = tf.keras.layers.Conv2D(16,(3,3),activation='relu',padding='same')(inputs)
pool1 = tf.keras.layers.MaxPool2D()(conv1)
conv2 = tf.keras.layers.Conv2D(32,(3,3),activation='relu',padding='same')(pool1)
pool2 = tf.keras.layers.MaxPool2D()(conv2)
conv3 = tf.keras.layers.Conv2D(64,(3,3),activation='relu',padding='same')(pool2)
pool3 = tf.keras.layers.MaxPool2D()(conv3)
conv4 = tf.keras.layers.Conv2D(64,(3,3),activation='relu',padding='same')(pool3)
upsm5 = tf.keras.layers.UpSampling2D()(conv4)
upad5 = tf.keras.layers.Add()([conv3,upsm5])
conv5 = tf.keras.layers.Conv2D(32,(3,3),activation='relu',padding='same')(upad5)
upsm6 = tf.keras.layers.UpSampling2D()(conv5)
upad6 = tf.keras.layers.Add()([conv2,upsm6])
conv6 = tf.keras.layers.Conv2D(16,(3,3),activation='relu',padding='same')(upad6)
upsm7 = tf.keras.layers.UpSampling2D()(conv6)
upad7 = tf.keras.layers.Add()([conv1,upsm7])
conv7 = tf.keras.layers.Conv2D(1,(3,3),activation='relu',padding='same')(upad7)
model = tf.keras.models.Model(inputs=inputs, outputs=conv7)
return model
images = []
labels = []
files = os.listdir('./dataset/images/')
random.shuffle(files)
for f in files:
img = cv2.imread('./dataset/images/' + f)
parts = f.split('_')
label_name = './dataset/labels/' + 'W0002_' + parts[1]
label = cv2.imread(label_name,2)
img = cv2.resize(img,(w,h))
label = cv2.resize(label,(w,h))
images.append(img)
labels.append(label)
images = np.array(images)
labels = np.array(labels)
labels = np.reshape(labels,
(labels.shape[0],labels.shape[1],labels.shape[2],1))
print(images.shape)
print(labels.shape)
images = images/255
labels = labels/255
model = tf.keras.models.load_model('my_model')
#model = create_model() # uncomment this to create a new model
print(model.summary())
model.compile(optimizer='adam', loss='binary_crossentropy',metrics=['accuracy'])
model.fit(images,labels,epochs=100,batch_size=10)
model.evaluate(images,labels)
model.save('my_model')
模型采用Adam優(yōu)化器進行編譯,由于只有缺陷和無缺陷兩類,我們使用二元交叉熵損失函數。
我們使用批大小為10的100 epoch(模型在所有輸入上運行的次數)。
請注意,調整這些超參數有很大的進一步提高模型性能的空間。
由于模型的輸入尺寸為512x512x3,我們將輸入尺寸調整為這個尺寸。接下來,我們將圖像歸一化,將其除以255,這樣計算速度更快。
該圖像被輸入到模型中,用于預測二進制輸出。為了放大像素的強度,二進制輸出被乘以1000。
然后將圖像轉換為16位整數,便于圖像操作。然后用算法檢測缺陷,通過顏色分級和根據缺陷的嚴重程度給有缺陷的像素分配權重,直觀地標記出缺陷的嚴重程度。然后在此圖像上考慮加權像素計算圖像矩。
最后將圖像轉換回8位整數,并顯示輸出圖像的顏色等級和嚴重性值。
import numpy as np
import cv2
from google.colab.patches import cv2_imshow
import os
import random
import tensorflow as tf
h,w = 512,512
num_cases = 10
images = []
labels = []
files = os.listdir('./dataset/images/')
random.shuffle(files)
model = tf.keras.models.load_model('my_model')
lowSevere = 1
midSevere = 2
highSevere = 4
for f in files[0:num_cases]:
test_img = cv2.imread('./dataset/images/' + f)
resized_img = cv2.resize(test_img,(w,h))
resized_img = resized_img/255
cropped_img = np.reshape(resized_img,
(1,resized_img.shape[0],resized_img.shape[1],resized_img.shape[2]))
test_out = model.predict(cropped_img)
test_out = test_out[0,:,:,0]*1000
test_out = np.clip(test_out,0,255)
resized_test_out = cv2.resize(test_out,(test_img.shape[1],test_img.shape[0]))
resized_test_out = resized_test_out.astype(np.uint16)
test_img = test_img.astype(np.uint16)
grey = cv2.cvtColor(test_img, cv2.COLOR_BGR2GRAY)
for i in range(test_img.shape[0]):
for j in range(test_img.shape[1]):
if(grey[i,j]>150 & resized_test_out[i,j]>40):
test_img[i,j,1]=test_img[i,j,1] + resized_test_out[i,j]
resized_test_out[i,j] = lowSevere
elif(grey[i,j]<100 & resized_test_out[i,j]>40):
test_img[i,j,2]=test_img[i,j,2] + resized_test_out[i,j]
resized_test_out[i,j] = highSevere
elif(resized_test_out[i,j]>40):
test_img[i,j,0]=test_img[i,j,0] + resized_test_out[i,j]
resized_test_out[i,j] = midSevere
else:
resized_test_out[i,j] = 0
M = cv2.moments(resized_test_out)
maxMomentArea = resized_test_out.shape[1]*resized_test_out.shape[0]*highSevere
print("0th Moment = " , (M["m00"]*100/maxMomentArea), "%")
test_img = np.clip(test_img,0,255)
test_img = test_img.astype(np.uint8)
cv2_imshow(test_img)
cv2.waitKey(0)
我們用于檢測嚴重程度的視覺度量是顏色。
在圖像中,顏色:
綠色表示有嚴重缺陷的區(qū)域。 藍色代表缺陷較嚴重的區(qū)域。 紅色區(qū)域表示最嚴重的缺陷。
0階矩作為一個百分比顯示在輸出圖像上作為一個經驗的嚴重程度度量。
下面是三個隨機樣本,分別顯示了我們模型生成的原始輸入、ground truth和輸出。
樣本1::

原始圖像

二值圖像(Ground Truth)

帶有嚴重程度的預測輸出
樣本2:

原始圖像

二值圖像(Ground Truth)

帶有嚴重程度的預測輸出
樣本3:

原始圖像

二值圖像(Ground Truth)


