1. 程式人生 > 程式設計 >基於OpenCV的路面質量檢測的實現

基於OpenCV的路面質量檢測的實現

本期我們將展示一種對路面型別和質量進行分類的方法及其步驟。為了測試這種方法,我們使用了我們製作的RTK資料集。

基於OpenCV的路面質量檢測的實現

路面分類

該資料集[1]包含用低成本相機拍攝的影象,以及新興國家常見的場景,其中包含未鋪砌的道路和坑窪。路面型別是有關人或自動駕駛車輛應如何駕駛的重要資訊。除了乘客舒適度和車輛維護以外,它還涉及每個人的安全。我們可以通過[2]中的簡單卷積神經網路(CNN)結構來實現。

基於OpenCV的路面質量檢測的實現

在這種方法中,我們對錶面型別分類任務使用特定的模型,我們將其定義為以下類別:瀝青,已鋪設(用於所有其他型別的路面)和未鋪設。對於表面質量,我們使用其他三種不同的模型,每種型別的表面都使用一種。這四個模型都具有相同的結構。我們從第一個模型中得出結果,並稱為特定質量模型。

在CNN結構之前,將感興趣區域(ROI)定義為每個輸入幀的預處理步驟。畢竟,我們不需要整個影象來對道路進行分類。ROI旨在僅保留影象中實際包含道路畫素的部分。影象的上半部分以及影象底部的一小部分都將被丟棄,因為在某些幀中,它可能包含負責捕獲影象的部分車輛。ROI採用硬編碼,因為如果我們使用自適應ROI,它可能會導致失敗並損害模型訓練。

基於OpenCV的路面質量檢測的實現

在此預處理之後執行資料擴充步驟。資料增強包括增加和減少每幀的亮度。這樣,我們可以改進訓練輸入集,並幫助我們的系統學習識別具有不同照明條件的相同型別和質量的道路。

最後,將輸入影象傳遞到包含三個卷積層和兩個完全連線層的CNN結構。

基於OpenCV的路面質量檢測的實現

01.RTK資料集

資料集包含具有不同型別的表面和質量的影象。

基於OpenCV的路面質量檢測的實現

可從以下位置下載RTK資料集:

http://www.lapix.ufsc.br/pesquisas/projeto-veiculo-autonomo/datasets/?lang=zh-CN

02.路面型別分類

我們使用了Python,TensorFlow和OpenCV。

讓我們逐步分析一下…

首先,我們需要建立表面型別分類模型。為此,您將需要準備資料以訓練模型。您可以使用RTK資料集中的影象或製作自己的影象。影象需要按地面道路型別進行組織。

基於OpenCV的路面質量檢測的實現

訓練資料資料夾結構

在我們的實驗中,我們使用了6264幀:

l鋪砌(瀝青):4344,用於柏油馬路。

l鋪砌的(混凝土的):1337用於不同的人行道,例如鵝卵石。

l未鋪砌:585用於未鋪砌,土路,越野。

接下來,在train.py中,定義從何處收集訓練資料。我們應該將20%的資料分開以自動用於驗證。我們還定義了batch_size為32。

classes = os.listdir('training_data')
num_classes = len(classes)


batch_size = 32
validation_size = 0.2
img_size = 128
num_channels = 3
train_path='training_data'

在train.py上設定的引數將在dataset.py類上讀取。

data = dataset.read_train_sets(train_path,img_size,classes,validation_size=validation_size)

在dataset.py類中,我們定義了ROI和資料擴充。帶有資料解釋功能的兩個函式,Adjust_gamma可以降低亮度,而Adjust_gammaness可以提高亮度。

def adjust_gamma(image):
 gamma = 0.5
 invGamma = 1.0 / gamma
 table = np.array([((i / 255.0) ** invGamma) * 255 
 for i in np.arange(0,256)]).astype("uint8")


 return cv2.LUT(image,table)


