0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【JavaScript】画像から特定の色を数える際、条件式で判定すべきか、テーブルを引くべきか?

0
Posted at

問題設定

入力される画像にあらかじめ決めた色があるかを判定したい。
今回は、R成分、G成分、B成分すべてについて、あらかじめ決めた色の対応する成分との差 (の絶対値) があらかじめ決めたしきい値以下であることを、「あらかじめ決めた色である」という。

比較方法

今回は、JSBench.me を用いて比較を行った。
画像データは、キャンバスから取得できる ImageData を扱うことを想定し、Uint8ClampedArray で表した。
また、単にあるかを判定するのではなく、あらかじめ決めた色であるピクセルの数を数える処理で比較した。

実験

前処理を行わない場合

2種類の手法に共通のコード。画像サイズと探す色を設定し、ランダムな画像データを用意する。

Setup JavaScript
const width = 1280;
const height = 720;

const targetR = 128;
const targetG = 128;
const targetB = 128;
const targetSize = 2;

const data = new Uint8ClampedArray(width * height * 4);
for (let i = 0; i < data.length; i++) {
	data[i] = ~~(Math.random() * 256);
}

条件式で判定することにより探す色を数えるコード。

if
let count = 0;
for (let i = 0; i < data.length; i += 4) {
	if (
		targetR - targetSize <= data[i] && data[i] <= targetR + targetSize &&
		targetG - targetSize <= data[i + 1] && data[i + 1] <= targetG + targetSize &&
		targetB - targetSize <= data[i + 2] && data[i + 2] <= targetB + targetSize
	) {
		count++;
	}
}

テーブルを引くことにより探す色を数えるコード。
それぞれの色が探す色かを表すテーブルを作る処理が入っている。

array
const hitArray = new Uint8Array(1 << 24);
const rMin = Math.max(0, targetR - targetSize);
const rMax = Math.min(255, targetR + targetSize);
const gMin = Math.max(0, targetG - targetSize);
const gMax = Math.min(255, targetG + targetSize);
const bMin = Math.max(0, targetB - targetSize);
const bMax = Math.min(255, targetB + targetSize);
for (r = rMin; r <= rMax; r++) {
	for (g = gMin; g <= gMax; g++) {
		for (b = bMin; b <= bMax; b++) {
			hitArray[r | (g << 8) | (b << 16)] = 1;
		}
	}
}

let count = 0;
const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
for (let i = 0; i < data.length; i += 4) {
	count += hitArray[dataView.getUint32(i, true) & 0xffffff];
}

Color search (version 1) - JavaScript benchmark at JSBench.me

実行結果は、以下のようになった。

ブラウザ 条件式 (if) テーブル (array)
Firefox 132.0.2 236 ops/s ± 0.65% 70 ops/s ± 1.6%
Google Chrome 131.0.6778.70 79 ops/s ± 2.73% 12 ops/s ± 4.22%

前処理を行う場合

2種類の手法に共通のコード。画像サイズと探す色を設定し、ランダムな画像データを用意する。
さらに、今回はそれぞれの色が探す色かを表すテーブルを作る処理をここで行う。

Setup JavaScript
const width = 1280;
const height = 720;

const targetR = 128;
const targetG = 128;
const targetB = 128;
const targetSize = 2;

const data = new Uint8ClampedArray(width * height * 4);
for (let i = 0; i < data.length; i++) {
	data[i] = ~~(Math.random() * 256);
}

const hitArray = new Uint8Array(1 << 24);
const rMin = Math.max(0, targetR - targetSize);
const rMax = Math.min(255, targetR + targetSize);
const gMin = Math.max(0, targetG - targetSize);
const gMax = Math.min(255, targetG + targetSize);
const bMin = Math.max(0, targetB - targetSize);
const bMax = Math.min(255, targetB + targetSize);
for (r = rMin; r <= rMax; r++) {
	for (g = gMin; g <= gMax; g++) {
		for (b = bMin; b <= bMax; b++) {
			hitArray[r | (g << 8) | (b << 16)] = 1;
		}
	}
}

条件式で判定することにより探す色を数えるコード。
行う前処理は無いので、「前処理を行わない場合」と同じである。

if
let count = 0;
for (let i = 0; i < data.length; i += 4) {
	if (
		targetR - targetSize <= data[i] && data[i] <= targetR + targetSize &&
		targetG - targetSize <= data[i + 1] && data[i + 1] <= targetG + targetSize &&
		targetB - targetSize <= data[i + 2] && data[i + 2] <= targetB + targetSize
	) {
		count++;
	}
}

テーブルを引くことにより探す色を数えるコード。
テーブルは前処理で作っているので、ここでは引くだけである。

array
let count = 0;
const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
for (let i = 0; i < data.length; i += 4) {
	count += hitArray[dataView.getUint32(i, true) & 0xffffff];
}

Color search 2 (version 1) - JavaScript benchmark at JSBench.me

実行結果は、以下のようになった。

ブラウザ 条件式 (if) テーブル (array)
Firefox 132.0.2 236 ops/s ± 1.1% 98 ops/s ± 1.99%
Google Chrome 131.0.6778.70 79 ops/s ± 4.58% 11 ops/s ± 6.55%

結論

今回の実験では、Firefox・Google Chrome ともに、テーブルを引いて判定するより条件式で判定するほうが速いという結果になった。
条件分岐をしなくてよいテーブルのほうが速いと予想したので、意外だった。
また、Firefox ではテーブルを作成する処理を前処理に移動するとパフォーマンスが改善したが、Google Chrome では改善はみられなかった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?