对文本倾斜角度的校正

上一篇我们提到了车牌的位置定位,主要运用的知识点是查找边缘的轮廓,并且使用形态学的操作扩大、缩小轮廓然后提取出来。其实在OCR(光学字符识别)中也是会用到这样的方法,但是在OCR识别中,就可能会出现文字方向并不是出于完全的垂直或者完全的水平,而是倾斜一定的角度。
在这里插入图片描述
比如像上图这样的图片,那么在进行识别的时候就可能会因为这个因素而造成结果上的误差。那么在这个时候就需要对文本倾斜的角度进行校正。

矩阵校正法

具体的方法可以通过矩阵进行旋转校正。在经过形态学操作后,我们会获得文本的大概外轮廓信息,然后我们就可以根据外轮廓的点所在位置,来得出这个区域的最小外接矩形。通过minAreaRect这个函数,不仅能获得矩形宽与高,还能获得角度,中心点位置。
根据中心点和角度这两个参数输入到getRotationMatrix2D函数中,就可以获得我们所需的仿射变换矩阵。但是这其中又有一个要求:因为minAreaRect返回的角度范围处于[-90-0)。
当倾斜角度范围为 (-45, 0) 时,即小于45度的负角度,表示文本逆时针倾斜。此时,对该角度不进行处理,在仿射变换时进行顺时针旋转。
但是当文本倾斜角度范围为 [-90, -45) 时,表示文本顺时针倾斜,对该角度加上90度后得到一个小于45度的正角度,在仿射变换时逆时针旋转。

