◆PROCESSING 逆引きリファレンス
カテゴリー:イメージ処理
画像をピクセル単位で操作するには
【概要】
※本記事は、以前「残像を描画するには」で紹介した命令の一部を、あらためて別記事として整理したものになります。
PROCESSINGは、手軽に図形を描いたり画像を表示できるのが特徴です。
画像をピクセル単位で取り出す方法については、「画像の一部を取り出すには」記事で紹介させていただきました。
ただし上記記事で紹介した方法は低速な方法であり、たくさんのピクセルを処理したい場合には速度が犠牲となります。
ここではより高速に、画像をピクセル単位で取り出す方法や、変更する方法を紹介したいと思います。
PROCESSINGはその内部に、pixelsという名前の画像データを格納する int型 のメモリ配列を保持しています。
この配列からデータを取り出すことで、すでに実行結果ウィンドウに表示されている画像を取得することが可能です。
またpixels配列を直接書き換えることで、その結果を実行結果ウィンドウに反映することもできます。
ただしpixels配列は、利用する前に読み出し処理(loadPixels)を行う必要があります。また変更したpixels配列を実行結果ウィンドウに反映するには、反映処理(updatePixels)を行う必要があります。
pixels配列は実行結果ウィンドウだけではなく、PImageクラスにもあります。PImageクラスがもつ配列を操作すると、PImageに保持されている画像を取得する事や変更する事ができます。
【詳細】
画像データを読み込む
loadPixels() は、PROCESSINGが用意しているpixels [] 配列に、実行結果ウィンドウに表示中の全画素を取り込みます。
(画像URL:王国興亡記 様)
pixels[] 配列は int 型の配列で、画面横サイズ×縦サイズ(width * height)分の領域があります。
loadPixel() を行うことで、はじめて実行結果ウィンドウの画素を pixels[] 配列に反映します。逆に言えば loadPixel() を行わないと pixels[] 配列は使えません。
たまにloadPixel()を行わなくてもpixels[] 配列を読み取れる場合があるようですが、公式リファレンスにある通り、これは推奨されていません。
pixels [ 0 ] が実行結果ウィンドウの左上隅の画素、pixels [ 1 ]がその右隣の画素データです。例えば幅が4、高さが2の実行結果ウィンドウの場合、以下のようになります。
pixels配列に格納されるデータは、8bit × ARGB の 32bit で構成されています。
先頭の 8bit部分(0xFF000000) がアルファー値(透明度)で、255なら不透明、0なら透明です。
次の8bit部分(0x00FF0000)が赤の濃度、その次の8bit部分(0x0000FF00)が緑の濃度、最後の8bit部分(0x000000FF)が青の濃度になります。
PImage オブジェクトにも pixels[] 配列があります。
こちらは PImageオブジェクトに読み込まれた(createImage() やloadImage() などが行われた)画素データを閲覧・加工するために用いるもので、基本的な機能は PROCESSING が用意している 実行結果ウィンドウ用の pixels[] 配列と同じです。
(画像URL:王国興亡記 様)
以下の例では、幅4、高さ2の上下が青と赤で塗られた画像を読み込み、loadPixels() で画素を pixels[] 配列に取り込んでいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
PImage test; void setup(){ //初期化 size( 4, 2 ); test = loadImage("small.png"); } void draw(){ //画面に test.png を表示 background(test); //現在の画面を pixels[]に取り込む loadPixels(); println( pixels.length ); //配列の大きさ //取り込んだデータを16進数で表示してみる for( int i = 0; i < 8; i++ ){ println( "index=" + i + " " + hex(pixels[ i ] ) ); } noLoop(); } |
pixels[] 配列は、この例ではPImageに読み込まれた画像サイズと同じだけ(つまり 8個(4×2))の領域になります。
左上から順番に画素情報を表示しています。表示される画素情報は16進の#ARGB形式です。最初の4つが#FF0000FFなので不透明の青、次の4つが#FFFF0000で不透明の赤になっています。
画像データを反映する
変更された pixels[] 配列は、updatePixels() によって実行結果ウィンドウに反映します。updatePixels() を行わないと反映されないので注意して下さい。
たまにupdatePixels()を行わなくても、pixels[] 配列への変更が画像に反映される場合があるようですが、公式リファレンスにある通り、これは推奨されていません。
また公式リファレンスには updatePixels() に、反映する領域を指定できる例が掲載されていますが、現時点では領域を指定した反映処理はサポートされていないようです。
【関連記事】
サンプルプログラム
背景画像の一部を書き換える例:
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 |
/** * PROCESSING 3.0 背景画像変更処理 Sample * @auther MSLABO * @version 2019/05 1.0 */ PImage elf; void setup(){ size(300,300); //背景用の画像を読み込む elf = loadImage("elf.png"); //背景に表示する background(elf); //背景画像を変更する changePixels(); } void draw(){ } void changePixels(){ //画素を読み込む loadPixels(); //(100,100)-(200,200)の領域を変更する for(int y = 100; y < 200; y++){ for( int x = 100; x < 200; x++){ int index = y * width + x; pixels[index] = 0xFF0000FF; } } //変更を反映する updatePixels(); } |
背景画像を読み込み、その一部(100,100 – 200,200)を青色に塗りつぶしています。
<出力サンプル>
(画像URL:illust-AC 様:YagiHikaru さん)
PImage画像を書き換える例:
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 |
/** * PROCESSING 3.0 PImage画像変更処理 Sample * @auther MSLABO * @version 2019/05 1.0 */ PImage elf; void setup(){ size(300,300); //画像を読み込む elf = loadImage("elf.png"); } void draw(){ background(elf); } void changePixels(){ //画素を読み込む elf.loadPixels(); //モノクロ化する for(int y = 0; y < height; y++){ for( int x = 0; x < width; x++){ int index = y * width + x; //画素の色(RGB)を取り出して平均化する color pixelColor = elf.pixels[index]; int r = (pixelColor >> 16) & 0xff; int g = (pixelColor >> 8 ) & 0xff; int b = pixelColor & 0xff; r = g = b = (r + g + b)/3; //画素を更新する elf.pixels[index] = color(r, g, b); } } //変更を反映する elf.updatePixels(); } void mouseClicked(){ //画像を変更する changePixels(); } |
先程の例と似ていますが、今度はPImageの持つ各画素に対して処理を行っています。
本例ではPImageの画素を1つずつ読み出し、RGBの色成分を平均化する事でモノクロ化処理を施しています。
なおモノクロ化する計算処理部分については
の内容を参考とさせていただきました。ありがとうございます。
<出力サンプル>
(画像URL:illust-AC 様:YagiHikaru さん)
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。