前回 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 も多分同じなんだろうな。
ということで、この方法は使えない。
同一画像がゼロにはなるので同一画像検索には使える。
って、それでいいならもっと簡単な手段があるってば。
縮小しなければなんとかなりそうだけど色々と効率が悪いかも。
外部ライブラリに頼るか別の手段にするか、うーん。。。