【OpenCVによる画像処理入門】濃淡変換
お久しぶりです。元八です。
ひじょ~にお久しぶりです。
唐突ですが、画像処理を勉強し始めました。
今読んでる本はこちら。
OpenCVというオープンソースを使って画像を処理してみようって本です。
今回はこの本の6章、「濃淡変換」の練習問題に取り組んでみたので記事にしてみます。
----------------------------------------------------------------------------------------------------------------------
練習問題6.2
1. 適当なグレースケール画像を用意し、度数分布と累積度数を求めよ。
2. 累積度数のグラフを描画せよ。
3. 疑似カラー変換するプログラムを作成せよ。
4. 入力されたカラー画像のRGB各色をガンマ変換して出力するプログラムを作成せよ。
----------------------------------------------------------------------------------------------------------------------
【解答】
問4はやってません!
LENAさん大活躍。。。
#define _CRT_SECURE_NO_WARNINGS #define _USE_MATH_DEFINES #include <iostream> #include <cmath> #include <string> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; string win_src = "src"; string win_dst = "dst"; string win_hst = "hst"; string win_intHST = "intHST"; string win_b = "blue"; string win_g = "green"; string win_r = "red"; int main() { string file_src = "C:\\作業ディレクトリ\\src.png"; string file_dst = "C:\\作業ディレクトリ\\dst.png"; string file_hst = "C:\\作業ディレクトリ\\hst.png"; string file_intHST = "C:\\作業ディレクトリ\\intHST.png"; string file_b = "C:\\作業ディレクトリ\\blue.png"; string file_g = "C:\\作業ディレクトリ\\green.png"; string file_r = "C:\\作業ディレクトリ\\red.png"; Mat img_src = imread(file_src, 0); Mat img_dst; if (!img_src.data) { cout << "error" << endl; return -1; } // ウィンドウ生成 namedWindow(win_src, WINDOW_AUTOSIZE); namedWindow(win_dst, WINDOW_AUTOSIZE); namedWindow(win_hst, WINDOW_AUTOSIZE); namedWindow(win_intHST, WINDOW_AUTOSIZE); namedWindow(win_b, WINDOW_AUTOSIZE); namedWindow(win_g, WINDOW_AUTOSIZE); namedWindow(win_r, WINDOW_AUTOSIZE); // ヒストグラムの表示(hst:度数分布、intHST:累積度数分布) Mat img_hst; Mat img_intHST; img_hst = Mat::zeros(100, 256, CV_8UC1); img_intHST = Mat::zeros(100, 256, CV_8UC1); const int hdims[] = {256}; const float hranges[] = {0, 256}; const float *ranges[] = { hranges }; Mat hist; calcHist(&img_src, 1, 0, Mat(), hist, 1, hdims, ranges); double hist_min, hist_max; minMaxLoc(hist, &hist_min, &hist_max); double V[256] = { 0 }; // int型にしないように注意 // 度数分布の作成 for (int i = 0; i <= 255; i++) { int v = saturate_cast<int>(hist.at<float>(i)); if (i == 0) { V[i] = v; } else { V[i] = v + V[i - 1]; } cout << i << " " << v << endl; line(img_hst, Point(i, img_hst.rows), Point(i, img_hst.rows - img_hst.rows * (v / hist_max)), Scalar(255, 255, 255)); } // 累積度数分布図の作成 for (int i = 0; i <= 255; i++) { cout << i << " " << V[i] << endl; line(img_intHST, Point(i, img_intHST.rows), Point(i, img_intHST.rows - img_intHST.rows * (V[i] / V[255])), Scalar(255, 255, 255)); } // 疑似カラー変換 Mat img_b; Mat img_g; Mat img_r; img_src.convertTo(img_b, img_src.type(), -255 / (127 - 63), -255 / (127 - 63) * (- 127)); // b用トーンカーブ img_src.convertTo(img_r, img_src.type(), 255 / (192 - 167), 255 / (192 - 167) * (- 167)); // r用トーンカーブ // g用ルックアップテーブル作成 Mat lut(256, 1, CV_8U); for (int i = 0; i <= 255; i++) { if (i <= 127) { lut.data[i] = (unsigned char)(255 / 63 * i); } else { lut.data[i] = (unsigned char)(- 255 /(255 - 192) * (i - 255)); } } LUT(img_src, lut, img_g); // 合成 Mat img_dst_b; Mat img_dst_g; Mat img_dst_r; Mat empty = Mat::zeros(img_src.size(), CV_8UC1); merge(vector<Mat>{img_b, img_g, img_r}, img_dst); merge(vector<Mat>{img_b, empty, empty}, img_dst_b); merge(vector<Mat>{empty, img_g, empty}, img_dst_g); merge(vector<Mat>{empty, empty, img_r}, img_dst_r); // 結果表示 imshow(win_src, img_src); imshow(win_hst, img_hst); imshow(win_intHST, img_intHST); imshow(win_b, img_dst_b); imshow(win_g, img_dst_g); imshow(win_r, img_dst_r); imshow(win_dst, img_dst); // 書き込み imwrite(file_src, img_src); imwrite(file_hst, img_hst); imwrite(file_intHST, img_intHST); imwrite(file_dst, img_dst); imwrite(file_b, img_dst_b); imwrite(file_g, img_dst_g); imwrite(file_r, img_dst_r); waitKey(0); return 0; }
ソースコードきれいに書けるようになりたい。。。
【コメント】
グレースケールの画像(入力画像)は各画素に0~255の数値を割り当てることで、明暗を表現しています(0:黒、255:白)。
ヒストグラムは画素値0~255がそれぞれどれくらいの頻度で使用されているかを表したものです。
累積度数は、画素値0のもの〇〇個、画素値0~1のもの〇〇個、・・・、画素値0~255のもの〇〇個、といった具合でカウントしたものです。
疑似カラー画像はある範囲の画素値には青色を、ある範囲の画素値には緑色を、ある範囲には赤色をといった具合で色を割り当てて、グレースケールの画像からカラー画像を作成したものです。
今回は、暗い部分(画素値が0付近)には青色を、明るい部分(画素値が255付近)には赤色、真ん中の帯域には緑色を割り当てて疑似カラー画像を作成しました。
もしかしたら、もっと詳しく追記するかもしれません。。。
To be continued...