天天看點

機器視覺執行個體(VC++6.0 + OpenCV1.0)

環境配置參考: 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;
}

           

所要用到的圖檔:

機器視覺執行個體(VC++6.0 + OpenCV1.0)

繼續閱讀