javascriptで画像処理をする【HTML5】

公開日: : 最終更新日:2014/08/14 JavaScript/jQuery, 画像処理

スポンサーリンク

HTML5でjavascriptを使って画像処理をしてみました。このページでは手始めにグレースケール化(白色・灰色・黒色にする)とソーベルフィルタの処理について取り組みます。

この記事では一部HTML5のcanvasを利用しておりこれはIEの8までは動かないのですが、ExploreCanvasというライブラリを使用することで他のブラウザと同じような挙動を見せることができます。

画像の読み込み

画像処理する対象の画像についてはじめからURLを指定するかHTML5のFile APIを利用してページを開いた方のローカルファイルから選ぶかで読み込ませることができます。

外部ファイルから読み込む

前述の通りHTML5のFileAPIを使います。

HTML側

<input type="file" id="selectfile" accept='image/*'>

JS側

//ファイルオープンの際のイベント
var ofd = document.getElementById("selectfile");
ofd.addEventListener("change", function(evt) {
    //ここに画像データを入力
    var img = null;

    var file = evt.target.files;
    var reader = new FileReader();

    //dataURL形式でファイルを読み込む
    reader.readAsDataURL(file[0]);

    //ファイルの読込が終了した時の処理
    reader.onload = function(){
        img = new Image();
        img.onload = function(){
                /*読み込み終了後ここで画像を加工して表示する*/
        }
        //読み込んだ画像ソースを入れる
        img.src = reader.result;
    }
}, false);

HTML側ではinputタグのtypeをfileにすることでファイルオープンのダイアログを出すボタンが作成されます。ここのaccept属性を「image/*」にするとデフォルトで画像ファイルの選択になります。

次に、JS側ではFileReaderクラスのreadAsDataURLメソッドを用いて取得したファイルパスからファイルを読み取ります。そして、今回は画像ファイルを読み込んでいるので取得したものをImageクラス(のsrcプロパティ)に代入してCanvasで使えるように準備をしておきます。

なおこのスクリプトは順序を逆にする場合は全てのデータを読み込ませてからスクリプトを動かした方がよいので次のイベント内に先ほどのスクリプトを書くといいです。(次からは省略します)

window.addEventListener("DOMContentLoaded", function(){
    /*ここにスクリプトを書く*/
}, false);

あらかじめ指定する

画像ファイルを外部読み込み式にするのでなく、指定のURLの画像にしたい場合は単純にImageのsrcプロパティに直接代入すればよいです。

img = new Image();
img.onload = function(){
    /*読み込み終了後ここで画像を加工して表示する*/
}
//読み込んだ画像ソースを入れる
img.src = "sample.jpg";

画像の操作・加工

画像処理というとピクセル単位で画像にアクセスして画素値を取得したり変更したりといった操作が要だと思います。この処理をするにあたってcanvasを使います。

canvasタグはあらかじめ設置しておくことになりますが、必ずしも設置せずともdocument.createElement(‘canvas’)で対応することができます。ただし、この場合画像の表示は別に考える必要が出てくるので注意してください。

以下、先ほどのImageクラスのonloadイベント内の処理です。

//キャンバスに画像をセット
var canvas = document.getElementById('canvas');
//var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var width = img.width;
var height = img.height;
canvas.width = width;
canvas.height = height;
context.drawImage(img, 0, 0);

canvasからcontextを生成してそのdrawImageメソッドでcanvasに絵を描きます(画像が設置される)。この際canvasのサイズも画像と同じサイズに変更しておかないと途中ではみ出る形になってしまうので気を付けてください。

画素値の取得と変更

画像に対してピクセル単位でアクセスするようにするにはimagedata形式にするとできるようになります。

imagedata形式

imagedata.width…画像の横幅(px)
imagedata.height…画像の縦幅(px)
imagedata.data…RGBA の順番のデータを含んだ1次元配列。それぞれの値は 0 ~ 255 の範囲。

画素値を変更するにはこのimagedata.dataの配列の値をいじくればいいということになります。このimagedataですが、contextから取得するにはcontextのgetImageDataメソッドおよびcreateImageDataメソッドで可能で、それぞれ保持している画像をimagedataとして返すというものと、空のimagedataを返すものとなっています。

imagedata = context.createImageData(sw, sh)
imagedata = context.createImageData(imagedata)
imagedata = context.getImageData(sx, sy, sw, sh)
(sx…開始X座標、sy…開始Y座標、sw…横幅、sh…縦幅)

