LabelingクラスをOpenCVで利用
学生時代にも一度お世話になったラベリングクラスhttp://imura-lab.org/products/labeling/を久々に使いました。
OpenCVで使える関数を作ったのでメモ。
2値化が大津の手法なので、琵琶湖の画像にしてみました。
素敵な写真はこちらから使わせていただきました。綺麗ですね。
https://www.itoen.co.jp/itoen-motherlake/photocontest.html
#include <iostream> #include <vector> #include "Labeling.h" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; // 適当な色を出す用 cv::RNG rnd(1192); cv::Scalar randomColor(){ return cv::Scalar(rnd.next() & 0xFF, rnd.next() & 0xFF, rnd.next() & 0xFF); } /** * @brief Label構造体 */ struct LabelData{ int ind;// インデックス cv::Point g;// 重心 vector<cv::Point> points; // 座標 }; /** * @brief 2値画像をラベリングする関数 * @param[in] in_img * @param[out] out_img * @param[out] points * @param[in] min_pix 最小ラベリング画像サイズ */ void Label(const cv::Mat& in_img, cv::Mat& out_img, vector<LabelData>& labels, int min_pix){ // ラベリングの結果を受け取る行列 cv::Mat label(in_img.size(), CV_16SC1); // ラベリングを実施 2値化した画像に対して実行する LabelingBS labeling; labeling.Exec( in_img.data, // 二値化画像 (short *)label.data, // ラベリング結果 in_img.cols, in_img.rows, true, // sortするかどうか min_pix); // TODO: sort == falseにするとmin_pixが有効にならない? // ラベルされた領域をひとつずつ描画 int num_label = labeling.GetNumOfRegions(); for( int i=0; i<num_label; i++){ // ラベリング結果の領域を抽出する cv::Mat labelarea; cv::compare(label, i+1, labelarea, CV_CMP_EQ); // 抽出結果の非ゼロ領域の座標を取得 LabelData l; vector<cv::Point> points; for(int x=0; x<in_img.cols; x++){ for(int y=0; y<in_img.rows; y++){ int ind = x*in_img.rows + y; // 1次元 if( labelarea.data[ind] != 0 ){ cv::Point pnt(x,y); points.push_back(pnt); } }} // 重心座標の取得 RegionInfoBS *ri; ri = labeling.GetResultRegionInfo(i); float x,y; ri->GetCenter(x, y); // ラベル構造体のvectorへ格納 l.g = {(int)x, (int)y}; l.ind = i; l.points = points; labels.push_back(l); // 抽出した領域にランダムな色を設定して出力画像に追加 cv::Mat color(in_img.size(), CV_8UC3, randomColor()); color.copyTo(out_img, labelarea); } } int main(int argc, char* argv[]){ // 元画像の用意 char* filename = argv[1]; cv::Mat src_img = cv::imread(filename, 0); // 二値化 cv::Mat bin_img; cv::threshold(src_img, bin_img, 0, 255, cv::THRESH_BINARY|cv::THRESH_OTSU); // ラベリング cv::Mat labeled_img; vector<LabelData> labels; Label(bin_img, labeled_img, labels, 2); // 結果の表示 cv::imshow("bin_img", bin_img); cv::imshow("labeled_img", labeled_img); cv::waitKey(0); // 結果の保存 cv::imwrite("binary.png", bin_img); cv::imwrite("labeled.png", labeled_img); return 0; }
$ g++ labeling.cpp -o labeling `pkg-config --libs opencv` `pkg-config --cflags opencv` -std=c++11
このラベリングクラスは4連結しか対応していないので、8連結できるものを探し中です。