[英]Get corners of rectangle from black and white image
Let's say that we have the following black and white image ( image.png
):假设我们有以下黑白图像(
image.png
):
We load the image using OpenCV2
with the following code:我们使用
OpenCV2
加载图像,代码如下:
import cv2
img = cv2.imread('image.png')
How can we detect the corners of all white rectangles in an image?我们如何检测图像中所有白色矩形的角? We can assume that all rectangles are parallel to the corners of the image.
我们可以假设所有矩形都平行于图像的角。
Result in this case should be in the following form ( res[0]
is left rectangle and res[1]
is right rectangle):这种情况下的结果应为以下形式(
res[0]
是左矩形, res[1]
是右矩形):
res = [
[
(20, 30), # upper left
(40, 30), # upper right
(20, 80), # bottom left
(40, 80) # bottom right
],
[
(100, 20), # upper left
(140, 20), # upper right
(100, 70), # bottom left
(140, 70) # bottom right
]
]
There are a few possibilities:有几种可能:
So, looking at the last option, if we slide a 2x2 pixel kernel over the image and multiply each of the elements underneath the kernel by 1 and add them all together, and then find all the pixels where that total comes to 255, that will be a 2x2 square where exactly one pixel is white - and that is a corner:所以,看看最后一个选项,如果我们在图像上滑动一个 2x2 像素 kernel 并将 kernel 下面的每个元素乘以 1 并将它们加在一起,然后找到总和为 255 的所有像素,这将是一个 2x2 的正方形,其中只有一个像素是白色的 - 那是一个角落:
import cv2
import numpy as np
# Load image as greyscale
im = cv2.imread('tZHHE.png',cv2.IMREAD_GRAYSCALE)
# Make a 2x2 kernel of ones
kernel = np.ones((2,2), dtype=np.uint8)
# Convolve the image with the kernel
res = cv2.filter2D(im.astype(np.int16), -1, kernel)
# Get coordinates of points where the sum of the 2x2 window comes to 255
corners = np.where(res==255)
Sample Output样品 Output
(array([101, 101, 118, 118, 166, 166, 174, 174]),
array([274, 307, 117, 134, 274, 307, 117, 134]))
Looking at the "Hit-or-Miss" morphology method, I will do it with ImageMagick straight in the Terminal, but you can equally do it with other Python libraries:查看“Hit-or-Miss”形态学方法,我将直接在终端中使用ImageMagick进行此操作,但您也可以使用其他 Python 库进行此操作:
magick tZHHE.png -alpha off -morphology HMT Corners result.png
As always, I am indebted to Anthony Thyssen for his ImageMagick examples as linked above.与往常一样,我感谢 Anthony Thyssen 提供的ImageMagick示例,如上所示。 We are looking for these specific shapes with the "Hit-or-Miss" morphology:
我们正在寻找具有“Hit-or-Miss”形态的这些特定形状:
Keywords : Python, OpenCV, image processing, convolution, corner detect, corner detector, corner detection, ImageMagick Hit-or-Miss morphology.关键词:Python, OpenCV, 图像处理, 卷积, 角点检测, 角点检测器, 角点检测, ImageMagick 命中或未命中形态。
I suggest you to try findContours() with its companion boundingRect() .我建议您尝试findContours()及其配套boundingRect() 。
Here is how you can make it work.以下是如何让它发挥作用。
Load the image in grayscale, then pass it to the function findContours().加载灰度图像,然后将其传递给 function findContours()。
img = cv2.imread('tZHHe.png', cv2.IMREAD_GRAYSCALE)
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
Getting the bounding box from contours, it returns x, y
coordinates of the top left corner and w, h
the width and height of the box:从轮廓中获取边界框,它返回左上角的
x, y
坐标和框的宽度和高度w, h
:
[cv2.boundingRect(contour) for contour in contours]
#=> [(117, 118, 17, 56), (274, 101, 33, 65)]
Try this maybe in a Jupyter Notebook to see a kind of animation:试试这个可能在 Jupyter Notebook 中看到一种 animation:
def corners_from_bounding_rect(bounding_rect):
x, y, w, h = bounding_rect
points = {'top_left': (x, y), 'top_right':(x+w, y), 'bottom-left': (x, y+h), 'bottom-rigth':(x+w, y+h)}
return points
Retrieve the points from contours using the method defined:使用定义的方法从轮廓中检索点:
corner_groups = [corners_from_bounding_rect(cv2.boundingRect(cnt)) for cnt in contours]
# [{'top_left': (117, 118),
# 'top_right': (134, 118),
# 'bottom-left': (117, 174),
# 'bottom-rigth': (134, 174)},
# {'top_left': (274, 101),
# 'top_right': (307, 101),
# 'bottom-left': (274, 166),
# 'bottom-rigth': (307, 166)}]
Then plot the sequence:然后 plot 序列:
pinned_img = img.copy()
for n, corners in enumerate(corner_groups):
for name, point in corners.items():
cv2.circle(pinned_img, point, 10, 255)
plt.title(f'{n}-{name}')
plt.imshow(pinned_img)
plt.show()
The first image from the squence:序列中的第一张图片:
This works for any number of rectangles:这适用于任意数量的矩形:
import cv2 as cv
import pprint as pprint
img = cv.imread("tZHHE.png") # read image
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # make grayscale image
cv.imshow("Our initial image",img) # show our original image
corners = cv.goodFeaturesToTrack(gray,2000,0.01,5) # find our corners, 2000 is the number of corners we can detect, 5 is the distance between corners
xylist = [] #put all of our xy coords in here
for corn in corners: # extract our corners and put them in xylist
x,y = corn[0]
xylist.append((x,y))
x = int(x)
y = int(y)
cv.rectangle(img, (x-2,y-2), (x+2,y+2), (100,100,0),-1) # now mark where our corners are on our original image
res = [[] for i in range(int(len(xylist)/4))] # generate i nested lists for our rectangles
for index, item in enumerate(xylist): # format coordinates as you want them
res[index % int(len(xylist)/4)].append(item)
print("\n"+"found ",int(len(xylist)/4) ,"rectangles\n") # how many rectangles did we have?
print(res)
cv.imshow("Corners?", img) # show our new image with rectangle corners marked
import cv2
img=cv2.imread('tZHHE.png') # Read my Image
imgContours=img.copy() # Copy my Image for Contours
imgCanny=cv2.Canny(imgContours,10,50) # Image to Edges
contours,hierarchy =cv2.findContours(imgCanny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
rectangles=[]
for cont in reversed(contours):
area=cv2.contourArea(cont)
x, y, w, h = cv2.boundingRect(cont)
rectangles.append([[x,y],[x+w,y],[x+w,y+h],[x,y+h]])
cv2.imshow("con", imgContours)
cv2.waitKey(0)
print(rectangles)
cv2.destroyAllWindows()
left to right rectangles从左到右的矩形
Output:
[[[273, 100], [307, 100], [307, 166], [273, 166]], [[116, 117], [134, 117], [134, 174], [116, 174]]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.