Python 图片倾斜校正

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Dreaming_of_you/article/details/89714959
#!/usr/bin/env python
# ---------ymd---------
# -*- coding:utf-8 -*-
import numpy as np
import cv2
from PIL import Image

#获取旋转角度
def get_rotate_angle(image):
    gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    gray=cv2.bitwise_not(gray)
    thresh=cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    coords=np.column_stack(np.where(thresh>0))
    angle=cv2.minAreaRect(coords)[2]
    return angle

#用Image模块旋转,字体会变模糊
def get_rotated_image(image_path,angle):
    img=Image.open(image_path)
    rotate=img.rotate(-angle,expand=1)
    alpha=Image.new('RGBA',rotate.size,(255,)*4)
    no_white_broder=Image.composite(rotate,alpha,rotate)
    rotated=np.array(no_white_broder)
    return rotated

#用矩阵旋转,字体不会变模糊。注意:warpAffine第三个参数(先列后行)。为防止信息丢失,W、H设置较大
def get_get_rotated_image1(image,angle):
    (h,w)=image.shape[:2]
    M=cv2.getRotationMatrix2D((h//2,w//2),-angle,1.0)
    sin=np.abs(M[0,1])
    cos=np.abs(M[0,0])
    a=np.maximum(h,w)
    W=int(a*sin+a*cos)
    H=int(a*cos+a*sin)
    M[0,2]=W/2-w//2
    M[1,2]=H/2-h//2
    rotated=cv2.warpAffine(image,M,(W,H),flags=cv2.INTER_CUBIC,     borderMode=cv2.BORDER_REPLICATE)
    return rotated

if __name__ == '__main__':
    path='D:/10.png'
    image=cv2.imread(path)
    angle=get_rotate_angle(image)
    #rotated_image=get_rotated_image(path,angle)
    rotated_image1=get_get_rotated_image1(image,angle)
    cv2.putText(rotated_image1,'angle:%.3f'%angle,(10,30),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
    print('rotate angle=%d'%angle)
    cv2.imshow('imput',image)
    #cv2.imshow('output',rotated_image)
    cv2.imshow('matrix_output',rotated_image1)
    cv2.waitKey(20000)

详细注释:

获取旋转角度部分

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  #转成单通道图片
gray = cv2.bitwise_not(gray)           #将上图颠倒黑白
thresh = cv2.threshold(gray, 0, 255,
        cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
#二值化,cv2.THRESH_BINARY(黑白二值),cv2.THRESH_OTSU自动判断最佳阈值(适合灰度图片有双峰的情况),使用cv2.THRESH_OTSU时阈值设置必须为0
#cv2.threshold函数是有两个返回值的,(常用)第二个返回值:阈值处理后的图像,第一个返回值:得到图像的阈值

coords = np.column_stack(np.where(thresh > 0))
#print(coords),所有黑色点的点集(数组型)

cv2.minAreaRect(coords)
#返回一个rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)
#rect[0]:中心坐标   rect[1][0]:矩形宽   rect[1][1]:矩形高    rect[2]:旋转角度θ
#旋转角度θ是水平轴(x轴)逆时针旋转,与碰到的矩形的第一条边的夹角。并且这个边的边长是width,另一条边边长是height。
#矩形的4个顶点坐标box, 通过函数 cv2.cv.BoxPoints() 获得

矩阵法变换部分

M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
#获得图像绕着某一点的旋转矩阵,为InputArray类型的2×3的变换矩阵。参数:(旋转中心,旋转角度,放缩因子)
#2×3变换矩阵的构成:[[cosθ  -sinθ  dx][sinθ cosθ dy]]  θ为逆时针旋转的角度,dx,dy为中心沿x,y方向的平移量


cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# 提取旋转矩阵 sin cos

a=np.maximum(h,w)
W=int(a*sin+a*cos)
H=int(a*cos+a*sin)
#定义输出图片大小,为防止图片信息缺失,输出图片比理论旋转后的图片大,理论旋转后的图片尺寸W = int((h * sin) + (w * cos)),H = int((h * cos) + (w * sin))。

M[0,2]+=W/2-w//2
M[1,2]+=H/2-h//2
#计算原图与输出图片的中心偏移量即2×3变换矩阵中的dx,dy

cv2.warpAffine(image, M, (nW, nH),flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
#cv2.warpAffine旋转图片
#参数(输入图像,变换矩阵(接收2*3的矩阵), 输出图像的大小(先列后行))
#flages表示插值方式,默认为 flags=cv2.INTER_LINEAR,表示线性插值,此外还有:cv2.INTER_NEAREST(最近邻插值) cv2.INTER_AREA (区域插值)  cv2.INTER_CUBIC(三次样条插值)    cv2.INTER_LANCZOS4(Lanczos插值)
#borderMode - 边界像素模式,cv2.BORDER_REPLICATE复制边界点扩充无像素区  borderValue -边界填充值; 默认情况下,它为None

主程序部分:

cv2.putText(rotated, 'angle:%.3f'%angle,
    (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
#putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)
#img图像 text要输出的文本 org文字的起点坐标 fontFace字体 fontScale字体大小 color字体颜色 thickness字图加粗

其他说明:
1.本文算法主要参考来源:(https://blog.csdn.net/u010379996/article/details/83088946)
2.最小外接矩形生成原理:(https://blog.csdn.net/lanyuelvyun/article/details/76614872)
3.旋转矩阵原理:(https://baike.baidu.com/item/旋转矩阵)

猜你喜欢

转载自blog.csdn.net/Dreaming_of_you/article/details/89714959