見出し画像

#今日の学び No.26「画像処理#後編」

どうもです!Anbyであります。
まずは謝りましょう。昨日の記事を書いているときに、急用が入りまして(衛星関連です…)また書き始めたのが一日が終わるぎりぎりの時間だったのであんな中途半端なところで終わりました。すみません。
何言っているのか分からないと言う人は、下に昨日の記事を貼っておくのでご覧くださいませ。今日はちゃんと最後まで書きますよ。では、参りましょ!

1.写真のグレースケール変換

と言われても分からないかも知れませんね。グレースケール変換とは、一般的なカラー画像をグレーの画像に変換することです。所謂白黒画像とは少し異なります。どちらかと言えば、デッサンのような鉛筆などで濃淡を表現したようなイメージですね。

昨日示したのは写真をグレースケール変換するプログラムコードでしたね。私が使用している開発環境はUbuntuと呼ばれる仮想環境で、ソフトはOpenCVを使用しています。というわけで、実物を見た方が早いので見せましょう。まずはダウンロードしておいたオリジナル写真「Earh.jpg」地球ですね[図1]。

画像1

図1 Earth.jpg

そしてこちらがグレースケール変換した画像です。

画像2

図2 グレースケール変換したEarth.jpg

どうですか?ちょっとレントゲンみたいですよね。ちなみに、このプログラムコードは下のようになるのですが、

 #include  <stdio.h>
 #include  <opencv2/opencv.hpp>
 #include  <opencv2/core/core.hpp>
 #include  <opencv2/highgui/highgui.hpp>

using namespace cv;

Mat img_src, img_dst;

int main(){
   char key;

   namedWindow("image",CV_WINDOW_AUTOSIZE);
   
   while (1) {
       img_src = imread("Earth.jpg");
       imshow("image",img_src);

	key = waitKey(10);
	if (key == 'q') break;
	else if (key == 's') imwrite("output.jpg",img_src);

   }

   destroyAllWindows();
   return 0;
}

プログラムの流れとしては、指定した写真を別ウィンドウで表示させ、その際にグレースケールに変換し、実行中に「q」のキーを入力すると表示を終了し、「s」を入力すると画像を保存します。保存後の名前を「outputo.jpg」としているのでその名前で保存されますね。

2.グレースケール変換からのネガ・ポジ反転

今度はグレースケール変換したものをネガ・ポジ反転させた画像を出力します。ネガ・ポジとは??という人もいるでしょう。

今でこそ写真と言えば、スマホで撮影したもののことでデジタル上に保存されるものを差すのでしょうが、昔は写真は現像して保存していました。写真を実物として保存していたわけですね。その写真の現像の過程でこのネガ・ポジが出てきます。日本語ではネガが陰画、ポジを陽画というそうです。おそらくネガティブ・ポジティブの略でしょうね。調べたら出てくると思いますが、はじめは写真はネガの状態です。それを反転させてポジの状態にします。ネガのままだと私たちが見ている世界の補色になっているので非常に見づらいです。ポジにして普段見ているような「写真」になるというわけですね。

というわけで、このネガ・ポジ反転なんですが、下に示すのが先に出てきた「Earth.jpg」のグレースケール変換された画像です。これは今はポジの状態ですので、反転させるとネガになります。

画像2

図2 グレースケール変換したEarth.jpg

これをネガに反転させると…

画像4

図3 ネガ・ポジ反転したEarth.jpg

こうなります。なんか私のところで実行したときよりも薄い気がします…サイトの画素値の限界なんですかね…

このプログラムコードは下のようになります。

 #include  <stdio.h>
 #include  <opencv2/opencv.hpp>
 #include  <opencv2/core/core.hpp>
 #include  <opencv2/highgui/highgui.hpp>

using namespace cv;
 #define  getV(img,x,y) (img.ptr<uchar>(y)[(x)])
 #define  setV(img,x,y,v) (img.ptr<uchar>(y)[(x)]=(v))

