前回 Gjs でやった近似画像検索を Web ブラウザで。
Web で画像のピクセルデータ取得は意外に簡単だった。
…けれど困った結果になってしもーたがね。
とりあえず
16 3月 2014 | while(isプログラマ)
なるほど、Image と Canvas だけでできるのか。
つまり外部ライブラリは必要無いと。
[3][HTML][canvas]canvasで画像解析 – wataメモ
ピクセル毎のデータはこんなにアッサリ得られるようだ。
ただ Web での画像読み込みはローカルファイルが使えない。
下記コードを試すには Apache 等を使う必要あり。
更に有名な話で、ブラウザの画像読み込みは非同期である。
処理は onload ハンドラから行うのを忘れずに。
現行ブラウザはまだ let が使えないので var に書き換えて。
それと webkit では sort 関数の戻り値は整数にする必要があった。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Similar Image Sample</title> <!-- for Smart Phone --> <meta name="viewport" content=" width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <style> body { -webkit-text-size-adjust: 100%; } </style> <script type="text/javascript"><!-- const XY = 48; function init() { // 画像のロードは非同期なので onload 内で処理 // ローカルファイルは読み込めないので Apache 等で var sample = new Image(); sample.onload = function() { // ロードしたので Lab 値を得る var sample_lab = getImageLab(sample); // 比較対象 var datas = ["nae01.jpg","nae02.jpg","nae03.jpg","nae04.jpg","nae05.jpg"]; var diff = []; datas.forEach(function(element, index) { var data = new Image(); data.onload = function() { var lab = getImageLab(this); // 比較 var distance = 0; sample_lab.forEach(function(element, index) { distance += getLabDistance(element, lab[index]); }); diff.push({n:distance, name:datas[index]}); // 5枚ともロードが完了したら出力 if (diff.length == 5) { output(diff); } } data.src = element; }); } sample.src = "nae.jpg"; } function output(diff) { // sort diff.sort(function(a, b) { //return a.n > b.n; // no webkit return a.n - b.n; }); // 確認 var out = ""; diff.forEach(function(element, index) { out += element.name + " " + element.n + "<br />"; }); document.getElementById("ID_TEXT").innerHTML += out; } // 画像をリサイズしピクセルごとのLab色空間上の座標を取得する function getImageLab(image){ // var canvas = document.createElement("canvas"); canvas.width = canvas.height = XY; var ctx = canvas.getContext("2d"); ctx.drawImage(image, 0, 0, XY, XY); // 取り出し、コレは同期する var pixeldata = ctx.getImageData(0, 0, XY, XY); var lab = []; for(var i=0; i<XY; i++){ for(var j=0; j<XY; j++){ var r = pixeldata.data[j*4 + i*XY*4]; var g = pixeldata.data[j*4 + i*XY*4 + 1]; var b = pixeldata.data[j*4 + i*XY*4 + 2]; lab.push(rgb2lab([r, g, b])); } } document.getElementById("ID_CANVAS").appendChild(canvas); return lab; } // xyz色空間上の座標をlab色空間上の座標に変換する function xyz2lab(xyz) { var threshold = 0.008856; var ref_x = 0.96422; var ref_y = 1.0000; var ref_z = 0.82521; var var_x = xyz[0] / (ref_x * 100); var var_y = xyz[1] / (ref_y * 100); var var_z = xyz[2] / (ref_z * 100); var_x = (var_x > threshold) ? var_x = Math.pow(var_x, 1/3 ) : (7.787 * var_x) + (16 / 116); var_y = (var_y > threshold) ? var_y = Math.pow(var_y, 1/3 ) : (7.787 * var_y) + (16 / 116); var_z = (var_z > threshold) ? var_z = Math.pow(var_z, 1/3 ) : (7.787 * var_z) + (16 / 116); var l = ( 116 * var_y ) - 16; var a = 500 * ( var_x - var_y ); var b = 200 * ( var_y - var_z ); return [l, a, b]; } // rgb値をxyz色空間上の座標に変換する function rgb2xyz(rgb) { var r = rgb[0] / 255; var g = rgb[1] / 255; var b = rgb[2] / 255; r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92; g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92; b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92; r = r * 100; g = g * 100; b = b * 100; var xyz = []; //sRGB D50 xyz.push(r * 0.4360747 + g * 0.3850649 + b * 0.1430804); xyz.push(r * 0.2225045 + g * 0.7168786 + b * 0.0606169); xyz.push(r * 0.0139322 + g * 0.0971045 + b * 0.7141733); return xyz; } // rgb値をlab色空間上の座標に変換する function rgb2lab(rgb) { var xyz = rgb2xyz(rgb); var lab = xyz2lab(xyz); return lab; } // 2つの座標を比較し距離を返す function getLabDistance(p1, p2){ return Math.sqrt( Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2) + Math.pow(p2[2] - p1[2], 2) ); } //--> </script> </head> <body onLoad="init()"> <div id="ID_TEXT" style="font-size:12pt"></div> <div id="ID_CANVAS"></div> </body> </html>
Gjs の時と全然順番が違うんですけど。
blink と webkit も数値が全然違う。
いや iPhone 版 Chrome は Safari と同じ数値になってしまう。
それより縮小率によって順番がコロコロ変わるのは頂けない。
色々とどういうことだってばよ。
Gjs は縮小率を変えても順番はほぼ変わらないようです。
圧縮手段が違うのがそんなに影響するのかな。
GdkPixbuf で上記と同じ 24x24px の画像を作って比較してみる。
#!/usr/bin/env python3 from gi.repository import Gtk, Gdk, GdkPixbuf class DrawWin(Gtk.Window): def __init__(self): Gtk.Window.__init__(self) self.pixs = [] for s in ["nae.jpg", "nae01.jpg","nae02.jpg","nae03.jpg","nae04.jpg","nae05.jpg"]: p = GdkPixbuf.Pixbuf.new_from_file(s) pixbuf = GdkPixbuf.Pixbuf.scale_simple(p, 24, 24, GdkPixbuf.InterpType.BILINEAR) self.pixs.append(pixbuf) # self self.resize(24*6, 24) self.connect("delete-event", Gtk.main_quit) self.show_all() def do_draw(self, cr): offset = 0 for pixbuf in self.pixs: Gdk.cairo_set_source_pixbuf(cr, pixbuf, offset, 0) offset += 24 cr.paint() DrawWin() Gtk.main()
って、小さすぎてわかんないや。
両方のスクリーンショットを撮って eog で拡大比較。
なんだこれ、blink 雑すぎ!
これじゃ縮小率でコロコロ順番が変わって当然。
webkit も多分同じなんだろうな。
ということで、この方法は使えない。
同一画像がゼロにはなるので同一画像検索には使える。
って、それでいいならもっと簡単な手段があるってば。
縮小しなければなんとかなりそうだけど色々と効率が悪いかも。
外部ライブラリに頼るか別の手段にするか、うーん。。。