【问题标题】:Crop an image, based on values根据值裁剪图像
【发布时间】:2016-05-04 11:45:03
【问题描述】:

我有多个图像,如下所示:

橙色代表数值等于0,白色代表数值等于255,蓝色代表字段,数值从0到255不等。我想去掉橙色区域,即每个图像都有点不同。最好的方法是什么?

编辑 1

我认为这个答案可能会有所帮助:bounding box approach。 除了,我想得到一个数组A_extract 而不是A_trim

A = np.array([[0,   0,   0,   0,   0,   0, 0],
              [0, 255,   0,   0,   0,   0, 0],
              [0,   0, 255, 255, 255, 255, 0],
              [0,   0, 255,   0, 255,   0, 0],
              [0,   0, 255, 255, 255,   0, 0],
              [0,   0,   0, 255,   0,   0, 0],
              [0,   0,   0,   0,   0,   0, 0]])

A_trim = np.array([[255,   0,   0,   0,   0],
                   [  0, 255, 255, 255, 255],
                   [  0, 255,   0, 255,   0],
                   [  0, 255, 255, 255,   0],
                   [  0,   0, 255,   0,   0]])

A_extract = np.array([[255, 255, 255],
                      [255,   0, 255],
                      [255, 255, 255])

所以基本上,代码应该找到一个边界框,其中第一行和最后一行(以及第一列和最后一列)中的所有元素都应该具有相同的值(例如 255)。

编辑 2

真实图像是分类卫星图像,存储为 numpy 数组(形状为 cca.7000x8000)而不是 RGB 图像。看起来是这样的:

  • 橙色 = 0
  • 绿色 = 2
  • 粉红色 = 3
  • 白色 = 255

目的是去除边缘的 0 值。

【问题讨论】:

  • 是的,找到边界框是第一步。如果边界框上的裁剪图像不理想,您可能希望在此示例中将不需要的橙色替换为白色,或使其透明。
  • 我建议上传真实图片,而不是“看起来像这样”的图片。就我个人而言,我不知道您在谈论“橙色代表等于 0 的值,白色代表等于 255 的值,蓝色代表字段,其中值从 0 到 255 不等”时是什么意思
  • @Bonzo:我希望我已经足够澄清了。如果没有,请告诉我。

标签: python numpy image-processing crop bounding-box


【解决方案1】:

用新方法编辑:

所以基本上,代码应该找到一个边界框,其中第一行和最后一行(以及第一列和最后一列)中的所有元素都应该具有相同的值(例如 255)。

这种方法有帮助,但不适用于示例图像。因此,我在此之上添加了额外的检查。速度可能是个问题,因为只使用了 PIL,而且真实图像很大。希望有人能想出一个numpy的解决方案。

以下代码中只需要两个变量:

1)。背景颜色:样本图像为 (250, 255, 255) (不是 255,255,255 ?);

2)。边距范围:代码使用范围(2,30)。它将影响处理时间,因为枚举了所有可能的值。

from PIL import Image

BG_COLOR = (250, 255, 255) # background color
MARGIN = range(2, 30) # Define your margin range
tuple_list = [] # hold the tuple list result

if __name__ == '__main__':
    im = Image.open('dEGdp.png').convert('RGB')    
    w,h = im.size
    pix = im.load()
    for x1 in MARGIN:
        for y1 in MARGIN:
            for x2 in MARGIN:
                for y2 in MARGIN:
                    if pix[x1,y1] == pix[w-x2,y1] == pix[x1, h-y2]== pix[w-x2,h-y2] == BG_COLOR and \
                        (any([pix[x1-1,y]!= BG_COLOR or pix[w-x2+1, y] != BG_COLOR for y in range(0, h)]) or \
                         any([pix[x, y1] != BG_COLOR or pix[x, h-y2+1] != BG_COLOR for x in range(0, w)])):
                        tuple_list.append(((w-x1-x2)*(h-y1-y2), x1, y1, w-x2, h-y2))
                    else: continue
    top_box = sorted(tuple_list).pop() #pick the top one
    im_c = im.crop((top_box[1:])) # crop the image
    im_c.save('cropped.png')

输出很好:

【讨论】:

    【解决方案2】:

    啊哈!现在我可以看到您的图像,也许我可以提供更好的帮助。同样,我将描述一种使用 ImageMagick 的方法,但您可以轻松地将其适应 OpenCV/Python。

    首先,您的图像是分类图像,它是 PNG,这意味着它非常好 - 只有 8 种颜色,没有量化伪影 - 最后!是时候有人为他们的图像处理任务使用正确的格式了:-)

    第一项工作是找出“讨厌的边缘像素”的颜色。一个简单的方法可以做到这一点,并且允许颜色变化,就是从一个角落取出一个 100x100 的块 - 确保找到一些 “讨厌的像素”。然后使白色透明并找到剩余可见像素的颜色。这是 ImageMagick 中的一行:

    convert satellite.png -fuzz 10% -crop 100x100+0+0 -transparent white result.png
    

    这显示了上下文中的裁剪区域:

    然后我们需要这张图片的平均颜色 - 这是“讨厌的像素”的颜色,因为白色是透明的:

    convert satellite.png -fuzz 10% -crop 100x100+0+0 -transparent white -resize 1x1 txt:
    # ImageMagick pixel enumeration: 1,1,255,srgba
    0,0: (61937,45232,11308,4857)  #F1B02C13  srgba(241,176,44,0.0741131)
    

    所以,橙色​​是srgba(241,176,44,0.0741131)

    现在,我们在小裁剪区域中找到一个像素,用作洪水填充的种子:

    # ImageMagick pixel enumeration: 100,100,255,srgba
    0,0: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    1,0: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    2,0: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    ...
    97,7: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    98,7: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    99,7: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    0,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    1,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    2,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    3,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    4,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    5,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    6,8: (65535,65535,65535,0)  #FFFFFF00  srgba(255,255,255,0)
    7,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)   <--- FIRST PESKY PIXEL
    8,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    9,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    10,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    11,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    12,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    13,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    14,8: (61937,45232,11308,65535)  #F1B02CFF  srgba(241,176,44,1)
    

    所以,任何带有srgba(241,176,44,0.0741131) 的人都可以,让我们选择第一个 - 像素[7,8]

    现在我们可以从那里开始填充图像:

    convert satellite.png -fill white -floodfill +7+8 "#F1B02CFF" result.png
    

    您可以看到它已经充满了 “讨厌的像素” 的左列。现在在其他三个角找到一个类似的种子像素并重复。

    【讨论】:

    • 如果我理解了这个问题,我认为问题是橙色代表的区域中的值也可能在蓝色代表的区域中?
    • @Bonzo 我也觉得这个问题令人困惑——我从表面上看,橙色区域是橙色,蓝色区域是蓝色。希望OP会澄清:-)
    • 我添加了一个EDIT 2
    【解决方案3】:

    在您到达橙色之前,发布的图片有一个白色边框,然后在三边有一些黑色线条。

    这将删除白色边框,然后将橙色变为白色:

     convert amGCH.png -trim -fill white -draw "color 5,5 floodfill" output.png
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-01
      • 2020-06-26
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多