• python 去除图像中的框


    最近在做图像标注,会出现以下的图片,需要去除其中的边框。
    原始图像

    1.思路

    1. 人工标注画框的范围P,并使用标注工具在画框上画一个点A。
    2. 获取点A的坐标和颜色。在范围P内,将与点A颜色相似的每一个点x的颜色,替换为点x上下(或左右)范围内若干个点的平均颜色。但是对于边缘部分,可能存在如下图所示的问题:
      边框存在问题
    3. 对边框的边缘部分Q进行额外处理。边框的颜色可能与点A的颜色有较大差异,因此需要利用其他方法进行处理。我使用异常值检测算法,因为Q中未在步骤2去除的一些残留点,与原始图片会存在较大差异,结合频度信息可以筛选出这些点,并得到以下的效果:
      在这里插入图片描述

    2.代码实现

    1. 导包和必要的参数、模型:
    from PIL import Image
    import numpy as np
    from sklearn.ensemble import IsolationForest
    from collections import Counter
    
    # 判断rgb相似度用,可以小一些
    threhold=15
    threhold_border=15
    
    # 采样半径,可以设的小一些,可以根据边框的粗细来设定
    redius=20
    redius_border=20
    
    # 对边框进行处理需要调整的参数
    step_add=37
    step_max=2000
    step=0
    all_outliers=[]
    top_outlier_num=10
    
    # 创建Isolation Forest模型
    model = IsolationForest(contamination=0.05)  # 设置异常点的比例
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. 辅助函数
    
    #判断颜色是否相似
    def my_similar(a,b):
        if sum([abs(x-y) for (x,y) in zip(list(a),list(b))])/3<threhold:
            return True
        return False
    
    # 判断颜色是否相似
    def my_similar_border(a,b_s):
        for b in b_s:
            if sum([abs(x-y) for (x,y) in zip(list(a),list(b)[0])])/3<threhold_border:
                return True
        return False
    
    # 获取异常值,用于处理边框的边缘Q
    def get_outlier(tmp,model):
        normal_point=[]
        unnormal_point=[]
        # 将数据传递给模型进行训练
        model.fit(tmp)
    
        # 获取每个数据点的预测标签,-1 表示异常点,1 表示正常点
        labels = model.predict(tmp)
    
        # 打印每个数据点的标签
        for i, label in enumerate(labels):
            if label == -1:
                unnormal_point.append(tmp[i])
            if label==1:
                normal_point.append(tmp[i])
        return normal_point,unnormal_point
    
    # 在水平或处置方向上获取邻居节点,以便进行颜色替换
    def get_right_neighborhood(target_color,neighborhood_x,neighborhood_y):
        diff_x=0
        diff_y=0
        
        for neighborhood in neighborhood_x:
            diff_x+=abs(sum([x-y for x,y in zip(list(neighborhood),list(target_color))])/3)
        for neighborhood in neighborhood_y:
            diff_y+=abs(sum([x-y for x,y in zip(list(neighborhood),list(target_color))])/3)
        if diff_x>diff_y:
            return neighborhood_x,1
        return neighborhood_y,2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    1. 主函数和必要的准备数据
    ########################################################################################
    ############################开始对区域P和点A进行人工指定################################
    ################################对应“思路”第1部分#####################################
    ########################################################################################
    
    # 利用手动或利用labelimg等标注工具,
    # 确定“思路”第1部分中的区域“P”
    #人工框选画框的大致位置,需要包裹住画框
    x_1=1427
    y_1=723
    x_2=2061
    y_2=1363
    
    # 利用手动或利用labelimg等标注工具,
    # 确定“思路”第1部分中的点“A”
    x = 1495 # 目标像素点的 x 坐标
    y = 1294 # 目标像素点的 y 坐标
    
    # 主要函数
    def replace_color_around_point(image_path, x, y, radius=redius):
        
        # 采样步数
        step=0
        
        # 打开图像
        image = Image.open(image_path)
        pixels = image.load()
    
        # 获取图像的宽度和高度
        width, height = image.size
    
        ########################################################################################
        ############################开始对边框的内部节点进行处理################################
        ################################对应“思路”第2部分#####################################
        ########################################################################################
        # 获取目标像素点的颜色
        target_color = pixels[x, y]
        # 循环遍历图像中的每个像素点
        for i in range(x_1,x_2):
            for j in range(y_1,y_2):
                # 如果像素颜色与目标颜色相同,则替换为周围区域颜色的平均值
                if my_similar(pixels[i, j],target_color):
                    # 计算周围水平和垂直区域的颜色平均值
                    neighborhood_x = []
                    neighborhood_y=[]
                    
                    for m in range(i - redius, i + radius + 1):
                            if 0 <= m < width:
                                neighborhood_x.append(pixels[m, j])
                                
                    for n in range(j - redius, j + radius + 1):
                            if 0 <= n < height:
                                neighborhood_y.append(pixels[i, n])
                                
                    neighborhood,direction=get_right_neighborhood(target_color,neighborhood_x,neighborhood_y)
                    neighborhood=[n for n in neighborhood if not my_similar(n,target_color)]
                    neighborhood = np.array(neighborhood)
                    average_color=tuple(np.mean(neighborhood, axis=0, dtype=int))
                    average_color_part_1 = tuple(np.mean(neighborhood[0:int(len(neighborhood)/2)], axis=0, dtype=int))
                    average_color_part_2 = tuple(np.mean(neighborhood[int(len(neighborhood)/2)+1:], axis=0, dtype=int))
                    
                    # 替换像素颜色
                    pixels[i, j] = average_color
                    
                    # 如果是水平方向
                    if direction==1:
                        for m in range(i - int(redius_border/3), i):
                            if 0 <= m < width:
                                    pixels[m,j]=average_color_part_1
    
                        for m in range(i, i + int(redius_border/3) + 1):
                            if 0 <= m < width:
                                    pixels[m,j]=average_color_part_2
                    
                    # 如果是垂直方向
                    if direction==2:            
                        for n in range(j - int(redius_border/3), j):
                            if 0 <= n < height:
                                    pixels[i,n]=average_color_part_1
    
                        for n in range(j ,j + int(redius_border/3) + 1):
                            if 0 <= n < height:
                                    pixels[i,n]=average_color_part_2
                    
                    step+=1
                    
                    if step%step_add==0 and step<step_max:
                        normal_point,unnormal_point=get_outlier(neighborhood,model)
                        unnormal_point=[tuple(x) for x in unnormal_point]
                        all_outliers.extend(unnormal_point)
    
        ########################################################################################
        ############################开始对边框的边缘节点进行处理################################
        ################################对应“思路”第2部分#####################################
        ########################################################################################
    
        # 使用Counter来统计三元组的出现次数
        all_outlier_counts = Counter(all_outliers)
    
        # 获取出现次数最多的十个三元组,用来去边框
        top_outliers = all_outlier_counts.most_common(top_outlier_num)
        
        # 循环遍历图像中的每个像素点
        for i in range(x_1,x_2):
            for j in range(y_1,y_2):
                
                # 如果该点和异常点中的颜色相似,就进行替换
                if my_similar_border(pixels[i, j] ,top_outliers):
                    # 计算周围水平和垂直区域的颜色平均值
                    neighborhood_x = []
                    neighborhood_y=[]
                    
                    for m in range(i - int(radius/3), i + int(radius/3) + 1):
                            if 0 <= m < width:
                                neighborhood_x.append(pixels[m, j])
                                
                    for n in range(j - int(radius/3), j + int(radius/3) + 1):
                            if 0 <= n < height:
                                neighborhood_y.append(pixels[i, n])
                                
                    neighborhood,direction=get_right_neighborhood(target_color,neighborhood_x,neighborhood_y)
                    neighborhood=[n for n in neighborhood if not n in top_outliers]
                    neighborhood = np.array(neighborhood)
                    average_color=tuple(np.mean(neighborhood, axis=0, dtype=int))
                    
                    # 替换像素颜色
                    pixels[i, j] = average_color
                                                   
        # 保存修改后的图像
        image.save(r"../data/bbb.jpg")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    1. 调用
    image_path = r"../data/aaa.jpg"  # 替换为您的输入图像路径
    replace_color_around_point(image_path, x, y)
    
    • 1
    • 2

    3.存在的问题

    1. 在进行颜色替换时,仅仅使用了平均值(代码中的average_color相关内容),也许可以使用其他线性插值算法。
    2. 需要对参数进行精心调节,否则可能导致框内的图像会出现以下的“毛刺现象”,且无法把“框”完全去除:
      参数调节的不太好
      将threhold参数调小后,毛刺消失。也可以对其他参数进行调节。在这里插入图片描述
  • 相关阅读:
    如何排查oracle连接数不足问题
    MouseBoost 3.2.3 Pro右键助手 for Mac
    学习太极创客 — MQTT 第二章(八)ESP8266 MQTT 用户密码认证
    StackExchange.Redis 高并发下timeout超时问题如何解决?
    万字总结线程池
    MySQL数据库(四)
    力扣labuladong一刷day14天翻转单链表共2题
    REF615 REU615 RED615 人工智能在工业中的第一步
    C#---第十四课:数组(Array)& 列表(List)之间的相同与不同
    Git基础入门
  • 原文地址:https://blog.csdn.net/weixin_37763484/article/details/134255184