矩形聚类参考文献
以下为上面参考文献的完整代码
使用ubuntu16.04 opencv3.4.1 Qt5.9.0
#include "cv.h"
#include"highgui.hpp"
#include"imgproc.hpp"
#include"opencv.hpp"
#define MIN_SQUARE_AREA 100
#define MIN_CENTER_DIS 10
using namespace cv;
using namespace std;
double otsuThreshold(IplImage* img);
void FindSquares( IplImage* src, CvSeq* squares, CvMemStorage* storage, vector<Point> &squares_centers, vector< vector<Point> > &squares_v, Point pt );
void drawSquares( IplImage* img_, CvSeq* squares ,const char* wndname);
void CenterClassification( vector<Point> &squares_centers, vector< vector<int> > &result);
double ComputeDistance (CvPoint pointO,CvPoint pointA );
const char* wndname = "Square Detection Demo";
CvSeq* squares_ = 0;
CvMemStorage* storage_ = NULL;
vector<Point> squares_centers_;
vector< vector<Point> > squares_v_;
Point pt_;
int main(int argc, char *argv[])
{
CvCapture* capture = 0;
capture = cvCaptureFromCAM(0);
// while (1)
// {
// IplImage* frame = 0;
// frame = cvQueryFrame( capture );
IplImage* frame = cvLoadImage("/home/lv/1.png");
IplImage* image = 0;
image = cvCreateImage( cvGetSize(frame), 8, 1 );
cvCvtColor(frame,image,CV_BGR2GRAY);
IplImage* image_threshold;
image_threshold = cvCreateImage( cvGetSize(frame), 8, 1 );
double threshold_ = otsuThreshold(image);
cvThreshold(image,image_threshold,threshold_,255,CV_THRESH_BINARY);
cvShowImage("阈值化图像",image_threshold);
if( storage_ == NULL)
{
storage_ = cvCreateMemStorage(0);
} else {
cvClearMemStorage(storage_);
}
CvSeq* squares_ = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage_ );
FindSquares(image_threshold,squares_,storage_,squares_centers_,squares_v_,pt_);
drawSquares(frame, squares_, wndname);
vector< vector<int> > result_;
result_.clear();
CenterClassification(squares_centers_,result_);
cvWaitKey(0);
// char c=waitKey(30); //延时30毫秒
// if (c == 27) //按ESC键退出
// break;
// }
}
double otsuThreshold(IplImage* img)
{
double T = 0;
int height = img->height;
int width = img->width;
int step = img->widthStep;
uchar* data = (uchar*)img->imageData;
double gSum0;
double gSum1;
double N0 = 0;
double N1 = 0;
double u0 = 0;
double u1 = 0;
double w0 = 0;
double w1 = 0;
double tempg = -1;
double g = -1;
double Histogram[256]={0};// = new double[256];
double N = width*height;
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
double temp =data[i*step + j * 3] * 0.114 + data[i*step + j * 3+1] * 0.587 + data[i*step + j * 3+2] * 0.299;
temp = temp<0? 0:temp;
temp = temp>255? 255:temp;
Histogram[(int)temp]++;
}
}
for (int i = 0;i<256;i++)
{
gSum0 = 0;
gSum1 = 0;
N0 += Histogram[i];
N1 = N-N0;
if(0==N1)break;
w0 = N0/N;
w1 = 1-w0;
for (int j = 0;j<=i;j++)
{
gSum0 += j*Histogram[j];
}
u0 = gSum0/N0;
for(int k = i+1;k<256;k++)
{
gSum1 += k*Histogram[k];
}
u1 = gSum1/N1;
//u = w0*u0 + w1*u1;
g = w0*w1*(u0-u1)*(u0-u1);
if (tempg<g)
{
tempg = g;
T = i;
}
}
return T;
}
//找四边形
void FindSquares( IplImage* src, CvSeq* squares, CvMemStorage* storage, vector<Point> &squares_centers, vector< vector<Point> > &squares_v, Point pt )
{
CvSeq* cv_contours; // 边缘
CvSeq* result; // the result of detecting squares
CvSeqReader reader; // the pointer to read data of "result"
CvPoint corner[4];
vector<Point> corner_v;
Point temp;
Point center;
cvFindContours( src, storage, &cv_contours, sizeof(CvContour),CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, pt ); //find contours
while(cv_contours)
{
if( fabs(cvContourArea(cv_contours)) > MIN_SQUARE_AREA ) //neglect the small contours
{
//findout the squares
result = cvApproxPoly( cv_contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(cv_contours)*0.02, 0 );
if( result->total == 4 && cvCheckContourConvexity(result))
{
cvStartReadSeq( result, &reader, 0 );
for( int i = 0; i < 4; i++ )
{
cvSeqPush( squares,(CvPoint*)cvGetSeqElem( result, i ));
memcpy( corner + i, reader.ptr, result->elem_size );
CV_NEXT_SEQ_ELEM( result->elem_size, reader );
}
for(int i =0; i < 4; i++) //save the corner points to corner_v, it will help us process the data
{
temp = corner[i];
corner_v.push_back(temp);
}
center.x = (corner[0].x + corner[1].x + corner[2].x + corner[3].x) / 4;
center.y = (corner[0].y + corner[1].y + corner[2].y + corner[3].y) / 4;
squares_centers.push_back(center);
squares_v.push_back(corner_v);
corner_v.clear();
}
}
cv_contours = cv_contours->h_next;
}
//auto iter = squares_centers.begin();
for(int i = 0;i<squares_centers.size();i++)
{
cout <<i<<":"<< squares_centers[i]<< endl;
}
cout<<endl;
}
//画出找到的矩形
void drawSquares( IplImage* img_, CvSeq* squares ,const char* wndname)
{
CvSeqReader reader;
IplImage* cpy = cvCloneImage( img_ );
CvPoint pt[4];
int i;
cvStartReadSeq( squares, &reader, 0 );
for( i = 0; i < squares->total; i += 4 )
{
CvPoint* rect = pt;
int count = 4;
memcpy( pt, reader.ptr, squares->elem_size );
CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
memcpy( pt + 1, reader.ptr, squares->elem_size );
CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
memcpy( pt + 2, reader.ptr, squares->elem_size );
CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
memcpy( pt + 3, reader.ptr, squares->elem_size );
CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );
//cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 1, CV_AA, 0 );//彩色绘制
}
cvShowImage( wndname, cpy );
cvReleaseImage( &cpy );
}
void CenterClassification( vector<Point> &squares_centers, vector< vector<int> > &result)
{
vector<int> centers_index;
vector<int> result_temp;
int index_i;
int index_j;
for(int i = 0; i < squares_centers.size(); i++)
{
centers_index.push_back(i); //save the index of squares centers
}
for(int i = 0; i < centers_index.size(); i++)
{
result_temp.push_back(centers_index[i]);
for(int j = i + 1; j < centers_index.size(); j++)
{
index_i = centers_index[i];
index_j = centers_index[j];
if( ComputeDistance( squares_centers[index_i], squares_centers[index_j] ) < MIN_CENTER_DIS )
{
result_temp.push_back(centers_index[j]);
centers_index.erase(centers_index.begin() + j );
j--;
}
}
result.push_back(result_temp);
auto iter = result_temp.begin();cout<<"聚类:[";
for(;iter != result_temp.end(); ++iter)
{
cout<<*iter<<" ";
}
cout<<"]";
cout<<endl;
result_temp.clear();
}
auto it = result.begin();
int x = (*it).size();int xx =0;int count=1;//x为聚类的矩形形心个数
for (it=result.begin()+1;it!=result.end();++it)
{
if (x < (*it).size())
{x = (*it).size();xx= count;}
count++;
}
//xx为最大矩形聚类size所在位置
if (x == 5){
double zd_x =0 ,zd_y = 0;
for(int lw = 0;lw<x;lw++)
{
zd_x = zd_x+squares_centers[result[xx][lw]].x;
zd_y = zd_y+squares_centers[result[xx][lw]].y;
}
//输出聚类的矩形平均形心位置
cout<<"location:["<<zd_x/x<<","<<zd_y/x<<"]"<<endl;
}
squares_centers.clear();
}
double ComputeDistance (CvPoint pointO,CvPoint pointA )
{
double distance;
distance = powf((pointO.x - pointA.x),2) + powf((pointO.y - pointA.y),2);
distance = sqrtf(distance);
return distance;
}
效果如下:
1.png
2020.7.29 in nwpu