def increase_brightness(img,value):
 hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
 h,s,v = cv2.split(hsv)


 lim = 255 - value
 v[v > lim] = 255
 v[v <= lim] += value


 final_hsv = cv2.merge((h,v))
 img = cv2.cvtColor(final_hsv,cv2.COLOR_HSV2BGR)


 return img

載入輸入資料時,將為每個影象定義ROI。

for fields in classes:
 index = classes.index(fields)
 print('Now going to read {} files (Index: {})'.format(fields,index))
 path = os.path.join(train_path,fields,'*g')
 files = glob.glob(path)
 for fl in files:
 image = cv2.imread(fl)


 # Region Of Interest (ROI)
 height,width = image.shape[:2]
 newHeight = int(round(height/2))
 image = image[newHeight-5:height-50,0:width]


 brght_img = increase_brightness(image,value=150)


 shaded_img = adjust_gamma(image)


 image = cv2.resize(image,(image_size,image_size),cv2.INTER_LINEAR)
 image = image.astype(np.float32)
 image = np.multiply(image,1.0 / 255.0)


 brght_img = cv2.resize(brght_img,cv2.INTER_LINEAR)
 brght_img = brght_img.astype(np.float32)
 brght_img = np.multiply(brght_img,1.0 / 255.0)


 shaded_img = cv2.resize(shaded_img,cv2.INTER_LINEAR)
 shaded_img = shaded_img.astype(np.float32)
 shaded_img = np.multiply(brght_img,1.0 / 255.0)

我們還會平衡輸入影象,因為瀝青的影象更多,而未鋪砌和未鋪砌的道路更少。

if index == 0: #asphalt
 images.append(image)
 images.append(brght_img)
 images.append(shaded_img)
elif index == 1: #paved
 for i in range(3):
 images.append(image)
 images.append(brght_img)
 images.append(shaded_img)
elif index == 2: #unpaved
 for i in range(6):
 images.append(image)
 images.append(brght_img)
 images.append(shaded_img)

回到train.py,讓我們定義TensorFlow教程[2]中所示的CNN層。所有選擇到訓練步驟的影象都將傳遞到第一卷積層,其中包含有關通道的寬度,高度和數量的資訊。前兩層包含32個大小為3x3的濾鏡。緊接著是一個具有3x3大小的64個濾鏡的圖層。所有的步幅都定義為1,填充的定義為0。正態分佈用於權重初始化。為了在尺寸上減少輸入,這有助於分析輸入子區域中的特徵資訊,在所有卷積層中應用了最大池。在每個卷積層的末尾,在最大合併功能之後,將ReLU用作啟用功能。

def create_convolutional_layer(input,num_input_channels,conv_filter_size,num_filters):


 weights = create_weights(shape=[conv_filter_size,num_filters])
 biases = create_biases(num_filters)


 layer = tf.nn.conv2d(input=input,filter=weights,strides=[1,1,1],padding='SAME')


 layer += biases


 layer = tf.nn.max_pool(value=layer,ksize=[1,2,padding='SAME')


 layer = tf.nn.relu(layer)

在卷積層之後,平坦層用於將卷積多維張量轉換為一維張量。

def create_flatten_layer(layer):
 layer_shape = layer.get_shape()


 num_features = layer_shape[1:4].num_elements()


 layer = tf.reshape(layer,[-1,num_features])


 return layer

最後新增兩個完全連線的層。在第一個完全連線的層中,應用了ReLU啟用功能。第二個完全連線的層具有可能的輸出,所需的類別。

def create_fc_layer(input,num_inputs,num_outputs,use_relu=True):


 weights = create_weights(shape=[num_inputs,num_outputs])
 biases = create_biases(num_outputs)


 layer = tf.matmul(input,weights) + biases
 if use_relu:
 layer = tf.nn.relu(layer)


 return layer

我們使用softmax函式來實現每個類的概率。最後,我們還使用Adam優化器,該優化器根據訓練中使用的輸入資料更新網路權重。

layer_conv1 = create_convolutional_layer(input=x,num_input_channels=num_channels,conv_filter_size=filter_size_conv1,num_filters=num_filters_conv1)


layer_conv2 = create_convolutional_layer(input=layer_conv1,num_input_channels=num_filters_conv1,conv_filter_size=filter_size_conv2,num_filters=num_filters_conv2)


layer_conv3= create_convolutional_layer(input=layer_conv2,num_input_channels=num_filters_conv2,conv_filter_size=filter_size_conv3,num_filters=num_filters_conv3)


layer_flat = create_flatten_layer(layer_conv3)


layer_fc1 = create_fc_layer(input=layer_flat,num_inputs=layer_flat.get_shape()[1:4].num_elements(),num_outputs=fc_layer_size,use_relu=True)


layer_fc2 = create_fc_layer(input=layer_fc1,num_inputs=fc_layer_size,num_outputs=num_classes,use_relu=False) 


y_pred = tf.nn.softmax(layer_fc2,name='y_pred')


y_pred_cls = tf.argmax(y_pred,dimension=1)
session.run(tf.global_variables_initializer())
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=layer_fc2,labels=y_true)
cost = tf.reduce_mean(cross_entropy)
optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(cost)
correct_prediction = tf.equal(y_pred_cls,y_true_cls)
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

