context shape形状上下文中对轮廓点随机采样的实现
http://www.cnblogs.com/xiaotie/ 用C#实现了该算法且有详细的说明,我用opencv实现了一下。
效果图:
// shapeContenx.cpp : 定义控制台应用程序的入口点。
//
# include "stdafx.h"
# include "highgui.h"
# include "cv.h"
# include "cxcore.h"
# include "ml.h"
# include <list >
using namespace std;
# ifdef DEBUG
# pragma comment(lib, "opencv_core231d.lib")
# pragma comment(lib, "opencv_features2d231d.lib")
# pragma comment(lib, "opencv_flann231d.lib")
# pragma comment(lib, "opencv_gpu231d.lib")
# pragma comment(lib, "opencv_highgui231d.lib")
# pragma comment(lib, "opencv_imgproc231d.lib")
# pragma comment(lib, "opencv_ml231d.lib")
# else
# pragma comment(lib, "opencv_core231.lib")
# pragma comment(lib, "opencv_features2d231.lib")
# pragma comment(lib, "opencv_flann231.lib")
# pragma comment(lib, "opencv_gpu231.lib")
# pragma comment(lib, "opencv_highgui231.lib")
# pragma comment(lib, "opencv_imgproc231.lib")
# pragma comment(lib, "opencv_ml231.lib")
# endif
typedef struct _pairDistance
{
int i;
int j;
int distance;
_pairDistance( int ni , int nj , int ndistance) :i(ni),j(nj),distance(ndistance)
{
}
bool operator < ( const _pairDistance &pd) const
{
return distance < pd.distance;
}
}pairDistance;
/*
函数:contoursample
功能:轮廓抽样
参数:seq ------ 轮廓点序列
samplearry --- 用于存放抽样点
samplearry ---- 抽样点数
*/
void contoursample(CvSeq * seq , CvPoint *samplearry, int samplenum)
{
int num = 0 ;
for (CvSeq *s = seq ; s !=NULL;s =s - >h_next)
num +=s - >total;
CvPoint *pointarray = (CvPoint *)malloc(num * sizeof(CvPoint));
int accum = 0 ;
for (CvSeq *s =seq ; s !=NULL;s =s - >h_next)
{
cvCvtSeqToArray( s, pointarray +accum);
accum +=s - >total;
}
if ( num < samplenum)
{
free(pointarray);
return ;
}
// 轮廓点随机打乱
CvRNG rng;
rng = cvRNG(cvGetTickCount());
CvPoint pointtemp;
int tagtemp = - 1;
for ( int i = 0 ; i < num ; ++i)
{
int index = cvRandInt( &rng) %(num -i) +i;
if(index !=i)
{
pointtemp = pointarray[index];
pointarray[index] = pointarray[i];
pointarray[i] = pointtemp;
}
}
// 如果*samplenum > num 即取样点数远远小于轮廓点数随即抽取samplenum个点节省运算时间
if (num > 3 * samplenum)
{
CvPoint *pointarray2 = (CvPoint *)malloc( 3 *samplenum * sizeof(CvPoint));
for ( int i = 0;i < 3 *samplenum; ++i)
{
pointarray2[i] = pointarray[i];
}
free(pointarray);
pointarray = pointarray2;
num = 3 * samplenum;
}
// 计算轮廓点与点间距离
list <pairDistance > list_pair;
for ( int i = 0 ; i < num ; i ++)
{
for ( int j = i + 1 ; j < num ; ++j)
{
list_pair.push_back(pairDistance( i , j ,(pointarray[i].x -pointarray[j].x) * (pointarray[i].x -pointarray[j].x) +
(pointarray[i].y -pointarray[j].y) * (pointarray[i].y -pointarray[j].y)));
}
}
// 排序
list_pair.sort();
// 删除最小距离点对中的其中一个点直到满足samplenum
int nneedremove = num - samplenum;
int *mask = ( int *)malloc( num * sizeof( int));
memset(mask, 0,num * sizeof( int));
//list<pairDistance>::iterator iter = list_pair.begin();
list <pairDistance > : :iterator iter = list_pair.begin();
while (nneedremove > 0)
{
int index0 = ( *iter).i;
int index1 = ( *iter).j;
if (mask[index0] == 0 && mask[index1] == 0)
{
mask[index1] = 1 ;
nneedremove --;
}
iter ++;
}
// 将抽样点存放到samplearry中
int nstartindex = 0 ;
for ( int i = 0 ; i < num ; ++i)
{
if (mask[i] == 0)
{
samplearry[nstartindex] = pointarray[i];
nstartindex ++;
}
}
free(pointarray);
}
int _tmain( int argc, _TCHAR * argv[])
{
//1 . 验证对数极坐标的缩放不变性
//IplImage * im_a1 = cvLoadImage("W1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//IplImage * im_a2 = cvLoadImage("W2.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//cvNot(im_a1,im_a1);
//cvNot(im_a2,im_a2);
//IplImage * im_show1 = cvCreateImage(cvSize(360,360),8,1);
//IplImage * im_show2 = cvCreateImage(cvSize(360,360),8,1);
//cvLogPolar(im_a1,im_show1,cvPoint2D32f(im_a1->width/2,im_a1->height/2),40,CV_INTER_NN+CV_WARP_FILL_OUTLIERS);
//cvLogPolar(im_a2,im_show2,cvPoint2D32f(im_a2->width/2,im_a2->height/2),40,CV_INTER_NN+CV_WARP_FILL_OUTLIERS);
//cvShowImage("a1",im_show1);
//cvShowImage("a2",im_show2);
IplImage * im_src = cvLoadImage( "a.PNG",CV_LOAD_IMAGE_GRAYSCALE);
IplImage * im_show = cvLoadImage( "a.PNG");
IplImage * im_threshold = cvCreateImage(cvGetSize(im_src), 8, 1);
// 1 . 统一尺寸大小
cvThreshold(im_src,im_threshold, 128, 255,CV_THRESH_BINARY_INV);
// 2 . 轮廓提取
CvMemStorage * storage = cvCreateMemStorage();
CvSeq * contour = NULL;
cvFindContours(im_threshold,storage, &contour, sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_NONE );
//for (CvSeq *s = contour ; s!=NULL ;s=s->h_next)
//{
// cvDrawContours(im_show,s,CV_RGB(255,0,0),CV_RGB(255,0,0),0);
//}
//cvShowImage("s",im_show);
// 3 . 轮廓抽样
int num = 100;
CvPoint *samplearray = (CvPoint *)malloc(num * sizeof(CvPoint));
contoursample(contour,samplearray,num);
for ( int i = 0 ; i < num ; ++i)
{
cvDrawCircle(im_show,samplearray[i], 3,CV_RGB( 255, 0, 0));
}
cvShowImage( "samplepoint",im_show);
// 4 . 以抽样点的切线作为X轴正方向建立logr-theta 直方图
// 5 . 计算const 找对应点
free(samplearray);
cvReleaseMemStorage( &storage);
cvWaitKey( - 1);
return 0;
}
//
# include "stdafx.h"
# include "highgui.h"
# include "cv.h"
# include "cxcore.h"
# include "ml.h"
# include <list >
using namespace std;
# ifdef DEBUG
# pragma comment(lib, "opencv_core231d.lib")
# pragma comment(lib, "opencv_features2d231d.lib")
# pragma comment(lib, "opencv_flann231d.lib")
# pragma comment(lib, "opencv_gpu231d.lib")
# pragma comment(lib, "opencv_highgui231d.lib")
# pragma comment(lib, "opencv_imgproc231d.lib")
# pragma comment(lib, "opencv_ml231d.lib")
# else
# pragma comment(lib, "opencv_core231.lib")
# pragma comment(lib, "opencv_features2d231.lib")
# pragma comment(lib, "opencv_flann231.lib")
# pragma comment(lib, "opencv_gpu231.lib")
# pragma comment(lib, "opencv_highgui231.lib")
# pragma comment(lib, "opencv_imgproc231.lib")
# pragma comment(lib, "opencv_ml231.lib")
# endif
typedef struct _pairDistance
{
int i;
int j;
int distance;
_pairDistance( int ni , int nj , int ndistance) :i(ni),j(nj),distance(ndistance)
{
}
bool operator < ( const _pairDistance &pd) const
{
return distance < pd.distance;
}
}pairDistance;
/*
函数:contoursample
功能:轮廓抽样
参数:seq ------ 轮廓点序列
samplearry --- 用于存放抽样点
samplearry ---- 抽样点数
*/
void contoursample(CvSeq * seq , CvPoint *samplearry, int samplenum)
{
int num = 0 ;
for (CvSeq *s = seq ; s !=NULL;s =s - >h_next)
num +=s - >total;
CvPoint *pointarray = (CvPoint *)malloc(num * sizeof(CvPoint));
int accum = 0 ;
for (CvSeq *s =seq ; s !=NULL;s =s - >h_next)
{
cvCvtSeqToArray( s, pointarray +accum);
accum +=s - >total;
}
if ( num < samplenum)
{
free(pointarray);
return ;
}
// 轮廓点随机打乱
CvRNG rng;
rng = cvRNG(cvGetTickCount());
CvPoint pointtemp;
int tagtemp = - 1;
for ( int i = 0 ; i < num ; ++i)
{
int index = cvRandInt( &rng) %(num -i) +i;
if(index !=i)
{
pointtemp = pointarray[index];
pointarray[index] = pointarray[i];
pointarray[i] = pointtemp;
}
}
// 如果*samplenum > num 即取样点数远远小于轮廓点数随即抽取samplenum个点节省运算时间
if (num > 3 * samplenum)
{
CvPoint *pointarray2 = (CvPoint *)malloc( 3 *samplenum * sizeof(CvPoint));
for ( int i = 0;i < 3 *samplenum; ++i)
{
pointarray2[i] = pointarray[i];
}
free(pointarray);
pointarray = pointarray2;
num = 3 * samplenum;
}
// 计算轮廓点与点间距离
list <pairDistance > list_pair;
for ( int i = 0 ; i < num ; i ++)
{
for ( int j = i + 1 ; j < num ; ++j)
{
list_pair.push_back(pairDistance( i , j ,(pointarray[i].x -pointarray[j].x) * (pointarray[i].x -pointarray[j].x) +
(pointarray[i].y -pointarray[j].y) * (pointarray[i].y -pointarray[j].y)));
}
}
// 排序
list_pair.sort();
// 删除最小距离点对中的其中一个点直到满足samplenum
int nneedremove = num - samplenum;
int *mask = ( int *)malloc( num * sizeof( int));
memset(mask, 0,num * sizeof( int));
//list<pairDistance>::iterator iter = list_pair.begin();
list <pairDistance > : :iterator iter = list_pair.begin();
while (nneedremove > 0)
{
int index0 = ( *iter).i;
int index1 = ( *iter).j;
if (mask[index0] == 0 && mask[index1] == 0)
{
mask[index1] = 1 ;
nneedremove --;
}
iter ++;
}
// 将抽样点存放到samplearry中
int nstartindex = 0 ;
for ( int i = 0 ; i < num ; ++i)
{
if (mask[i] == 0)
{
samplearry[nstartindex] = pointarray[i];
nstartindex ++;
}
}
free(pointarray);
}
int _tmain( int argc, _TCHAR * argv[])
{
//1 . 验证对数极坐标的缩放不变性
//IplImage * im_a1 = cvLoadImage("W1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//IplImage * im_a2 = cvLoadImage("W2.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//cvNot(im_a1,im_a1);
//cvNot(im_a2,im_a2);
//IplImage * im_show1 = cvCreateImage(cvSize(360,360),8,1);
//IplImage * im_show2 = cvCreateImage(cvSize(360,360),8,1);
//cvLogPolar(im_a1,im_show1,cvPoint2D32f(im_a1->width/2,im_a1->height/2),40,CV_INTER_NN+CV_WARP_FILL_OUTLIERS);
//cvLogPolar(im_a2,im_show2,cvPoint2D32f(im_a2->width/2,im_a2->height/2),40,CV_INTER_NN+CV_WARP_FILL_OUTLIERS);
//cvShowImage("a1",im_show1);
//cvShowImage("a2",im_show2);
IplImage * im_src = cvLoadImage( "a.PNG",CV_LOAD_IMAGE_GRAYSCALE);
IplImage * im_show = cvLoadImage( "a.PNG");
IplImage * im_threshold = cvCreateImage(cvGetSize(im_src), 8, 1);
// 1 . 统一尺寸大小
cvThreshold(im_src,im_threshold, 128, 255,CV_THRESH_BINARY_INV);
// 2 . 轮廓提取
CvMemStorage * storage = cvCreateMemStorage();
CvSeq * contour = NULL;
cvFindContours(im_threshold,storage, &contour, sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_NONE );
//for (CvSeq *s = contour ; s!=NULL ;s=s->h_next)
//{
// cvDrawContours(im_show,s,CV_RGB(255,0,0),CV_RGB(255,0,0),0);
//}
//cvShowImage("s",im_show);
// 3 . 轮廓抽样
int num = 100;
CvPoint *samplearray = (CvPoint *)malloc(num * sizeof(CvPoint));
contoursample(contour,samplearray,num);
for ( int i = 0 ; i < num ; ++i)
{
cvDrawCircle(im_show,samplearray[i], 3,CV_RGB( 255, 0, 0));
}
cvShowImage( "samplepoint",im_show);
// 4 . 以抽样点的切线作为X轴正方向建立logr-theta 直方图
// 5 . 计算const 找对应点
free(samplearray);
cvReleaseMemStorage( &storage);
cvWaitKey( - 1);
return 0;
}