Python OpenCV实现任意角度二维码矫正

 更新时间:2022年05月31日 14:48:07   作者:水中加点糖  
这篇文章主要为大家详细介绍了如何利用Python OpenCV实现任意角度的二维码快速矫正,文中的示例代码讲解详细,感兴趣的小伙伴可以尝试一下

前言

那天听到领导他们在讨论,说要将图片进行个矫正处理,还叫来了算法部的大佬来讨论将要如何处理这个,讨论场面很是激烈

不得不说好奇心是个很神奇的东西,就把我给吸引过去了

我定眼一看,感觉作为JAVA开发的我自己也能进行处理

因为看到了图片后,发现了图片中一个很重要的特征点:

要进行矫正的图片中都会有一个二维码图案,想要矫正的文字和二维码图案是处于同一水平线的。

如下面这个

要把图片中的“水中加点糖”四个字矫正,只需要把二维码矫正就可以了。

具体想法就是,求得二维码矫正的角度a,对原图整体按照角度a进行旋转就可以了。

有了想法后,就趁热打铁,正好周末了在家试试。

一般图片矫正方式

对于一般的图片矫正,最常见的做法有这么两种:

对图片进行预处理获取出轮廓,并求得轮廓的近似矩形,通过矩形的定位点来进行透视变换

对图片进行预处理后,进行霍夫变换进行直线检测,再根据直线的倾斜角进行旋转

但是对于图片中有二维码的图片进行矫正就可以更加简单了,因为二维码中有定位点并且成熟框架很多,实现起来也更加方便且识别率非常高。

二维码图片矫正

思路

识别出二维码的角点,通过相邻两个角点的坐标计算出夹角度数,再次用此度数对图片进行旋转。

以下面图为例:

先获取出二维码正方向时底部的两点坐标,并求得两点的倾斜角。

斜率计算用初中数学中求两点坐标斜率的公式算一下即可,忘了就搜搜回忆一下:

两点的斜率公式:k=(y1-y2)/(x1-x2),x1≠x2。其中(x1,y1),(x2,y2)是已知两点的坐标,x1≠x2。

斜率是表示一条直线(或曲线的切线)关于(横)坐标轴倾斜程度的量。它通常用直线(或曲线的切线)与(横)坐标轴夹角的正切,或两点的纵坐标之差与横坐标之差的比来表示。记作k,k=tgα。

一条直线与某平面直角坐标系横坐标轴正半轴方向所成的角的正切值即该直线相对于该坐标系的斜率。如果直线与x轴互相垂直,直角的正切值为tan90°,故此直线不存在斜率(也可以说直线的斜率为无穷大)。当直线L的斜率存在时,对于一次函数y=kx+b(斜截式),k即该函数图像的斜率。

编码实现

实现时对于二维码的识别用到了pyzbar库,对图片处理用的opencv包

"""
author: puhaiyang
blog: https://blog.csdn.net/puhaiyang
github: https://github.com/puhaiyang
"""
import math
import cv2
from pyzbar import pyzbar
import imutils


def azimuthangle(x1, y1, x2, y2):
    """ 已知两点坐标计算角度 -
    :param x1: 原点横坐标值
    :param y1: 原点纵坐标值
    :param x2: 目标点横坐标值
    :param y2: 目标纵坐标值
    """
    dx = x2 - x1
    dy = y2 - y1
    # 求斜率
    k = dy / dx
    # 结果是弧度值
    angle = math.atan(k)
    # 弧度值转为角度
    return angle * 180 / math.pi


def get_angle(qr_item):
    """
    获取出进行矫正所需要的角度
    """
    # 将坐标从下到上,从左到右进行排序
    locs = {qr_item.polygon[0], qr_item.polygon[1], qr_item.polygon[2], qr_item.polygon[3]}
    locs = sorted(locs, key=lambda x: x.y * 100000 + x.x * 1000)
    return azimuthangle(locs[2].x, locs[2].y, locs[3].x, locs[3].y)


def to_up_angle(qr_item):
    """
    获取出使二维码朝上的角度
    """
    if qr_item.orientation == 'UP':
        angle_ext = 0
    elif qr_item.orientation == 'RIGHT':
        angle_ext = 270
    elif qr_item.orientation == 'DOWN':
        angle_ext = 180
    else:
        angle_ext = 90
    return angle_ext


def resize_img(ori_img):
    """
    图片压缩
    """
    height = ori_img.shape[0]
    width = ori_img.shape[1]
    # 执行压缩,按照500的宽度为标准
    if width > 500:
        scale_percent = int(500 / width * 100)
        s_width = int(width * scale_percent / 100)
        s_height = int(height * scale_percent / 100)
        # 新的宽度和高度
        dim = (s_width, s_height)
        return cv2.resize(ori_img, dim, interpolation=cv2.INTER_AREA)
    else:
        return ori_img


def adjust_rotae_angle(img):
    angle = 0
    # 对图片进行压缩
    img = resize_img(img)
    # symbol为64代表二维码
    qr_result = pyzbar.decode(img, symbols=[64])
    if len(qr_result) == 1:
        # 识别到了一个二维码,将二维码朝上旋转
        first_adjust_angle = to_up_angle(qr_result[0])
        # 进行旋转
        img_rotae_to_up = imutils.rotate_bound(img, first_adjust_angle)
        # 再次识别
        qr_result2 = pyzbar.decode(img_rotae_to_up, symbols=[64])
        if len(qr_result2) == 1:
            last_adjust_angle = -get_angle(qr_result2[0])
            angle = first_adjust_angle + last_adjust_angle
            print("first angle:%d last angle:%d angle:%d" % (first_adjust_angle, last_adjust_angle, angle))
        else:
            print('last 未识别到二维码')
    else:
        print('first 未识别到二维码')
    return angle


if __name__ == '__main__':
    # 加载图片
    img = cv2.imread('123.jpg')
    adjust_angle = adjust_rotae_angle(img.copy())
    if adjust_angle != 0:
        img_rotae = imutils.rotate_bound(img, adjust_angle)
        cv2.imwrite('img_rotae.jpg', img_rotae)

最终输出的图片结果:

矫正成功!

需要说明的是,上面之所以要进行对图片的resize,是因为图片太大的话pyzbar可能会识别不出来二维码

到此这篇关于Python OpenCV实现任意角度二维码矫正的文章就介绍到这了,更多相关Python OpenCV二维码矫正内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 如何把python项目部署到linux服务器

    如何把python项目部署到linux服务器

    这篇文章主要介绍了如何把python项目部署到linux服务器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • 中秋快到了利用python画个月亮和月饼

    中秋快到了利用python画个月亮和月饼

    眼看中秋又快到了,今天小编就利用python画出月亮和月饼,感兴趣的小伙伴一定要收藏起来送给远方的朋友呀
    2021-09-09
  • Python基础之hashlib模块subprocess模块logging模块

    Python基础之hashlib模块subprocess模块logging模块

    这篇文章主要为大家介绍了Python基础之hashlib模块subprocess模块logging模块示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 一文了解conda虚拟环境的使用及常见问题

    一文了解conda虚拟环境的使用及常见问题

    管理不同项目的依赖关系是一个常见而棘手的问题,本文主要介绍了一文了解conda虚拟环境的使用及常见问题,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Python中字符串和列表去重方法总结

    Python中字符串和列表去重方法总结

    这篇文章主要为大家整理了Python中实现字符串和列表去重的常用方法,文中的示例代码讲解详细,对我们深入了解Python有一定的帮助,感兴趣的可以了解一下
    2023-04-04
  • Python中threading模块join函数用法实例分析

    Python中threading模块join函数用法实例分析

    这篇文章主要介绍了Python中threading模块join函数用法,以实例形式较为详细的分析了join函数的功能与使用方法,需要的朋友可以参考下
    2015-06-06
  • Python检测端口IP字符串是否合法

    Python检测端口IP字符串是否合法

    这篇文章主要介绍了Python检测端口IP字符串是否合法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Python实现softmax反向传播的示例代码

    Python实现softmax反向传播的示例代码

    这篇文章主要为大家详细介绍了Python实现softmax反向传播的相关资料,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的可以了解一下
    2023-04-04
  • 详解Python中各种运算符的使用

    详解Python中各种运算符的使用

    在 Python 编程中,运算符是用于执行各种数学和逻辑操作的特殊符号,本文我们就深入探讨 Python 中的常见运算符,并通过丰富的案例来说明它们的用法和功能吧
    2023-07-07
  • python 随机生成10位数密码的实现代码

    python 随机生成10位数密码的实现代码

    这篇文章主要介绍了python 随机生成10位数密码的实现代码,在文中给大家提到了生成随机密码要实现的功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-06-06

最新评论