サイトアイコン CV & Technologies

C++版 OpenCVの基本

OpenCVはライブラリの一つです。したがって、C++のソースコード内でOpenCVを使うためには、ヘッダファイルをインクルードして名前空間を指示しなければなりません。基本的にはインクルードするのは2つですが、OpenCVのより多くの機能を使う場合にはインクルードファイルの数が増えることがあります。標準ライブラリでusing namespace std; としたように、OpenCVではプログラムの最初にusing namespace cv; と書く必要があります。

#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;

 

OpenCVで画像を扱う

静止画像と動画で扱い方が変わることはあまりありません。動画は多数の静止画の集まりだからです(パラパラ漫画のイメージ)。動画を扱う場合には、動画ファイルから1枚ずつ静止画を取り出して処理します。
さて、静止画像をプログラムの中で扱うために入れ物が必要です。OpenCVではMatという二次元行列(マス目のようなイメージ)型があり、画像を効率的に扱えます。Matを扱う上で重要なのが、左上端が原点(0,0)となることです。右に行くに従ってx座標が増えていくのは普通に感じると思いますが、下に行くに従ってy座標が増えていくのには違和感を覚えるかもしれません。しかし、これは画像処理ライブラリ全般によく見られる仕様です。宣言は今までの型と同じようにできます。 「Mat img」とすることでimgという名前のMat型変数を宣言できます。

Matに画像を読み込む

imread関数を使います。2つ目の引数にはカラーで読み込むならIMREAD_UNCHANGEDを、グレースケールで読み込むならIMREAD_GRAYSCALEを指定します。IMREAD_GRAYSCALEを指定してカラー画像を読み込んだ場合は自動的にグレースケール化されます。WindowsとMacで画像ファイルへのパスの記述法が異なるので注意が必要です。

Mat img = imread("images¥¥sample.png", IMREAD_UNCHANGED); //Windowsの場合 パス中の¥は重ねて¥¥とする
Mat img = imread("images/sample.png", IMREAD_UNCHANGED); //Macの場合

 

動画を読み込む

VideoCaptureという型を持ったもの(下の例ではcap)を作成してそこに動画のある場所を覚えさせておき、必要な時にそこから画像を1枚ずつ取り出します。

Mat img;
VideoCapture cap("videos¥¥sample.mp4"); //Windowsの場合 パス中の¥は重ねて¥¥とする
VideoCapture cap("videos/sample.mp4"); //Macの場合
cap>>img ; //1フレーム分取り出してimgに保持させる

 

動画の情報の取得と設定
動画の縦横の大きさや長さ(何フレームあるか)を知りたい時にはgetを使います。下の例では縦の大きさ、横の大きさ、フレーム数、フレームレートを取得しています。また、動画を途中から再生することもできます。

int v_w=cap.get(CV_CAP_PROP_FRAME_WIDTH); //縦の大きさ
int v_h=cap.get(CV_CAP_PROP_FRAME_HEIGHT); //横の大きさ
int max_frame=cap.get(CV_CAP_PROP_FRAME_COUNT); //フレーム数
int fps=cap.get(CV_CAP_PROP_FPS); //フレームレート
cap.set(CV_CAP_PROP_POS_FRAMES,100); //100フレーム目から再生

 

画像の表示

imshow関数を使います。1つ目の引数にウィンドウの名前、2つ目の引数に表示したいMatの名前を指定します。下の例では動画を最後まで再生します。なお、表示した後にウィンドウが再描画されるための時間を空けなければなりません。そのためにwaitKey()関数で待つという処理を行います。この関数は1つの整数値の引数をとり、ms単位で待ちます。0を指定した場合には、ずっと待ち続けるという意味になるので注意が必要です。

#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;
int main(){
    Mat img;
    VideoCapture cap("videos¥¥sample.mp4"); //Windowsの場合 パス中の¥は重ねて¥¥とする
    VideoCapture cap("videos/sample.mp4"); //Macの場合
    int max_frame=cap.get(CV_CAP_PROP_FRAME_COUNT); //フレーム数
    for(int i=0; i<max_frame;i++){ cap>>img ; //1フレーム分取り出してimgに保持させる
        imshow("Video",img);
        waitKey(1); // 表示のために1ms待つ
    }
    return 0;
}

 

Matに直線 円 矩形 文字を描画する

