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:

  • 相关阅读:
    Tips on Hair and Final gathering
    数学公式和符号的念法
    How to use Intel C++ Compiler in Visual Studio 2008
    Number Prefixes in Mathematics
    Glossy reflections/refractions in large scene
    atomic flushing data
    elvish Template Library Plan
    [Maxim07]中光线与三角形求交算法的推导
    C# 关闭窗体立即停止进程
    MS SQL 索引设计的准则
  • 原文地址:https://www.cnblogs.com/mousezhou/p/9260523.html
Copyright © 2011-2022 走看看