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

根据前面获得的行、列分割,我们可以得到 37 * 37个矩阵。根据每个矩阵内的数值信息,可以计算出当前矩阵所代表的数据点,是黑色格子还是白色格子。

从发票的二维码分析,存在以下几种图形特征:

1.图形整体界限分明,每个黑色格子内容饱满,白色格子留白清晰
2.图形大体界限分明,白色格子留白清晰,存在部分黑色格子打印质量较差,无法占满一行,只能占中心部分
3.图形整体糊化严重,黑色格子边界溢出严重,白色格子严重被侵蚀
4.图形大体界限分明,部分格子出现向右溢出的情况,部分格子无法清晰的分辨黑白

根据这些特征,我们编写多种策略,每个策略都生成对应的目标图形,按照概率从高到低一一输入给zbar进行扫描

为了匹配这些特征,我需要对每个格子计算以下信息值:

avg_center_mean:中心点的颜色平均值
avg_total_mean:整个矩阵颜色平均值
avg_round_mean:矩阵外围2px的包围图形的颜色平均值,用于计算周边格子的颜色侵入性
avg_margin_center_mean:矩阵向右偏移的中心点的颜色平均值,用于计算右侧便宜的图形的真实颜色
avg_margin_total_mean:矩阵向右便宜的整体图形的颜色平均值
avg_left_center_mean:矩阵左侧图形颜色均值
avg_right_center_mean:矩阵右侧图形颜色均值
avg_right_1_3_center_mean:矩阵右侧三分之一的颜色均值
avg_offset_3_center_mean:矩阵左侧3个px的图形中心的平均颜色,用于计算图片的向右偏移度

代码如下:


    # 根据原图和行列分割线生成新的二维码图片
    def generate_image(self, image, point_rows, point_columns, defect_flag):
        offset = 6 if defect_flag else 0
        margin_offset = 0
        round_offset = 2

        strategy_001 = np.zeros((407, 407), np.uint8)
        strategy_002 = np.zeros((407, 407), np.uint8)
        strategy_003 = np.zeros((407, 407), np.uint8)
        strategy_004 = np.zeros((407, 407), np.uint8)
        strategy_005 = np.zeros((407, 407), np.uint8)
        strategy_001[0:407, 0:407] = 255
        strategy_002[0:407, 0:407] = 255
        strategy_003[0:407, 0:407] = 255
        strategy_004[0:407, 0:407] = 255
        strategy_005[0:407, 0:407] = 255

        for i in range(-1, len(point_rows) - 1):
            margin_offset = 0
            for j in range(-1, len(point_columns) - 1):

                start_x = 0 if j == -1 else point_columns[j]
                start_y = 0 if i == -1 else point_rows[i]
                end_x = point_columns[j + 1]
                end_y = point_rows[i + 1]
                avg_center = image[start_y + round_offset:end_y - round_offset,
                             start_x + round_offset:end_x - round_offset]
                avg_total = image[start_y:end_y, start_x:end_x]
                avg_round = image[min(start_y - round_offset, 0):min(end_y + round_offset, 406),
                            min(start_x - round_offset, 0):max(end_x + round_offset, 406)]
                avg_y_round = image[min(start_y - round_offset, 0):min(end_y + round_offset, 406),
                              min(start_x, 0):max(end_x, 406)]
                avg_x_round = image[min(point_rows[i], 0):min(point_rows[i + 1], 406),
                              min(point_columns[j] - round_offset, 0):min(point_columns[j + 1] + round_offset, 406)]
                avg_offset_3_center = image[start_y + round_offset:end_y - round_offset, start_x:start_x + 3]
                avg_left_center = image[start_y + round_offset:end_y - round_offset,
                                  start_x:round((start_x + end_x) / 2)]
                avg_margin_center = image[start_y + round_offset:end_y - round_offset,
                                    start_x + round_offset + margin_offset:min(end_x - round_offset + margin_offset,
                                                                               406)]
                avg_margin_total = image[start_y:end_y,
                                   start_x + margin_offset:min(end_x + margin_offset, 406)]
                avg_right_center = image[start_y + round_offset:end_y - round_offset,
                                   round((start_x + end_x) / 2):end_x]
                avg_right_1_3_center = image[start_y + round_offset:end_y - round_offset,
                                       end_x - round((end_x - start_x) / 3):end_x]

                # 整体偏黑判定为黑色
                avg_center_mean = avg_center.mean()
                avg_total_mean = avg_total.mean()
                avg_round_mean = avg_round.mean()
                avg_margin_center_mean = avg_margin_center.mean()
                avg_margin_total_mean = avg_margin_total.mean()
                avg_left_center_mean = avg_left_center.mean()
                avg_right_center_mean = avg_right_center.mean()
                avg_right_1_3_center_mean = avg_right_1_3_center.mean()
                avg_offset_3_center_mean = avg_offset_3_center.mean()
                avg_inner_round_mean = (avg_total.sum() - avg_center.sum()) / (
                        avg_total.shape[0] * avg_total.shape[1] - avg_center.shape[0] * avg_center.shape[1])
                avg_out_round_mean = (avg_round.sum() - avg_total.sum()) / (
                        avg_round.shape[0] * avg_round.shape[1] - avg_total.shape[0] * avg_total.shape[1])
                avg_y_round_mean = (avg_y_round.sum() - avg_total.sum()) / (
                        avg_y_round.shape[0] * avg_y_round.shape[1] - avg_total.shape[0] * avg_total.shape[1])
                avg_x_round_mean = (avg_x_round.sum() - avg_total.sum()) / (
                        avg_x_round.shape[0] * avg_x_round.shape[1] - avg_total.shape[0] * avg_total.shape[1])

                # 如果整体判定为黑色,判断是否存在向右偏移的情况
                # 当前格子的偏移将影响下一个格子的偏移情况
                if avg_center_mean < 50:
                    current_offset = int(round(avg_offset_3_center_mean / 255.0 * 3))
                    margin_offset = current_offset if margin_offset < current_offset else margin_offset
                    if margin_offset == None:
                        margin_offset = 0

                # print("x轴:" + str(j + 1) + ",y轴:" + str(i + 1))
                # print("avg_center_mean:" + str(avg_center_mean))
                # print("avg_total_mean:" + str(avg_total_mean))
                # print("avg_round_mean:" + str(avg_round_mean))
                # print("avt_inner_round_mean:" + str(avg_inner_round_mean))
                # print("avt_out_round_mean:" + str(avg_out_round_mean))

                # 策略1:中心点策略,用于打印标准且溢出较小的情况
                # 中心点:低于80认为黑
                # 中心点:高于150认为白
                # 中心点高于内圈周边认为白
                # 其他认为黑
                if avg_center_mean < 50:
                    strategy_001[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0  # 表示为黑色
                elif avg_center_mean > 150:
                    # 中心点偏白判定为白色
                    strategy_001[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                elif avg_center_mean > avg_inner_round_mean:
                    strategy_001[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                else:
                    strategy_001[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0

                # 策略2:全局策略 + 向右偏移策略
                # 中心点:低于80认为黑
                # 中心点:高于150认为白
                # 右侧偏移中心点:低于80认为黑
                # 右侧偏移中心点:高于150认为白
                # 其他认为黑

                if margin_offset < 3:
                    if avg_center_mean < 120:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0  # 表示为黑色
                    elif avg_center_mean > 150:
                        # 中心点偏白判定为白色
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                    elif avg_center_mean > avg_inner_round_mean:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                    else:
                        strategy_002[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0
                else:
                    if avg_margin_center_mean < 120:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0  # 表示为黑色
                    elif avg_margin_center_mean > 150:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                    elif avg_left_center_mean < 30 and avg_right_center_mean > 100 and avg_right_1_3_center_mean > 150:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                    elif avg_right_center_mean < 80:
                        strategy_002[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0
                    elif avg_right_center_mean >= 150:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                    elif avg_total_mean < avg_out_round_mean:
                        strategy_002[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0
                    elif avg_margin_center_mean > avg_inner_round_mean:
                        strategy_002[i * 11 + 11:i * 11 + 22,
                        (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色
                    else:
                        strategy_002[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0

                # 策略3:全局策略,黑色溢出严重
                # 中心点:低于50认为黑
                # 中心点:高于50认为白
                if avg_center_mean < 50:
                    strategy_003[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 0  # 表示为黑色
                elif avg_center_mean > 50:
                    # 中心点偏白判定为白色
                    strategy_003[i * 11 + 11:i * 11 + 22, (j + offset) * 11 + 11: (j + offset) * 11 + 22] = 255  # 表示为白色

        strategy_001 = self.fill_detect(strategy_001)
        strategy_002 = self.fill_detect(strategy_002)
        strategy_003 = self.fill_detect(strategy_003)
        strategy_004 = self.fill_detect(strategy_004)
        strategy_005 = self.fill_detect(strategy_005)

        strategy_001_path = self.tmp_image_path + "strategy001_" + self.image_name
        strategy_002_path = self.tmp_image_path + "strategy002_" + self.image_name
        strategy_003_path = self.tmp_image_path + "strategy003_" + self.image_name
        strategy_004_path = self.tmp_image_path + "strategy004_" + self.image_name
        strategy_005_path = self.tmp_image_path + "strategy005_" + self.image_name

        cv2.imwrite(strategy_001_path, strategy_001)
        cv2.imwrite(strategy_002_path, strategy_002)
        cv2.imwrite(strategy_003_path, strategy_003)
        cv2.imwrite(strategy_004_path, strategy_004)
        cv2.imwrite(strategy_005_path, strategy_005)

        return strategy_001_path, strategy_002_path, strategy_003_path, strategy_004_path, strategy_005_path

    # 补齐缺失图片
    def fill_detect(self, image):
        # 重构左侧坐标点
        image[0:77, 0:77] = 0
        image[11:66, 11:66] = 255
        image[22:55, 22:55] = 0

        image[330:407, 0:77] = 0
        image[341:396, 11:66] = 255
        image[352:385, 22:55] = 0

        # 重构右侧坐标点
        image[0:77, 330:407] = 0
        image[11:66, 341:396] = 255
        image[22:55, 352:385] = 0

        # 重构定位点
        image[66:77, 77:88] = 255
        image[66:77, 88:99] = 0
        image[66:77, 99:110] = 255
        image[66:77, 110:121] = 0
        image[66:77, 121:132] = 255
        image[66:77, 132:143] = 0
        image[66:77, 143:154] = 255
        image[66:77, 154:165] = 0
        image[66:77, 165:176] = 255
        image[66:77, 176:187] = 0
        image[66:77, 187:198] = 255
        image[66:77, 198:209] = 0
        image[66:77, 209:220] = 255
        image[66:77, 220:231] = 0
        image[66:77, 231:242] = 255
        image[66:77, 242:253] = 0
        image[66:77, 253:264] = 255
        image[66:77, 264:275] = 0
        image[66:77, 275:286] = 255
        image[66:77, 286:297] = 0
        image[66:77, 297:308] = 255
        image[66:77, 308:319] = 0
        image[66:77, 319:330] = 255

        image[77:88, 66:77] = 255
        image[88:99, 66:77] = 0
        image[99:110, 66:77] = 255
        image[110:121, 66:77] = 0
        image[121:132, 66:77] = 255
        image[132:143, 66:77] = 0
        image[143:154, 66:77] = 255
        image[154:165, 66:77] = 0
        image[165:176, 66:77] = 255
        image[176:187, 66:77] = 0
        image[187:198, 66:77] = 255
        image[198:209, 66:77] = 0
        image[209:220, 66:77] = 255
        image[220:231, 66:77] = 0
        image[231:242, 66:77] = 255
        image[242:253, 66:77] = 0
        image[253:264, 66:77] = 255
        image[264:275, 66:77] = 0
        image[275:286, 66:77] = 255
        image[286:297, 66:77] = 0
        image[297:308, 66:77] = 255
        image[308:319, 66:77] = 0
        image[319:330, 66:77] = 255

        # 重构右下角定位点
        # [29:34,29:34] 0
        # [30:33,30:33] 255
        # [31:32,31:32] 0
        image[308:363, 308:363] = 0
        image[319:352, 319:352] = 255
        image[330:341, 330:341] = 0
        return image

生成的图片,每个策略偏向于不同的图片场景,只需要确保所有策略生成的图片中存在可以扫描的一张即可:

策略1:

策略2:

策略3:

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

时间: 2024-10-09 02:47:42

发票二维码扫描增强_05_构建目标二维码的相关文章

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

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

发票二维码扫描增强_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 对图片基于

二维码扫描开源库ZXing定制化

(抱歉文章还在修改但是不小心发布了= =) 最近在用ZXing这个开源库做二维码的扫描模块,开发过程的一些代码修改和裁剪的经验和大家分享一下. 我的代码库: https://github.com/SickWorm/ZXingDialog 代码没有在github维护,所以没有log.但是所有修改的地方我都加上了“@ch”的注释,以方便定位 官方源码: https://github.com/zxing/zxing 实现功能: 1.功能裁剪(只保留QRCode二维码扫描功能,去掉条形码等其他码扫描功能

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

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

你不知道的二维码扫描模组、二维码读头行业应用?

随着二维码识别技术的发展,近些年以二维码扫描模组为核心扫码硬件无论是生活还是工作,都给我们带来了前所未有的改变.设备扫描读取乘车码乘坐公交地铁.在自助机上刷支付宝微信付款码实现二维码支付等一系列O2O智能设备都离不开它.二维码扫描模组也称为二维码读头(或嵌入式二维码扫描器),可实现对纸质条码/屏幕二维码信息进行扫描和解码,接下来我们就来了解一下它有哪些热门行业应用呢?以便于帮助正在挑选二维码扫描器(嵌入式系列)的集成商客户的您有所帮助. (1)应用于公共交通扫码收费:嵌入集成到公交扫码支付.闸机

二维码扫描

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 AV Foundation 二维码扫描 04 使用合成语音朗读二维码内容

前一节,我们为程序识别到的二维码提供了可视化的显示,这一节,我们使用合成语音朗读扫描到的二维码的内容. 修改ViewController.m,定义以下实例变量并进行初始化: AVSpeechSynthesizer *_speechSynthesizer; _speechSynthesizer = [[AVSpeechSynthesizer alloc] init]; 初始化语音合成器十分简单.语音合成器会控制对每个语音数据的回放和顺序.初始化完成后,Metadata output将触发语音合成器

【转】 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