Mat::zeros関数を使って作成した500×500ピクセルの黒色のMatに直線などを書き込みましょう。色を指定するにはScalar(255,255,0)というようにします。BGR(青緑赤)の順に0~255で指定するため、この場合は青緑色になります。直線はline関数、円はcircle関数、矩形はrectangle関数で描くことができます。変数の値を含む文字列を描くときには、もう一つステップが必要です。一時的な文字列を保持するchar型の変数を作り、そこに書き込みたい文字列をsprintfで作り、それをputText関数で描画する流れになります。

#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;
int main(){
    Mat img = Mat::zeros(500, 500, CV_8UC3); //500×500ピクセルの黒色のMat
    
    line(img, Point(100, 300), Point(400, 300), Scalar(255,0,0), 10, CV_AA); //(100,300)と(400,300)を結ぶ太さ10の青色直線
    
    rectangle(img, Point(200,200), Point(300, 300), Scalar(0,255,0), 5, 8); //左上が(200,200)で右下が(300,300)の太さ5の緑色矩形
    rectangle(img, Point(200,350), Point(300, 450), Scalar(0,0,255), -1, CV_AA); //左上が(200,350)で右下が(300,450)の赤色塗りつぶし矩形
    
    circle(img, cv::Point(300, 150), 100, Scalar(0,0,255), 3, 4); //中心(300,150)で半径100の太さ3の赤色の円
    
    double value=20.3;
    char value_c[256]; //次の行で使う一時的な変数
    sprintf(value_c, "value=%f", value); //変数の値も含めた表示したい文字列をchar型変数に格納
    putText(img, value_c, Point(20,100), FONT_HERSHEY_SIMPLEX, 2, Scalar(0,0,255), 1, CV_AA); //(20,100)の位置に大きさ2、太さ1の赤色文字で描画
    
    imshow("Sample",img);
    waitKey(10000);
    return 0;
}

 

2値化する前にグレースケール化する

2値化は白黒の画像にすること、グレースケール化は白黒とその間の灰色だけの彩度0の画像にすることを言います。OpenCVの2値化関数は入力にグレースケール画像を受け付けるため、カラー画像を2値化するなら、最初にグレースケール化を行う必要があります。
Point:カラー画像→グレースケール画像→2値画像

グレースケール化する

cvtColor関数でグレースケール化できます。第一引数にカラー画像のMatを、第二引数にグレースケール画像を入れるためのMatを、第三引数にCV_BGR2GRAYを指定します。

Mat input_img = imread("sample.png", IMREAD_UNCHANGED);
Mat gray_img; //グレースケール画像を入れておくためのMat
cvtColor(input_img, gray_img, CV_BGR2GRAY); //グレースケールに変換

 

2値化する

2値化はthreshold関数によって行います。何度も言いますが、この2値化関数は入力にグレースケール画像を必要とします。第一引数にグレースケール画像のMatを、第二引数に2値画像を入れるためのMatを指定します。さらに、どれくらいの明るさ以上で白にするかという指標を閾値として0~255で第三引数に与えます。この閾値は自動で設定するようにもできます。

Mat input_img = imread("sample.png", IMREAD_UNCHANGED);
Mat gray_img; //グレースケール画像を入れておくためのMat
Mat bin_img; //2値画像を入れておくためのMat
cvtColor(input_img, gray_img, CV_BGR2GRAY); //グレースケールに変換
threshold(gray_img,bin_img,160,255,THRESH_BINARY); //閾値160で2値画像に変換
threshold(gray_img, bin_img, 0, 255, THRESH_BINARY | THRESH_OTSU); //閾値を自動で設定

 

画像の書き出し

imwrite関数で画像を保存できます。第一引数に出力する場所へのパスを指定します。拡張子はpng、jpgなどが可能です。Mat型のimgに対して下のようにして画像を書き出せます。

imwrite("img.png", img);

 

動画の書き出し

VideoWriterを使って動画を書き出せます。#include <opencv2/highgui/highgui.hpp>を先頭に記述する必要があります。「<<」を使ってMatを次々に動画のフレームとして継ぎ足していきます。

#include "opencv/cv.h"
#include "opencv/highgui.h"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
int main(){
    Mat img;
    VideoCapture cap("sample.mp4");
    int max_frame=cap.get(CV_CAP_PROP_FRAME_COUNT);
    VideoWriter writer("output.avi", CV_FOURCC_DEFAULT, 30, cv::Size(600, 600), true);
    for(int i=0; i<max_frame;i++){
        cap>>img ;
        writer << img;
        imshow("Video",img);
        waitKey(1);
    }
    return 0;
}

 

モバイルバージョンを終了