画像処理ソフト ImageMagick を使って,二つの画像の差分をビジュアル化する方法について紹介します.
はじめに
例として,次のような間違い探し画像の違いを自動検出してみます.
出力は次のようになります.画像の中で赤色や青色になっている部分が違いがある部分になります.

以下,環境の整備から順に説明していきます.
準備
ImageMagick をインストールします.
Windows の場合はいろいろファイルがありますが,普通に使う分には差がありませんので,一番上にあるものを選んでおけば OK.
インストールする際に「Add application directory to your system path」にチェックするのを忘れずに.

Download ページから「ImageMagick-XXX-Q16-x64-dll.exe」(XXX はバージョン番号)
青赤画像の生成
まず,比較対象の画像(a.jpg, b.jpg)を次のような赤色画像(a_red.png)と青色画像(b_blue.png)に変換します.
これには,コマンドプロンプトから以下のコマンドを実行します.
| 1 2 | > convert -type GrayScale +level-colors Red,White a.jpg a_red.png > convert -type GrayScale +level-colors Blue,White b.jpg b_blue.png | 
ちなみに,コマンドプロンプトはエクスプローラでフォルダを選択した状態で Shift を押しながら右クリックで出てくる「コマンドウィンドウをここで開く」を選択することで開けます.
差分画像の生成
続いて以下のコマンドを実行することで,冒頭の差分画像が生成できます.
| 1 | > convert -compose Multiply -composite a_red.png b_blue.png diff.png | 
原理
画素ごとに色の乗算(Multiply)を行うことで,差分をビジュアル化しています.
白色,赤色,青色に対して乗算を行うと以下のようになります.
| 1 2 3 4 | 白 × 白 = 白 白 × 青 = 青 白 × 赤 = 赤 赤 × 青 = 黒 | 
従って,赤色画像と青色画像の乗算を行うと,一致している部分は黒色になり,不一致箇所は赤色や青色になります.
自動化
作業を自動化するスクリプトを紹介します.
以下の内容を img_diff.bat という名前で保存し,img_diff.bat a.jpg b.jpg と実行すれば OK.
冒頭に記載してある ImageMagick のパスは,インストールしたフォルダに書き換えてください.
| 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 | @if(0)==(0) ECHO OFF cscript.exe //nologo //E:JScript "%~f0" %* GOTO :EOF @end // ImageMagick のパス // Windows に付属している convert コマンド(*1) と ImageMagick の convert // コマンドで名前がかぶっているために,絶対パスの指定が必要 // *1: C:\Windows\system32\convert.exe IMAGEMAGICK_PATH='C:\\Application\\Image\\ImageMagick'; function get_prep_image_path(input_img_path) {     return input_img_path.replace(/^(.*)\.\w{3,4}$/, '$1_prep.png'); } function get_diff_image_path(from_img_path, to_img_path) {     from_img_name = from_img_path.replace(/^.*[\\\/]?([^\\\/]+)\.\w{3,4}/, '$1');     to_img_name = to_img_path.replace(/^.*[\\\/]?([^\\\/]+)\.\w{3,4}/, '$1');     return 'diff_' + from_img_name + '_to_' + to_img_name + '.png'; } function run_command(shell, command) {     WScript.StdErr.Write('[RUN] ' + command + "\n");     exec = shell.Exec(command);     // 100ms 間隔でコマンドの終了を待つ     while (exec.Status == 0) {         WScript.Sleep(100);     }     stdout = '';     stderr = '';     if (!exec.StdOut.AtEndOfStream) {         stdout = exec.StdOut.ReadAll();     }     if (!exec.StdErr.AtEndOfStream) {         stderr = exec.StdErr.ReadAll();     }     return {         exit: exec.ExitCode,         stdout: stdout,         stderr: stderr     }; } function generate_prep_image(shell, color, input_img_path, output_img_path) {     result_info =         run_command(shell,                     IMAGEMAGICK_PATH + '\\convert.exe ' +                     '-type GrayScale +level-colors ' + color + ',White ' +                     input_img_path + ' ' + output_img_path); } function generate_diff_image(shell, from_img_path, to_img_path, diff_img_path) {     result_info =         run_command(shell,                     IMAGEMAGICK_PATH + '\\convert.exe ' +                     '-compose Multiply -composite ' +                     from_img_path + ' ' + to_img_path + ' ' + diff_img_path); } args = WScript.Arguments; if (args.length < 2) {     WScript.StdErr.Write("比較対象のファイルのパスを指定してください\n");     WScript.StdErr.Write("例: " + WScript.ScriptName + " a.jpg b.jpg\n");     WScript.Quit(-1); } input_img_info = {     a: {         path: args(0),         color: 'Red'     },     b: {         path: args(1),         color: 'Blue'     } }; shell = WScript.CreateObject('Wscript.Shell'); for (i in input_img_info) {     prep_path = get_prep_image_path(input_img_info[i]['path']);     generate_prep_image(shell, input_img_info[i]['color'],                         input_img_info[i]['path'], prep_path);     input_img_info[i]['prep_path'] = prep_path; } diff_img_path = get_diff_image_path(input_img_info['a']['path'],                                     input_img_info['b']['path']); generate_diff_image(shell,                     input_img_info['a']['prep_path'],                     input_img_info['b']['prep_path'],                     diff_img_path); | 
 
  
  
  
  





コメント