检测图像中的水平线
Posted
技术标签:
【中文标题】检测图像中的水平线【英文标题】:Detecting a horizontal line in an image 【发布时间】:2020-09-05 15:15:53 【问题描述】:问题: 我正在使用一个包含许多看起来像这样的图像的数据集:
现在我需要将所有这些图像水平或垂直定向,以便调色板位于图像的底部或右侧。这可以通过简单地旋转图像来完成,但棘手的部分是确定哪些图像应该旋转,哪些不应该。
我尝试过的:
我认为最好的方法是检测将调色板与图像分开的白线。我决定旋转所有底部有调色板的图像,使其位于右侧。
# yes I am mixing between PIL and opencv (I like the PIL resizing more)
# resize image to be 128 by 128 pixels
img = img.resize((128, 128), PIL.Image.BILINEAR)
img = np.array(img)
# perform edge detection, not sure if these are the best parameters for Canny
edges = cv2.Canny(img, 30, 50, 3, apertureSize=3)
has_line = 0
# take numpy slice of the area where the white line usually is
# (not always exactly in the same spot which probably has to do with the way I resize my image)
for line in edges[75:80]:
# check if most of one of the lines contains white pixels
counts = np.bincount(line)
if np.argmax(counts) == 255:
has_line = True
# rotate if we found such a line
if has_line == True:
s = np.rot90(s)
一个正常工作的例子:
一个不正常工作的例子:
这可能适用于 98% 的图像,但在某些情况下,它会旋转不应旋转的图像或不旋转应旋转的图像。也许有一种更简单的方法可以做到这一点,或者可能有一种更复杂、更一致的方法?我可以手动完成,但我要处理很多图像。感谢您的帮助和/或 cmets。
以下是我的代码在测试时失败的一些图片:
【问题讨论】:
所有图像中彩条的数量是否始终相同? 是的,总是 6 种颜色 是否可以假设对于所有相同类型的图像,白条始终位于相同位置? 是的,但它们并不完全是像素完美的。我可能可以检测到图像底部是否有 5 个垂直条并这样做。 我这样做的方法是为白色区域(水平和垂直)创建两个蒙版,在图像和全白图像之间的蒙版区域中进行绝对差异(基本上,我只会得到带有白条的区域的差异图像),将所有像素增量相加并选择差异最小的那个。 (注意:我在这里写这个而不是作为答案,因为我现在没有时间/机会将其进一步阐述为完整的答案) 【参考方案1】:您可以通过设置一个非常高的阈值(例如 250)来对图像进行阈值处理,以利用线条为白色的特性。这将使所有背景变黑。现在创建一个特殊的水平内核,其形状类似于(1, 15)
,并用它腐蚀你的图像。这将做的是从图像中删除垂直线,只留下水平线。
import cv2
import numpy as np
img = cv2.imread('horizontal2.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)
kernel_hor = np.ones((1, 15), dtype=np.uint8)
erode = cv2.erode(thresh, kernel_hor)
如问题中所述,色板只能位于右侧或底部。所以我们可以测试检查正确区域有多少轮廓。为此,只需将图像分成两半并取正确的部分。在找到轮廓之前,先扩大结果以用正常的(3, 3)
内核填充任何空白。使用cv2.RETR_EXTERNAL
查找轮廓并计算我们找到了多少,如果大于某个数字,则图像正确的一面朝上,无需旋转。
right = erode[:, erode.shape[1]//2:]
kernel = np.ones((3, 3), dtype=np.uint8)
right = cv2.dilate(right, kernel)
cnts, _ = cv2.findContours(right, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(cnts) > 3:
print('No need to rotate')
else:
print('rotate')
#ADD YOUR ROTATE CODE HERE
附:我测试了您提供的所有四张图片,效果很好。如果它不适用于任何图像,请告诉我。
【讨论】:
以上是关于检测图像中的水平线的主要内容,如果未能解决你的问题,请参考以下文章
Python 如何使用 HoughLines 和 OpenCV 检测图像中的垂直线和水平线?