如何从二值图像中找到四个点?

How to find four points from the binary image?

我有一张像下面这样的图片,我想从这张图片中找到四个坐标(角)。

我试过以下代码:

# dilate thresholded image - merges top/bottom 
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(img, kernel, iterations=3)
# Finding contours for the thresholded image
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

首先,我将图像放大,使其填满散点部分,然后尝试从那里找出轮廓。但它给了我错误的输出。 我可以做什么来找出四个角坐标?

我已经找到你的观点,方法是在你的每一侧放置一条回归线并取其截取点。

首先我导入东西并用打开的 cv 找到轮廓点。

import numpy as np
import cv2
import matplotlib.pyplot as plt
from scipy.stats import linregress
from sympy import solve, symbols
import itertools

img = cv2.imread('ZrSqG.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

threshold, binarized_img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(binarized_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = (contours[1].reshape(-1,2)).T

现在我得到了一些最上面的、最左边的等等点,然后把它们扔了一条线。然后我计算他们的截距并绘制出来。

def interpolate_function(x,y):
    line = interpolate(x,y)
    return lambda x: x*line.slope+line.intercept 

def interpolate(x,y):
    idx = np.argsort(x)
    line = linregress(x[idx], y[idx])
    return line

def interception(line1, line2):
    x = symbols('x')
    x = solve(x*line1.slope+line1.intercept-(x*line2.slope+line2.intercept))[0]
    return (x,x*line1[0]+line1[1])

idx_x = np.argsort(contours[0])
idx_y = np.argsort(contours[1])
left = [contours[0][idx_x[:30]], contours[1][idx_x[:30]]]
right = contours[0][idx_x[-10:]], contours[1][idx_x[-10:]]
top = contours[0][idx_y[:10]], contours[1][idx_y[:10]]
bottom = contours[0][idx_y[-30:]], contours[1][idx_y[-30:]]

contour_functions = [interpolate_function(*left), interpolate_function(*right),interpolate_function(*top), interpolate_function(*bottom)]
contour_function_eqs = [[interpolate(*left), interpolate(*right)],
    [interpolate(*top), interpolate(*bottom)]]

for f in contour_functions:
    t = np.linspace(0, img.shape[1], 10**4)
    t = t[(0 < f(t)) & (f(t) < img.shape[0])]
    plt.plot(t,f(t))
    
itersections = np.array([interception(line1, line2) 
    for line1, line2 in itertools.product(contour_function_eqs[0], contour_function_eqs[1])])
plt.scatter(itersections[:,0], itersections[:,1])
plt.imshow(img, cmap='gray')

然后我明白了

或者如果你更喜欢跟随左下角的部分,你只需通过重播来减少底部的点数

bottom = contours[0][idx_y[-30:]], contours[1][idx_y[-30:]]

bottom = contours[0][idx_y[-10:]], contours[1][idx_y[-10:]]

然后你得到