因此,我正在编写这段代码以从图像中的某些图形中提取数据。这些图像都是从一本书中扫描出来的。由于我们在这里讨论的是 100 多张图像,因此我当然想自动化该过程。我的第一步是确保所有图像都对齐。因为这本书的页面是手工扫描的,所以扫描件彼此之间都有轻微的偏移或旋转。幸运的是,图像上有一些虚线,可以用作对齐它们的参考点。之后,我可以通过在这些虚线上对图像进行切片,将图像分成更小的子图像。这样,所有扫描图像的所有子图像都是相同的。
所以,第一步当然是检测这些虚线。我的策略可以用 4 个步骤来描述:
- 使用形态变换将虚线变为实线
- 使用 Canny Edge Detection 检测所有边缘
- 使用 HoughLines 识别线条
- 在蒙版上绘制这些线以供进一步使用
现在可能会出现几个问题。有时 HoughLines 会检测到错误的线条(例如书中下一页的折叠),但这可以通过在右侧稍微裁剪图像来解决(总是欢迎更好的解决方案)。第二个(也是最大的)问题是 HoughLines 有时倾向于将单行识别为多行。我认为这与 Canny Edge Detection 对边缘过于粗糙或模糊有关,因此 HoughLines 实际上会看到多条线。有没有一种方法可以“平滑” Canny 的输出,以便 HoughLines 准确检测每条线一次?
在这个特定图像的情况下,中间的垂直虚线没有被识别,而书中下一页的折叠却被识别。此外,垂直虚线被识别为多条线。(左源图像,检测到中间边缘,检测到右线)
# load image
img_large = cv2.imread("image.png")
# resize for ease of use
img_ori = cv2.resize(img_large, None, fx=0.2, fy=0.2, interpolation=cv2.INTER_CUBIC)
# create grayscale
img = cv2.cvtColor(img_ori, cv2.COLOR_BGR2GRAY)
# create mask for image size
mask = np.zeros((img.shape[:2]), dtype=np.uint8)
# do a morphologic close to merge dotted line
kernel = np.ones((8, 8))
res = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
# detect edges for houghlines
edges = cv2.Canny(res, 50, 50)
# detect lines
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
# draw detected lines
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*a)
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*a)
cv2.line(mask, (x1, y1), (x2, y2), 255, 2)
cv2.line(img, (x1, y1), (x2, y2), 127, 2)