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;
}