そして後はこのimagedataのdata配列をいじるだけです。

例)

var src = context.getImageData(0,0,width,height);
for (var i = 0; i < height; i++) {
    for (var j = 0; j < width; j++) {
        var idx = (j + i * width) * 4;
        var r = src[idx]; //赤
        var g = src[idx+1]; //緑
        var b = src[idx+2]; //青
        var a = src[idx+3]; //透明度
        
        var gray = (r+g+b)/3;
        src[idx] = gray;
        src[idx+1] = gray;
        src[idx+2] = gray;
        //src[idx+3] = a; //透明度は同じ値
    }
}

この例では各画素値を取得してグレースケール化しています。グレースケール化はRGBの値を足して3で割り、同じ値をその画素値とするだけです。

ここの値について色々な操作をすることで様々なフィルタを作成することができます。

画像の表示

最後に画像の表示についてですが、canvasタグをそのまま表示させている場合はすでに表示されていると思うのでもう結構なのですが、使っていない場合には表示させる解決策の一つとして指定の位置に画像を挿入させます。

canvasのtoDataURLメソッドを利用することで画像のURLが取得できるようになるのでそれをimgタグのsrcにそのまま代入してしまうと画像が表示されます。

例)

//画像タグに代入して表示
var dataurl = canvas.toDataURL();
document.getElementById("output").innerHTML = "<img src='" + dataurl + "'>";

id名がoutputのタグのinnerHTMLにtoDataURLで取得したURLをsrc属性とした画像タグを設置しました。

フィルター処理について

ソーベルフィルタの他にもエッジ検出フィルタとしてラプラシアンフィルタやプリューウィットフィルタなどの空間フィルタリングがあります。デモではソーベルフィルタを使用しています。

デモ

いままでのものを利用して作成したデモです。ファイルを読み込んだらグレースケール変換ではなく、ソーベルフィルターをかける処理を行い、その後にimgタグに代入しています。

ソーベルフィルターはエッジ検出の空間フィルタです。グレースケールではつまらないのでこちらにしました。

<div id="output">
</div>

ソース

JS側

//グレースケール変換関数
var grayFilter = function(src, dst, width, height) {
    for (var i = 0; i < height; i++) {
        for (var j = 0; j < width; j++) {
            var idx = (j + i * width) * 4;
            var gray = (src[idx] + src[idx + 1] + src[idx + 2]) / 3;
            dst[idx] = gray;
            dst[idx + 1] = gray;
            dst[idx + 2] = gray;
            dst[idx + 3] = src[idx + 3];
        }
    }
};
//ソーベルフィルタ関数
var sobelFilter = function(src, dst, width, height) {
    var weight = [
        -1,0,1,
        -2,0,2,
        -1,0,1
    ];
    for (var i = 0; i < height; i++) {
        for (var j = 0; j < width; j++) {
            var idx = (j + i * width) * 4;
            var val = [0,0,0];
            for(var k = -1; k <= 1; k++){
                for(var l = -1; l <= 1 ; l++){
                    var x = j + l;
                    var y = i + k;
                    if(x < 0 || x >= width || y < 0 || y >= height){
                        continue;
                    }
                    var idx1 = (x + y * width) * 4;
                    var idx2 = (l + 1) + (k + 1)*3;
                    val[0] += weight[idx2]*src[idx1];
                    val[1] += weight[idx2]*src[idx1 + 1];
                    val[2] += weight[idx2]*src[idx1 + 2];
                }
            }
            dst[idx] = val[0];
            dst[idx + 1] = val[1];
            dst[idx + 2] = val[2];
            dst[idx + 3] = src[idx + 3];
        }
    }
};

window.addEventListener("DOMContentLoaded", function(){
    //ファイルオープンの際のイベント
    var ofd = document.getElementById("selectfile");
    ofd.addEventListener("change", function(evt) {
        var img = null;
        var canvas = document.createElement("canvas");
        //var canvas = document.getElementById('canvas');

        var file = evt.target.files;
        var reader = new FileReader();

        //dataURL形式でファイルを読み込む
        reader.readAsDataURL(file[0]);

        //ファイルの読込が終了した時の処理
        reader.onload = function(){
            img = new Image();
            img.onload = function(){
                //キャンバスに画像をセット
                var context = canvas.getContext('2d');
                var width = img.width;
                var height = img.height;
                canvas.width = width;
                canvas.height = height;
                context.drawImage(img, 0, 0);

                //フィルター処理
                var srcData = context.getImageData(0, 0, width, height);
                var dstData = context.createImageData(width, height);
                var src = srcData.data;
                var dst = dstData.data;
                //grayFilter(src, dst, width, height);
                sobelFilter(src, dst, width, height);
                context.putImageData(dstData, 0, 0);

                //画像タグに代入して表示
                var dataurl = canvas.toDataURL();
                document.getElementById("output").innerHTML = "<img src='" + dataurl + "'>";
            }
            img.src = reader.result;
        }
    }, false);
});

