OpenCV FractalDimension - eiichiromomma/CVMLAB GitHub Wiki
OpenCV) Fractal Dimension
(ボックスカウント法 (box counting method)でフラクタル次元(Fractal dimension)を求める
やり方
ボックスカウント法については解説しているページがあちこちにあるので、そちらを参照。 手順は以下の通りとなる。
- ROIの設定(大きさe:2の階乗、1channel、ROIの大きさを1として1画素は1/eの大きさになる)
- ROIを2値化
- "白"の画素数N(1/e)をカウント(log10する)
- ROIを1/2にリサイズ
- 2-4を分割可能な限り繰り返す
- log10(1/e)に対するlog10(N(1/e))の近似直線の傾きがフラクタル次元(負になるが絶対値とする)
2,3をmyFractalDimCore()、4-6をmyFractalDim()で行なう。
かなりおおざっぱだが多分あってる。
myFractalDimCore
double myFractalDimCore(IplImage *src, int eps)
{
long cores;
IplImage *resizedImage = cvCreateImage(cvSize(eps,eps),IPL_DEPTH_8U,1);
IplImage *binImage = cvCreateImage(cvSize(eps,eps),IPL_DEPTH_8U,1);
cvResize(src,resizedImage,CV_INTER_LINEAR);
cvThreshold(resizedImage,binImage,128,255,CV_THRESH_BINARY);
cores=(long)cvSum(binImage).val[0];
cvReleaseImage(&resizedImage);
cvReleaseImage(&binImage);
return log10(cores==0?1.0:(double)cores/255.0);
}
※追記:カウント数が0だと-∞になりコケるので便宜上log10(1.0)を返すようにしてみた。coresはlong型に。
myFractalDim
voidとなっているがB[0]を返せばフラクタル次元を得る関数になる。
近似直線を求めるのは面倒なのでLAPACKの最小二乗法関数dgels_()を用いた。
void myFractalDim(IplImage *src)
{
//マスクとしてROIを使うので事前に設定しておく必要あり
int size=cvGetImageROI(src).height;
int m = (int)(log(size)/log(2));
int n=2; //a,b
int lda= m;
int ldb= m;
int info,nrhs=1;
int ldwork=m+n;
int x;
int i;
double *A = (double *)malloc(sizeof(double)*m*n);
double *B = (double *)malloc(sizeof(double)*m);
double *work = (double *)malloc(sizeof(double)*(m+n));
for(i=0,x=2; x<=size; x*=2,i++){
A[i]=log10(1.0/x);
A[i+m]=1;
B[i]=myFractalDimCore(src,x);
//for debug
printf("%lf,%lf\n",A[i],B[i]);
}
//CLAPACK
dgels_("N",&m,&n,&nrhs,A,&lda,B,&ldb,work,&ldwork,&info);
printf("a,b=%lf,%lf\n",B[0],B[1]);
}