【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...
世の中には抱負が豊富。
待っておくれよ、お正月、、、
元八です。今日はもやもや記事です。虚無です。
新年になって、みなさん心機一転、抱負・今年の目標を掲げているのを見かけます。
(今週のお題「2019年の抱負」)
うらやましい。。。立派な人たちやで。。。
僕自身も割と、何かしらの目標をもって行動する(時があるまれに)人間なのですが、
今年は何ででしょうか、な~んか目標が定まりません...
実は、僕は今現在、一くそ大学院生であります。来年からは社会人です。
(ミステリアスな存在でありたかったけど、まぁええか...)
このはざまの時期が良くないんですかね。
研究するにしても、残り時間の少なさをどうしても考えてしまう...
来年度からの準備をするにしても、やるべきことってなんなんだろ?
だめ人間発揮中です。
去年は就活とか、社会人になるまでにこれに挑戦してみよう!とか、それはそれは抱負が豊富な人材だったのに。。。
目標がはっきりしないうちは、とりあえず目の前のことをがむしゃらにするしかないですね。これが目標のふりしときます。
あぁ、正月も、モラトリアムも終わってしまう...
全然関係ないですけど、みなさん「平成最後の」って言いすぎですね。なんや、平成最後の焼きそばって。
テレビとかYouTubeとか
じいちゃんちにいます。元八です。
ぬくぬくと、過ごしております。
先日、NHKの番組「新春テレビ放談2019」をみました。
ゴッドタンでお馴染み、佐久間さんをはじめとした真剣にテレビ番組を制作されている方々の話を聞くことができました。
一生懸命に努力されている方の話はいくらでも聞けますね。
さて、今回はその話を伺って考えたことを。
この番組内でも何度か出てきていたワード「テレビからYouTubeへ」。
最近ではよく聞きます。テレビがおもしろくなくなったからなんでしょうか?
それはちょっと違う気も。。。
僕も以前よりテレビを見る機会が減りました。おもしろくないからではないです。
むしろ、YouTubeでみられる個人投稿の動画と見比べると、如何にテレビ番組というものが作りこまれているのか感心させられることが多いです。
関わっている人の数や予算の差ですね。
では、「テレビからYouTubeへ」、何がこの流れを?
僕がそうなった理由。。。
YouTubeって、だらだら生活に最適なんですよね。
- いつでもどこでも見れる
- 勝手にオススメしてくれる
- 短い
頭を使わずに、何となくでアクセスしやすいんですよね。
だからついつい見ちゃいます。
テレビだけみていた時代、そのときも一緒で、ただ何となくテレビのスイッチを入れてました。でも今は、変に「テレビ」と「YouTube」を比較しちゃいます。
そのせいで、テレビは「(YouTubeより)おもしろいものを!」って気持ちでみようと意気込んでしまっている気がします。
この意気込みはだらだら生活にとっては邪魔者。
僕は何も考えない、ゴミくず生活を送りたい。。。
僕の求めるだらだら生活は本当に「無意味な」時間。テレビは位置づけ的に、「有意義な」ものとなり過ぎた気がします。僕個人の理由としては、ここが一番なんだと思います。
一人一人が超便利情報板こと、スマホを持つ時代。誰かが答えをくれるから、頭を使わなくてもいい機会が増えました。みんなのだらだらが加速し、そのだらだらに合ってたのがネット動画だったのかなと思います。
でも、正月はやっぱりテレビですね。
初投稿
新年、明けましておめでとうございます。
初詣はもういってきましたよ、元八です。
新年だし、新しいこと始めたいっ!ていうわけではないのに、
この時期にブログを始めるっていうのは何だか。。。
何はともあれ、今日からちょくちょく記事を更新していこうと思います。
あぁ、いい抱負。