根の長さを測定する

findContours関数で輪郭を検出する

輪郭の周の長さを求め、根量の指標とします。ここで輪郭長を1/2にすれば根の長さの総和を近似できるということが、根の細長いことから考えられます。この長さを推定根長和とします。OpenCVでは輪郭は点の集合として保持されます。findContours関数は2値画像を入力に使い、すべての輪郭、すなわち、すべての白と黒の境界線を検出します。輪郭を構成する点の情報はvectorの入れ子構造になります。初めはわかりにくいと思いますが、こういうものとして覚えてもらっても実質上の問題はありません。輪郭を保持する入れ物は下のように宣言します。これをfindContour関数に渡すと、輪郭を検出してこの中に点の集合として輪郭の情報を入れて戻してくれます。findContour関数はダンゴムシの追跡プログラムでも扱っていますので、ぜひ参考にしてみてください。

vector<vector<Point> > contours;
findContours(bin_img, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

findContours関数のオプション

findContour関数の第三引数は輪郭の検出方法を指定します。上の例のCV_RETR_LISTは白の輪郭、黒の輪郭、内側、外側関係なく、すべての輪郭を取得することを意味します。ダンゴムシの追跡のときの輪郭検出にはCV_RETR_EXTERNALを使いましたがそれと異なることに注意してください。CV_RETR_EXTERNALは一番外側の白の輪郭のみを取得することを意味します。

輪郭の長さの計算

findContour関数はすべての輪郭を取得します。今回はすべての根の長さの和を計算したいので各輪郭についてその周長を計算し和を計算します。輪郭の周はarcLength関数で計算することができます。第二引数には輪郭が閉じているか否かを指定しますが、今回は閉じているので1を指定します。開いている場合には0を指定します。下の例では、contour_lenという変数に輪郭の周の和を保持させています。contour_lenを2で割ることで推定根長和とし、標準ライブラリを使って出力しています。なお、輪郭はvectorを使った構造に保持されているため、任意番目の輪郭にat()を使ってアクセスできます。

#include "opencv/cv.h"
#include "opencv/highgui.h"
#include <iostream> //追加
using namespace cv;
using namespace std; //追加
int main(){
    Mat img = imread("root.jpg", IMREAD_UNCHANGED);
    Mat gray_img;
    cvtColor(img, gray_img, CV_BGR2GRAY);
    Mat bin_img;
    threshold(gray_img, bin_img, 0, 255, THRESH_BINARY|THRESH_OTSU);
    bin_img = ~bin_img;
    //追加ここから
    vector<vector<Point> > contours;
    findContours(bin_img, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    double contour_len=0;
    for(int i = 0; i < contours.size(); ++i) {
        contour_len += arcLength(contours.at(i),1);
    }
    cout<<"estimated root length = "<<contour_len/2<<endl;
    //追加ここまで
    imshow("IMAGE",bin_img);
    waitKey(10000);
    return 0;
}