根の長さを測定する

  1. 根の長さを測定する
  2. 輪郭線検出に向けた下準備として2値化する
  3. findContours関数で輪郭を検出する
  4. 収縮処理

収縮処理

根長測定も最終回です。ダンゴムシの追跡で膨張処理を施しましたが、それとは反対の処理です。用意した根の写真では主根と側根の間に大きな太さの差があるため、白い部分を収縮させることで側根を消すことができます。下の画像はerodeによる収縮処理後の画像です。その細い根を消した2値画像、すなわち、主根のみの2値画像で同様に根長を求めれば主根の長さが求まります。収縮処理はerode関数により実装されています。下のコードでは側根も含めた合計の長さから主根の長さを引くことで側根の長さも求めています。一つ注意が必要なのはfindContour関数が入力画像を変更してしまうことです。今回は2回の輪郭検出を行う必要があるため、コピーを作成しています。コピーには.clone()を使います。 最終的に、以下のような出力が得られました。主根が510、側根が8184であることがわかります。なお、長さの単位はpixelです。

estimated root length (total) = 8694.72
estimated root length (main) = 510.685
estimated root length (lateral) = 8184.04

main_root

#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;
    Mat bin_img_copy=bin_img.clone(); //追加
    Mat element = Mat::ones(9,9,CV_8UC1); //追加
    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),0);
    }
    cout<<"estimated root length (total) = "<<contour_len/2<<endl;
    //追加ここから
    erode(bin_img_copy, bin_img_copy, element, Point(-1,-1), 1);
    imshow("IMAGE_main_root",bin_img_copy);
    vector<vector<Point> > contours_main;
    findContours(bin_img_copy, contours_main, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    double contour_len_main=0;
    for(int i = 0; i < contours_main.size(); ++i) {
        contour_len_main += arcLength(contours_main.at(i),0);
    }
    cout<<"estimated root length (main) = "<<contour_len_main/2<<endl;
    cout<<"estimated root length (lateral) = "<<(contour_len-contour_len_main)/2<<endl;
    //追加ここまで
    waitKey(10000);
    return 0;
}
1 2 3 4