このページの本文へ

前へ 1 2 3 4 次へ

古籏一浩のJavaScriptラボ ― 第43回

Web WorkersでPhotoshop風ヒストグラムを作ろう

2010年10月19日 11時00分更新

古籏一浩

  • この記事をはてなブックマークに追加
  • 本文印刷
js-labo

 JavaScriptで並列処理を実現する「Web Workers」。前回はWeb Workersの基本的な使い方を学び、バイナリデータを解析するプログラムを作りました。今回は、Photoshopのヒストグラムのように、RGB(赤、緑、青)の輝度のピクセル数を調べる画像解析プログラムを作りましょう。画像処理は時間がかかることが多いので、Web Workersを利用するにはもってこいです。

【図16】fig16.png
Photoshopのヒストグラム。今回は同様のサンプルをWeb Workersで作成する

 まず、調べたい輝度と画像データを以下のようにワーカーに渡します。


myWorker.postMessage({
    width: canvasW,      //キャンバスの横幅
    height: canvasH,        //キャンバスの縦幅
    brightness: brightness,   // 調べたい輝度
    imageData: context.getImageData(0, 0, canvasW, canvasH).data    // ピクセルデータ配列
});


 ワーカー内では呼び出し元から指定されたRGBの輝度が、配列内にいくつあるかを調べます。配列にはCanvasに描画された画像のピクセルデータがRGBα形式で格納されています。R/G/B/αそれぞれの値が配列の1要素になるので、1ピクセルあたり4要素(4バイト)使うことになります。ピクセルデータは画面の左上から右下に向かって順番に格納されています。

 ピクセルデータを1ピクセル分ずつ読み出して、指定された輝度と一致するかどうか、for()を使って縦横のサイズ分だけ繰り返し調べていきます。


for(var y=0; y<event.data.height; y++){
    for(var x=0; x<event.data.width; x++){
        var ptr = (y * event.data.width + x) * 4;
        var R = pixels[ptr + 0];
        var G = pixels[ptr + 1];
        var B = pixels[ptr + 2];
        if (R == c) { countR++; }
        if (G == c) { countG++; }
        if (B == c) { countB++; }
    }
}


 調べた結果は以下のようにして呼び出し元に送信します。redに赤の輝度のピクセル数、greenに緑の輝度のピクセル数、blueに青の輝度のピクセル数が入ります。


postMessage({
    red : countR,
    green : countG,
    blue : countB
});


 呼び出し元ではワーカーから返された結果を以下のようにしてページ上に表示します。


myWorker.addEventListener("message", function(event){
    var txt = brightness+" = RGB["+event.data.red+","+event.data.green+","+event.data.blue+"]";
    document.getElementById("result").innerHTML = txt+"<br>";
}, true);


 サンプル6は指定された輝度のRGBピクセル数がいくつあるかを調べ、ページ内に表示します。

【図17】fig17.png
ボタンをクリックすると輝度が20のピクセルがいくつあるかを表示する

サンプル6[HTML]


<!DOCTYPE html>
    <head>
        <meta charset="utf-8" />
        <title>画像分析(1)</title>
    </head>
    <body>
        <h1>画像分析(1)</h1>
        <canvas id="myCanvas" style="width:300px;height:150px;border:1px solid black">
            Canvasに対応したブラウザーでご覧下さい。
        </canvas>
        <form action="./image.cgi" method="get">
            <input type="button" id="checkStart" value="分析開始" />
        </form>
        <div id="result"></div>
        <script>
            document.getElementById("checkStart").addEventListener("click", function(){
                document.getElementById("result").innerHTML = "分析中...";
                var brightness = 20;    // チェックする輝度
                // ワーカー設定
                var myWorker = new Worker("analysis.js");
                myWorker.addEventListener("message", function(event){
                    var txt = brightness+" = RGB["+event.data.red+","+event.data.green+","+event.data.blue+"]";
                    document.getElementById("result").innerHTML = txt+"<br>";
                }, true);
                myWorker.postMessage({
                    width: canvasW,   
                    height: canvasH,
                    brightness: brightness,
                    imageData: context.getImageData(0, 0, canvasW, canvasH).data
                });
            }, true);
            var canvasObj = document.getElementById("myCanvas");
            var context = canvasObj.getContext("2d");
            var canvasW = canvasObj.width;
            var canvasH = canvasObj.height;
            var imgObj = new Image();
            imgObj.src = "sunflower.jpg";
            imgObj.onload = function(){
                context.drawImage(imgObj,0,0,300,150);
            }
        </script>
    </body>
</html>


●サンプル6[analysis.js]


addEventListener("message", analysis, false);
function analysis(event){
    var countR = countG = countB = 0;
    var pixels = event.data.imageData;
    var c = event.data.brightness;  // 輝度
    for(var y=0; y<event.data.height; y++){
        for(var x=0; x<event.data.width; x++){
            var ptr = (y * event.data.width + x) * 4;
            var R = pixels[ptr + 0];
            var G = pixels[ptr + 1];
            var B = pixels[ptr + 2];
            if (R == c) { countR++; }
            if (G == c) { countG++; }
            if (B == c) { countB++; }
        }
    }
    postMessage({
        red : countR,
        green : countG,
        blue : countB
    });
}


書影

「まとめてじっくり読みたい!」という読者のみなさまの声にお応えし、この連載が本になりました。書籍化にあたって加筆修正し、記事公開後の最新情報やコラムも盛り込んでいます。

HTML5+JavaScript アイデア&実践サンプル

本体 2,800+税、B5変形判312ページ(オール4色刷)
ISBN:978-4-04-870448-9

Amazon.co.jpで買う 楽天ブックスで買う

前へ 1 2 3 4 次へ

この連載の記事

ASCII.jp会員サービス 週刊Web Professional登録

Webディレクター江口明日香が行く

みんなが買ってる最新アイテムはコレだ!

Microsoft Windows 7 Home Premium 通常版 Service Pack 1 適用済み

iPhone 4S/4 防指紋性・高光沢機能性フィルム PRO GUARD AF for iPhone 4S/4 / PGAF-IPH4

iPhone 4S/4 防指紋性・高光沢機能性フィルム PRO GUARD AF for iPhone 4S/4 / PGAF-IPH4

マイクロソリューション Micro Solution Inc.

83人が購入

BenQ 24型 LCDワイドモニタ XL2420T

BenQ 24型 LCDワイドモニタ XL2420T

ベンキュージャパン

37,238円〜

3人が購入

jQuery Mobile スマートフォンサイト デザイン入門 (WEB PROFESSIONAL)

jQuery Mobile スマートフォンサイト デザイン入門 (WEB PROFESSIONAL)

アスキー・メディアワークス

2,499円〜

20人が購入

メモリーカード 32GB (PCH-Z321J)

メモリーカード 32GB (PCH-Z321J)

ソニー・コンピュータエンタテインメント

7,772円〜

6人が購入

Amazon.co.jp