可以python train.py在終端中訓練模型的執行:

現在,有了經過訓練的模型,我們就可以測試。首先,讓我們準備好接收輸入測試幀和輸出檔名。

outputFile = sys.argv[2]


# Opening frames
cap = cv.VideoCapture(sys.argv[1])


vid_writer = cv.VideoWriter(outputFile,cv.VideoWriter_fourcc('M','J','P','G'),15,(round(cap.get(cv.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv.CAP_PROP_FRAME_HEIGHT))))

檢索訓練好的模型並訪問圖形。

sess = tf.Session()
saver = tf.train.import_meta_graph('roadsurface-model.meta')
saver.restore(sess,tf.train.latest_checkpoint('./'))


graph = tf.get_default_graph()


y_pred = graph.get_tensor_by_name("y_pred:0")


x = graph.get_tensor_by_name("x:0")
y_true = graph.get_tensor_by_name("y_true:0")
y_test_images = np.zeros((1,len(os.listdir('training_data'))))

請記住,我們不需要整個影象,我們的培訓著重於使用ROI,在這裡我們也使用它。

width = int(round(cap.get(cv.CAP_PROP_FRAME_WIDTH)))
height = int(round(cap.get(cv.CAP_PROP_FRAME_HEIGHT)))


newHeight = int(round(height/2))


while cv.waitKey(1) < 0:


 hasFrame,images = cap.read()


 finalimg = images


 images = images[newHeight-5:height-50,0:width]
 images = cv.resize(images,cv.INTER_LINEAR)
 images = np.array(images,dtype=np.uint8)
 images = images.astype('float32')
 images = np.multiply(images,1.0/255.0)

最後,基於輸出預測,我們可以在每幀中列印分類的表面型別。

x_batch = images.reshape(1,image_size,num_channels)


feed_dict_testing = {x: x_batch,y_true: y_test_images}
result = sess.run(y_pred,feed_dict=feed_dict_testing)


outputs = [result[0,0],result[0,2]]


value = max(outputs)
index = np.argmax(outputs)


if index == 0:
 label = 'Asphalt'
 prob = str("{0:.2f}".format(value))
 color = (0,0)
elif index == 1:
 label = 'Paved'
 prob = str("{0:.2f}".format(value))
 color = (153,102,102)
elif index == 2:
 label = 'Unpaved'
 prob = str("{0:.2f}".format(value))
 color = (0,153,255)


cv.rectangle(finalimg,(0,0),(145,40),(255,255,255),cv.FILLED)
cv.putText(finalimg,'Class: ',(5,15),cv.FONT_HERSHEY_SIMPLEX,0.5,1)
cv.putText(finalimg,label,(70,color,prob,35),1)


vid_writer.write(finalimg.astype(np.uint8))

