首页 > 解决方案 > 在python中正确旋转或翻转图像[发票,表格]到正确的方向

问题描述

我正在尝试将包含发票和表格的图像旋转到正确的方向。我试图找到角度,然后旋转图像。只有少数图像被正确旋转。下面是我试图以正确方向旋转的代码和图像,第一个图像旋转正确,其他图像旋转不正确


import numpy as np
import cv2
import math
from scipy import ndimage

img_before = cv2.imread('rotate_me.png')

cv2.imshow("Before", img_before)    
key = cv2.waitKey(0)

img_gray = cv2.cvtColor(img_before, cv2.COLOR_BGR2GRAY)
img_edges = cv2.Canny(img_gray, 100, 100, apertureSize=3)
lines = cv2.HoughLinesP(img_edges, 1, math.pi / 180.0, 100, minLineLength=100, maxLineGap=5)

angles = []

for x1, y1, x2, y2 in lines[0]:
    cv2.line(img_before, (x1, y1), (x2, y2), (255, 0, 0), 3)
    angle = math.degrees(math.atan2(y2 - y1, x2 - x1))
    angles.append(angle)

median_angle = np.median(angles)
img_rotated = ndimage.rotate(img_before, median_angle)

print "Angle is {}".format(median_angle)
cv2.imwrite('rotated.jpg', img_rotated) 

第一个图像 - [左侧倒置] ---旋转后正确旋转第二个图像 - 右侧倒置 - 错误旋转 两个图像都有 -90 度角。最终输出必须像 image3

https://i.stack.imgur.com/XpFVy.png

https://i.stack.imgur.com/bGI3k.png

https://i.stack.imgur.com/jHNgD.png

标签: pythonopencvimage-processingpython-imaging-libraryopencv-contour

解决方案


我建议不要找到线条,而是找到彩色区域。

如果该区域在图像的右侧,则需要旋转图像。

查找彩色区域的方法如下:

  • 计算每两个颜色通道之间的绝对差,并对结果求和。
    结果在有颜色(不是黑色/白色)的地方具有很高的值。
  • 应用阈值 - 低于阈值的值将为零(视为黑色/白色),高于阈值的值为 255(彩色像素)。
  • 使用connectedComponentsWithStats找到阈值图像中的最大集群。
  • 如果最大的白色簇的中心在右侧,则旋转图像。

这是一个代码示例:

import numpy as np
import cv2

im = cv2.imread("rotate_me1.png", cv2.IMREAD_UNCHANGED);

# Compute difference between each two color channels for finding colored pixels.
cdiff = cv2.absdiff(im[:,:,0], im[:,:,1])//3 + cv2.absdiff(im[:,:,0], im[:,:,2])//3 + cv2.absdiff(im[:,:,1], im[:,:,2])//3;
ret, cmask = cv2.threshold(cdiff, 10, 255, cv2.THRESH_BINARY)

# Find clusters.
# https://answers.opencv.org/question/194566/removing-noise-using-connected-components/
nlabel,labels,stats,centroids = cv2.connectedComponentsWithStats(cmask, connectivity=8)

# Find second largest cluster (the largest is the background?):
stats[np.argmax(stats[:, cv2.CC_STAT_AREA])] = 0
idx_max_size = np.argmax(stats[:, cv2.CC_STAT_AREA])
center = centroids[idx_max_size]

# True if the center of the centroid is at the right side of the image
is_center_at_right_side = center[0] > im.shape[1]//2

if is_center_at_right_side:
    rotated_im = im[::-1, ::-1, :].copy()  # Reverse left/right and up/down
    cv2.imshow('rotated_im', rotated_im)

# Draw green circle at the center (for testing)
cv2.circle(im, (int(center[0]), int(center[1])), 10, (0, 255, 0), thickness=10)

cv2.imshow('cmask', cmask)
cv2.imshow('im', im)
cv2.waitKey(0)
cv2.destroyAllWindows()

示例cmask
在此处输入图像描述

用绿色圆圈标记最大簇的中心:
在此处输入图像描述

旋转图像:
在此处输入图像描述


更新:

旋转 90 度:

# https://stackoverflow.com/questions/2259678/easiest-way-to-rotate-by-90-degrees-an-image-using-opencv
if is_center_at_right_side:
    rotated_im = cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE)
else:
    rotated_im = cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE)

结果:
在此处输入图像描述


推荐阅读