我需要在给定图像上检测纸张的角。它始终将是整个图片的裁剪部分,仅包含一个角。我的想法是通过模糊和Canny边缘检测来变换图像以获取轮廓,然后使用Houghlines来获取角坐标。
但是我遇到了一些问题,实际上无法通过霍夫线连续,精确地检测到任何东西,而我的想法已经耗尽了。
我尝试过套牢而不是Canny,但是由于适用图像的许多变化,因此无法使用。我缩小了整个图像的尺寸,以使其更容易看到纸张的边缘,但仍然没有任何改善。线阈值的增加使纸张含量从纸质消失,但同时边线不时消失
输入
边缘
结果
要复制的代码
import cv2
import numpy as np
img = cv2.imread('inv_0001-01.1_0_corner.jpg')
resized = cv2.resize(img, (250,250), interpolation = cv2.INTER_AREA)
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)
edges = cv2.Canny(blur_gray,50,150,apertureSize = 3)
cv2.imshow('edges', edges)
cv2.waitKey()
min_line_length = 50
max_line_gap = 20
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 5, np.array([]), min_line_length, max_line_gap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(resized,(x1,y1),(x2,y2),(255,0,0),5)
cv2.imshow('hough', resized)
cv2.waitKey()
我要去的结果是给定图像中纸角的坐标,但是在这篇文章中,我希望寻找一些帮助,以了解如何使用Houglines完成此类任务
答案 0 :(得分:2)
此答案说明了如何找到角落。找到角落需要两部分解决方案。首先,需要将图像分为两个区域:纸张和背景。其次,您可以在分割的图像中寻找角落。
找到边缘后,对图像进行填充以从背景中分割纸张(这是填充图像):
mask = np.zeros((h+2, w+2), np.uint8)
# Floodfill from point (0, 0)
cv2.floodFill(edges, mask, (0,0), 123);
现在您已经对图像进行了分割,请使用蒙版(这是标题为“ Masking”的图像)去除纸上的文字:
bg = np.zeros_like(edges)
bg[edges == 123] = 255
获得蒙版后,再次应用canny边缘过滤器以获取纸张的轮廓线(HoughLines需要轮廓而不是蒙版...这是“蒙版后的边缘”图像):
bg = cv2.blur(bg, (3,3))
edges = cv2.Canny(bg,50,150,apertureSize = 3)
现在,您可以在更清晰的图像上运行HoughLines算法。我使用的HoughLines算法与您使用的算法不同,但是您的算法也应该工作。这是我使用的完整代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Create a multi plot
f, axarr = plt.subplots(2,3, sharex=True)
img = cv2.imread('/home/stephen/Desktop/IRcCAWL.png')
resized = cv2.resize(img, (250,250), interpolation = cv2.INTER_AREA)
# Show source image
axarr[0,0].imshow(resized)
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)
edges = cv2.Canny(blur_gray,50,150,apertureSize = 3)
# Show first edges image
axarr[0,1].imshow(edges)
h, w = edges.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
# Floodfill from point (0, 0)
cv2.floodFill(edges, mask, (0,0), 123);
# Show the flood fill image
axarr[0,2].imshow(edges)
floodfill = edges.copy()
bg = np.zeros_like(edges)
bg[edges == 123] = 255
# Show the masked image
axarr[1,0].imshow(bg)
bg = cv2.blur(bg, (3,3))
edges = cv2.Canny(bg,50,150,apertureSize = 3)
# Show the edges after masking
axarr[1,1].imshow(edges)
min_line_length = 50
max_line_gap = 20
def intersection(line1, line2):
"""Finds the intersection of two lines given in Hesse normal form.
Returns closest integer pixel locations.
See https://stackoverflow.com/a/383527/5087436
"""
rho1, theta1 = line1[0]
rho2, theta2 = line2[0]
A = np.array([
[np.cos(theta1), np.sin(theta1)],
[np.cos(theta2), np.sin(theta2)]
])
b = np.array([[rho1], [rho2]])
x0, y0 = np.linalg.solve(A, b)
x0, y0 = int(np.round(x0)), int(np.round(y0))
return [[x0, y0]]
import math
lines = cv2.HoughLines(edges, 1, np.pi / 180, 100, None, 0, 0)
# Draw 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 + 1000*(-b)), int(y0 + 1000*(a)))
pt2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a)))
cv2.line(resized, pt1, pt2, (123,234,123), 2, cv2.LINE_AA)
xy = tuple(intersection(lines[0], lines[1])[0])
resized = cv2.circle(resized, xy, 5, 255, 2)
# Show the image with the corner
axarr[1,2].imshow(resized)
# Add titles
axarr[0,0].set_title('Source Image')
axarr[0,1].set_title('Edges')
axarr[0,2].set_title('Floodfill')
axarr[1,0].set_title('Masking')
axarr[1,1].set_title('Edges after masking')
axarr[1,2].set_title('Hough Lines')
# Clean up
axarr[0,0].axis('off')
axarr[0,1].axis('off')
axarr[1,0].axis('off')
axarr[1,1].axis('off')
axarr[1,2].axis('off')
axarr[0,2].axis('off')
plt.show()