#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
#include <tclap/CmdLine.h>
#include <cmath>
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <ietl/interface/ublas.h>
#include <ietl/vectorspace.h>
#include <ietl/lanczos.h>
#include <boost/random.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/limits.hpp>
#include <cmath>
#include <limits>
using namespace std;
using namespace TCLAP;
using namespace cv;
using namespace boost::numeric;
using namespace boost;
using namespace ietl;
typedef double FP_Type;
typedef Vec3d Point_Type;
typedef ublas::compressed_matrix<FP_Type> UBMat;
typedef ublas::vector<FP_Type> UBVector;
inline FP_Type distanceAffinity(FP_Type x1, FP_Type y1, FP_Type x2, FP_Type y2,FP_Type scale)
{
return -((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))/scale;
}
inline FP_Type intensityAffinity(FP_Type i1, FP_Type i2, FP_Type scale)
{
return -(i1-i2)*(i1-i2)/scale;
}
template <typename T,int c>
inline FP_Type vecAffinity(const cv::Vec<T,c>& x,const cv::Vec<T,c>& y,FP_Type scale)
{
return - (x-y).dot(x-y)/scale;
}
Mat_<FP_Type> getGaussianKernel2D(FP_Type sigma1, FP_Type sigma2, FP_Type angle, int size)
{
assert(size%2==1);
Mat_<FP_Type> rot = getRotationMatrix2D(Point2f(size/2+1.0,size/2+1.0),angle,1.0);
Mat_<FP_Type> sigma(3,2);
sigma(0,0)=1.0/sigma1;
sigma(0,1)=0;
sigma(1,0)=0;
sigma(1,1)=1.0/sigma2;
sigma(2,0)=0.0;
sigma(2,1)=0.0;
Mat_<FP_Type> invsigma=rot*sigma;
FP_Type factor = 1.0/(2.0*M_PI*sqrt(sigma1*sigma2));
Mat_<FP_Type> mu(2,1);
mu(0)=size/2+1.0;
mu(1)=size/2+1.0;
Mat_<FP_Type> kernel(size,size);
Mat_<FP_Type> x(2,1);
for(int r=0;r<size;r++)
{
FP_Type * row=(FP_Type*)kernel.ptr(r);
for(int c=0;c<size;c++)
{
x(0)=r;
x(1)=c;
Mat_<FP_Type> tmp=invsigma*(x-mu);
FP_Type m=(x-mu).dot(tmp);
row[c]=factor*exp(-0.5*m);
}
}
return kernel;
}
Mat_<FP_Type> getDoGKernel2D(FP_Type sigma1, FP_Type sigma2, FP_Type angle,int size,FP_Type K)
{
return getGaussianKernel2D(sigma1,sigma2,angle,size)-getGaussianKernel2D(K*sigma1,K*sigma2,angle,size);
}
vector<Ptr<FilterEngine> > createFilterBank(int size)
{
vector<Ptr<FilterEngine> > bank;
//Point filters
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(0.2,0.2,0.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(0.8,0.8,0.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(1.2,1.2,0.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(2.,2.,0.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.,3.,0.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.0,0.4,0.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.0,0.4,30.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.0,0.4,60.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.0,0.4,90.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.0,0.4,120.0,size)));
bank.push_back(createLinearFilter(CV_64FC3,CV_64FC3,getGaussianKernel2D(3.0,0.4,150.0,size)));
return bank;
}
Mat_<Vec<FP_Type,33> > filterImage(Mat_<Point_Type> img, vector<Ptr<FilterEngine> > filterBank)
{
assert(filterBank.size()==11);
assert(img.channels()==3);
Mat_<Vec<FP_Type,33> > filteredAll(img.rows,img.cols);
namedWindow("Filtered",WINDOW_AUTOSIZE);
int f=0;
Mat_<Point_Type> filtered(img.rows,img.cols);
for(vector<Ptr<FilterEngine> >::const_iterator iter=filterBank.begin();
iter!=filterBank.end();
iter++,f++
)
{
Ptr<FilterEngine> filter = *iter;
Mat_<Point_Type> myimg(2,2);
const Mat& myotherimg=myimg;
CV_Assert( img.type() == myimg.type());
filter->apply(img,filtered);
imshow("Filtered",filtered);
for(int r=0;r<img.rows;r++)
{
FP_Type * filteredRow = (FP_Type*)filtered.ptr(r);
for(int c=0;c<img.cols;c++)
{
for(int channel=0;channel<3;channel++)
{
filteredAll(r,c).val[f*3+channel]=filteredRow[c*3 + channel];
}
}
}
}
destroyWindow("Filtered");
return filteredAll;
}
struct AdjListEntry{
public:
int j;
FP_Type a;
};
struct AdjList{
AdjListEntry * entries;
int size;
};
/**
* @param A affinity matrix
* @param img the image
* @param scale1/2/3 the scale factor for the affinity calculation
* @param sparsity_factor number of sample standard deviations to use as a cutoff criterion
*/
void createAffinityMatrix(Mat_<Point_Type> img, FP_Type scale1, FP_Type scale2, FP_Type scale3, UBMat& A, UBMat& N, UBMat& D, FP_Type sparsity_factor=0.01)
{
int size=(size_t)img.rows*img.cols;
Mat_<Vec<FP_Type,33> > filteredImg = filterImage(img,createFilterBank(11));
A.resize(size,size,false);
N.resize(size,size,false);
D.resize(size,size,false);
//Construct an adjacency list
AdjList * adjList=new AdjListEntry[size];
for(int r=0;r<img.rows;r++)
{
for(int c=0;c<img.cols;c++)
{
int adjListSize=(max(0,c+5)-max(img.cols,c+5))*(max(0,r+5)-max(img.rows,r+5));
AdjListEntry * adjListEntry=new AdjListEntry[adjListSize];
adjList[r*img.cols+c].entries=adjListEntry;
adjList[r*img.cols+c].size=adjListSize;
int k=0;
for(int i=max(0,r-5);i<min(img.rows,r+5);i++)
{
for(int j=max(0,c-5);j<min(img.cols,c+5);j++)
{
FP_Type affinity=distanceAffinity(r,c,i,j,scale1);
affinity+=vecAffinity<uchar,3>(img(r,c),img(i,j),scale2);
affinity+=vecAffinity<FP_Type,33>(filteredImg(r,c),filteredImg(i,j),scale3);
adjListEntry[k++].a=exp(affinity);
adjListEntry[k++].j=i*img.cols+j;
}
}
}
}
//Create normalized affinity matrix
double d[size];
for(int i=0;i<size;i++)
{
FP_Type degree=0.0;
for(int j=0;j<adjList[i].size;j++)
{
A(i,adjList[i]->entries[j].j)=adjList[i]->entries[j].a;
degree+=adjList[i]->entries[j].a;
}
d[i]=1.0/sqrt(degree+DBL_EPSILON);
D(i,i)=d[i];
}
//Right multiplication with D^(-1/2)
for(int i=0;i<size;i++)
{
int row=i%img.cols;
for(int j=0;j<adjList[i].size;j++)
{
adjList[i].entries[j].a*=d[adjList->entries[i].j];
}
}
//Left multiplication with D^(-1/2)
for(int i=0;i<size;i++)
{
int row=i%img.cols;
for(int j=0;j<adjList[i].size;j++)
{
N(i,adjList[i]->entries[j].j)=adjList[i].entries[j].a*d[i];
}
}
}
UBVector eigenSolve(UBMat& N)
{
vectorspace<UBVector> vec(N.size1());
lagged_fibonacci607 mygen;
lanczos<UBMat,vectorspace<UBVector> > solver(N,vec);
//First we compute the two lowest eigenvalues, the lowest is guaranteed to be 0
//The second smallest is what we are looking for
int max_iter = N.size1();
FP_Type rel_tol = 50000*numeric_limits<FP_Type>::epsilon();
FP_Type abs_tol = pow(numeric_limits<FP_Type>::epsilon(),20./3);
int n_lowest_eigenval = 2;
vector<FP_Type> eigen;
vector<FP_Type> err;
//std::vector<int> multiplicity;
lanczos_iteration_nlowest<FP_Type> iter(max_iter,n_lowest_eigenval,rel_tol,abs_tol);
solver.calculate_eigenvalues(iter,mygen);
eigen = solver.eigenvalues();
err = solver.errors();
//multiplicity = solver.multiplicities();
assert(eigen.at(0)<eigen.at(1));
//Now we compute the eigenvector belonging to the second largest eigenvalue
vector<UBVector> eigenvectors;
Info<FP_Type> info;
solver.eigenvectors(eigen.begin()+1,eigen.end(),back_inserter(eigenvectors),info,mygen);
return eigenvectors.at(0);
}
FP_Type cut(UBMat& A, UBVector& v, FP_Type threshold)
{
FP_Type cut=0.0;
for(size_t i=0;i<v.size();i++)
{
bool lower=v(i)<threshold;
for(size_t j=0;j<v.size();j++)
{
if(lower && v(j)>=threshold)
cut+=A(i,j);
}
}
return cut;
}
FP_Type assoc(UBMat& A, UBVector& v, FP_Type threshold,bool a)
{
FP_Type cut=0.0;
for(size_t i=0;i<v.size();i++)
{
bool lower;
if(a)
lower=v(i)<threshold;
else
lower=v(i)>=threshold;
if(lower)
{
for(size_t j=0;j<v.size();j++)
{
cut+=A(i,j);
}
}
}
return cut;
}
inline void indexToRowCol(int index, int cols, int& row, int& col)
{
row=index/cols;
col=index/cols;
}
Mat_<uchar> getMask(Mat_<Point_Type> img, UBVector& v, UBMat& A)
{
//find best threshold
FP_Type best_threshold=0.0;
FP_Type lowest_cost=FLT_MAX;
for(size_t i=0;i<v.size();i++)
{
FP_Type threshold=v(i);
FP_Type cutAB = cut(A,v,threshold);
FP_Type assocAV = assoc(A,v,threshold,true);
FP_Type assocBV = assoc(A,v,threshold,false);
FP_Type cost = cutAB/assocAV + cutAB/assocBV;
if(cost<lowest_cost)
{
lowest_cost=cost;
best_threshold=threshold;
}
}
Mat_<uchar> mask(img.rows,img.cols);
//create Mask
for(size_t i=0;i<v.size();i++)
{
int r,c;
indexToRowCol(i,img.cols,r,c);
if(v(i)<best_threshold)
{
mask(r,c)=1;
}
else
{
mask(r,c)=0;
}
}
return mask;
}
tuple<Mat_<Point_Type>,Mat_<Point_Type> > segment(Mat_<uchar> mask, Mat_<Point_Type> img)
{
Mat_<Point_Type> A(img.size().width,img.size().height);
Mat_<Point_Type> B(img.size().width,img.size().height);
for(int i=0;i<mask.size().width;i++)
{
for(int j=0;j<mask.size().height;j++)
{
if(mask(i,j)==0)
{
A(i,j)=Point_Type(0,0,0);
}else
{
A(i,j)=img(i,j);
}
}
}
Mat_<uchar> inv_mask(mask.size().width,mask.size().height);
for(int i=0;i<mask.size().width;i++)
{
for(int j=0;j<mask.size().height;j++)
{
inv_mask(i,j)=1-mask(i,j);
}
}
for(int i=0;i<inv_mask.size().width;i++)
{
for(int j=0;j<inv_mask.size().height;j++)
{
if(inv_mask(i,j)==0)
{
B(i,j)=Point_Type(0,0,0);
}else
{
B(i,j)=img(i,j);
}
}
}
return tuple<Mat_<Point_Type>,Mat_<Point_Type> >(A,B);
}
int main(int argc, char ** argv)
{
CmdLine cmdLine("Normalized cut demo");
ValueArg<string> imgArg("i","image","the image to be segmented",true,"","string");
ValueArg<unsigned int> segArg("n","segments","the number of segments",false,2,"int >= 2");
ValueArg<FP_Type> sigmaArg("s","scale","scale parameter for affinity matrix construction",false,1.0,"decimal");
cmdLine.add(imgArg);
cmdLine.add(segArg);
cmdLine.add(sigmaArg);
cmdLine.parse(argc,argv);
cout<<imgArg.getValue()<<endl;
Mat img = imread(imgArg.getValue().c_str());
//assert(img.depth()==IPL_DEPTH_8U && img.channels()==3);
Mat lab(img.rows,img.cols,img.type());
//convert image to a uniform color space
cvtColor(img,lab,CV_RGB2Lab);
lab.convertTo(lab,CV_64FC3);
const char * hOrig ="Original";
const char * hGrey= "LAB";
namedWindow(hOrig,CV_WINDOW_AUTOSIZE);
namedWindow(hGrey,CV_WINDOW_AUTOSIZE);
imshow(hOrig,img);
imshow(hGrey,lab);
UBMat A;//Affinity matrix
UBMat N;//Normalized affinity matrix
UBMat D;//Actually, its D^(-1/2)
createAffinityMatrix(lab,1.0,1.0,1.0,A,N,D,-30);
UBVector y=prod(D,eigenSolve(N));
Mat_<uchar> mask = getMask(lab,y,A);
tuple<Mat_<Point_Type>,Mat_<Point_Type> > segmented = segment(mask,img);
const char * hSegment1="Segment1";
const char * hSegment2="Segment2";
namedWindow(hSegment1,CV_WINDOW_AUTOSIZE);
namedWindow(hSegment2,CV_WINDOW_AUTOSIZE);
imshow(hSegment1,segmented.get<0>());
imshow(hSegment2,segmented.get<1>());
waitKey(0);
destroyWindow(hOrig);
destroyWindow(hGrey);
destroyWindow(hSegment1);
destroyWindow(hSegment2);
}
BIT 数字图像处理 实验3:Normalized cuts and image segmentation
猜你喜欢
转载自blog.csdn.net/weixin_44936889/article/details/113481818
今日推荐
周排行