首页 > 解决方案 > 如何从二值图像中找到四个点?

问题描述

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

我试过下面的代码:

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

在此处输入图像描述

首先,我扩大了图像以填充散点部分并尝试从那里找出轮廓。但它给了我错误的输出。我能做些什么来找出四个角坐标?

标签: pythonnumpyopencvcv2

解决方案


我通过将回归线扔到你的每一边并取他们的拦截点来找到你的观点。

首先,我导入东西并使用打开的 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:]]

你得到 在此处输入图像描述


推荐阅读