可以測試在終端中執行的模型:python test.py PATH_TO_YOUR_FRAMES_SEQUENCE NAME_YOUR_VIDEO_FILE.avi。

03.路面質量分類

現在讓我們包括質量分類。我們僅使用用於訓練表面型別分類模型的相同CNN架構,並分別在每個表面類別上應用每個質量類別。因此,除了現有模型外,我們還培訓了3種新模型。為此,大家將需要準備用於訓練每個表面類別的模型的資料。在RTK資料集頁面中,我們已經給出了按班級組織的框架。

基於OpenCV的路面質量檢測的實現

用於質量課程的培訓資料資料夾結構

要訓練每種模型,小夥伴們可以在終端中執行:

python trainAsphaltQuality.py 
python trainPavedQuality.py 
python trainUnpavedQuality.py

現在,預測部分發生了什麼變化。我們使用四個不同的圖,每個訓練模型一個。

graph = tf.Graph()
graphAQ = tf.Graph()
graphPQ = tf.Graph()
graphUQ = tf.Graph()

04.模型恢復

恢復型別模型

with graph.as_default():
 saver = tf.train.import_meta_graph('roadsurfaceType-model.meta')


 y_pred = graph.get_tensor_by_name("y_pred:0")


 x = graph.get_tensor_by_name("x:0")
 y_true = graph.get_tensor_by_name("y_true:0")
 y_test_images = np.zeros((1,len(os.listdir('training_data_type'))))


sess = tf.Session(graph = graph)
saver.restore(sess,tf.train.latest_checkpoint('typeCheckpoint/'))

恢復瀝青質量模型

with graphAQ.as_default():
 saverAQ = tf.train.import_meta_graph('roadsurfaceAsphaltQuality-model.meta')


 y_predAQ = graphAQ.get_tensor_by_name("y_pred:0")


 xAQ = graphAQ.get_tensor_by_name("x:0")
 y_trueAQ = graphAQ.get_tensor_by_name("y_true:0")
 y_test_imagesAQ = np.zeros((1,len(os.listdir('training_data_asphalt_quality'))))


sessAQ = tf.Session(graph = graphAQ)
saverAQ.restore(sessAQ,tf.train.latest_checkpoint('asphaltCheckpoint/'))

恢復鋪砌的質量模型

with graphPQ.as_default():
 saverPQ = tf.train.import_meta_graph('roadsurfacePavedQuality-model.meta')


 y_predPQ = graphPQ.get_tensor_by_name("y_pred:0")


 xPQ = graphPQ.get_tensor_by_name("x:0")
 y_truePQ = graphPQ.get_tensor_by_name("y_true:0")
 y_test_imagesPQ = np.zeros((1,len(os.listdir('training_data_paved_quality'))))


sessPQ = tf.Session(graph = graphPQ)
saverPQ.restore(sessPQ,tf.train.latest_checkpoint('pavedCheckpoint/'))

恢復未鋪砌的質量模型

with graphUQ.as_default():
 saverUQ = tf.train.import_meta_graph('roadsurfaceUnpavedQuality-model.meta')


 y_predUQ = graphUQ.get_tensor_by_name("y_pred:0")


 xUQ = graphUQ.get_tensor_by_name("x:0")
 y_trueUQ = graphUQ.get_tensor_by_name("y_true:0")
 y_test_imagesUQ = np.zeros((1,len(os.listdir('training_data_unpaved_quality'))))


sessUQ = tf.Session(graph = graphUQ)
saverUQ.restore(sessUQ,tf.train.latest_checkpoint('unpavedCheckpoint/'))

此時,輸出預測也要考慮質量模型,我們可以在每個幀中列印分類的表面型別以及該表面的質量。

