簡體   English   中英

Python OpenCV 背景減法和邊界框

[英]Python OpenCV Background Subtraction and Bounding Box

我是使用 OpenCV 的新手,因此對這個問題的替代解決方案持開放態度。 我試圖獲取印刷電路板的周邊邊界框,以從我的 RGB-D 相機中裁剪 ROI,以便僅從包含印刷電路板的區域中提取深度數據。

由於相機將是靜止的,我最初的想法是使用 cv2.subtract() 使用空背景的圖像和放置在同一背景上的印刷電路板的圖像。 輸出如下所示。

我現在不確定如何獲得 PCB 的邊界框。 當我使用 findContours 時,我獲得了 373 個不同的輪廓,我認為這是由於 PCB 組件的顏色不同,但是我只需要周長邊界框。

提前致謝。 傑頓在此處輸入圖片說明

編輯 1:img1 是背景,img2 是帶有 PCB 的圖像。 我相信主要問題是有太多的輪廓,我不確定如何選擇一個來創建周邊邊界框。

diff = cv2.subtract(img1, img2)
imgray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, 
cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
cnt = contours[0]

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(diff, (x,y), (x+w, y+h), (0,255,0),2)

我寫了一個例子,其中我:

  • 增加圖像的亮度:將圖像乘以(255/img.max())
  • 應用threshold轉換為二值圖像(黑白)
  • 應用erode來擦除小點和細小的白色元素
  • 應用dilate來減小黑洞的大小

此時,如果您感興趣的對象是唯一的白色區域,則可以使用boundingRect 不幸的是,在您的圖像中,左側的背景太亮了......然后您可以繼續:

  • 或者,應用Canny - 而不是閾值/侵蝕/擴張 - 來查找輪廓並檢索二值圖像
  • 在二值圖像上應用findContours (在下面的代碼中,我多余地使用 Canny-ed 圖像只是為了公開示例,但它可能是來自閾值/侵蝕/膨脹的二值圖像,具有類似的結果)
  • 可選地應用approxPolyDPhull來平滑輪廓(在下面的示例中,我繪制了這些操作的結果,但我實際上並沒有使用它們)
  • 計算每個輪廓的輪廓contourAreaboundingRect contourArea
  • 只返回面積最大的輪廓

結果是: 帶有輪廓的原始圖像 (紅色是boundingRect ,綠色是approxPolyDP ,藍色是hull

幾乎所有這些操作在 openCV 站點的教程部分都有工作示例。

代碼

import cv2 as cv
import numpy as np
import random as rng

src = cv.imread("1KbH6.png")
src_gray = cv.cvtColor(src,cv.COLOR_BGR2GRAY)

# adjust brightness
src_bright = cv.convertScaleAbs(src_gray, alpha = 255.0/src.max(), beta = 0)
# apply threshold
threshold = 100
_, img_thresh = cv.threshold(src_bright, threshold, 255, 0)
# apply erode
erosion_size = 7
erosion_type = cv.MORPH_ELLIPSE
element = cv.getStructuringElement(erosion_type, (2*erosion_size + 1, 2*erosion_size+1), (erosion_size, erosion_size))
img_erosion = cv.erode(img_thresh, element)
# apply dilate
dilatation_size = 17
dilatation_type = cv.MORPH_ELLIPSE
element = cv.getStructuringElement(dilatation_type, (2*dilatation_size + 1, 2*dilatation_size+1), (dilatation_size, dilatation_size))
img_dilate = cv.dilate(img_erosion, element)

# apply canny and find contours
threshold = 100
canny_output = cv.Canny(img_dilate, threshold, threshold * 2)
contours = cv.findContours(canny_output, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

# apply approxPolyDP, hull, boundingRect and calculate areas for each contour
contours_poly = [None]*len(contours[1])
boundRect = [None]*len(contours[1])
areas = [None]*len(contours[1])
hull_list = []
for i, c in enumerate(contours[1]):
    contours_poly[i] = cv.approxPolyDP(c, 3, True)
    hull_list.append(cv.convexHull(contours[1][i]))
    boundRect[i] = cv.boundingRect(contours_poly[i])
    areas[i] = cv.contourArea(c)

# set drawing 
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
# draw only the contour with the greatest area
i = areas.index(max(areas))
color = (0,0,255)
cv.drawContours(drawing, contours_poly, i, (0,255,0),2)
cv.drawContours(drawing, hull_list, i, (255,0,0),2)
cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \
  (int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), (0,0,255), 3)

# # Alternatively, you can draw contours with area bigger than some value
# for i in range(len(contours[1])):
#     if areas[i] > 1000:
#         color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
#         cv.drawContours(drawing, contours_poly, i, color)
#         cv.drawContours(drawing, hull_list, i, color)
#         cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \
#           (int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2)

cv.imwrite('new.png',cv.add(drawing,src))
cv.imshow('blend',cv.add(drawing,src))
cv.waitKey()

# # If you want to see partial results of image processing
# cv.imshow('src', src)
# cv.imshow('src_bright', src_bright)
# cv.imshow('img_thresh', img_thresh)
# cv.imshow('img_erosion', img_erosion)
# cv.imshow('img_dilate', img_dilate)
# cv.imshow('canny_output', canny_output)
# cv.imshow('drawing',drawing)

備選:色度鍵

另一種改善檢測的好方法是使用色度鍵之類的東西:選擇特定的背景顏色,將彩色圖像從 RGB 轉換為 HSV,並創建一個按色調過濾的蒙版(二值圖像)。 這是一個例子: https : //docs.opencv.org/master/da/d97/tutorial_threshold_inRange.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM