我正在撰寫一個接受視頻輸入的 python 腳本,并且應該找到一個刻度板的中心。截至目前,我能夠找到板的輪廓,但我不知道如何繼續尋找每個小盒子的中心。
這是代碼:
import numpy as np
import cv2
video = cv2.VideoCapture(0)
while 1:
ret, frame = video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray, 3)
thresh = cv2.adaptiveThreshold(blur, 255, 1, 1, 11, 2)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
c = 0
for i in contours:
area = cv2.contourArea(i)
if area > 200:
cv2.drawContours(frame, contours, c, (0, 255, 0), 3)
c =1
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
這是我得到的框架:

uj5u.com熱心網友回復:
這個概念
使用基本演算法來查找影像中的輪廓。在這種情況下,只會檢測到 2 個輪廓;整個井字游戲網格,以及井字游戲網格的中心框。
獲取 2 個輪廓的

- 有了這些資訊,我們就可以計算出每個盒子的中心。對于 4 個角框中的每一個,只需找到組成框的 2 條線的尖端的中心。對于其余的框,只需找到組成框的 4 個點的中心:

代碼
import cv2 import numpy as np def process(img): img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_blur = cv2.GaussianBlur(img_gray, (5, 5), 0) img_canny = cv2.Canny(img_blur, 0, 100) kernel = np.ones((2, 2)) img_dilate = cv2.dilate(img_canny, kernel, iterations=8) return cv2.erode(img_dilate, kernel, iterations=2) def convex_hull(cnt): peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, peri * 0.02, True) return cv2.convexHull(approx).squeeze() def centers(inner, outer): c = inner[..., 0].argsort() top_lef2, top_rit2 = sorted(inner[c][:2], key=list) bot_lef2, bot_rit2 = sorted(inner[c][-2:], key=list) c1 = outer[..., 0].argsort() c2 = outer[..., 1].argsort() top_lef, top_rit = sorted(outer[c1][:2], key=list) bot_lef, bot_rit = sorted(outer[c1][-2:], key=list) lef_top, lef_bot = sorted(outer[c2][:2], key=list) rit_top, rit_bot = sorted(outer[c2][-2:], key=list) yield inner.mean(0) yield np.mean([top_lef, top_rit, top_lef2, top_rit2], 0) yield np.mean([bot_lef, bot_rit, bot_lef2, bot_rit2], 0) yield np.mean([lef_top, lef_bot, top_lef2, bot_lef2], 0) yield np.mean([rit_top, rit_bot, top_rit2, bot_rit2], 0) yield np.mean([top_lef, lef_top], 0) yield np.mean([bot_lef, lef_bot], 0) yield np.mean([top_rit, rit_top], 0) yield np.mean([bot_rit, rit_bot], 0) img = cv2.imread(r"D:/OpenCV Projects/TicTacToe centers/tictactoe.png") contours, _ = cv2.findContours(process(img), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) inner, outer = sorted(map(convex_hull, contours), key=len) for x, y in centers(inner, outer): cv2.circle(img, (int(x), int(y)), 5, (0, 0, 255), -1) cv2.imshow("result", img) cv2.waitKey(0)輸出

說明
- 匯入必要的庫:
import cv2 import numpy as np- Define a function,
process(), that takes in an image array and returns a binary image (that is the processed version of the image) that will allow proper contour detection on the image later on:
def process(img): img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_blur = cv2.GaussianBlur(img_gray, (5, 5), 0) img_canny = cv2.Canny(img_blur, 0, 100) kernel = np.ones((2, 2)) img_dilate = cv2.dilate(img_canny, kernel, iterations=8) return cv2.erode(img_dilate, kernel, iterations=2)- Define a function,
convex_hull(), that takes in a contour array and returns an array that is the convex hull of the approximated version of the contour:
def convex_hull(cnt): peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, peri * 0.02, True) return cv2.convexHull(approx).squeeze()- Define a function,
centers(), that takes in two arrays; the convex hull of the inner box of the tic-tac-toe grid, and the convex hull of the entire tic-tac-toe grid. In the function, do the necessary sorting so that each individual point is in a variable with the variable name corresponding to the position of the point; this will allow for easy calculation of each center point:
def centers(inner, outer): c = inner[..., 0].argsort() top_lef2, top_rit2 = sorted(inner[c1][:2], key=list) bot_lef2, bot_rit2 = sorted(inner[c1][-2:], key=list) c1 = outer[..., 0].argsort() c2 = outer[..., 1].argsort() top_lef, top_rit = sorted(outer[c1][:2], key=list) bot_lef, bot_rit = sorted(outer[c1][-2:], key=list) lef_top, lef_bot = sorted(outer[c2][:2], key=list) rit_top, rit_bot = sorted(outer[c2][-2:], key=list)- 仍然在
center()函式內,讓出盒子的中心。當用作關鍵字引數時,該np.mean()方法將回傳傳遞給該方法的坐標陣列中的坐標中心:0axis
yield inner.mean(0) yield np.mean([top_lef, top_rit, top_lef2, top_rit2], 0) yield np.mean([bot_lef, bot_rit, bot_lef2, bot_rit2], 0) yield np.mean([lef_top, lef_bot, top_lef2, bot_lef2], 0) yield np.mean([rit_top, rit_bot, top_rit2, bot_rit2], 0) yield np.mean([top_lef, lef_top], 0) yield np.mean([bot_lef, lef_bot], 0) yield np.mean([top_rit, rit_top], 0) yield np.mean([bot_rit, rit_bot], 0)- 讀入影像,找到它的輪廓(也是
process()先用函式處理影像),找到輪廓的凸包,用函式在框的中心繪制centers():
img = cv2.imread(r"D:/OpenCV Projects/TicTacToe centers/tictactoe.png") contours, _ = cv2.findContours(process(img), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) inner, outer = sorted(map(convex_hull, contours), key=len) for x, y in centers(inner, outer): cv2.circle(img, (int(x), int(y)), 5, (0, 0, 255), -1)- 最后,顯示生成的影像:
cv2.imshow("result", img) cv2.waitKey(0)uj5u.com熱心網友回復:
我認為這不是正確的方法,因為刻度板線是相連的,我們很可能總是以單一的大輪廓結束。為了使事情變得簡單,您可以嘗試檢測影像中的線條。
您可以嘗試
cv2.HoughLinesP或cv2.createLineSegmentDetector識別線條。我相信您可以在檢測到線路后繼續進行。另外,您可以查看如何在 OpenCV 中檢測線條?,不同的用例也可以根據您的目的進行擴展。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/442190.html上一篇:如何將點從二維環的表面映射到矩形
下一篇:輪廓元組的長度必須為2或3,否則OpenCV會再次更改其cv2.findContours回傳簽名-在特定區域中查找輪廓
