HTMLのCanvasでピクセルソート(Pixel sort)

Canvas要素に画像を貼り付けてピクセルを操作できます。JavaScriptには、型付き配列というものがあります。これを使うことで、RGBA単位の操作またはピクセル単位の操作をうまく切り替えることができます。

参考資料

https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Pixel_manipulation_with_canvas

CanvasのImageData.data属性の、型付き配列Uint8ClampedArrayとその使い方のチュートリアルです。このチュートリアルやデモを見ると画像をCanvasに表示して、グレースケールにする方法などが分かります。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Typed_arrays

型付き配列の説明です。型付き配列にはちょっと名前とは違い、バッファーとビューという概念があるためこれが理解する必要があります。逆にこれを使わずに、Uint8ClampedArrayを使うと、ループ処理のステップアップする数の調整などが非常に面倒になります。

 

デモ

See the Pen Pixel sort by dev001hajipro (@dev001hajipro) on CodePen.0

ソースコード

解説

5行目のimg.crossOrigin=”Anonymous”;は外部サイトの画像ファイルをCanvasに読み込むとセキュリティーエラーが発生するので、記述しています。

画像はWikipediaの320×320の画像で、Canvasのサイズを640×320にして、左側に修正していない画像を貼り付けて、右側にピクセルソートした結果を表示しています。

ctx.drawImage(img, 0, 0)が、オリジナルの画像をCanvasに描画している部分です。これはCanvasの入門情報を調べるとすぐに分かります。

var imageData = ctx.getImageData(0, 0, 320, 320);でCanvasに描画したピクセルデータが入ったImageDataオブジェクトを取得します。(ImageData -MDN) ImageData.dataプロパティーには、Uint3ClampedArray型のピクセルデータが入っています。何か難しい型に感じますが、単純に、RGBAのデータが並んでいるだけです。

単純にfor文で、ステップをi += 4にして、ループすることで、RGBAを操作することも可能です。

 

初期設定では、imageData.dataは、Uint8ClampedArray型で、ループなどをする場合は、ステップを4にする必要があります。ピクセルの移動のようにピクセル単位で操作したい場合は、forループなどのステップが1の場合の方が都合がよいです。そのような場合は、imageData.data.bufferから、Uint32Array型を用意して操作します。

ピクセル単位のソート処理

ピクセル単位に操作できるようになったので、Arrays.sortでソート処理を行います。引数p1は1ピクセルを表し、Uint32型なので符号なしの32ビットです。つまり以下のように、ABGRの順で1ピクセルを表します。

ビット演算

ビット演算は、RGBのr,g,bを各8bitとして取り出したいので、以下の手順で行います。

  1. シフト演算で、8bit単位で下位にずらす。
  2. 0xFF=11111111と論理積(AND)でマスクをする。

ビット演算の経験がなくちょっとわかりづらい場合は、ピクセルソートはひとまず置いておいて、ビット演算のみを勉強してみるとすんなり理解できると思います。

ビット演算で、r,g,bを取得できたので、とりあえずの明度としてr+g+b/3で値を用意して、比較しています。

あとは、putImageDataで、右側に書き込むだけです。

 

まとめ

最初は、Processingでピクセルソートをする動画を見たので試しました。Processingでのピクセル操作は分かりやすかったのですが、バブルソートで非常に遅く、原始的にRGBAを操作するのではなく、colorオブジェクトのように少しラップされたAPIのため、逆に分かりづらかったです。

そのためp5.jsなどがありますが、素のJavaScriptでピクセルソートを試してみました。Uint32Arrayと型付き配列を理解出来たら、あとは配列を操作するだけなので手間はありますが、非常に理解しやすかったです。

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA