画素ごとの濃淡変換をやってみる

2020年6月7日

前回はヒストグラムの可視化をしてみました。今回は、濃淡変換によって明るさやコントラストの変換等をやっていきたいと思います。

明暗やコントラストの変換を行うことでくっきりとした画像にしたり色を強調したりすることができます。今回は、入力画像の値をある一定の値の変化をさせて出力するということなので実装と結果等について書いていきたいと思います。変換方法は色々とあります。例えばγ変換やネガ・ポジ反転、ポスタリゼーションとかでしょうか。興味を持った方は調べてやってみていただければと思います。




実装について

ルックアップテーブルとは(簡単に)

今回の実装では、ルックアップテーブルというものを使用しました。ルックアップテーブルとは、複雑な計算処理を単純な配列の参照に置き換えるための配列の名前になります。例えば、マイコンや計算時間の短縮をするために、先に複雑な計算等をした結果を配列に保持しておいて、使用するときはその配列にアクセスすることで代用するということをされたりすると思います。その配列のことをルックアップテーブルといいます。

実装

今回は、例としてトーンカーブを作成して画像データを返してもらう関数とルックアップテーブルの内容で変換をした画像を返す関数の2つを実装しました。ルックアップテーブルの内容を入れる方が応用が利くので使いやすいかなとか思っています。

Mat myToneCurve(Mat data, float tilt, int x_offset, int y_offset, int8_t color)
{

	int width = data.size().width;
	int height = data.size().height;

	Mat out;
	out = data.clone();

	vector<int> lut(256);

	for (int i = 0; i < 256; i++) {
		float check = tilt * (i - x_offset) + y_offset;
		if (check >= 255.0f) check = 255.0;
		else if (check < 0.0f) check = 0.0;

		lut[i] = (int)check;
		//cout << lut[i] << endl;
	}

	if (color == 1) {
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				out.at<Vec3b>(y, x)[0] = lut[data.at<Vec3b>(y, x)[0]];
				out.at<Vec3b>(y, x)[1] = lut[data.at<Vec3b>(y, x)[1]];
				out.at<Vec3b>(y, x)[2] = lut[data.at<Vec3b>(y, x)[2]];
			}
		}
	}
	else {
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < 256; y++) {
				out.at<uchar>(y,x) = lut[data.at<uchar>(y, x)];
			}
		}
	}

	return out;
}

Mat myConvertionLut(Mat data, vector<int>lut, int8_t color)
{
	int width = data.size().width;
	int height = data.size().height;

	Mat out;
	out = data.clone();

	if (lut.size() != 256) {
		cout << "not satisfy data size " << lut.size() << endl;
		return data;
	}

	if (color == 1) {
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				out.at<Vec3b>(y, x)[0] = lut[data.at<Vec3b>(y, x)[0]];
				out.at<Vec3b>(y, x)[1] = lut[data.at<Vec3b>(y, x)[1]];
				out.at<Vec3b>(y, x)[2] = lut[data.at<Vec3b>(y, x)[2]];
			}
		}
	}
	else {
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				out.at<uchar>(y, x) = lut[data.at<uchar>(y, x)];
			}
		}
	}

	return out;
}

使い方(例)

使用例を示しておきます。この例では、ネガポジ反転用のルックアップテーブルを作成して変換した画像を出力するようにしています。

	vector<int> lut(256);

	for (int i = 0; i < 256; i++) {
		lut[i] = 255 - i;
	}

	imshow("my lut", myConvertionLut(data, lut));

実行結果(例)

オリジナル画像は以下のものを使用しました。最近のブログでよく使用しているハーフマウスの重さをはかっている写真です。

変換前のヒストグラムは以下の通りです。

ヒストグラムの表示については前回の記事を参照していただければと思います。

ネガポジ反転

 

 

使用したルックアップテーブルは以下の通り。

γ変換

γ = 2.0のとき

使用したルックアップテーブルは以下の通り。

さいごに

今回は、画素の値を変換するということをしてみました。ヒストグラムの変化を確認しながら実行すると何がおきているのかわかりやすいですね。グラフのプロットはPythonで行っています。γ変換やネガポジ反転等について詳しく知りたい方は調べてみていただければと思います。次は、色空間等の勉強をしてHSV系で色検知をしてみるということをしてみたいと思っています。

参考文献

ディジタル画像処理[改訂新版]