如何使用 OpenCV python 对网格的轮廓进行排序?
How to sort contours of a grid using OpenCV python?
我正在尝试对棋盘网格内的以下方块进行排序。
我在 NumPy 数组中有有效的轮廓。
这是一段代码,说明了我如何获得有效的正方形轮廓。
# Find contours and find squares with contour area filtering + shape approximation
cnts = cv2.findContours(invert, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
r = 0
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
sort_contours(cnts, "bottom-to-top")
sort_contours(cnts, "left-to-right")
valid_cnts = []
v = []
areas = []
for c in cnts:
area = cv2.contourArea(c)
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4 and area > 150 and area < 15000:
areas.append(area)
x, y, w, h = cv2.boundingRect(c)
s = img[y:y + h, x:x + w]
imgStr = "squares/square" + str(r) + ".png"
v.insert(r, [x, y, w, h])
cv2.imwrite(imgStr, s)
cv2.drawContours(original, [c], -1, (36, 255, 12), 2)
cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
valid_cnts.insert(r, c)
r = r + 1
我的目标也是从左到右然后从下到上对它们进行排序。这样我就可以认出它们上的每一块。这是我当前的排序功能:
def sort_contours(cnts, method="left-to-right"):
# initialize the reverse flag and sort index
reverse = False
i = 0
# handle if we need to sort in reverse
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
# handle if we are sorting against the y-coordinate rather than
# the x-coordinate of the bounding box
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
# construct the list of bounding boxes and sort them from top to
# bottom
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b[1][i], reverse=reverse))
# return the list of sorted contours and bounding boxes
return (cnts, boundingBoxes)
不幸的是,它不起作用,我认为这与相机角度有关。因为当我将照片裁剪为 64 个正方形时,它们不会按照我想要的顺序出现。如果有人能指导我如何正确准确地对它们进行排序,那就太好了!
想法是在阈值图像上找到轮廓后,我们利用 imutils.contours.sort_contours()
从 bottom-to-top
中对轮廓进行排序。接下来我们取每行 8 个正方形,并从 left-to-right
开始对这一行进行排序。这是排序的可视化:
import cv2
from imutils import contours
# Load image, grayscale, gaussian blur, Otsu's threshold
image = cv2.imread("1.jpg")
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Find all contour and sort from top-to-bottom or bottom-to-top
cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
(cnts, _) = contours.sort_contours(cnts, method="bottom-to-top")
# Take each row of 8 and sort from left-to-right
checkerboard_row = []
row = []
for (i, c) in enumerate(cnts, 1):
row.append(c)
if i % 8 == 0:
(cnts, _) = contours.sort_contours(row, method="left-to-right")
checkerboard_row.append(cnts)
row = []
# Draw text
number = 0
for row in checkerboard_row:
for c in row:
M = cv2.moments(c)
x = int(M['m10']/M['m00'])
y = int(M['m01']/M['m00'])
cv2.putText(original, "{}".format(number + 1), (x - 20,y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,50,10), 2)
number += 1
cv2.imshow('original', original)
cv2.waitKey()
注意:您还可以更改排序方向,例如right-to-left
或top-to-bottom
等
我正在尝试对棋盘网格内的以下方块进行排序。
我在 NumPy 数组中有有效的轮廓。
这是一段代码,说明了我如何获得有效的正方形轮廓。
# Find contours and find squares with contour area filtering + shape approximation
cnts = cv2.findContours(invert, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
r = 0
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
sort_contours(cnts, "bottom-to-top")
sort_contours(cnts, "left-to-right")
valid_cnts = []
v = []
areas = []
for c in cnts:
area = cv2.contourArea(c)
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4 and area > 150 and area < 15000:
areas.append(area)
x, y, w, h = cv2.boundingRect(c)
s = img[y:y + h, x:x + w]
imgStr = "squares/square" + str(r) + ".png"
v.insert(r, [x, y, w, h])
cv2.imwrite(imgStr, s)
cv2.drawContours(original, [c], -1, (36, 255, 12), 2)
cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
valid_cnts.insert(r, c)
r = r + 1
我的目标也是从左到右然后从下到上对它们进行排序。这样我就可以认出它们上的每一块。这是我当前的排序功能:
def sort_contours(cnts, method="left-to-right"):
# initialize the reverse flag and sort index
reverse = False
i = 0
# handle if we need to sort in reverse
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
# handle if we are sorting against the y-coordinate rather than
# the x-coordinate of the bounding box
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
# construct the list of bounding boxes and sort them from top to
# bottom
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b[1][i], reverse=reverse))
# return the list of sorted contours and bounding boxes
return (cnts, boundingBoxes)
不幸的是,它不起作用,我认为这与相机角度有关。因为当我将照片裁剪为 64 个正方形时,它们不会按照我想要的顺序出现。如果有人能指导我如何正确准确地对它们进行排序,那就太好了!
想法是在阈值图像上找到轮廓后,我们利用 imutils.contours.sort_contours()
从 bottom-to-top
中对轮廓进行排序。接下来我们取每行 8 个正方形,并从 left-to-right
开始对这一行进行排序。这是排序的可视化:
import cv2
from imutils import contours
# Load image, grayscale, gaussian blur, Otsu's threshold
image = cv2.imread("1.jpg")
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Find all contour and sort from top-to-bottom or bottom-to-top
cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
(cnts, _) = contours.sort_contours(cnts, method="bottom-to-top")
# Take each row of 8 and sort from left-to-right
checkerboard_row = []
row = []
for (i, c) in enumerate(cnts, 1):
row.append(c)
if i % 8 == 0:
(cnts, _) = contours.sort_contours(row, method="left-to-right")
checkerboard_row.append(cnts)
row = []
# Draw text
number = 0
for row in checkerboard_row:
for c in row:
M = cv2.moments(c)
x = int(M['m10']/M['m00'])
y = int(M['m01']/M['m00'])
cv2.putText(original, "{}".format(number + 1), (x - 20,y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,50,10), 2)
number += 1
cv2.imshow('original', original)
cv2.waitKey()
注意:您还可以更改排序方向,例如right-to-left
或top-to-bottom
等