このページの本文へ

Web WorkersでPhotoshop風ヒストグラムを作ろう (3/4)

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

文●古籏一浩

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

複数のワーカーを生成して並列に処理する

 最近のコンピューターは2コアや4コアなど複数のCPUを搭載しています。せっかく複数のCPUを搭載しているのですから、Web Workersを同時に複数動作させることでCPUパワーを余すことなく利用できそうです。現実的にはワーカーの処理方法はブラウザーによって異なるので、必ずしも期待どおりの結果は得られませんが(ブラウザーごとの結果の違いは最後に紹介します)、複数のワーカーを生成して並列に処理させてみましょう。

 サンプル7はワーカー1つにつき256回呼び出し、ワーカー内で赤、緑、青の輝度のピクセル数を調べていました。今度はワーカー内では与えられた輝度と指定されたチャンネル(RGB/赤緑青)だけの結果を返すようにします。

 ワーカーを呼び出す側ではR/G/Bそれぞれに対応した3つのワーカーを生成し、調べたい輝度とチャンネル(実際は配列のオフセット)を指定します。これでまとめて3つのワーカーが動作することになります。

 実際のプログラムはサンプル8です。実行すると3つのワーカーが同時に処理され、ヒストグラムが順次表示されていきます。

【図19】fig19.png

複数のワーカーが動作しヒストグラムが表示される。Operaでは高速だがFirefoxでは時間がかかる

サンプル8[HTML]


<!DOCTYPE html>
    <head>
        <meta charset="utf-8" />
        <title>画像分析(複数のワーカーを利用)</title>
    </head>
    <body>
        <h1>画像分析(複数のワーカーを利用)</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 = "分析中...<br>";
                var brightness = 0;   // チェックする輝度
                var red = "";
                var green = "";
                var blue = "";
                // ワーカー設定
                var myWorker = new Worker("analysis.js");
                myWorker.addEventListener("message", function(event){
                    red += '<img src="r.gif" width="1" height="'+(event.data.red/8)+'">';
                    green += '<img src="g.gif" width="1" height="'+(event.data.green/8)+'">';
                    blue += '<img src="b.gif" width="1" height="'+(event.data.blue/8)+'">';
                    document.getElementById("result").innerHTML = red+green+blue;
                    brightness++;
                    if (brightness < 256) {
                        startWorker();
                    }
                }, true);
                var img = context.getImageData(0, 0, canvasW, canvasH).data;
                function startWorker(){
                    myWorker.postMessage({
                        width: canvasW,   
                        height: canvasH,
                        brightness: brightness,
                        imageData: img
                    });
                }
                startWorker();
            }, 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>


サンプル8[analysis.js]


addEventListener("message", analysis, false);
function analysis(event){
    var count = 0;
    var pixels = event.data.imageData;
    var ofst = event.data.offset; // 読み出すチャンネルのオフセット
    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 n = pixels[ptr + ofst];
            if (n == c) { count++; }
        }
    }
    postMessage(count);
}


この連載の記事

一覧へ

この記事の編集者は以下の記事をオススメしています