環境配置參考: VC6.0+opencv1.0配置
執行個體内容:
1.實作圖像的去背景,将原始圖像,背景圖像和去背景圖像儲存下來
2.實作圖像的門檻值分割,分别用均值灰階,疊代門檻值,OTSU方法進行分割
3.實作數米粒功能,輸出米粒的顆數,最大米粒的面積,周長,在圖像中位置
4.在黑色背景下用白色畫出所有米粒的輪廓,并将最大米粒的輪廓用紅色顯示
完整代碼如下:
#include "stdio.h"
#include "cv.h"
#include "highgui.h"
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cvaux.lib")
#pragma comment(lib,"cvcam.lib")
int aver(IplImage *inputGrayImg)
{
uchar *data= (uchar *)inputGrayImg->imageData;
int wp = inputGrayImg->widthStep;
int i,j;int sum=0;
for( i = 0; i < inputGrayImg->height; i++)
{
for(j = 0; j < inputGrayImg->width; j++)
{
sum = sum + data[i * wp + j];
}
}
return int(sum*1.0/(inputGrayImg->height*inputGrayImg->width)+0.5);
}
int iterate(IplImage *inputGrayImg,int a)
{
int threshold = 0; int newThreshold = a;
while(threshold != newThreshold){
int p=1,q=1;int sum1=0,sum2=0;
uchar *data= (uchar *)inputGrayImg->imageData;
int wp = inputGrayImg->widthStep;
int i,j;
for( i = 0; i < inputGrayImg->height; i++)
{
for(j = 0; j < inputGrayImg->width; j++)
{
if(data[i * wp + j]<newThreshold)
{
sum1+=data[i * wp + j];p++;}
else
{
sum2+=data[i * wp + j];q++;
}
}
}
int avg1=int(sum1/p);int avg2=int(sum2/q);
threshold = newThreshold;
newThreshold = (avg1+avg2)/2;
}
return threshold;
}
int otsu(IplImage *inputGrayImg,int u)
{
int hui[256]={0};float g[256];
uchar *data= (uchar *)inputGrayImg->imageData;
int wp = inputGrayImg->widthStep;
int i,j;
for( i = 0; i < inputGrayImg->height; i++)
{
for(j = 0; j < inputGrayImg->width; j++)
{
hui[data[i * wp + j]]+=1;
}
}
int sum=inputGrayImg->height*inputGrayImg->width;
for(i=0;i<256;i++)
{
int sum1=1,sum2=1;int hui1=1,hui2=1;
for(j=0;j<i;j++)
{
sum1+=hui[j];hui1+=hui[j]*j;
}
for(j=i;j<256;j++)
{
sum2+=hui[j];hui2+=hui[j]*j;
}
float w0,w1;int u0,u1;
w0=sum1*1.0/sum;
w1=sum2*1.0/sum;
u0=int(hui1/sum1);
u1=int(hui2/sum2);
g[i]=w0 * (u0 - u) * (u0 - u) + w1 * (u1 - u) * (u1 - u);
}
int max=0;
for(i=1;i<256;++i)
{
if(g[max]<g[i])max=i;
}
return max;
}
int main(int argc,char *argv[])
{
IplImage *src,*backImg,*backRImg,*cutImg,*result,*show,*dst_contours;//定義
int averyuzhi,iteryuzhi,otsuyuzhi;//定義三種門檻值參數
src = cvLoadImage("C:\\Users\\\\實驗圖檔\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);
backImg = cvLoadImage("C:\\Users\\實驗圖檔\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);
backRImg = cvLoadImage("C:\\Users\\實驗圖檔\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);
cutImg = cvLoadImage("C:\\Users\\實驗圖檔\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);
dst_contours = cvLoadImage("C:\\Users\\實驗圖檔\\rice.jpg");
//背景圖像
IplConvKernel* element=cvCreateStructuringElementEx(4,4,1,1,CV_SHAPE_ELLIPSE,0);
cvErode(src,backImg,element,5);//腐蝕
cvDilate(backImg,backImg,element,5);//膨脹
cvSub(src,backImg,backRImg,0);//去背景圖像
//分割圖像
averyuzhi=aver(backRImg);//函數調用
iteryuzhi=iterate(backRImg,averyuzhi);//函數調用
otsuyuzhi=otsu(backRImg,averyuzhi);//函數調用
printf("均值方法門檻值:%d\n",averyuzhi);
printf("疊代方法門檻值:%d\n",iteryuzhi);
printf("OTSU門檻值:%d\n",otsuyuzhi);
cvThreshold(backRImg,cutImg,averyuzhi,255,CV_THRESH_BINARY);
// cvThreshold(backRImg,cutImg,iteryuzhi,255,CV_THRESH_BINARY);//其他兩種方法
// cvThreshold(backRImg,cutImg,otsuyuzhi,255,CV_THRESH_BINARY);
cvErode(cutImg,cutImg,element,1);//腐蝕
cvDilate(cutImg,cutImg,element,1);//膨脹
cvThreshold(backRImg,cutImg,50,255,CV_THRESH_BINARY);
//數米粒數
CvMemStorage* stor=cvCreateMemStorage(0);
CvSeq *cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);
CvSeq *cont1 = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);
int numberOfObject = cvFindContours(cutImg,stor,&cont,sizeof(CvContour),CV_RETR_TREE);
int numberOfObject1 = cvFindContours(cutImg,stor,&cont1,sizeof(CvContour),CV_RETR_TREE);
printf("圖中的米粒數為:%d\n",numberOfObject);
//米粒面積,周長,位置
float area=0;
float length=0;
int x1,y1;
for (;cont != NULL;cont=cont->h_next)
{
CvRect rect=cvBoundingRect(cont,0);
double area1=fabs(cvContourArea(cont,CV_WHOLE_SEQ));
double length1=cvArcLength(cont);
if(area<area1)
{
area=area1;
length=length1;
y1=rect.y;
}
cvDrawContours(dst_contours,cont,CV_RGB(255,255,255),CV_RGB(255,0,0),0,1,8,cvPoint(1,1));
}
printf("面積為:%f\n周長為:%f\n",area,length);
printf("最大面積位置坐标為:%d %d\n",x1,y1);
//輪廓
for (;cont1 != NULL;cont1=cont1->h_next)
{
CvRect rect=cvBoundingRect(cont1,0);
float area1=fabs(cvContourArea(cont1,CV_WHOLE_SEQ));
if(rect.x==x1&&y1==rect.y&&area1==area)
cvDrawContours(dst_contours,cont1,CV_RGB(255,0,0),CV_RGB(255,0,0),0,1,8,cvPoint(1,1));
}
//視窗
cvNamedWindow("show");
cvShowImage("show",src);
cvNamedWindow("show2");
cvShowImage("show2",backImg);
cvNamedWindow("show3");
cvShowImage("show3",backRImg);
cvNamedWindow("show4");
cvShowImage("show4",cutImg);
cvNamedWindow("show5");
cvShowImage("show5",dst_contours);
cvWaitKey(0);
return 0;
}
所要用到的圖檔:
