我最近不得不合并这样的图像:
这些图像代表了在不同地点发生的不同种类的事件。我们的想法是合并这些图像,以保持每个图像(红黄绿)的“热点”区域,从而获得全球发生的情况的全局图片。
在我目前的方法中,我取第二幅图像并提取红色/绿色通道,以便形成相关部分的遮罩,如下所示:
然后我用这个遮罩把它和第一个图像合并,这样就只复制了相关的部分。
以下是用于此操作的脚本:

#!/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

以下是我目前的结果:
如你所见,红黄绿部分效果良好,但蓝色部分不见了。问题是,如果我放大遮罩以包含蓝色部分,那么它将用第二个图像中的蓝色部分覆盖第一个图像中的红黄绿部分这在最终结果中已经可见,左上角第一个图像的红色部分被第二个图像的绿色部分覆盖。
正确获取蓝色部分比较困难,但我认为以下算法应该有效(伪代码):
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,如何:
使用任何技术/什么来获得想要的结果?
从上面实现算法?
你不需要同时回答这两个问题,只要找到一种获得理想结果的imagemagick方法就可以了。
[编辑]
提示:我刚刚有一个想法,我想你可以为两个图像生成遮罩(包括蓝色部分),并对遮罩做一些“设置交集/并集/差分/其他”来生成适当的“最终”遮罩,这样只复制图像B的真实相关部分。

最佳答案

好的,我做了“合并像素”的策略,它成功了!

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

这是结果(不是完美的,但很好地适应了我对真实图片的需要):

07-24 09:38
查看更多