opencv-python实战项目十三:文档倾斜校正

一,简介

在日常生活中,我们经常会遇到拍摄文档时出现的倾斜问题,这不仅影响文档的美观,还可能导致OCR识别率降低。为了解决这一问题,本文将带您走进OpenCV的世界,教您如何利用Python和OpenCV库轻松实现文档倾斜校正。

二,校正流程

首先读取JPEG图片并将其灰度化,接着通过形态学操作去除噪声并模糊文字信息,然后使用Canny算法进行边缘检测,并应用霍夫变换检测图像中的直线。通过计算直线的斜率并转换为角度,最后根据这个角度对原始图像进行旋转校正。

三,算法实现

需要校正的文档图像:
在这里插入图片描述

3.1 提取图像中的文字区域

首先将原始图像转换为灰度图,然后创建一个5x5的核用于形态学操作,接着对灰度图进行腐蚀和膨胀处理,进而提取出图像的文字信息
实现代码:

    gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    # 创建一个5x5的核,用于形态学操作
    kernel = np.ones((5, 5), np.uint8)
    # 对灰度图进行腐蚀操作
    erode_Img = cv2.erode(gray, kernel)
    # 对腐蚀后的图像进行膨胀操作
    eroDil = cv2.dilate(erode_Img, kernel)

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

3.2,霍夫直线获得图像倾斜角度

算法流程为首先对图像进行canny算子计算图像边缘,然后通过cv2.HoughLinesP()函数获取到直线的起点终点,之后就可根据公式k=x2−x1/y2−y1计算斜率k,最后根据斜率k计算出旋转角度thera
霍夫直线检测是一种在图像中检测直线的计算机视觉技术,它基于霍夫变换的原理。在霍夫变换中,图像空间中的直线被映射到参数空间(通常是一个二维空间,表示直线的斜率和截距)中的一个点上。通过统计参数空间中的累积投票,可以确定图像中直线的位置和方向。霍夫直线检测特别适用于含有噪声的图像,能够有效识别出图像中的直线段,即使这些直线段在图像中不是完全连续的。在opencv中使用cv2.HoughLinesP()获取霍夫直线。
函数介绍:

cv2.HoughLinesP(image, rho, theta, threshold, minLineLength=None, maxLineGap=None)
输入:
● image: 输入图像,通常是经过边缘检测(如 Canny 检测)的二值图像。
● rho: 参数空间中极坐标的半径步长,以像素为单位。
● theta: 参数空间中极坐标的角度步长,以弧度为单位。
● threshold: 累计投票的阈值,只有当参数空间中的点的累计票数超过这个阈值时,才被认为是直线。
● minLineLength: 最小直线长度,单位为像素,低于这个长度的线段不会被检测出来。
● maxLineGap: 允许线段之间的最大间隙,单位为像素,如果线段之间的间隙超过这个值,它们将被视为两条不同的线段。
返回值:
cv2.HoughLinesP() 函数返回一个列表,列表中的每个元素都是一个包含四个整数的元组,代表检测到的线段的起点和终点的坐标 (x1, y1, x2, y2)。

实现代码:

 canny = cv2.Canny(eroDil, 50, 150)
    # 使用霍夫变换检测图像中的直线
    lines = cv2.HoughLinesP(canny, 1.2, np.pi / 180, 90, minLineLength=100, maxLineGap=10)
    # 创建一个与原图同样大小的黑色背景图像,用于绘制线条
    drawing = np.zeros(src.shape[:], dtype=np.uint8)
    thera = 0
    # 遍历检测到的线条,并在黑色背景上绘制
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(drawing, (x1, y1), (x2, y2), (0, 255, 0), 1, lineType=cv2.LINE_AA)
        # 计算直线的斜率
        k = float(y1 - y2) / (x1 - x2)
        # 将斜率转换为角度
        thera = np.degrees(math.atan(k))

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

3.3 对图像旋转theta度

图像旋转使用opencv自带函数cv2.getRotationMatrix2D(center, angle, scale),与cv2.warpAffine(image, wrapMat, (h, w)),前者生成旋转矩阵,后者将旋转矩阵应用到图像上,函数解释可以看我的文章从零开始学cv-5:图像的仿射变换。
实现代码:

def rotate(image, angle, center=None, scale=1.0):
    # 获取图像的宽度和高度
    (w, h) = image.shape[0:2]
    # 如果没有提供旋转中心,则默认为图像中心
    if center is None:
        center = (w // 2, h // 2)
        # 获取旋转矩阵
    wrapMat = cv2.getRotationMatrix2D(center, angle, scale)
    # 应用旋转矩阵到图像上,并返回旋转后的图像
    return cv2.warpAffine(image, wrapMat, (h, w))

四,整体代码实现

import numpy as np
import os
import cv2
import math
from scipy import misc, ndimage


# 定义一个函数,用于旋转图像
def rotate(image, angle, center=None, scale=1.0):
    # 获取图像的宽度和高度
    (w, h) = image.shape[0:2]
    # 如果没有提供旋转中心,则默认为图像中心
    if center is None:
        center = (w // 2, h // 2)
        # 获取旋转矩阵
    wrapMat = cv2.getRotationMatrix2D(center, angle, scale)
    # 应用旋转矩阵到图像上,并返回旋转后的图像
    return cv2.warpAffine(image, wrapMat, (h, w))


# 定义主函数,用于图像校正
def getCorrect2():
    # 读取图片,并显示原始图像
    src = cv2.imread(r'F:\traditional_vison\Inpainted.jpg')
    showAndWaitKey("src", src)
    # 将图像转换为灰度图,并显示
    gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    # 创建一个5x5的核,用于形态学操作
    kernel = np.ones((5, 5), np.uint8)
    # 对灰度图进行腐蚀操作
    erode_Img = cv2.erode(gray, kernel)
    # 对腐蚀后的图像进行膨胀操作
    eroDil = cv2.dilate(erode_Img, kernel)
    # 显示膨胀后的图像
    showAndWaitKey("eroDil", eroDil)

    # 使用Canny算法进行边缘检测
    canny = cv2.Canny(eroDil, 50, 150)

    # 使用霍夫变换检测图像中的直线
    lines = cv2.HoughLinesP(canny, 1.2, np.pi / 180, 90, minLineLength=100, maxLineGap=10)
    # 创建一个与原图同样大小的黑色背景图像,用于绘制线条
    drawing = np.zeros(src.shape[:], dtype=np.uint8)
    thera = 0
    # 遍历检测到的线条,并在黑色背景上绘制
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(drawing, (x1, y1), (x2, y2), (0, 255, 0), 1, lineType=cv2.LINE_AA)
        # 计算直线的斜率
        k = float(y1 - y2) / (x1 - x2)
        # 将斜率转换为角度
        thera = np.degrees(math.atan(k))
        print(thera)
    # 显示绘制线条的图像
    showAndWaitKey("houghP", drawing)

    # 根据计算出的角度旋转原始图像
    rotateImg = rotate(src, thera)
    # 显示旋转后的图像
    cv2.imshow("rotateImg", rotateImg)
    # 等待按键后继续
    cv2.waitKey()
    # 关闭所有OpenCV窗口
    cv2.destroyAllWindows()
    # 保存旋转后的图像
    cv2.imwrite('result.jpg', rotateImg)


# 定义一个辅助函数,用于显示图像并等待按键
def showAndWaitKey(winName, img):
    cv2.imshow(winName, img)
    cv2.waitKey()
# 程序入口
if __name__ == "__main__":
    getCorrect2()

五,效果:

在这里插入图片描述

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值