发票二维码扫描增强_06_持续优化

整个功能完成后,对扫描速度进行了测试,在I7 6700的CPU机器上,一个图片扫描的时间大概在5-7秒之间:

"E:\python workspace\qrcode-complement\venv\Scripts\python.exe" "E:/python workspace/qrcode-complement/main.py"
对二维码部分进行切片处理:0.25531697273254395
对图片进行预处理:0.013962984085083008
对图片基于极点进行拉伸转换:1.6815056800842285
将图片基于自适应阈值进行二值化:0.007976531982421875
left_top_flag:all
left_bottom_flag:none
right_top_flag:all
right_bottom_flag:all
将图片恢复竖直状态:0.2682826519012451
寻找图片的分割线:1.8709981441497803
生成目标图片:0.26429295539855957
总共耗费时间:4.4122045040130615
总共扫描出:0

从时间耗费来看,拉伸转换和分割线耗费了大部分的时间。经过分析程序,应该是有两段for循环赋值的逻辑导致的速度过慢。

按照我们预计的407 * 407 的图片大小,每次执行for循环都需要执行16.5万次,是一种比较低效的写法。

比较高效的写法应该是采用numpy提供的一些矩阵运算的函数来进行计算,自己琢磨了一下,改进了一下算法

矩阵运算

自定义灰度算法


    # 加权平均值法灰度化
    def gray_scale(self, image):
        gray_image = image.copy()

        # 循环写法
        # for i in range(image.shape[0]):
        #     for j in range(image.shape[1]):
        #         if (image[i, j][0] < image[i, j][1] or image[i, j][0] < image[i, j][2]) and image[i, j][0] < 150:
        #             # 其他颜色值高于蓝色,且蓝色低于150,说明是其他颜色覆盖
        #             gray_image[i][j] = 255
        #         else:
        #             # gray_image[i, j] = min(0.8 * image[i, j][0] + 0.1 * image[i, j][1] + 0.1 * image[i, j][2],255)
        #             grayResult = max(min(-1.5 * image[i, j][0] + 1.5 * image[i, j][1] + 1.5 * image[i, j][2], 255), 0)
        #             gray_image[i][j] = grayResult
        # return gray_image

        # 矩阵算法
        ratio = 1.5
        b = np.ones((image.shape[0], image.shape[1]), np.int16)
        g = np.ones((image.shape[0], image.shape[1]), np.int16)
        r = np.ones((image.shape[0], image.shape[1]), np.int16)
        source_b, source_g, source_r = cv2.split(gray_image)

        b[:, :] = source_b[:, :]
        g[:, :] = source_g[:, :]
        r[:, :] = source_r[:, :]

        g_minus_b = g - b
        r_minus_b = r - b

        g_minus_b = np.where(g_minus_b > 0, 1000, 0)
        r_minus_b = np.where(r_minus_b > 0, 1000, 0)

        g_minus_b_150 = np.where((g_minus_b - b) >= 850, 255, 0)
        r_minus_b_150 = np.where((r_minus_b - b) >= 850, 255, 0)
        g_r_minus_b_150 = g_minus_b_150 + r_minus_b_150
        not_b_lt_150 = np.where(g_r_minus_b_150 >= 255, -9999, 0)

        b_plus_g_r = -1 * ratio * b + ratio * g + ratio * r
        b_plus_g_r = np.where(b_plus_g_r < 0, 0, b_plus_g_r)
        b_plus_g_r = np.where(b_plus_g_r > 255, 255, b_plus_g_r)
        b_result = not_b_lt_150 + b_plus_g_r
        b_result = np.where(b_result < -9000, 255, b_result)
        b_result = np.where(b_result < 0, 0, b_result)
        b_result = np.where(b_result > 255, 255, b_result)

        gray_image[:, :, 0] = b_result[:, :]
        gray_image[:, :, 1] = b_result[:, :]
        gray_image[:, :, 2] = b_result[:, :]

        return gray_image

寻找分割线


def Point_rows(mat, border):
    # 先找上下限
    cv2.imwrite("images/erode9.1.jpg", mat)

    # loop写法
    # lower_limit_j = []
    # for i in range(0, mat.shape[1]):
    #     for j2 in range(0, min(border, mat.shape[0]) - 1):
    #         if mat[0:j2 + 1, i].mean() == 255 and mat[j2 + 1, i] == 0 and j2 > 2:  # 如果这一列,超过5个全是白色,下一个是黑色  则认为也到了边界
    #             lower_limit_j.append(j2)
    #             break
    #         elif mat[j2, i] == 0 and mat[j2 + 1, i] == 255 and j2 > 2:  # 如果这个是黑色而且下一个是白色,并且黑色数量大于五个,则认为到达了下限边界
    #             lower_limit_j.append(j2)
    #             break
    #     if mat[:, i].mean() == 0:  # 如果这一列全部为黑色,则占满13
    #         # lower_limit_j.append(12.4)
    #         continue
    #     elif mat[:, i].mean() == 255:  # 如果这一列全部为白色色,则占11
    #         # lower_limit_j.append(11.3)
    #         continue
    # if len(lower_limit_j) == 0:
    #     return 6
    # return max(int(np.median(np.array(lower_limit_j))), int((np.array(lower_limit_j).mean())))

    # 矩阵算法
    gap = 3
    result_array = []
    white_tmp_matrix = np.zeros((1, mat.shape[1]), np.int16)
    black_last_matrix = np.zeros((1, mat.shape[1]), np.int16)
    # 从白色点变为黑色点,白色连续线段超过2,下一个点为黑点
    for i in range(0, min(border, mat.shape[0])):
        # 循环所有列
        if i == 0:
            white_tmp_matrix = np.where(mat[i, :] == 255, 1, 0)
        else:
            white_current_matrix = np.where(mat[i, :] == 255, 1, -1)
            white_cal_matrix = white_tmp_matrix * white_current_matrix
            white_count_matrix = np.where(white_cal_matrix == -1, 1, 0)
            white_change_count = white_count_matrix.sum()

            # 变更tmp,将已经变化的点修改为0
            white_tmp_matrix = white_tmp_matrix * np.where(white_cal_matrix == -1, 0, 1)
            # j > gap宽度则计入计算
            if i > gap and white_change_count > 0:
                for k in range(0, white_change_count):
                    result_array.append(i - 1)

        # 循环所有列
        if i == 0:
            black_last_matrix = np.where(mat[i, :] == 0, 1, 0)
        else:
            black_current_matrix = np.where(mat[i, :] == 0, 5, 1)
            # 计算结果为:
            # 上次为白,本次为黑:5
            # 上次为黑,本次为白,2
            # 上次为白,本次为白,1
            # 上次为黑,本次为黑,6
            # 历史存在过黑, 1000 +,不参与计算

            black_cal_matrix = black_last_matrix + black_current_matrix
            # 统计上次为黑本次为白
            black_count_matrix = np.where(black_cal_matrix == 2, 1, 0)
            black_change_count = black_count_matrix.sum()

            # 变更tmp
            black_last_matrix = black_cal_matrix
            # 上次为白,本次为白,更新为0
            black_last_matrix = np.where(black_last_matrix == 1, 0, black_last_matrix)
            # 上次为黑,本次为白,更新为1000
            black_last_matrix = np.where(black_last_matrix == 2, 1000, black_last_matrix)
            # 上次为白,本次为黑,更新为1
            black_last_matrix = np.where(black_last_matrix == 5, 1, black_last_matrix)
            # 上次为黑,本次为黑,更新为1
            black_last_matrix = np.where(black_last_matrix == 6, 1, black_last_matrix)

            # j > gap宽度则计入计算
            if i > gap and black_change_count > 0:
                for k in range(0, black_change_count):
                    result_array.append(i - 1)

        # 无需考虑_白点和黑点的变更都计入,不在参与下一行的处理
        # if i != 0:
        #     white_change_matrix = np.where(white_cal_matrix == -1, 1000, 0)
        #     black_change_matrix = np.where(black_current_matrix == 2, 0, 1)
        #
        #     black_last_matrix = black_last_matrix + white_change_matrix
        #     white_tmp_matrix = white_tmp_matrix * black_change_matrix
    result = max(int(np.median(np.array(result_array))), int((np.array(result_array).mean())))
    return result

优化后的扫描速度:1.4秒

对二维码部分进行切片处理:0.2293868064880371
对图片进行预处理:0.011968851089477539
对图片基于极点进行拉伸转换:0.0857694149017334
将图片基于自适应阈值进行二值化:0.007978439331054688
left_top_flag:all
left_bottom_flag:none
right_top_flag:all
right_bottom_flag:all
将图片恢复竖直状态:0.2982046604156494
寻找图片的分割线:0.3809800148010254
生成目标图片:0.37898731231689453
总共耗费时间:1.4411475658416748

从时间耗费来看,只要存在循环处理的部分,程序的速度还是偏慢,而调用opencv的api确实速度非常快。

这种优化的主要思想是:

借助数值分段,将原本需要进行循环读取,进行if判断的逻辑,通过存储的数值的分段进行分割。最终通过numpy.where方法,将分段区间内的数字转换成目标值。

降低运算量

还有一种速度优化的思路,就是降低目标图片的分辨率。这种方案可能对图片的识别效果产生一定的不良影响,但是可以极大的提升扫描速度。

例如,当我们定义每一个单元格由5px组成是,那么整个图片的目标面积为 37 * 5 * 37 * 5 = 3.4万,比起目前的16.5万整体运算量直接降低到20%

这个识别率和扫描速度最优的点需要调试后才能得出,作为后续持续优化的一个方向。

原文地址:https://www.cnblogs.com/mousezhou/p/9261165.html

时间: 2024-11-10 17:41:14

发票二维码扫描增强_06_持续优化的相关文章

发票二维码扫描增强_05_构建目标二维码

根据前面获得的行.列分割,我们可以得到 37 * 37个矩阵.根据每个矩阵内的数值信息,可以计算出当前矩阵所代表的数据点,是黑色格子还是白色格子. 从发票的二维码分析,存在以下几种图形特征: 1.图形整体界限分明,每个黑色格子内容饱满,白色格子留白清晰 2.图形大体界限分明,白色格子留白清晰,存在部分黑色格子打印质量较差,无法占满一行,只能占中心部分 3.图形整体糊化严重,黑色格子边界溢出严重,白色格子严重被侵蚀 4.图形大体界限分明,部分格子出现向右溢出的情况,部分格子无法清晰的分辨黑白 根据

发票二维码扫描增强_02_算法概述

技术选型 为了解决二维码无法扫描的问题,必须选择合适的技术手段.由于我们的App引用的是别人开发的基于Zbar的图像识别插件,在没有能力修改图像识别插件的前提下,我决定在服务端解决这个问题,考虑到算法的通用型,在服务端验证通过的程序后期也可以考虑移植到App端,提高本地扫描速度,降低服务器性能消耗.IOS和Android的插件都存在相机对焦完成的事件,在该事件中可以拿到图像信息,我计划在拿到对焦完成的图片后,进行简单压缩后传输至服务器进行解析处理,再将服务器返回的解析结果作为解码结果传递给前台应

二维码扫描

1.将ZBar的SDK导入工程 SDK下载地址:https://i.cnblogs.com/Files.aspx 或者去官网下载:https://github.com/bmorton/ZBarSDK 2.设置依赖库 需要添加AVFoundation  CoreMedia  CoreVideo QuartzCore libiconv 3.修改工程配置 1)      Framework Search Path 2)      如果使用xcode7.0以上 ,还需设置: /* 4. 版本说明  1.

iOS使用AVFoundation实现二维码扫描

实现过程如下: Step1:需要导入:AVFoundation Framework 包含头文件: #import <AVFoundation/AVFoundation.h> Step2:设置捕获会话 设置 AVCaptureSession 和 AVCaptureVideoPreviewLayer 成员 1 2 3 4 5 6 7 8 9 10 #import <AVFoundation/AVFoundation.h> static const char *kScanQRCodeQu

【转】 iOS使用AVFoundation实现二维码扫描

原文:http://strivingboy.github.io/blog/2014/11/08/scan-qrcode/ 关于二维码扫描有不少优秀第三方库如: ZBar SDK 里面有详细的文档,相应介绍也非常多,如:http://rdcworld-iphone.blogspot.in/2013/03/how-to-use-barcode-scanner-br-and-qr-in.html ZXing google推出的开源项目,相应介绍如:http://blog.devtang.com/blo

iOS开发-二维码扫描和应用跳转

iOS开发-二维码扫描和应用跳转 序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar.使用时集成麻烦,出错也不方便调试.在iOS7之后,苹果自身提供了二维码的扫描功能,从效率上来说,原生的二维码远高于这些第三方框架.本文讲解如何使用原生框架实现二维码扫描功能,并且进行扫描后的项目跳转.ps:本期的源代码会在文章结尾给出链接 扫描相关类 二维码扫描需要获取摄像头并读取

Swift:使用系统AVFoundation实现二维码扫描和生成

系统提供的AVCaptureSession仅仅适用于iOS7.0以上的系统.之前的请用Zbar来替代 下载地址:http://download.csdn.net/detail/huobanbengkui/8881097 配置project: 引入: import Foundation import AVFoundation 接受AVCaptureMetadataOutputObjectsDelegate(如: class QrcodeVC: UIViewController,AVCaptureM

iOS 系统二维码扫描(可限制扫描区域)

使用 AVFoundation系统库来进行二维码扫描并且限制扫描二维码的范围.(因为默认的是全屏扫描) -(void)beginCode { //1.摄像头设备 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; /* // Media types AVMediaTypeVideo AVMediaTypeAudio AVMediaTypeText AVMediaTypeC

Ios二维码扫描(系统自带的二维码扫描)

Ios二维码扫描 这里给大家介绍的时如何使用系统自带的二维码扫描方法和一些简单的动画! 操作步骤: 1).首先你需要搭建UI界面如图:下图我用了俩个imageview和一个label 2).你需要在你当前的控制器中导入 #import <AVFoundation/AVFoundation.h> <AVCaptureMetadataOutputObjectsDelegate>代理 3).在@interface中定义 @property (nonatomic,strong)AVCapt