if index == 0: #Asphalt
  label = 'Asphalt'
  prob = str("{0:.2f}".format(value))
  color = (0,0)
  x_batchAQ = images.reshape(1,num_channels)


  feed_dict_testingAQ = {xAQ: x_batchAQ,y_trueAQ: y_test_imagesAQ}
  resultAQ = sessAQ.run(y_predAQ,feed_dict=feed_dict_testingAQ)
  outputsQ = [resultAQ[0,resultAQ[0,2]]
  valueQ = max(outputsQ)
  indexQ = np.argmax(outputsQ)
  if indexQ == 0: #Asphalt - Good
   quality = 'Good'
   colorQ = (0,0)
   probQ = str("{0:.2f}".format(valueQ))
  elif indexQ == 1: #Asphalt - Regular
   quality = 'Regular'
   colorQ = (0,204,255)
   probQ = str("{0:.2f}".format(valueQ))
  elif indexQ == 2: #Asphalt - Bad
   quality = 'Bad'
   colorQ = (0,255)
   probQ = str("{0:.2f}".format(valueQ)) 
 elif index == 1: #Paved
  label = 'Paved'
  prob = str("{0:.2f}".format(value))
  color = (153,102)
  x_batchPQ = images.reshape(1,num_channels)


  feed_dict_testingPQ = {xPQ: x_batchPQ,y_truePQ: y_test_imagesPQ}
  resultPQ = sessPQ.run(y_predPQ,feed_dict=feed_dict_testingPQ)
  outputsQ = [resultPQ[0,resultPQ[0,2]]
  valueQ = max(outputsQ)
  indexQ = np.argmax(outputsQ)
  if indexQ == 0: #Paved - Good
   quality = 'Good'
   colorQ = (0,0)
   probQ = str("{0:.2f}".format(valueQ))
  elif indexQ == 1: #Paved - Regular
   quality = 'Regular'
   colorQ = (0,255)
   probQ = str("{0:.2f}".format(valueQ))
  elif indexQ == 2: #Paved - Bad
   quality = 'Bad'
   colorQ = (0,255)
   probQ = str("{0:.2f}".format(valueQ))
 elif index == 2: #Unpaved
  label = 'Unpaved'
  prob = str("{0:.2f}".format(value))
  color = (0,255)
  x_batchUQ = images.reshape(1,num_channels)


  feed_dict_testingUQ = {xUQ: x_batchUQ,y_trueUQ: y_test_imagesUQ}
  resultUQ = sessUQ.run(y_predUQ,feed_dict=feed_dict_testingUQ)
  outputsQ = [resultUQ[0,resultUQ[0,1]]
  valueQ = max(outputsQ)
  indexQ = np.argmax(outputsQ)
  if indexQ == 0: #Unpaved - Regular
   quality = 'Regular'
   colorQ = (0,255)
   probQ = str("{0:.2f}".format(valueQ))
  elif indexQ == 1: #Unpaved - Bad
   quality = 'Bad'
   colorQ = (0,255)
   probQ = str("{0:.2f}".format(valueQ))

列印結果

cv.rectangle(finalimg,80),cv.FILLED)
cv.putText(finalimg,cv.FONT_HERSHEY_DUPLEX,0))
cv.putText(finalimg,color)
cv.putText(finalimg,'Quality: ',55),quality,colorQ)
cv.putText(finalimg,probQ,75),0))

大家可以在終端中測試執行情況:python testRTK.py PATH_TO_YOUR_FRAMES_SEQUENCE NAME_YOUR_VIDEO_FILE.avi。

一些結果樣本:

基於OpenCV的路面質量檢測的實現

致謝

lThiago Rateke<< span="">[email protected]>

lKarla Aparecida Justen<< span="">[email protected]>

lAldo von Wangenheim<< span="">[email protected]>

參考文獻

[1] T. Rateke,K. A. Justen and A. von Wangenheim,Road Surface Classification with Images Captured From Low-cost Cameras — Road Traversing Knowledge (RTK) Dataset,(2019),Revista de Informática Teórica e Aplicada (RITA)

[2] A. Sachan,Tensorflow Tutorial 2: image classifier using convolutional neural network,(2017),CV-Tricks.com

到此這篇關於基於OpenCV的路面質量檢測的文章就介紹到這了,更多相關基於OpenCV的路面質量檢測內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!