Processingで画像の色情報を取得するアプリを作ってみた

Processing触ってみたら、思いのほか楽しかったので簡単なGUIアプリを作成してみた。
画像を読み込んで、Ctrl+マウスで選択した矩形範囲のRGB平均値を表示するだけのアプリ。


こんなん。


hキーを押すと、ヘルプが表示される。



地味にハマったのがフォントの作成。
フォントはProcessingのMENUから予め作成しておく必要がある。




以下、コード。
calcal.pde

PImage img;
int winWidth, winHeight;
ArrayList selecters;  // Select Rect Class
boolean selecting = false;
boolean showingHelp = false;

void setup() {
	img = loadImage( selectInput() );

	/* Resize Image */
	if (640 < img.width) {
		img.resize(640, 0);
	}
	if (480 < img.height) {
		img.resize(0, 480);
	}
	winWidth  = img.width;
	winHeight = img.height;
	size(winWidth, winHeight);
	noStroke();

	/* Init ArrayList */
	selecters = new ArrayList();
}

void draw() {
	background(0);
	image(img, 0, 0);

	int size = selecters.size();
	if (0 < size) {
		for (int i=0; i<size-1; i++) {
			((CRect)selecters.get(i)).update();
		}
		if (selecting) {
			((CRect)selecters.get(size-1)).update(mouseX, mouseY);
		} else {
			((CRect)selecters.get(size-1)).update();
		}
	}

	if (showingHelp) {
		stroke(80, 180, 0);
		fill(0, 120, 20, 150);
		rect(0, 0, 240, winHeight);

		PFont font = loadFont("SansSerif.plain-12.vlw");
		textFont(font, 12);
		fill(255);
		int str_x = 10;
		int str_y = 30;
		text("--- Help ---", str_x, str_y);
		text("Ctrl + MouseLeftPress :", str_x, str_y+=25);
		text("Select Color Analyzing Area", str_x+10, str_y+=16);
		text("key \'h\' :", str_x, str_y+=30);
		text("Show/Hide Help", str_x+10, str_y+=16);
		text("key \'r\' :", str_x, str_y+=20);
		text("Clear All Select Area", str_x+10, str_y+=16);
		text("key \'d\' :", str_x, str_y+=20);
		text("Remove Lateset Select Area", str_x+10, str_y+=16);
	}
}

void mousePressed() {
	switch (mouseButton) {
		case LEFT:
			if ((true == keyPressed) && (CONTROL == keyCode)) {
				selecters.add( new CRect(mouseX, mouseY) );
				selecting = true;
			}
			break;
		default:
			break;
	}
}

void mouseReleased() {
	selecting = false;
}

void keyPressed() {
	switch (key) {
		case 'd':	/* delete latest selecter */
			if (0 < selecters.size()) {
				selecters.remove( selecters.size()-1 );
			}
			break;
		case 'r':	/* clear selecters */
			selecters.clear();
			break;
		case 'h':	/* show/hide help */
			showingHelp = (false == showingHelp) ? true : false;
			break;
		default:
			break;
	}
}

void keyReleased() {
	selecting = false;
}


選択領域クラスのコード。
CRect.pde

/* Convert RGB to YUV */
int Y_yuv(color rgb) {
	int y = int(0.299*red(rgb) + 0.587*green(rgb) + 0.114*blue(rgb));
	return y;
}

int Cb_yuv(color rgb) {
	int cb = int(0.169*red(rgb) - 0.331*green(rgb) + 0.500*blue(rgb));
	return cb;
}

int Cr_yuv(color rgb) {
	int cr = int(0.500*red(rgb) - 0.419*green(rgb) - 0.081*blue(rgb));
	return cr;
}


class CRect {
	int sx, sy, ex, ey;
	int small_x, small_y, large_x, large_y;
	color rgb;
	int yuv_y, yuv_cb, yuv_cr;
	int xyz_x, xyz_y, xyz_z;

	CRect(int x, int y) {
		this.sx = x;
		this.sy = y;
		this.ex = this.sx;
		this.ey = this.sy;
	}

	void update() {
		this.select();
		this.textcolor();
	}

	void update(int x, int y) {
		this.ex = x;
		this.ey = y;

		this.config();
		this.select();
		this.ave();
		this.yuv();
		this.textcolor();
	}

	private void config() {
		/* rect(x1, y1, x2, y2)で x1>x2 もしくは y1>y2 になると落ちる対策 */
		if (this.sx > this.ex) {
			this.small_x = this.ex;
			this.large_x = this.sx;
		} else {
			this.small_x = this.sx;
			this.large_x = this.ex;
		}
		if (this.sy > this.ey) {
			this.small_y = this.ey;
			this.large_y = this.sy;
		} else {
			this.small_y = this.sy;
			this.large_y = this.ey;
		}
	}

	private void select() {
		stroke(40, 0, 80);
		fill(255, 255, 255, 40);
		rect(this.small_x, this.small_y, (this.large_x - this.small_x), (this.large_y - this.small_y));
	}

	private void ave() {
		long sum_r = 0, sum_g = 0, sum_b = 0;
		long count = 0;

		for (int i=this.small_x; i<=this.large_x; i++) {
			for (int j=this.small_y; j<=this.large_y; j++) {
				color c = get(i, j);
				sum_r += red(c);
				sum_g += green(c);
				sum_b += blue(c);
				count++;
			}
		}

		this.rgb = color( int(sum_r/count), int(sum_g/count), int(sum_b/count) );
	}

	private void yuv() {
		this.yuv_y  = Y_yuv(this.rgb);
		this.yuv_cb = Cb_yuv(this.rgb);
		this.yuv_cr = Cr_yuv(this.rgb);
	}

	private void textcolor() {
		PFont font = loadFont("SansSerif.plain-12.vlw");
		textFont(font, 10);
		fill(0);
		String str_rgb = "RGB: " + int(red(this.rgb)) + ", " + int(green(this.rgb)) + ", " + int(blue(this.rgb));
		String str_yuv = "YUV: " + this.yuv_y    + ", " + this.yuv_cb     + ", " + this.yuv_cr;
		text(str_rgb, this.small_x+5, this.small_y+10);
		text(str_yuv, this.small_x+5, this.small_y+25);
	}
}


GitHubでも、はてなダイアリーでもProcessingってサポートされてないのね…。


参考ページ
Processing.org
yoppa org – Processingで画像データを扱う
Processing基礎最速入門 - catch.jp-wiki
建築発明工作ゼミ2008: Processing 文字と画像
[Processing]マウス座標の取得とArrayListを使った応用 | うえちょこ@ぼろぐ
a-07 画像を使う - Processing 学習ノート