[英]Detect markers in 2D Image [Python/OpenCV]
我想在 Python 中創建一個腳本(使用 OpenCV 庫)來確定圖片中的標記。 標記看起來像這樣:
加載圖像后,腳本應打印圖片中的標記(返回標記數)。 例如,如果我加載這張圖片:
對於這個圖像,腳本應該返回三個數字:1、2 和 3。我有一個腳本,它加載圖像並識別圖形(圓形、正方形等 - 在下面的腳本中只有正方形),但我不知道識別整個標記,由幾個數字組成。 有什么想法嗎? 請提供有關算法或任何解決方案的任何建議。
import numpy as np
import cv2
img = cv2.imread('B.jpg')
gray = cv2.imread('B.jpg',0)
ret,thresh = cv2.threshold(gray,120,255,1)
contours,h = cv2.findContours(thresh,1,2)
for cnt in contours:
approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)
print len(approx)
if len(approx)==4:
print "square"
cv2.drawContours(img,[cnt],0,(0,0,255))
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
但顯然這不是我所需要的,它只圍繞矩形。 感謝您提供任何提示和幫助。
特征匹配的效果會很差,因為這些標記的特征很少(您需要角點簇和特征匹配的精細細節)。
這些標記更適合模板匹配方案。 對於正確的模板類型(假設模板被正確定位、定向和縮放),輸入圖像和模板之間的相關性將是最高的。 以下代碼適用於您的示例。 它包括許多必需的預處理,但本質是找到最高的相關性: np.correlate(img.flatten(), templ.flatten())
。 可以通過多種方式改進代碼,以使其對標記位置、比例、方向、噪聲等變化的魯棒性更強。
import matplotlib.pyplot as plt
import numpy as np
import cv2
# Detect and store the 6 templates (markers)
fig0, axs0 = plt.subplots(2)
imgs = cv2.imread("markers.png")
imgs_gray = cv2.cvtColor(imgs, cv2.COLOR_BGR2GRAY)
ret, imgs_th = cv2.threshold(imgs_gray, 100, 255, cv2.THRESH_BINARY)
xywh = np.zeros((0, 4), dtype=np.int32)
contours, hierarchies = cv2.findContours(
imgs_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
)
for idx, c in enumerate(contours):
if hierarchies[0, idx, 3] == 0 and cv2.contourArea(c) > 20000:
x, y, w, h = cv2.boundingRect(c)
xywh = np.vstack((xywh, np.array([x, y, w, h])))
axs0[0].set_title("thresholded markers image")
axs0[0].imshow(imgs_th, cmap="gray")
sortx_xywh = xywh[np.argsort(xywh[:, 0])]
sortyx_xywh = sortx_xywh[np.argsort(sortx_xywh[:, 1])]
max_w = np.amax(sortyx_xywh[:, 2])
max_h = np.amax(sortyx_xywh[:, 3])
templates = np.zeros((max_h, max_w, 6))
for i, xy in enumerate(sortyx_xywh[:, 0:2]):
templates[:, :, i] = imgs_th[xy[1] : xy[1] + max_h, xy[0] : xy[0] + max_w]
# Detect the marker regions in the input image
img_in = cv2.imread("input.jpg")
img_gray = cv2.cvtColor(img_in, cv2.COLOR_BGR2GRAY)
ret, img_th = cv2.threshold(img_gray, 100, 255, cv2.THRESH_BINARY)
xywh = np.zeros((0, 4), dtype=np.int32)
contours, hierarchies = cv2.findContours(img_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for idx, c in enumerate(contours):
if hierarchies[0, idx, 3] == 0 and cv2.contourArea(c) > 20000:
x, y, w, h = cv2.boundingRect(c)
xywh = np.vstack((xywh, np.array([x, y, w, h])))
axs0[1].set_title("thresholded input image")
axs0[1].imshow(img_th, cmap="gray")
fig0.show()
# Use simplified template matching (correlation) to determine marker type and orientation
for xy in xywh[:, 0:2]:
fig1, axs1 = plt.subplots(5, 6)
img = img_th[xy[1] : xy[1] + max_h, xy[0] : xy[0] + max_w]
axs1[0, 0].imshow(img, cmap="gray")
axs1[0, 0].set_title("input image")
corr = np.zeros((4, 6))
for t in range(6): # 6 templates
templ = templates[:, :, t]
for o in range(4): # 4 orientations
corr[o, t] = np.correlate(img.flatten(), templ.flatten())
axs1[o + 1, t].imshow(templ, cmap="gray")
axs1[o + 1, t].set_title("corr = {:.2e}".format(corr[o, t]))
templ = np.rot90(templ)
rot, typ = np.unravel_index(np.argmax(corr, axis=None), corr.shape)
print("Input marker at ({},{}) is type {}, rotated {} degrees.".format(xy[0], xy[1], typ + 1, rot * 90))
fig1.tight_layout(pad=0.001)
fig1.show()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.