輪郭抽出

根の写真をもとに、根の量がどれくらいあるのかを調べる方法として、面積で計算するような場合は根の太さに影響されますが、それに影響されずに長さを調べたいと思うのなら、輪郭線を抽出し、その長さを求めた後に、その長さを1/2倍するという方法があるでしょう。この方法は根が十分に細いことから利用できる計算方法です。面積計算と同様に、はじめにカラー画像をcvtColor関数によりグレースケールに変換し、それをthreshold関数により二値化します。続いてfindcontour関数により輪郭を検出し、その長さを計算し出力します。findcontour関数のオプションのCV_RETR_LISTはすべての輪郭線を検出しますが、検出した輪郭線のデータ保持を階層構造を持たせないで保持することを意味します。 CV_CHAIN_APPROX_NONEはすべての輪郭点を完全に格納することを意味します。すなわち、この手法により格納された任意の隣り合う2点は互いに8近傍に存在します。よって、隣接する輪郭線要素のx、yのどちらかが等しい時には輪郭線要素の長さは1、どちらも異なる場合には√2となります。

root root_contour

ソースコード

このソースコードはGNU GPLライセンスにより保護されています。GNU GPLライセンスの条項に関してはこちらをご覧ください。

//
//  contour length
//
//  Copyright 2015 Yuki Mochizuki
//

#include <iostream>
#include <stdio.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
#include <cmath>

using namespace std;
using namespace cv;


int main()
{
    Mat src_img = imread("/Users/YM/Desktop/root.jpg");

    Mat gray_img;
    cvtColor(src_img, gray_img, CV_BGR2GRAY);
    
    Mat bin_img;
    threshold(gray_img, bin_img, 0, 255, THRESH_BINARY|THRESH_OTSU);
    
    bin_img = ~bin_img;
    imshow("bin", bin_img);
    cvNamedWindow("bin", CV_WINDOW_AUTOSIZE);
    
    vector<vector<Point>> contours;
    findContours(bin_img, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    double contour_len=0;
    drawContours(bin_img,contours,-1,Scalar(255,125,0),1,8);
    for(int i = 0; i < contours.size(); ++i) {
        double x=contours.at(i).at(0).x;
        double y=contours.at(i).at(0).y;
        
        size_t count = contours[i].size();
        for(int ii=1;ii<count;ii++){
            if(contours.at(i).at(ii).x==x || contours.at(i).at(ii).y==y)contour_len+=1;
            else contour_len+=1.41421356;
            x=contours.at(i).at(ii).x;
            y=contours.at(i).at(ii).y;
        }
    }
    
    imshow("bin", bin_img);
    cout<<"total contours length; "<<contour_len<<endl;
    cout<<"estimated root length; "<<contour_len/2<<endl;
    
    cvWaitKey(0);
}