def rotated_img_with_radiation(gray, is_show=False):
    thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    # 计算包含了旋转文本的最小边框
    coords = np.column_stack(np.where(thresh > 0))
    angle = cv2.minAreaRect(coords)[-1]
    
    if angle < -45:
        angle = -(90 + angle)
    else:
        angle = -angle
    
    h, w = gray.shape[:2]
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    rotated = cv2.warpAffine(gray, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
    return rotated
    

快速傅里叶变换法

上述方法中,对于垂直的图像就似乎不能为力了。但是因为通过傅里叶变换,再使用霍夫直线检测,就可以根据这条线段两个端点的坐标来判断出水平方向角度、垂直方向角度,找到角度值后也就可以识别出图像中物体的几何相关方向,通过这个角度来纠正图像。所以也可以使用FFT变换,然后再校正、变换回来。傅里叶变换的原理在于,任何一个函数都可以分解为无数个正弦函数和无数个余弦函数的和,所以就可以将图像从空间域转换到频率域。
在一幅图像的频率域中,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。就像下图:越靠近中心,越亮,频率也越低,越靠近边缘,越暗,频率也随之变高。我们可以对变换后处于频率域中的图像进行处理,这与信号处理的基本思想是相通的,倘若对一幅精细的图像使用低通滤波器,那么滤波后的结果就剩下了轮廓了。
如果图像受到的噪声恰好位于某个特定的“频率”范围内,则可以通过滤波器来恢复原来的图像。
在这里插入图片描述

def rotated_img_with_fft(gray):
    # 图像延扩
    h, w = gray.shape[:2]
    #以空间换时间,一般应该是2的n次方,这样便于FFT进行更多层次的二分,从而加快变换速度扩大数值到特定值来加速傅里叶变换
    new_h = cv2.getOptimalDFTSize(h) 
    new_w = cv2.getOptimalDFTSize(w)
    right = new_w - w
    bottom = new_h - h
    #扩充图像的边界,
    img = cv2.copyMakeBorder(gray, 0, bottom, 0, right, borderType=cv2.BORDER_CONSTANT, value=0)

    # 执行傅里叶变换,并过得频域图像
    f = np.fft.fft2(img )
    fshift = np.fft.fftshift(f)

    fft_img = np.log(np.abs(fshift))
    fft_img = (fft_img - np.amin(fft_img)) / (np.amax(fft_img) - np.amin(fft_img))

    fft_img *= 255
    ret, thresh = cv2.threshold(fft_img, 150, 255, cv2.THRESH_BINARY)

    # 霍夫直线变换
    thresh = thresh.astype(np.uint8)
    lines = cv2.HoughLinesP(thresh, 1, np.pi / 180, 30, minLineLength=40, maxLineGap=100)
    try:
        lines1 = lines[:, 0, :]
    except Exception as e:
        lines1 = []

    piThresh = np.pi / 180
    pi2 = np.pi / 2
    angle = 0
    for line in lines1:
        x1, y1, x2, y2 = line
        if x2 - x1 == 0:
            continue
        else:
            theta = (y2 - y1) / (x2 - x1)
        if abs(theta) < piThresh or abs(theta - pi2) < piThresh:
            continue
        else:
            angle = abs(theta)
            break
    
    angle = math.atan(angle)
    angle = angle * (180 / np.pi)

    center = (w // 2, h // 2)
    height_1 = int(w * fabs(sin(radians(angle))) + h * fabs(cos(radians(angle))))
    width_1 = int(h * fabs(sin(radians(angle))) + w * fabs(cos(radians(angle))))
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    M[0, 2] += (width_1 - w) / 2
    M[1, 2] += (height_1 - h) / 2
    rotated = cv2.warpAffine(gray, M, (width_1, height_1), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

    return rotated

最后效果图:在这里插入图片描述

### 使用霍夫变换实现文本倾斜校正 在处理文档图像时,为了提高OCR识别精度和其他后续操作的效果,通常需要先对输入图像进行预处理。其中一个重要环节就是纠正由于拍摄角度或其他原因造成的文本区域倾斜问题。 对于这一过程,在给定的描述中提到,会利用到一系列计算机视觉技术来完成这项工作[^1]。具体来说: - **图像读取与初步处理** 需要加载待矫正的目标图片,并将其颜色空间由RGB转为单通道灰度图表示形式;这一步骤有助于减少数据量的同时也方便之后的操作。 - **特征增强** 应用了高斯滤波器去除噪声干扰以及Canny算子检测边缘轮廓,从而更好地突出目标对象——即可能存在的直线结构。 - **线段提取** 基于上述准备好的二值化边缘映射,采用霍夫标准变换算法搜索符合条件(如长度超过一定限度)的所有潜在直线条目。这里特别关注那些接近垂直方向和平行于X轴延伸出来的候选者们。 - **几何关系分析** 计算了所选直线之间的交叉位置作为未来构建四边形顶点的基础依据。理想情况下,应该能够获得正好位于矩形四个角落处的关键坐标集合。 - **视角调整** 创建一张空白画布用来承载最终输出版本的内容。同时借助OpenCV库提供的`getPerspectiveTransform()`函数求解源域至目的域间的投影变化参数矩阵M。 - **执行变形转换** 利用得到的结果作用于原始素材之上实施仿射变换,使得原本歪斜的文字排列变得整齐有序。最后再把修正完毕的新图形展示出来供用户查看或进一步编辑保存。 下面给出一段Python脚本示范了整个流程的实际编码方式: ```python import cv2 import numpy as np def find_corners(edges): lines = cv2.HoughLinesP( edges, rho=1, theta=np.pi / 180, threshold=100, minLineLength=100, maxLineGap=10) horizontal_lines = [] vertical_lines = [] for line in lines: x1, y1, x2, y2 = line[0] if abs(y2 - y1) < abs(x2 - x1): # Horizontal Line horizontal_lines.append(line) elif abs(x2 - x1) < abs(y2 - y1): # Vertical Line vertical_lines.append(line) intersections = [] # Calculate intersection points between all pairs of h/v lines. for hl in horizontal_lines: for vl in vertical_lines: px, py, qx, qy = hl[0] rx, ry, sx, sy = vl[0] det = (qx - px)*(sy - ry)-(qy-py)*(sx-rx) if det != 0: # Check parallelism t = ((px - rx)*(sy - ry) - (py - ry)*(sx - rx)) / det u = -((px - qx)*(py - ry) - (py-qy)*(px-rx))/det if 0<=t<=1 and 0<=u<=1: ix = int(px+t*(qx-px)) iy = int(py+t*(qy-py)) intersections.append([ix,iy]) corners = sorted(intersections,key=lambda p:(p[0],p[1])) return np.array(corners[:4]) img = cv2.imread('skewed_image.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray,(5,5),sigmaX=0) edges = cv2.Canny(blurred,threshold1=50,threshold2=150) corners = find_corners(edges) pts_src = np.float32([[0,0],[img.shape[1]-1 ,0], [0,img.shape[0]-1 ],[img.shape[1]-1 ,img.shape[0]-1 ]]) matrix = cv2.getPerspectiveTransform(np.float32(corners), pts_src ) result = cv2.warpPerspective(img,matrix,dsize=(img.shape[1], img.shape[0])) cv2.imwrite("deskewed_image.jpg", result) ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值