OpenCV Labeling - eiichiromomma/CVMLAB GitHub Wiki
(OpenCV) Labeling
floodFill関数を用いてラベリング処理
任意の色で塗り潰しが可能なfloodFill関数を使ったラベリング処理
- 0 or 255の8bit画像を32bit画像へ変換し,255を0.5にする
- 画像をスキャンして0.5だったら1から始まるラベル番号++で塗る
- ヒストグラムを取得
- 背景のカウントを0
- std::sortまたはqsortを使ってサイズ順に並べ替え
- おしまい
- OpenCVで完結
- 8近傍, 4近傍が選択可能
- 256個以上のBlobでも処理が可能
- それなりに速い
- 凸包や重心などの計算が未実装(OpenCVのの関数を使えば可能)
- 多分無駄が多い
/*
* floodFill_Labeling.cpp
*
* Created on: 2011/02/01
* Author: Eiichiro Momma
*/
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace cv;
enum{
nNeighbors = 8, // 4 or 8 近傍
isVisible = 1, // 処理の過程,結果を表示
vDelay = 10 // isVisibleでの遅延時間[ms]
};
//並び替え用
struct histo_dat{
int idx;
float val;
};
bool operator<(const histo_dat& left, const histo_dat& right)
{
return left.val < right.val;
}
bool operator>(const histo_dat& left, const histo_dat& right)
{
return left.val > right.val;
}
int main(void)
{
Mat fsrc;
//0 or 255の2値画像
Mat src = imread("test3.png)", CV_LOAD_IMAGE_GRAYSCALE);
if (src.empty())
{
return 1;
}
//255個以上のBlobへ対応するためCV_32Fへ
src.convertTo(fsrc, CV_32FC1, 1, 0);
// 0~255 -> 0~0.5
threshold(fsrc, fsrc, 128, 0.5, CV_THRESH_BINARY);
int nL=1;
if(isVisible)
{
namedWindow("src",CV_WINDOW_AUTOSIZE);
imshow("src",fsrc);
waitKey(0);
}
for (int y=0; y<fsrc.rows; y++)
{
for (int x=0; x<fsrc.cols; x++)
{
//floodFillでラベル=濃度の塗り潰し
if (fsrc.at<float>(y,x) > 0.25 && fsrc.at<float>(y,x)< 0.75)
{
floodFill(fsrc, Point(x,y), Scalar(nL), NULL, Scalar(0.25), Scalar(0.25), nNeighbors);
if (isVisible)
{
imshow("src",fsrc);
waitKey(vDelay);
}
nL++;
}
}
}
//BlobのサイズをcalcHistで求める
Mat histo;
float range[]={0,nL};
const float* ranges[]={range};
calcHist(&fsrc, 1, 0, Mat(), histo, 1,&nL ,ranges, true, false);
//std::sortで並び替え
std::vector<histo_dat> vhd;
histo_dat hd;
for (int i=0; i<nL; i++)
{
hd.idx = i;
hd.val = histo.at<float>(i);
vhd.push_back(hd);
}
//ignore background
vhd[0].val = 0.0;
std::sort(vhd.begin(), vhd.end(), std::greater<histo_dat>());
for (int i=0; i<nL; i++)
{
std::cout << vhd[i].idx << ": " << vhd[i].val << " pixel\n";
}
double maxVal;
Point mP;
minMaxLoc(histo, 0, &maxVal, 0, &mP, Mat());
std::cout << "max idx is " << mP.y << ":" << maxVal << std::endl;
if (isVisible)
{
fsrc.convertTo(fsrc, CV_32FC1, 1.0/nL , 0);
imshow("src",fsrc);
waitKey(0);
}
return 0;
}
/*
* CfloodFill_Labeling.cpp
*
* Created on: 2011/02/11
* Author: Eiichiro Momma
*/
#include <opencv2/core/core_c.h>
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/highgui/highgui_c.h>
#include <stdio.h>
#include <stdlib.h>
//compat.hppから拝借
#define cvGetHistValue_1D( hist, idx0 ) \
((float*)cvPtr1D( (hist)->bins, (idx0), 0))
enum{
nNeighbors = 8,
isVisible = 1,
vDelay = 10
};
//並び替え用
typedef struct {
int idx;
float val;
}histo_dat;
int comp(const void *d1, const void *d2)
{
histo_dat left = *(histo_dat *)d1;
histo_dat right = *(histo_dat *)d2;
return right.val - left.val;
}
int main(void)
{
IplImage *fsrc;
//0 or 255の2値画像
IplImage *src = cvLoadImage("test3.png)", CV_LOAD_IMAGE_GRAYSCALE);
if (src==NULL)
{
return 1;
}
//255個以上のBlobへ対応するためCV_32Fへ
fsrc = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);
cvConvertScale(src, fsrc, 1, 0);
// 0~255 -> 0~0.5
cvThreshold(fsrc, fsrc, 128, 0.5, CV_THRESH_BINARY);
int nL=1;
if(isVisible)
{
cvNamedWindow("src",CV_WINDOW_AUTOSIZE);
cvShowImage("src",fsrc);
cvWaitKey(0);
}
for (int y=0; y< fsrc->height; y++)
{
for (int x=0; x<fsrc->width; x++)
{
//floodFillでラベル=濃度の塗り潰し
if (cvGetReal2D(fsrc, y, x) > 0.25 && cvGetReal2D(fsrc, y, x) < 0.75)
{
cvFloodFill(fsrc, cvPoint(x,y), cvScalar(nL), cvScalar(0.25), cvScalar(0.25), NULL, nNeighbors);
if (isVisible)
{
cvShowImage("src",fsrc);
cvWaitKey(vDelay);
}
nL++;
}
}
}
//BlobのサイズをcalcHistで求める
int size[] = {nL};
float range[]={0,nL};
float* ranges[]={range};
IplImage *imgs[]={fsrc};
CvHistogram *h = cvCreateHist(1, size, CV_HIST_ARRAY, ranges, 1);
cvCalcHist(imgs, h);
float *fval;
histo_dat hd;
histo_dat *vhd = (histo_dat*)malloc(sizeof(hd)*nL);
for (int i=0; i<nL; i++)
{
hd.idx = i;
fval=cvGetHistValue_1D(h,i);
hd.val = *fval;
vhd[i] = hd;
}
//ignore background
vhd[0].val = 0.0;
cvSetReal1D(h->bins, 0, 0.0);
qsort(vhd, nL, sizeof(hd), comp);
for (int i=0; i<nL; i++)
{
printf("%d: %f\n", vhd[i].idx, vhd[i].val);
}
float maxVal;
int mI;
cvGetMinMaxHistValue(h, NULL, &maxVal, NULL, &mI);
printf("max: %d, %f\n", mI, maxVal);
if (isVisible)
{
cvConvertScale(fsrc, fsrc, 1.0/nL, 0);
cvShowImage("src",fsrc);
cvWaitKey(0);
}
free(vhd);
return 0;
}