谁能推荐一个轻量级的c++ mean shift集群实现?我已经在使用OpenCV,但是他们的mean shift实现是用于跟踪,而不是集群。我见过EDISON,但是,这是用于图像分割而不是聚类。
我可以自己实现它,但是我宁愿不投入时间,也不愿冒bug的风险。
谢谢
这是旧的,但我现在正在与mean shift工作,所以我认为最好回答。
我想我理解你在这里所做的区别,但是当你说你正在寻找模式检测时,从算法的角度来看,这在技术意义上是模糊的,因为算法本质上是用于搜索"模式",这是局部最小值或最大值,取决于你如何构建优化问题(梯度下降或上升)。
这个在EDISON网站上找到的源码,声称是mean shift聚类算法的c++实现,但正如上面所讨论的,聚类是模式搜索行为的主要实现,而其他所有mean shift的使用都是基于这种行为,尤其是分割,所以你当然可以使用EDISON源码来找到一个聚类实现,即使你必须搜索它一点。
我也发现了这个Github项目,因为它是值得的,但我以前没有使用过它。
最后注意:我还注意到你说的"轻量级"实现。注意,均值移位不是一个非常有效的算法(我认为它是O(N^3),但我会检查一下)。也就是说,它仍然可以有效地实施,尽管如何衡量这一点更加模糊。毋庸置疑,Quick Shift, UCLA研究人员试图解决更有效的medioid Shift问题,一个类似的非参数模式搜索算法,可能更像你在"轻量级"算法中寻找的东西。
这是我的c++版本的mean shift对象跟踪方法。要成功运行代码,需要将tf.h头文件添加到主代码目录中。
#include "tf.h" // include the header file
using namespace cv;
using namespace std;
#include <stdio.h>
makerect mkr; // rectangle for encompassing target
// rcs for row coordination of target window center
//ccs for column coordination of target window center
double rcs=0,ccs=0;
// w for width of target window
// l for length of target window
double W=70,L=60;
const int mySizes[3]={16,16,16}; // vector for number of histogram bins
cv::Mat q4hsv = Mat::zeros(3,mySizes,CV_64F); // initializing histogram variable
uchar nbins=16; // var for num of histogram bins
int main(void){
printf("enter 14 or 36: t"); // enter number of input video name
uint flag; // var for video flag or number
cin>>flag;
Mat ref4frame; // reference frame which is used for initializing mean shift parameters
char filename [50];
sprintf(filename,"im%d.avi",flag);
VideoCapture capture(filename);
if( !capture.isOpened() )
throw "Error when reading steam_avi";
unsigned long int f4counter=0; // frame counter var
histhsv hsv; // instantiating histhsv class
for (f4counter=1;f4counter<=40000000;f4counter++){ // a big number to support many frames
capture >> ref4frame; //reading input image from specified directory
if( !(ref4frame.data )) // checking the read status
{
printf("Cannot load file image %sn", filename);
break; }
uchar ndiv = uchar(256/nbins); // division value to which intesity values are divided
if (f4counter==1) { // special for 1st frame
char modelname[20];
if(flag==36){
sprintf(modelname,"data%d.png",flag);
}
else if (flag==14){
sprintf(modelname,"data%d.jpg",flag);
}
// imread is defined in tf.h
Mat img = imread(modelname,1);//reads 1st image
if( !(img.data ))//check if file loading is ok
{
printf("Cannot load file image %sn", modelname);
break; }
hsv.img=img;//assign new image to hsv object (calculates hsv or rgb hist)
hsv.run();//run the histogram calculator
// assign temporary hsv object to reference hist q4hsv object
for (int i=0;i<16;i++){
for(int j=0;j<16;j++){
for(int k=0;k<16;k++){
q4hsv.at<double>(i,j,k)=hsv.q[i][j][k];
}
}
}
}
if(f4counter<5){averageglobalhsv(ref4frame,q4hsv,rcs,ccs);}
averagelocalhsv(ref4frame,q4hsv,rcs,ccs);//normalizing histogram values (0-1)
Point pt1; pt1.x=ccs; pt1.y=rcs;
int thickness=4;//thickness of marker - here is a circle
int lineType=8;
int shift=0;
RNG rng(0xFFFFFFFF);
cv::circle(ref4frame, pt1, 5, randomColor(rng), thickness, lineType,
shift); //marking object center with a circle
myimshow("reference frame",ref4frame);//show current image
waitKey(1);
}
int c=waitKey(0);
//release memory
ref4frame.release();
destroyAllWindows();
return 0;
}
下面是tf.h头文件的内容:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2opencv.hpp"
#include "corecore.hpp"
#include <cstdio>
#include <iostream>
#include <fstream>
#include <math.h>
using namespace cv;
using namespace std;
// makerect class: to create the desired size encompassing window
class makerect
{
public:
double rcs,ccs,w,l; // ctl row, ctl column, width, length
uint rmin,rmax,cmin,cmax,height,length;//min max coordination vars
void run(void);
makerect();
};
makerect::makerect(){
rmin=0;rmax=0;cmin=0;cmax=0;rcs=0;ccs=0;w=0;l=0;
}
void makerect::run(){
//not that all points must be either integer or floating point
rmin=uint(rcs-floor(w/2));//min row coordination
rmax=uint(rmin+w);//max row coordination
cmin=uint (ccs-floor(l/2));//min column coordination
cmax=uint(cmin+l);//max column coordination
if(cmax>length){cmax=length;cmin=cmax-l;// checking column to be inside image}
if(rmax>height){rmax=height;rmin=rmax-w;//checking row to be inside image}
}
static Scalar randomColor(RNG& rng)
{
int icolor = (unsigned)rng;
return Scalar(icolor&255, (icolor>>8)&255, (icolor>>16)&255);
}
//myimshow: is a function to to show image
void myimshow(char* name4window,Mat &tmp4image){
namedWindow(name4window,1); imshow(name4window,tmp4image);
}
void averageglobalhsv(Mat ref4frame,Mat &f,double &rcs,double &ccs)
{
Mat img;
cvtColor(ref4frame,img,CV_BGR2HSV);//rgb2hsv conversion
uint n4rowsref=ref4frame.rows;// num of rows
uint n4colsref=ref4frame.cols;// num of cols
double *im4bp = new double [n4rowsref*n4colsref];//1-D dynamic array equal to image pixels
uint nbins=16;// num of histogram bins
uint ndiv=256/nbins; //division value to which intensities are divided
//vars for image moments (zero to second moments)
double m00=0,m01=0,m10=0,m20=0,m02=0,m11=0,w=0;
uint R=0,G=0,B=0; //red bin num, green bin num, blue bin num
for(uint i=0;i<n4rowsref;i++){ //loop through all image rows
for(uint j=0;j<n4colsref;j++){//loop through all image columns
Vec3b inten=img.at<Vec3b>(i,j);//a vector of three element
R=inten.val[2]; G=inten.val[1]; B=inten.val[0];
R/=ndiv; G/=ndiv; B/=ndiv;//calculating the bin to which current pixel intensity belong
im4bp[i*n4colsref+j]=1.3*sqrt(f.at<double>(R,G,B));//calculating spatial weighted kernel histogram formula
}
}
for(uint i=0;i<n4rowsref;i++){//loop through all image rows
for(uint j=0;j<n4colsref;j++){//loop through all image columns
w=im4bp[j+n4colsref*i];// weight for pixel at (i,j)
m01=m01+double(i)*w;//first moment on y/row coordination
m10=m10+double(j)*w;//first moment on x/column coordination
m00=m00+w;//zeroth moment which is sum of all moments
}
}
if(m00>0){
rcs=ceil(m01/m00);//central point for row
ccs=ceil(m10/m00);}//central point for column
delete im4bp;//cleaning memory
}
void averagelocalhsv(Mat ref4frame,Mat &f,double &rcs,double &ccs)
{
Mat img;
cvtColor(ref4frame,img,CV_BGR2HSV);
makerect mkr;
int sz[]={2,2};
uint n4rowsref=ref4frame.rows;
uint n4colsref=ref4frame.cols;
double *im4bp = new double [n4rowsref*n4colsref];
uint nbins=16;
uint ndiv=256/nbins;
double m00=0,m01=0,m10=0,m20=0,m02=0,m11=0,w=0,Dxx,Dyy,Dxy;
uint R=0,G=0,B=0;
for(uint i=0;i<n4rowsref;i++){
for(uint j=0;j<n4colsref;j++){
Vec3b inten=img.at<Vec3b>(i,j);
R=inten.val[2]; G=inten.val[1]; B=inten.val[0];
R/=ndiv; G/=ndiv; B/=ndiv;
im4bp[i*n4colsref+j]=1.3*sqrt(f.at<double>(R,G,B));
}
}
for(int iter=1;iter<5;iter++){
mkr.rcs=rcs;mkr.ccs=ccs;mkr.w=100;mkr.l=100;mkr.height=ref4frame.rows;
mkr.length=ref4frame.cols; mkr.run();
m00=0;m01=0;m10=0;m20=0;m02=0;m11=0;
for(uint i=mkr.rmin;i<mkr.rmax;i=i+1){
for(uint j=mkr.cmin;j<mkr.cmax;j=j+1){
w=im4bp[j+n4colsref*i];
m01=m01+double(i)*w;
m10=m10+double(j)*w;
m00=m00+w;
}
}
}
if(m00>0){
rcs=ceil(m01/m00);
ccs=ceil(m10/m00);
}
delete im4bp;
}
class histhsv{
public:
histhsv();
void run(void);
Mat img;
double q[16][16][16];
};
histhsv::histhsv(){};
void histhsv::run(void){
//Mat hsv4image;
double sum4hist=0;
uchar nbins=16;
uchar ndiv=256/nbins;
double wmax =0;;
double r_center=0;
double c_center =0;
r_center = img.rows/2;
c_center = img.cols/2;
for (int i=0;i<nbins;i++){for(int j=0;j<nbins;j++){for(int k=0;k<nbins;k++){
q[i][j][k]=0; } } };
cvtColor(img,img,CV_BGR2HSV);
int H=0,S=0,V=0;
for(int r=0;r<img.rows;r++){
for(int c=0;c<img.cols;c++){
Vec3b intensity = img.at<Vec3b>(r,c);
H=intensity.val[0]/ndiv;
S=intensity.val[1]/ndiv;
V=intensity.val[2]/ndiv;
q[H][S][V]+=wmax-(pow(r-r_center,2)+pow(c-c_center,2));
sum4hist+=q[H][S][V];
}
}
for (int i=0;i<nbins;i++){
for(int j=0;j<nbins;j++){
for(int k=0;k<nbins;k++){
q[i][j][k]/=sum4hist;
}
}
}
}