HTML5のcanvasを使って簡単な画像処理をやってみます。
試してみたのは基本的な畳み込みフィルタ。
今回はAS3のConvolutionFilter風のインタフェースで作りました。
Demo: HTML5 Image Processing (Convolution Filter)
汎用的に作ろうとすると少し時間がかかりそうだったので、ひとまず畳み込みフィルタの部分だけ。
引数はAS3のものよりずっと少なく、matrix, divisor, bias の3つ。
matrixXやmatrixYも用意してないのでフィルタカーネルのサイズは3×3限定だし、
異常系の処理も不十分で修正が必要ですが;;
他のフィルタ類は時間を見つけて作ってみようと思います。
・クライアント例
1 2 3 4 5 6 |
var context = document.getElementById('Canvas').getContext('2d'); var bmp = new Bitmap('sample.jpg', context); var matrix = [-1, -1, -1, -1, 8, -1, -1, -1, -1]; // フィルタカーネル var divisor = 1; var bias = 0; bmp.applyFilter(new ConvolutionFilter(matrix, divisor, bias)); |
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 |
var Class = { create : function() { var properties = arguments[0]; function self() { this.initialize.apply(this, arguments); } for(var i in properties) { self.prototype[i] = properties[i]; } if(!self.prototype.initialize) { self.prototype.initialize = function() {}; } return self; } }; /*----------------------------------------*/ /** * Classes for Image Processing. */ var Bitmap = Class.create({ initialize : function(source, context) { this.bitmapData = new Image(); this.bitmapData.src = source; this.context = context; this.bitmapData.addEventListener('error', function() { alert("can't load image"); }, false); }, applyFilter : function(filter) { try { if(this.bitmapData.complete) { this.context.drawImage(this.bitmapData, 0, 0); var w = this.bitmapData.width, h = this.bitmapData.height; var src = this.context.getImageData(0, 0, w, h); var dst = this.context.createImageData(w, h); filter.apply(src, dst); this.context.putImageData(dst, 0, 0); }else { throw new Error("load image incomplete"); } }catch(e) { throw e; } } }); var ConvolutionFilter = Class.create({ initialize : function(matrix, divisor, bias) { this.matrix = matrix; this.divisor = divisor; this.bias = bias; }, apply : function(src, dst) { var w = src.width, h = src.height; var srcData = src.data; var dstData = dst.data; var len = dstData.length; var r, g, b, i, j, k, step, kStep; for(var y=1; y<h-1; y++) { step = y*w; for(var x=1; x<w-1; x++) { r = 0, g = 0, b = 0; i = (step + x) << 2; k = 0; for(var ky=-1; ky<=1; ky++) { kStep = ky*w; for(var kx=-1; kx<=1; kx++) { j = (kStep << 2) + (kx << 2); r += srcData[i + j]*this.matrix[k]; g += srcData[i + j + 1]*this.matrix[k]; b += srcData[i + j + 2]*this.matrix[k++]; } } dstData[i] = r/this.divisor + this.bias; dstData[i + 1] = g/this.divisor + this.bias; dstData[i + 2] = b/this.divisor + this.bias; dstData[i + 3] = 255; } } for(var l=0; l<len; l++) { var value = dstData[l]; dstData[l] = value<0 ? 0 : value>255 ? 255 : value; } } }); |
ポイントを絞って簡単に説明を。
(以下 context は getContext(‘2d’) で取得したオブジェクト)
* imagedata = context.createImageData(sw, sh)
幅sw, 高さshのImageDataオブジェクトを生成します。
ピクセルデータ(imageData.data)はすべて0(黒)になっています。
* imageData = context.getImageData(sx, sy, sw, sh)
(x, y)=(sx, sy) を基準に幅sw, 高さshの領域のピクセルデータを取得できます(imageData.data)。
これはAS3における BitmapData.getPixels() のようなもので、ARGB32bitのデータを扱い、
インデックスは 0 から 幅×高さ×4-1 まで。
* context.putImageData(imagedata, dx, dy)
指定されたImageDataオブジェクトを (x, y)=(dx, dy) を基準に描画します。
・参考記事
createImageData, getImageData, putImageData メソッド – Canvasリファレンス – HTML5.JP
・関連記事
HTML5の勉強