检测图像中的水平线

Ahm*_*ssa 5 python opencv image python-imaging-library

问题: 我正在处理一个包含许多看起来像这样的图像的数据集:

图像2 图像1

现在我需要将所有这些图像水平或垂直定向,以便调色板位于图像的底部或右侧。这可以通过简单地旋转图像来完成,但棘手的部分是弄清楚哪些图像应该旋转,哪些不应该旋转。

我尝试过的:

我认为最好的方法是检测将调色板与图像分开的白线。我决定旋转底部带有调色板的所有图像,使其位于右侧。

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

Run Code Online (Sandbox Code Playgroud)

它正常工作的一个例子:

在此处输入图片说明

它工作不正确的一个例子:

在此处输入图片说明

这可能适用于 98% 的图像,但在某些情况下,它会旋转不应旋转的图像或不旋转应旋转的图像。也许有一种更简单的方法可以做到这一点,或者可能有一种更精细、更一致的方法?我可以手动完成,但我正在处理很多图像。感谢您的任何帮助和/或评论。

以下是我的代码无法用于测试目的的一些图像:

在此处输入图片说明 在此处输入图片说明

Var*_*wal 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)
Run Code Online (Sandbox Code Playgroud)

脱粒侵蚀

正如问题中所述,调色板只能位于右侧或底部。所以我们可以测试一下正确区域有多少个轮廓。为此,只需将图像分成两半并取出正确的部分。在找到轮廓之前,请先扩大结果以用正常内核填充任何间隙(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
Run Code Online (Sandbox Code Playgroud)

PS 我测试了您提供的所有四张图像,效果很好。如果万一它不适用于任何图像,请告诉我。