简体   繁体   English

从黑白图像中获取矩形的角

[英]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:有几种可能:

  • the "Harris Corner Detector" is good at finding corners - see here “Harris Corner Detector”擅长寻找角落 - 见这里
  • you can use OpenCV's findContours()你可以使用 OpenCV 的findContours()
  • you could use "Hit-or-Miss" morphology to look for corners你可以使用“Hit-or-Miss”形态来寻找角落
  • you could convolve the image with a kernel and look for specific outputs您可以使用 kernel 对图像进行卷积并查找特定输出

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 命中或未命中形态。

Try findContours()尝试 findContours()

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)]

View in action在行动中查看

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

Try this code试试这个代码在此处输入图像描述

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM