#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "cv.h"
#include "highgui.h"
using namespace cv;
using namespace std;
int Otsu(IplImage* src)
{
int height=src->height;
int width=src->width;
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++]++;
}
int size=height*width;
for(int i=0; i<256;i++)
histogram[i]=histogram[i]/size;
float avgValue=0;
for(int i=0;i<256;i++)
avgValue=avgValue+i*histogram[i]; //整幅图像的平均灰度
int threshold;
float maxVariance=0;
float w=0,u=0;
for(int i=0;i<256;i++)
{
w=w+histogram[i]; //假设当前灰度i为阈值, 0~i 灰度的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例
u=u+i*histogram[i]; // 灰度i 之前的像素(0~i)的平均灰度值: 前景像素的平均灰度值
float t=avgValue*w-u;
float variance=t*t/(w*(1-w));
if(variance>maxVariance)
{
maxVariance=variance;
threshold=i;
}
}
return threshold;
}
int main(int argc, char** argv)
{
IplImage *img_in = cvLoadImage("test1.jpg");
cvNamedWindow("img_in");
cvShowImage("img_in",img_in);
IplImage *img_gray = cvCreateImage(cvGetSize(img_in),8,1);
int thresh=Otsu(img_in); //求平均灰度的函数
cvCvtColor(img_in,img_gray,CV_BGR2GRAY);
cvThreshold(img_gray, img_gray,thresh,255,CV_THRESH_BINARY_INV);
cvDilate(img_gray,img_gray,0,2);//可以使图像膨胀,获得更大的连通区域
cvNamedWindow("img_gray");
cvShowImage("img_gray",img_gray);
CvSeq *pContour = NULL;
CvSeq *pConInner = NULL;
CvMemStorage *pStorage = NULL;
pStorage = cvCreateMemStorage(0);
cvFindContours(img_gray,pStorage,&pContour,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
cvDrawContours(img_gray,pContour,CV_RGB(255,255,255),CV_RGB(255,255,255),2);
cvNamedWindow("img_gray2");
cvShowImage("img_gray2",img_gray);
for (;pContour!=NULL;pContour=pContour->h_next)
{
CvRect rect=cvBoundingRect(pContour,0);
cvRectangle(img_in,cvPoint(rect.x, rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),CV_RGB(0,0,255));
}
cvNamedWindow("img_gray3");
cvShowImage("img_gray3",img_in);
cvWaitKey();
return 0;
}
测试用图:
运行结果: