zoukankan      html  css  js  c++  java
  • 发票二维码扫描增强_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:

  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/mousezhou/p/9260523.html
Copyright © 2011-2022 走看看