HTML側

<input type="file" id="selectfile" accept='image/*'>
<div id="output" style="border: none; margin: 30px; background-color: #f8f8f8; min-height: 40px;">
</div>

ソーベルフィルタの部分では元の入力画像は変更せずに新しい空のimagedataを作成して変換した値を代入しています。こうすることで元の画像を保持することができます。(Cなどで使える画像処理ライブラリのOpenCVにある関数もこういった形になっています)

ちなみにソーベルフィルタ関数のweightの配列の値を変更することで色々なフィルタリング関数を作ることができます。

まとめ

javascriptで画像処理をするにあたって、FileAPIを使って画像ファイルを読み込み、canvasから画素単位で画像の加工を行うことでグレースケール変換やソーベルフィルタを行いました。

これをベースにして色々な画像処理を作ることができるのではないかと思います。

スポンサーリンク
Amazon
  • このエントリーをはてなブックマークに追加

関連記事

jQueryにおけるcreateElement

jQueryでcreateElementに変わる関数は単純で、例えばvar dom = docume

記事を読む

【javascript/jQuery】強制的にページをスクロールさせる方法

強制的にページをスクロールさせたいと思って調べていたのですが、なかなか思うようなものが見つからず困っ

記事を読む

【jQuery】クリックイベントでマウスホイールクリックを検知する

$("a").click(function(){ … }); によりクリックイベントを関連付け

記事を読む

【jQuery】サイドバー固定に役立つサイト集

縦スクロール 縦方向にスクロールして指定の位置に来たら要素を固定させる方法のリンク集を紹介させてい

記事を読む

WordPressの記事内でJavaScriptを動かす

WordPressでは厄介なことにJavaScriptが動かない場合があります。この記事では動かない

記事を読む

ニコニコ動画のURLリンクから外部プレイヤーのスクリプトに正規表現で置換する

ニコニコ動画の動画のアドレスを抽出して外部プレイヤー貼りつけソースのスクリプトに変換するソースです。

記事を読む

【jQuery UI】タブをクリックしたときのイベントでselectが使えない

jQuery UIは1.10のバージョンではタブをクリックしたときのイベントの名前が変わっているよう

記事を読む

jQueryのカラーピッカーライブラリFarbtastic Color Pickerを使う

.farbtastic .wheel { background: url(http://mem

記事を読む

【3DCG・MMD】カメラレンズによる見え方シミュレータ作成について

カメラのレンズが違うことでどのくらい出来上がる写真に差が出てくるのかを確かめることのできるシミュレー

記事を読む

【javascript】RSSを読み込んで表示させる【Google Feed API】

jQueryで簡単にRSSフィードを表示させる方法としてGoogleFeedAPIを利用するというの

記事を読む

UWSCを使ったソフト自動立ち上げ【SoftEther VPN Server】

やりたいこと 最近SoftEtherという筑波大学発のベンチャー企業

【PHP】headerでContent-Typeを指定したのに効かない場合の対処法

PHPでサイトマップを作ろうと思い、XML形式のファイルを出力しようと

スマホ向け幅固定サイトの回転時の幅対応方法

幅固定サイトでのスマホ回転時Webサイトの横幅を合わせる方法のメモ。

【PHP】特定のURLからそのAtomやRSSのフィードを抽出する方法

特定のURLからRSSやATOMのフィードを抽出する方法をメモ。 流

フィード抽出ツール(RSS1.0、RSS2.0、atom)

任意URL サイト名 サイトURL RSS1.0

格安プラン限定レンタルサーバー機能比較表(2016年)

はじめに  最近新しい共用サーバーをレンタルしようと思い調査およびそ

kindle unlimitedが便利だったのでお勧めの使い方など感想メモ

 kindle unlimitedというサービスが8/3からAmazo

→もっと見る

  • Author : ががんぼ
    プログラミングやWeb関係で気付いたことについてメモしていく予定。だいたいが備忘録ですが、自分でサンプルを作って動かしてみたりしています。
PAGE TOP ↑