问题:
我正在处理一个包含许多看起来像这样的图像的数据集:
现在我需要将所有这些图像水平或垂直定向,以便调色板位于图像的底部或右侧。这可以通过简单地旋转图像来完成,但棘手的部分是弄清楚哪些图像应该旋转,哪些不应该旋转。
我试过的:
我认为最好的方法是检测将调色板与图像分开的白线。我决定旋转底部带有调色板的所有图像,使其位于右侧。
# 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% 的图像,但在某些情况下,它会旋转不应旋转的图像或不旋转应旋转的图像。也许有一种更简单的方法可以做到这一点,或者可能有一种更精细、更一致的方法?我可以手动完成,但我正在处理很多图像。感谢您的任何帮助和/或评论。
以下是我的代码无法用于测试目的的一些图像:
最佳答案
您可以通过设置一个非常高的阈值(例如 250)来对图像进行阈值处理,以利用您的线条是白色的属性。这将使所有背景变黑。现在创建一个特殊的水平内核,形状类似于 (1, 15)
并用它侵 eclipse 你的形象。这将做的是从图像中删除垂直线,只留下水平线。
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 - 检测图像中的水平线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61893048/