Mat img_src, img_dst;
int main(int argc, char* argv[]){
   char key;
   uchar v_src, v_dst;
   img_src = imread(argv[1],0);
   img_dst = Mat::zeros(img_src.rows,img_src.cols, CV_8UC1);
   for (int y=0; y<img_src.rows; y++) {
	for (int x=0; x<img_src.cols; x++) {
	    v_src = getV(img_src, x, y);
	    v_dst = 255 - v_src;
	    setV(img_dst, x, y, v_dst);
	}
   }
  
   namedWindow(argv[1], CV_WINDOW_AUTOSIZE);
   namedWindow("output", CV_WINDOW_AUTOSIZE);
   
   while (1) {
	imshow(argv[1], img_src);
	imshow("output",img_dst);
	key = waitKey(10);
	if (key == 'q') break;
	else if(key == 's') imwrite("output_8.jpg", img_dst);
   }
   destroyAllWindows();
   return 0;
}

ちょっと長いですね。ネガ・ポジ反転の仕組みは、ここでは一つ一つの画素の値を読み取り反転させて出力としています。

3.ポスタリゼーション

これは、絵を描いたような(ポスター)画像に変換する処理のことですね。ポスターみたいな画像になります。これも下に比較しやすいようにグレースケール変換したEarth.jpgの写真を載せますね。

画像2

図2 グレースケール変換したEarth.jpg

この画像のポスタリゼーションの結果…

画像6

図4 ポスタリゼーションしたEarth.jpg

どうですか?ポスターみたいじゃありません?これはちなみに4階調のポスタリゼーションです。つまり、4段階の濃淡で表現されています。そしてこのプログラムコードは下のようになります。

 #include  <stdio.h>
 #include  <opencv2/opencv.hpp>
 #include  <opencv2/core/core.hpp>
 #include  <opencv2/highgui/highgui.hpp>

using namespace cv; #define  getV(img,x,y) (img.ptr<uchar>(y)[(x)])
 #define  setV(img,x,y,v) (img.ptr<uchar>(y)[(x)]=(v))

Mat img_src, img_dst;
int main(int argc, char* argv[]){
   char key;
   uchar v_src, v_dst;
   img_src = imread(argv[1], 0);
   img_dst = Mat::zeros(img_src.rows,img_src.cols, CV_8UC1);
   for (int y=0; y<img_src.rows; y++) {
	for (int x=0; x<img_src.cols; x++) {
	    v_src = getV(img_src, x, y);
	    if (v_src < 64) {
		v_dst = 0;
	    } else if (v_src < 128) {
		v_dst = 85;
	    } else if (v_src < 192) {
		v_dst = 170;
	    } else {
		v_dst = 255;
	    }
	    setV(img_dst, x, y, v_dst);
	}
   }
  
   namedWindow(argv[1], CV_WINDOW_AUTOSIZE);
   namedWindow("output", CV_WINDOW_AUTOSIZE);
   
   while (1) {
	imshow(argv[1], img_src);
	imshow("output",img_dst);
	key = waitKey(10);
	if (key == 'q') break;
	else if(key == 's') imwrite("output_9.jpg", img_dst);
   }
   destroyAllWindows();
   return 0;
}

大まかな枠組みは先と同じなのでそこはコピペして使っています。ですので変えているのは一部分だけです。どこか分かりますか?
このプログラミングでは8ビットで計算しているので、深度0~255の256段階で、幅も同じく256段階です。256を4でわって分けた4つの範囲で出力値を調整します。

4.最後に

このように画像処理は行われるわけですが、普段使っているような写真加工アプリも、原型は同じです。プログラムを組むことでこのようなことができるってすごいですよね。やってて楽しいです。ちゃんと実行できて成功した時の達成感はすごく大きいですよ。

というわけで今回はこの辺で終わりたいと思います。明日試験があるので勉強します…ここまでお読みいただきありがとうございました!それではまた明日!夜は寒いので風邪ひかないようにしてくださいね!

第27号

この記事が気に入ったらサポートをしてみませんか?