OpenCVはバージョンが1.0のころに使っていましたが、久しぶりに使おうとするとバージョンが3.0になって、ガラッと様子が変わってしまっていることに気がついた。
- IplImageはどこへいった?
- cvのプリヘッダがなくなった!?
- Matってメモリの割り当てはどうするんだ?
- ピクセルへのアクセスってどうやるの?
などなど、疑問が山のようにでてきました。そんな疑問に答えるべく、OpenCV3の使い方とサンプルをまとめてみたので、どうぞ活用してやって下さい。ちなみに、サンプル写真にはレナ嬢ではなく京都の風景を使用しています(笑)
- 画像を表示する
- グレースケール変換
- 2値化
- リサイズ
- トリミング
- 図形を描画する
- 画像の保存
- 画像の上下左右反転
- ぼかしフィルタ
- ガウシアンフィルタ
- Sobelフィルタ
- Cannyフィルタ
- 透視変換
- ヒストグラムの平滑化
- 参考図書
画像を表示する
OpenCV3を使って、画像を表示するだけのプログラムです。
void main() { Mat img = imread("img.png"); imshow("image",img); waitKey(0); }
OpenCV3からは画像を格納する型としてIplImageではなくMatを使います。画像の読み込みにはimread関数を使います。引数は次のようになります。
■imread(filename, flag)
引数 | 意味 |
---|---|
filename | 読み込みファイル名 |
flag | >0: 3チャンネルカラー =0: グレースケール <0 読み込み画像に従う |
画像の表示はimshow関数で、第1引数にウインドウ名、第2引数に表示したいMatを指定します。
■imshow(name, img)
引数 | 意味 |
---|---|
name | ウインドウの名前 |
img | 表示する画像 |
グレースケール変換
画像をグレースケールに変換するプログラムです。
void main() { Mat img = imread("img.png"); Mat dst; cvtColor(img, dst, COLOR_RGB2GRAY); imshow("image",dst); waitKey(0); }
グレースケール変換にはcvtColor関数を使います。第3引数に指定するコードで変換前と変換後の画像フォーマットを指定します。ここではRGBからグレースケールに変換するため、COLOR_RGB2GRAYを指定しています。第3引数を変更することでHSVなどのフォーマットに変換することも出来ます。
■cvtColor(src, dat, code)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
code | RGB→GRAY COLOR_RGB2GRAY RGB→HSV COLOR_RGB2HSV ・・・など |
ここで、出力画像のメモリ割り当てを行っていないことに注目して下さい。IplImageとは異なり、Matでは自動的にメモリの割り当て&開放を行ってくれるようになっています。
2値化
画像を白黒の2値に変換するプログラムです。
void main() { Mat img = imread("img.png"); Mat gray, dst; cvtColor(img, gray, COLOR_RGB2GRAY); threshold(gray, dst, 80, 200, 0); imshow("image",dst); waitKey(0); }
画像を2値化するには、まずグレースケールに変換し、その画像に対してしきい値以上なら該当するピクセルを白、しきい値以下なら黒にする処理を行います。この処理はthreshold関数で行っています。
■threshold(src, dat, thresh, max, type)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
thresh | 閾値 |
max | 明度の最大値 |
type | THRESH_BINARY THRESH_BINARY_INV ・・・など |
リサイズ
画像のサイズを変更するプログラムです。
void main() { Mat img = imread("img.png"); Mat dst; resize(img, dst, Size(150, 100)); imshow("image",dst); waitKey(0); }
画像のサイズを変更するにはresize関数の第3引数に、出力画像のサイズを指定します。あとはこの関数がメモリ割り当てなども自動的に行なってくれます。
■resize(src, dat, size)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
size | 出力画像のサイズ |
トリミング
画像の一部をトリミングするためのプログラムです。
void main() { Mat img = imread("img.jpg"); Mat dst(img, Rect(50, 100, 200, 200));; imshow("result", dst); waitKey(0); }
Matクラスのコンストラクタに元画像の変数と、トリミングする長方形をRect型で指定します。
図形を描画する
円や長方形、直線などを描画するプログラムです。
void main() { Mat img(512,512, CV_8UC3, Scalar(100, 100, 100)); circle(img, Point(256, 256), 100, Scalar(200, 100, 100), 5); line(img, Point(0, 0), Point(512, 512), Scalar(0, 200, 0), 3, 4); rectangle(img, Point(100, 100), Point(300, 200), Scalar(0, 0, 200), 2, 4); imshow("image",img); waitKey(0); }
図形を描画するためのキャンバスを最初に作ります。ここでは大きさを指定してMat型の変数を作成しています。
円を描くにはcircle関数、長方形はrectangle関数、線はline関数を使います。それぞれの関数の引数は次のようになります。図形を塗りつぶすにはticknessの値をマイナスにします。
■circle(img, center, radius, coor, tickness)
引数 | 意味 |
---|---|
img | 描画する画像 |
center | 円の中心座標 |
radius | 円の半径 |
color | 円の色 |
tickness | >=0: 線の太さ <0: 塗りつぶし |
■rectangle(img, pt1, pt2, coor, tickness)
引数 | 意味 |
---|---|
img | 描画する画像 |
pt1 | 左上座標 |
pt2 | 右下座標 |
color | 円の色 |
tickness | >=0: 線の太さ <0: 塗りつぶし |
■line(img, pt1, pt2, coor, tickness)
引数 | 意味 |
---|---|
img | 描画する画像 |
pt1 | 開始座標 |
pt2 | 終点座標 |
color | 円の色 |
tickness | >=0: 線の太さ <0: 塗りつぶし |
画像の保存
画像を保存するプログラムです。
void main() { Mat img = imread("img.png"); imwrite("img.jpg", img); }
画像を保存するにはimwriteを使用します。第1引数には保存ファイル名を指定します。拡張子によって自動的に保存形式が選択されます。
■imwrite(filename, img)
引数 | 意味 |
---|---|
filename | 保存するファイル名 |
img | 保存する画像 |
画像の上下左右反転
画像を上下反転・左右反転(フリップ)するプログラムです。
void main() { Mat img = imread("img.png"); Mat dst; flip(img, dst,0); imshow("image",dst); waitKey(0); }
画像を反転するにはflip関数を使います。filp関数の第3引数に反転方向を指定します。反転方向の指定は次のようになります。
■flip(src, dat, code)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
code | 反転方向の指定 > 0: 左右の反転 = 0 上下の反転 < 0 左右上下の反転 |
ぼかしフィルタ
ボックスフィルタを使って画像をぼかすプログラムです。
void main() { Mat img = imread("img.png"); Mat dst; blur(img, dst, Size(7,7)); imshow("image",dst); waitKey(0); }
ボックスフィルタを使って画像をぼかすにはblur関数を使います。ボックスフィルタは周辺のピクセルの平均値を現在のピクセルの値にします。どの範囲の平均値をとるかは、第3引数にぼかしフィルタのカーネルサイズで指定します。
■blur(src, dat, ksize)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
ksize | ボックスフィルタのカーネルサイズを指定します |
ガウシアンフィルタ
ガウシアンフィルタを使って画像をぼかすプログラムです。
void main() { Mat img = imread("img.png"); Mat dst; GaussianBlur(img, dst, Size(7,7), 10, 10); imshow("image",dst); waitKey(0); }
ガウシアンフィルタを使って画像をぼかすにはgaussianBlur関数を使います。ボックスフィルタに比べて綺麗にぼけ、またぼけの量を微調整できるのが特徴です。調整項目は次のようになります。
■gaussianBlur(src, dat, ksize, sigma)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
ksize | ガウシアンフィルタのカーネルサイズを指定します |
sigma | ガウシアンフィルタのシグマ値を指定します |
Sobelフィルタ
Sobelフィルタを使って画像から輪郭線を抽出するプログラムです。
void main() { Mat dst, gray; Mat img = imread("img.jpg"); cvtColor(img, gray, COLOR_RGB2GRAY); Sobel(gray, dst, -1, 1, 0); imshow("image",dst); waitKey(0); }
Sobelフィルタを使うことで画像中からエッジを検出することが出来ます。第4引数と第5引数に横方向と縦方向の微分係数を指定します。上のサンプルでは(1, 0)を指定しているので、縦方向のエッジが検出できます。逆に(0, 1)を指定すると横方向のエッジを検出できます。
全てのエッジを検出するには、縦と横の両方向に処理が必要になります。Sobelフィルタの計算は一次微分なので、ノイズの影響を受けにくく比較的処理速度も速いです。
■sobel(src, dat, depth, dx, dy)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
depth | 出力画像のビット深度 |
dx | 横方向の微分係数 |
dy | 縦方向の微分係数 |
Cannyフィルタ
Cannyフィルタを使って画像から輪郭線を抽出するプログラムです。
void main() { Mat img = imread("img.jpg"); Mat dst, gray; cvtColor(img, gray, COLOR_RGB2GRAY); Canny(gray, dst, 40, 150); imshow("image",dst); waitKey(0); }
CannyフィルタはSobelフィルタやLaplacianフィルタと比べて非常に綺麗にエッジを検出することが出来ますが・・・それに比例して処理負荷と処理時間も大きくなります。とにかく綺麗にエッジを抽出したいときはCannyフィルタを使うと良いでしょう。
■ Canny(src, dat, thresold1, thresold2)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
thresold1 | 閾値1 |
thresold2 | 閾値2 |
透視変換
画像を透視変換によって変形するプログラムです。
void main() { Mat img = imread("img.png"); Mat dst; Point2f srcPoint[] = { Point(0, 0), Point(0, img.cols), Point(img.rows, img.cols), Point(img.rows, 0), }; Point2f dstPoint[] = { Point(100, 100), Point(0, 300), Point(400, 450), Point(500, 50), }; Mat H = getPerspectiveTransform(srcPoint, dstPoint); warpPerspective( img, dst, H, Size(512, 512)); imshow("image", dst); waitKey(0); }
OpenCVで透視変換を行うためには、まず変換前の4点と変換後の4点の座標を指定します。これらの座標をgetPerspectiveTransform関数に渡すことで、透視変換行列が得られます。この透視変換行列をwarpPerspectiveに渡すことで、画像を変形することができます。
透視変換をよく使う場面としては、QRコードの解析などX軸やY軸に沿って処理を進めたいときに使います。オリジナル画像で処理をすすめると、数学的に大変になるので、一度透視変換で正方形に変形してから、処理をすることでプログラムが簡単になります。
■ getPerspectiveTransform(src, dat)
引数 | 意味 |
---|---|
src | 入力座標の配列 |
dst | 出力座標の配列 |
戻り値 | 透視変換行列 |
■ warpPerspective(src, dat, M, size)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |
M | 透視変換行列 |
size | 出力画像のサイズ |
ヒストグラムの平滑化
グレースケール画像のヒストグラムを均一化するプログラムです。
void main Mat img = imread("img.png"); Mat gray, dst; cvtColor(img, gray, COLOR_RGB2GRAY); equalizeHist(gray, dst); imshow("image",dst); waitKey(0); }
ヒストグラムを均一化することで、とコントラストを向上させたり、画像の全体的な明るさのバランスを改善することが出来ます。変換前のヒストグラム(左)と変換後のヒストグラム(右)は次のようになります。
均一化したことで、ヒストグラムが左右に広がって平らになったことがわかると思います。OpneCV3でヒストグラムの均一化を行うためにはequalizeHist関数を使います。
■ equalizeHist(src, dat)
引数 | 意味 |
---|---|
src | 入力画像 |
dst | 出力画像 |