[英]Rectangle detection / tracking using OpenCV
我目前正在研究增強現實游戲。 游戲使用的控制器(我在這里談論的是物理輸入設備)是單色的矩形紙張。 我必須檢測相機的捕獲流中該矩形的位置,旋轉和大小。 檢測應在比例上不變,並且在沿X和Y軸的旋轉上不變。
如果用戶將紙張移開或移向相機,則需要縮放比例不變。 我不需要知道矩形的距離,因此比例不變會轉化為尺寸不變。
如果用戶沿矩形的局部X和/或Y軸傾斜矩形,則需要旋轉不變性。 這種旋轉將紙張的形狀從矩形更改為梯形。 在這種情況下,可以使用面向對象的邊界框來測量紙張的尺寸。
開始時有一個校准步驟。 窗口顯示攝像機的提要,用戶必須單擊矩形。 單擊時,將鼠標指向的像素顏色作為參考顏色。 幀被轉換為HSV顏色空間以改善顏色區分。 我有6個滑塊,用於調整每個通道的上限和下限閾值。 這些閾值用於對圖像進行二值化(使用opencv的inRange
函數)。
我正在侵蝕和擴張的二值圖像噪聲去除團結nerby塊后(使用的OpenCV的erode
和dilate
功能)。
下一步是在二進制圖像中查找輪廓(使用opencv的findContours
函數)。 這些輪廓用於檢測最小的定向矩形(使用opencv的minAreaRect
函數)。 最終結果是,我使用面積最大的矩形。
該程序的簡短結論:
您可能會注意到,我沒有利用有關紙張實際形狀的知識,只是因為我不知道如何正確使用此信息。
我還考慮過使用opencv的跟蹤算法。 但是有三個原因使我無法使用它們:
一般而言,我如何才能改善檢測效果,尤其是要使其更能抵抗光照變化?
這是一些原始圖像供測試。
您不能只使用較厚的材料嗎?
是的,我可以而且我已經可以了(不幸的是,目前我無法訪問這些片段)。 但是,問題仍然存在。 即使我使用紙板等材料。 它不像紙一樣容易彎曲,但仍然可以彎曲。
如何獲得矩形的大小,旋轉和位置?
opencv的minAreaRect
函數返回RotatedRect
對象。 該對象包含我需要的所有數據。
注意
由於矩形是單色的,因此無法區分頂部和底部或左側和右側。 這意味着旋轉始終在[0, 180]
范圍內[0, 180]
這對我來說是完全可以的。 矩形的兩側之比始終為w:h > 2:1
。 如果矩形將是正方形,則旋轉范圍將更改為[0, 90]
0,90 [0, 90]
,但是在此可以將其視為無關緊要的。
正如評論中所建議的那樣,我將嘗試直方圖均衡化以減少亮度問題,並介紹一下ORB,SURF和SIFT。
我將更新進度。
我知道自問這個問題已經有一段時間了。 我最近繼續討論該主題並解決了我的問題(盡管不是通過矩形檢測)。
cv::equalizeHist
直方圖 cv::aruco::detectMarkers
查找標記, 事實證明,標記檢測對於照明變化和不同的視角非常強大,這使我可以跳過任何校准步驟。
我在每個控制器上放置了2個標記,以進一步提高檢測的魯棒性。 兩種標記僅需檢測一次(以測量它們之間的相關性)。 之后,每個控制器僅找到一個標記就足夠了,因為可以從先前計算的相關性中推斷出另一個標記。
這是在明亮環境下的檢測結果:
在更黑暗的環境中:
並且隱藏其中一個標記時(藍點表示推斷的標記位置):
我實施的初始形狀檢測效果不佳。 照明變化非常脆弱。 此外,它需要一個初始校准步驟。
在使用形狀檢測方法之后,我嘗試將SIFT和ORB與蠻力和knn匹配器結合使用以提取和定位框架中的特征。 事實證明,單色對象沒有提供太多關鍵點(令人驚訝)。 無論如何,SIFT的性能都很糟糕(540p時約為10 fps)。 我在控制器上畫了一些線和其他形狀,這導致更多的關鍵點出現。 但是,這並沒有帶來巨大的改進。
HSV空間中的H通道是色相,並且對光線變化不敏感。 紅色范圍約為[150,180]。
根據上述信息,我進行以下工作。
PS。 由於網絡原因,我無法提取您在保管箱上載的圖像。 因此,我僅將第二張圖像的右側的 crop作為輸入。
imgname = "src.png"
img = cv2.imread(imgname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## Split the H channel in HSV, and get the red range
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
h[h<150]=0
h[h>180]=0
## normalize, do the open-morp-op
normed = cv2.normalize(h, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)
kernel = cv2.getStructuringElement(shape=cv2.MORPH_ELLIPSE, ksize=(3,3))
opened = cv2.morphologyEx(normed, cv2.MORPH_OPEN, kernel)
res = np.hstack((h, normed, opened))
cv2.imwrite("tmp1.png", res)
現在,我們得到如下結果(h,歸一化,打開):
然后找到輪廓並對其進行過濾。
contours = cv2.findContours(opened, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))[-2]
bboxes = []
rboxes = []
cnts = []
dst = img.copy()
for cnt in contours:
## Get the stright bounding rect
bbox = cv2.boundingRect(cnt)
x,y,w,h = bbox
if w<30 or h < 30 or w*h < 2000 or w > 500:
continue
## Draw rect
cv2.rectangle(dst, (x,y), (x+w,y+h), (255,0,0), 1, 16)
## Get the rotated rect
rbox = cv2.minAreaRect(cnt)
(cx,cy), (w,h), rot_angle = rbox
print("rot_angle:", rot_angle)
## backup
bboxes.append(bbox)
rboxes.append(rbox)
cnts.append(cnt)
結果是這樣的:
rot_angle: -2.4540319442749023
rot_angle: -1.8476102352142334
由於源圖像中的藍色矩形標簽,該卡被分為兩個側面。 但是干凈的圖像不會有問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.