IMAGEMAGICK:合并多个图像,但保留带有特定颜色的区域

时间:2014-01-27 13:21:06

标签: algorithm image-processing imagemagick

我最近不得不合并这些图像:

a.png b.png

这些图像代表在不同位置发生的不同类型的事件。我们的想法是合并这些图像,以保持每个图像(红 - 黄 - 绿)的“热”区域,以全局了解全局发生的事情。

在我目前的方法中,我拍摄第二张图像并提取红色/绿色通道,以形成相关部分的掩模,如下所示:

b-mask.png

然后我使用此蒙版将其与第一张图像合并,因此只复制相关部分。

以下是用于此目的的脚本:

#!/bin/bash

# Extract RGB
convert b.png -colorspace RGB -separate b-sep-%d.png

# Keep red & green only
convert b-sep-2.png b-sep-0.png -compose minus -composite b-tmp-br.png
convert b-sep-2.png b-sep-1.png -compose minus -composite b-tmp-bg.png
convert b-tmp-br.png b-tmp-bg.png -compose plus -composite -level 10%,100% b-mask.png

# Composite!
composite b.png a.png b-mask.png final.png

这是我目前的结果:

enter image description here

如您所见,它适用于红黄绿色部分,但缺少蓝色部分。问题是,如果我将遮罩放大以包含蓝色部分,那么它将覆盖第一个图像中的红黄绿色部分,第二个部分使用蓝色部分!这在最终结果中已经可见,左上角的第一个图像红色部分被第二个图像的绿色部分覆盖。

正确获取蓝色部分比较棘手,但我认为以下算法应该有效(伪代码):

function merge_pixel(pixel a, pixel b)
{
  points = { :red => 4, :yellow => 3, :green => 2, :blue => 1, :default => 0 }
  a_points = points[a.color()]
  b_points = points[b.color()]
  return a_points > b_points ? a : b
}

也就是说,在合并图像时,根据哪种颜色对最终图像最重要,从图像a或b复制像素。也许这个算法不合理(例如如何处理渐变部分,可能有一个阈值),随意揭穿它。

真实问题:

使用imagemagick,如何:

  1. 使用任何技术/其他方式获得所需的结果?
  2. 从上面实现算法?
  3. 你不需要回答这两个问题,只需找到一种获得所需结果的图像匹配方法就可以了。

    [编辑]

    提示:我刚才有一个想法,我认为你可以为这两个图像生成蒙版(包括蓝色部分)并做一些“设置交集/联合/差异/任何”的蒙版来生成适当的“最终”蒙版所以只复制了图像b的真实相关部分。

1 个答案:

答案 0 :(得分:0)

好的,我做了“merge_pixel”策略并且有效!

require 'RMagick'
include Magick

def pixel_score(p)
  r, g, b = [p.red, p.green, p.blue].map{ |i| i / 256 }

  is_flat   = (r-g).abs < 20 && (r-b).abs < 20 && (g-b).abs < 20

  is_grey   = is_flat && r < 200

  is_red    = r >= 240 && g <= 100 # && b < 10
  is_yellow = r >= 150 && g >= 100 && b <= 10
  is_green  = r <= 200 && g >= 200 && b <= 100
  is_cyan   = r <= 10  && g >= 100 && b >= 30
  is_blue   = r <= 10  && g <= 100 && b >= 200

  if is_red
    (999**8) + (r - g)
  elsif is_yellow
    (999**7) + (r + g)
  elsif is_green
    (999**6) + (g - b)
  elsif is_cyan
    (999**5) + (g + b)
  elsif is_blue
    (999**4) + (b - g)
  else
    (999**1) + r ** 3 + g ** 2 + b
  end
end

def rmagick_merge(file_a, file_b, file_merged)
  img_a = ImageList.new(file_a)
  img_b = ImageList.new(file_b)
  result = Image.new(img_a.columns, img_a.rows)
  img_a.columns.times do |col|
    img_a.rows.times do |row|
      pixel_a = img_a.pixel_color(col, row)
      pixel_b = img_b.pixel_color(col, row)

      pixel = [pixel_a, pixel_b].sort_by{ |p| pixel_score(p) }.last
      #pixel = [pixel_a, pixel_b].sort_by{ |p| [p.red - p.green, p.green, p.blue] }.first
      #pixel = [pixel_a, pixel_b].sort_by{ |p| [p.red - p.green - p.blue * 100, p.green, p.blue] }.last

      result.pixel_color(col, row, pixel)
    end
  end
  result.format = "PNG"
  result.write(file_merged)
end

if __FILE__ == $0
  if ARGV.size < 3
    puts "usage #{__FILE__} a.png b.png merged.png"
    exit 1
  end
  rmagick_merge(ARGV[0], ARGV[1], ARGV[3])
end

这是结果(不完美,但根据我对真实照片的需求进行了微调):

ok.png