canvasで画像比較したい
最近ffmpegを使って音をいじいじする機会がありました。
いろんなパターンで音を編集してみたのですが、音の変化を耳で感じるのに限界を感じ、視覚的に見る方法ないかなぁと思っていました。
そしたらffmpegには音の波形を画像で出す機能があるようで。
波形の画像を生成したは良いが、微妙な違いを確認するためには結局目を凝らすしかないという結果に。。
Rubyにはrmagickがありますが、javascriptでなんかできないかなぁと思いcanvasを使ってやってみることにしました。
どうやったか
概要
wave_1.png
とwave_1.png
を用意し、canvasに順番にレンダリング。
レンダリングした情報を変数に格納。
画像を比較して差分がある箇所だけ色を付ける。
index.html
<body>
<p>image1</p>
<img id="image_1" src="wave_1.png" />
<p>image2</p>
<img id="image_2" src="wave_2.png" />
<p>diff</p>
<canvas id="my-canvas" width="480" height="270"></canvas>
<script type="application/javascript" src="canvas.js"></script>
</body>
class WaveDiffChecker {
load() {
this.image1 = document.getElementById("image_1");
this.image2 = document.getElementById("image_2");
this.c1 = document.getElementById("my-canvas");
this.ctx1 = this.c1.getContext("2d");
this.width = this.image1.clientWidth;
this.height = this.image1.clientHeight;
this.checkWave();
}
checkWave() {
this.ctx1.drawImage(this.image1, 0, 0, this.width, this.height);
const frame1 = this.ctx1.getImageData(0, 0, this.width, this.height);
this.ctx1.drawImage(this.image2, 0, 0, this.width, this.height);
const frame2 = this.ctx1.getImageData(0, 0, this.width, this.height);
const pixels = frame1.data.length / 4; // 同じ画像サイズなのでdotsは1つでOK
for (let i = 0; i < pixels; i++) {
const index = i * 4;
const isSame = [0, 1, 2].every(value => {
return frame1.data[index + value] === frame2.data[index + value];
});
frame1.data[index] = isSame ? 0 : 100; // Red値
frame1.data[index + 3] = isSame ? 0 : 100; // Alpha値
}
this.ctx1.putImageData(frame1, 0, 0);
}
}
const diffChecker = new WaveDiffChecker();
diffChecker.load();
ポイント
this.ctx1.getImageData(0, 0, this.width, this.height)
getImageDataの返り値はimageData
であり、imageData.dataでUint8ClampedArray
にアクセスできます。
このArrayはRGBAの順で0から255のデータを持っています。
//1ピクセルの構成
frame1.data[0] //=> 0(Red)
frame1.data[1] //=> 255(Green)
frame2.data[2] //=> 100(Blue)
frame3.data[3] //=> 150(Alpha)
各ピクセルの要素を順に確認していき、RGBAのどこかに差分がある場合のみ色をつけています。