利用paddleocr解决图片旋转问题

由于之前使用easyocr识别图片的时候发现旋转的图片或者倒置的图片效果很差,来利用 cv2.minAreaRect()获取旋转角度,只能解决0-90,对于倒置的图片不能很好解决,因此使用paddleocr中方向分类检测(只能返回0,180)刚好可以用于倒置的图片判断。(当前问题仅仅考虑的是横向文本,不考虑纵向文本,由于paddleocr中方向分类检测0,180也不是100%准确。旋转矫正效果不是100%)

案例演示

在这里插入图片描述

第一步:cv2.minAreaRect()获取旋转角度

cv2.minAreaRect()在opencv中老版本返回的是-90到0,新版本0到90,当前使用的是新版处理方式

#获取旋转角度
def get_angle(result):
    longs = []  # 记录文本框的长度
    weights = []  # 记录文本框的长度*angle
    angles = []
    for line in result:
        points = line.get('box')
        # angles.append(int(line.get('angle')[0]))
        # print("文本框的坐标:", points, line.get('text'), line.get('angle'))
        # 计算角度(示例中为简单的两点计算)
        # 假设 points 是四个点的坐标
        x1, y1 = points[0]
        x2, y2 = points[1]
        x3, y3 = points[2]
        x4, y4 = points[3]
        # print(x1, y1, x2, y2, x3, y3, x4, y4)
        # 根据4个点坐标求最小外接矩阵
        cnt = np.array([[x1, y1], [x2, y2], [x3, y3], [x4, y4]], dtype=np.float32)  # 必须是array数组的形式
        rect = cv.minAreaRect(cnt)  # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
        box = cv.boxPoints(rect)  # cv2.boxPoints(rect) for OpenCV 3.x 获取最小外接矩形的4个顶点坐标
        # box = np.int0(box)
        box = np.intp(box)
        # 旋转角度
        width, height = cv.minAreaRect(cnt)[1]
        # print(width, height)
        # 示例矩形点
        # rect_points = [[2240.0, 1214.0], [3120.0, 1214.0], [3120.0, 1338.0], [2240.0, 1338.0]]
        is_skewed = is_rectangle_skewed(points)
        if is_skewed:
            # 矩形倾斜
            pass
        else:
            x_w = x2 - x1
            y_h = y3 - y2
            if x_w > y_h:
                width, height = y_h, x_w
            else:
                width, height = y_h, x_w

        theta = cv.minAreaRect(cnt)[2]  # (0,90)
        if width < height:  # 切换新版本
            if theta == 90 or theta == 0:  # 长方形正常的时候返回的角度,0获取90,默认就是没有转
                angle = 0
            else:
                angle = theta - 90
            # print("angle1", angle)
            longs.append(height)
            angles.append(angle)
        else:
            if theta == 90 or theta == 0:  # 长方形垂直的时候返回的角度,0获取90,默认就是转90
                angle = 90
            else:
                angle = theta
            # print("angle2", angle)
            angles.append(angle)
            longs.append(width)
            # weights.append(angle * width)

    weights = [i * abs(j) for i, j in zip(longs, angles)]
    angle_s = (sum(weights) / sum(longs))

    # 判断正负
    is_numbers = len([num for num in angles if num > 0])
    ne_numbers = len([num for num in angles if num < 0])
    if is_numbers < ne_numbers:
        angle_s = -angle_s
    # print("angle_s", angle_s)
    all_angles=[int(i.get("angle")[0]) for i in result]  #paddleocr给的整体旋转角度(0,180)

    median_angle = np.median(all_angles)  # 中位数抗噪性更好
    # print(median_angle)
    median_angle_0 = all_angles.count(0)
    if median_angle_0 / len(all_angles) >= 0.4:
        median_angle = 0
    res_angle=median_angle+angle_s
    # print(median_angle)
    # print(res_angle)
    return res_angle

第二步:使用paddleocr进行判断角度是0还是180

因为安装paddleocr太麻烦了,当前使用是imgocr调用的是paddleocr的模型

import sys,cv2,os
import numpy as np
from imgocr import ImgOcr
from imgocr import draw_ocr_boxes
import shutil
from  get_paddleocr_angle import get_angle
## 图片旋转
def rotate_image(image, angle):
    # 获取图像的高度和宽度
    (h, w) = image.shape[:2]

    # 计算图像的中心
    (cX, cY) = (w // 2, h // 2)

    # 获取旋转矩阵,参数为旋转中心、旋转角度和缩放因子
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)

    # 计算旋转后图像的新宽度和高度
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # 计算旋转后的图像尺寸
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # 调整旋转矩阵,确保旋转后图像不被裁切
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # 使用 warpAffine 进行旋转
    rotated_image = cv2.warpAffine(image, M, (nW, nH), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

    return rotated_image



if __name__ == "__main__":
    m = ImgOcr(use_gpu=True, is_efficiency_mode=True)  #is_efficiency_mode=True表示使用移动端的模型
    img_path = r"Snipaste_2025-02-21_180.png"
    img_save_path = "temp.jpg"
    # first_set_right
    result = m.ocr(img_path, cls=True)
    pic_angle = get_angle(result)
    if abs(pic_angle) < 10:
        shutil.copy(img_path, img_save_path)
    else:
        cv_img = cv2.imread(img_path)
        rotate_img = rotate_image(cv_img, -pic_angle)
        cv2.imwrite(img_save_path, rotate_img)
    # second_set_right
    img_path = img_save_path
    result = m.ocr(img_path, cls=True)
    pic_angle = get_angle(result)
    if abs(pic_angle) < 10:
        pass
    else:
        cv_img = cv2.imread(img_path)
        rotate_img = rotate_image(cv_img, -pic_angle)
        cv2.imwrite(img_save_path, rotate_img)
    result_cls = m.ocr(img_path, cls=True)
    draw_ocr_boxes(img_path, result_cls, 'temp_custom.jpg')

根据上面矫正之后的图片进行识别效果会更友好,其次大家也可以尝试使用easyocr和paddleocr的检测、识别功能混合使用进行测试。

代码、模型已经打包放入资源里了

当前个人部署服务器,体验地址:输入图片识别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空弹壳

你的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值