使用 Python / Computer Vision 等获取图像中的顶点? (附图片)
Get vertices in a image using Python / Computer Vision , etc ? ( Images Attached )
你好,我需要在图像中找到给定形状的顶点(x 和 y 坐标),在进行分割和边缘提取之后,以下是获得的图像:
以下是我需要找到其坐标的顶点:
我想你可能想先用霍夫线变换来找到线条。然后,您可以从检测到的线中获取交点。你可能会找到OpenCV关于霍夫线变换的教程here。
这是我使用霍夫线变换的结果:
代码:
import numpy as np
import cv2 as cv2
import math
img_path = 'hSAdf.png'
# Read the original image
img = cv2.imread(img_path)
# Convert to graycsale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = cv2.threshold(img_gray, 50, 255, cv2.THRESH_BINARY)[1]
cdst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
lines = cv2.HoughLines(dst, 1, np.pi / 180, 180, None, 0, 0)
# Drawing the lines
if lines is not None:
for i in range(0, len(lines)):
rho = lines[i][0][0]
theta = lines[i][0][1]
a = math.cos(theta)
b = math.sin(theta)
x0 = a * rho
y0 = b * rho
pt1 = (int(x0 + 10000*(-b)), int(y0 + 10000*(a)))
pt2 = (int(x0 - 10000*(-b)), int(y0 - 10000*(a)))
cv2.line(cdst, pt1, pt2, (0,0,255), 3, cv2.LINE_AA)
cv2.imshow("Detected Lines (in red) - Standard Hough Line Transform", cdst)
cv2.imwrite("output.png", cdst)
cv2.waitKey(0)
这里我没有使用 Canny 边缘检测,因为我认为图像本身非常 line-clear,这使得边缘检测变得多余。
函数HoughLines()
returns直线的rho(像素)和theta(弧度),对应直线方程:
编辑 1:rho、theta 和 m、c 之间的简单转换:
m = tan(theta + PI/2)
c = rho / sin(theta)
图片来自Socret Lee
我想你可以继续调整线路检测功能。您可以手动调整阈值,甚至可以在函数中限制线条的梯度。然后,您可以通过裁剪和限制渐变来定位一行。
或者您可以拒绝相差约 90 度的线的交点。然后,您将获得所需的积分。
使用Contour detection和近似你可以得到外部顶点,并计算它们:
[1737 197]
[616 199]
[225 596]
[ 226 1708]
[ 610 2102]
[1717 2121]
[2118 1732]
[2134 601]
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img = cv2.imread("input.png", 0)
def fillhole(input_image):
'''
input gray binary image get the filled image by floodfill method
Note: only holes surrounded in the connected regions will be filled.
:param input_image:
:return:
'''
im_flood_fill = input_image.copy()
h, w = input_image.shape[:2]
mask = np.zeros((h + 2, w + 2), np.uint8)
im_flood_fill = im_flood_fill.astype("uint8")
cv2.floodFill(im_flood_fill, mask, (0, 0), 255)
im_flood_fill_inv = cv2.bitwise_not(im_flood_fill)
img_out = input_image | im_flood_fill_inv
return img_out
res = fillhole(img)
contours = cv2.findContours(res, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
peri = cv2.arcLength(contours[945], True)
approx = cv2.approxPolyDP(contours[945], 0.04 * peri, True)
im = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
s = 10
for p in approx:
p = p[0]
print(p)
im[p[1]-s:p[1]+s, p[0]-s:p[0]+s] = (255, 255, 0)
cv2.drawContours(im, contours, 945, (0, 200, 255), 3)
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.imshow("img", im)
cv2.waitKey(0)
你好,我需要在图像中找到给定形状的顶点(x 和 y 坐标),在进行分割和边缘提取之后,以下是获得的图像:
以下是我需要找到其坐标的顶点:
我想你可能想先用霍夫线变换来找到线条。然后,您可以从检测到的线中获取交点。你可能会找到OpenCV关于霍夫线变换的教程here。
这是我使用霍夫线变换的结果:
代码:
import numpy as np
import cv2 as cv2
import math
img_path = 'hSAdf.png'
# Read the original image
img = cv2.imread(img_path)
# Convert to graycsale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = cv2.threshold(img_gray, 50, 255, cv2.THRESH_BINARY)[1]
cdst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
lines = cv2.HoughLines(dst, 1, np.pi / 180, 180, None, 0, 0)
# Drawing the lines
if lines is not None:
for i in range(0, len(lines)):
rho = lines[i][0][0]
theta = lines[i][0][1]
a = math.cos(theta)
b = math.sin(theta)
x0 = a * rho
y0 = b * rho
pt1 = (int(x0 + 10000*(-b)), int(y0 + 10000*(a)))
pt2 = (int(x0 - 10000*(-b)), int(y0 - 10000*(a)))
cv2.line(cdst, pt1, pt2, (0,0,255), 3, cv2.LINE_AA)
cv2.imshow("Detected Lines (in red) - Standard Hough Line Transform", cdst)
cv2.imwrite("output.png", cdst)
cv2.waitKey(0)
这里我没有使用 Canny 边缘检测,因为我认为图像本身非常 line-clear,这使得边缘检测变得多余。
函数HoughLines()
returns直线的rho(像素)和theta(弧度),对应直线方程:
编辑 1:rho、theta 和 m、c 之间的简单转换:
m = tan(theta + PI/2)
c = rho / sin(theta)
我想你可以继续调整线路检测功能。您可以手动调整阈值,甚至可以在函数中限制线条的梯度。然后,您可以通过裁剪和限制渐变来定位一行。
或者您可以拒绝相差约 90 度的线的交点。然后,您将获得所需的积分。
使用Contour detection和近似你可以得到外部顶点,并计算它们:
[1737 197] [616 199] [225 596] [ 226 1708] [ 610 2102] [1717 2121] [2118 1732] [2134 601]
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img = cv2.imread("input.png", 0)
def fillhole(input_image):
'''
input gray binary image get the filled image by floodfill method
Note: only holes surrounded in the connected regions will be filled.
:param input_image:
:return:
'''
im_flood_fill = input_image.copy()
h, w = input_image.shape[:2]
mask = np.zeros((h + 2, w + 2), np.uint8)
im_flood_fill = im_flood_fill.astype("uint8")
cv2.floodFill(im_flood_fill, mask, (0, 0), 255)
im_flood_fill_inv = cv2.bitwise_not(im_flood_fill)
img_out = input_image | im_flood_fill_inv
return img_out
res = fillhole(img)
contours = cv2.findContours(res, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
peri = cv2.arcLength(contours[945], True)
approx = cv2.approxPolyDP(contours[945], 0.04 * peri, True)
im = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
s = 10
for p in approx:
p = p[0]
print(p)
im[p[1]-s:p[1]+s, p[0]-s:p[0]+s] = (255, 255, 0)
cv2.drawContours(im, contours, 945, (0, 200, 255), 3)
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.imshow("img", im)
cv2.waitKey(0)