效果还不错,不过问题就是代码都是用的较老的opencv语法,里面有一些处理不好容易报错。。
#include "cv.h" #include "highgui.h" #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <iostream> #include <string> #include <cstdio> using namespace std; using namespace cv; // implementation of otsu algorithm // author: onezeros#yahoo.cn // reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB void cvThresholdOtsu(IplImage* src, IplImage* dst) { int height=src->height; int width=src->width; //histogram float histogram[256]={0}; for(int i=0;i<height;i++) { unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i; for(int j=0;j<width;j++) { histogram[*p++]++; } } //normalize histogram int size=height*width; for(int i=0;i<256;i++) { histogram[i]=histogram[i]/size; } //average pixel value float avgValue=0; for(int i=0;i<256;i++) { avgValue+=i*histogram[i]; } int threshold; float maxVariance=0; float w=0,u=0; for(int i=0;i<256;i++) { w+=histogram[i]; u+=i*histogram[i]; float t=avgValue*w-u; float variance=t*t/(w*(1-w)); if(variance>maxVariance) { maxVariance=variance; threshold=i; } } cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY); } void cvSkinOtsu(IplImage* src, IplImage* dst) { assert(dst->nChannels==1&& src->nChannels==3); IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3); IplImage* cr=cvCreateImage(cvGetSize(src),8,1); cvCvtColor(src,ycrcb,CV_BGR2YCrCb); //show ycrcb cvShowImage("ycrcb",ycrcb); cvSplit(ycrcb,0,cr,0,0); cvThresholdOtsu(cr,cr); cvShowImage("out2",cr); //cvWaitKey(0); //cvCopyImage(cr,dst); //cvReleaseImage(&cr); cvReleaseImage(&ycrcb); } int main() { IplImage* img = cvLoadImage( "earth.jpg" ); //out用以保存输出图像 IplImage * out = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 3 ); cvShowImage("in",img); cvSkinOtsu(img,out); //cvShowImage("out",out); cvWaitKey(0); cvReleaseImage(&img);//用完清理 cvReleaseImage(&out);//用完清理 cvDestroyWindow("in"); cvDestroyWindow("out"); return 0; }