【问题标题】:How to find four points from the binary image?如何从二值图像中找到四个点?
【发布时间】:2021-11-22 03:05:12
【问题描述】:

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

我尝试过以下代码:

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

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

【问题讨论】:

  • 尝试找到 4 条边(最长的线还是 approxPolyDp?)并使用交点。
  • @Micka,它没有给出预期的结果。 :(
  • 那句话是不充分的。你总是不得不说做了什么,发生了什么,以及你期望会发生什么。 -- 我会推荐使用minAreaRect
  • @Md.RezwanulHaque 看user2640045的回答,和我的方法基本一样。

标签: python numpy opencv cv2


【解决方案1】:

我已经找到了你的观点,方法是在你的每一边都放置一条回归线并获取他们的拦截点。

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

然后你得到

【讨论】:

  • contours = (contours[1].reshape(-1,2)).T,这里,contours[1] 可能不同,我该如何选择这个索引号?
  • @Md.RezwanulHaque 您的示例只有一个轮廓。如果你有多个,可能会用不同的颜色绘制不同的轮廓,然后从那里开始?
  • 如果我使用这个contours = (contours[2].reshape(-1,2)).T,那会发生什么?我认为它无法捕捉所有要点。此代码是否仅适用于此图像?
  • @Md.RezwanulHaque 我怀疑它只适用于这张照片。我很难在无法访问您的其他图片的情况下调试您的问题。也许你只是用它打开一个新问题?
  • @Md.RezwanulHaque 取决于轮廓 [2]、轮廓 [0]。如果它是您希望完成的轮廓上的点,那么它应该做您想做的事情。不过,您可能需要调整它所基于的点数。我建议你散点图左右,顶部等点,看看它们是否重新组装顶部底部等。
猜你喜欢
  • 1970-01-01
  • 2019-12-14
  • 1970-01-01
  • 2017-08-19
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
相关资源
最近更新 更多