python - 在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
解决方案
我建议不要找到线条,而是找到彩色区域。
如果该区域在图像的右侧,则需要旋转图像。
查找彩色区域的方法如下:
- 计算每两个颜色通道之间的绝对差,并对结果求和。
结果在有颜色(不是黑色/白色)的地方具有很高的值。 - 应用阈值 - 低于阈值的值将为零(视为黑色/白色),高于阈值的值为 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()
更新:
旋转 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)
推荐阅读
- swift - 结合 if 语句和 for 循环,这样循环只会在 swift 中每次执行 if 语句时执行一次
- angular - Angularfire auth guard 和 Angular Material 不能一起工作
- amazon-web-services - AWS Code Deploy Deployment Failed 作为用户 root 运行失败
- python - 如何创建具有多个颜色图的热图?
- c# - WinForms 编辑器:如何在设计器中将子对象显示为嵌套对象
- node.js - (节点:11536)UnhandledPromiseRejectionWarning:TypeError:无法读取 null 的属性“x”
- c# - C# 在运行时重新编译和重新加载静态类
- python-3.x - Discord Bot 任务未更新
- regex - apikey 模式的正则表达式
- teradata - 如果存在统计信息,Teradata 会删除统计信息