Pythonでやりたい人はこっち〜〜
https://github.com/yoyoyo-yo/Gasyori100knock/blob/master/Tutorial/README.md
JavaScriptでやりたい人はこっち〜〜
https://github.com/yoyoyo-yo/Gasyori100knock/blob/master/Tutorial/README_javascript.md
Ubuntu-16.04(18.04でも可)を想定してます。Dockerを使うと便利だと思います。
$ apt install build-essential cmake checkinstall libgtk-3-dev libjpeg-dev libpng++-dev wget emacs vim sudo
$ mkdir opencv
$ cd oepncv
$ wget https://github.com/opencv/opencv/archive/3.4.0.tar.gz
$ tar zxvf 3.4.0.tar.gz
$ cd opencv-3.4.0
$ mkdir build
$ cd build
$ cmake ..
$ make -j4
$ make install
以下をsample.cppとして保存
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
int main(int argc, const char* argv[]){
cv::Mat redImg(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
cv::namedWindow("red", cv::WINDOW_AUTOSIZE);
cv::imshow("red", redImg);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
次にコンパイル
$ g++ sample.cpp -o sample -lopencv_core -lopencv_imgcodecs -lopencv_highgui
これで、コンパイルが通れば、フォルダ内に sample というものができてます。 あとは実行しましょう。
$ ./sample
んでこんなウィンドウが出たら成功です!!
次に画像処理の基本操作を説明していきます。(もう知ってるという人はスキップして、問題に進んでください!)
C++でOepncvを使う時、必ずこれをincludeしなきゃいけません。
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
画像を読み込むときはこうします。Mat型変数に入れる。opencv系の変数は全てcvという名前の名前空間にあります。
cv::Mat img = cv::imread("imori.jpg", cv::IMREAD_COLOR);
画像の高さ、幅を読み取るには、
int width = img.rows;
int height = img.cols;
画像の表示にはimshowとwaitKey()を使います。imshowの1つ目の引数は、表示のウィンドウの名前です。今は気にしなくていいです。2つ目の引数は表示したい画像です。なにかキーボードを押すとウィンドウが消えます。
cv::imshow("sample", img);
cv::waitKey(0);
cv::destroyAllWindows();
画素をいじるにはatメソッドを用いる。これで画素にx=30, y=20の位置にアクセスできます。
std::cout << img.at<cv::Vec3b>(30,20) << std::endl;
例えば、画像の左上半分を赤にするには、
int i = 0, j = 0;
for (i = 0; i < width / 2; i++){
for (j = 0; j < height / 2; j++){
img.at<cv::Vec3b>(y,x)[0] = 0;
img.at<cv::Vec3b>(y,x)[1] = 0;
img.at<cv::Vec3b>(y,x)[2] = 255;
}
}
ちなみにC++の方では[0, 255]を超える範囲の値を入れると、コンパイル時にオーバーフローのwarningをはいてくれます。
例えば、
for(i=0; i<width/2; i++){
for(j=0; j<height/2; j++){
img.at<cv::Vec3b>(j, i)[0] = 0;
img.at<cv::Vec3b>(j, i)[1] = 400;
img.at<cv::Vec3b>(j, i)[2] = -200;
}
}
として、x=30, y=20の値をとると、
[0, 144, 56]
となる。144 = 400 - 256, 56 = 256 - 200から得られ、画像もあきらかに緑がかっています。
img.atcv::Vec3b(j, i)にはunsigned char型で値が入っているので、RGB値を取るには、こんな風にしなきゃいけない。
unsigned char tmp = img.at<cv::Vec3b>(j,i);
画像を違う変数にコピーしたいときは、clone()メソッドを使います。
cv::Mat img2 = img.clone();
Opencvで2つ並べた画像を作るにはこんな風に作ります。
cv::Mat disp;
cv::Mat tmp[3];
tmp[0] = img;
tmp[1] = cv::Mat (cv::Size(10, height), CV_8UC3, cv::Scalar(0,0,0));
tmp[2] = img2;
cv::hconcat(tmp, 3, disp);
cv::imshow("sample", disp);
cv::waitKey(0);
これでこんな表示になる。
保存する時は、cv::imwrite()メソッドを使います。
cv::imshow("out.jpg", disp);
画像の左半分上のRとBを入れ替えて表示してみましょう。
回答例
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
int main(int argc, const char* argv[]){
cv::Mat img = cv::imread("imori.jpg", cv::IMREAD_COLOR);
int width = img.rows;
int height = img.cols;
cv::Mat out = img.clone();
for(int i=0; i<width/2; i++){
for(int j=0; j<height/2; j++){
unsigned char tmp = out.at<cv::Vec3b>(j, i)[0];
out.at<cv::Vec3b>(j, i)[0] = out.at<cv::Vec3b>(j, i)[2];
out.at<cv::Vec3b>(j, i)[2] = tmp;
}
}
cv::imwrite("out.jpg", out);
cv::imshow("sample", out);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
答え >> https://github.com/yoyoyo-yo/Gasyori100knock/blob/master/Tutorial/answer.cpp
以上でチュートリアルは終了です。
あとはばんばん問題を解いて下さい!!!!