opencv1.0 + vc++1.0数米粒 (基于c++)

opencv1.0 + vc++1.0数米粒 (基于c++)

1.关于配置

2.关于分割算法

3.关于具体代码实现

关于配置
参考此文
关于分割算法
看到写的不错【👇】:
七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)

关于具体代码实现
相关代码借鉴:
样例1
样例2
mycode:

#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <iostream>
using namespace std;


#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];   //获得所有灰度的和sum
		}
	}
	return int(sum*1.0/(inputGrayImg->height*inputGrayImg->width)+0.5);
}


// 迭代阈值  初始阈值分为两类不断迭代改进阈值
int iteration(IplImage *inputGrayImg,int aver)
{  
	int threshold = 0;
	int newThreshold = aver;   //初始阈值 (max+min)/2,这里用均值代替
    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 aver1=int(sum1/p);
		int aver2=int(sum2/q);
		threshold = newThreshold; 
		newThreshold = (aver1+aver2)/2;
	}
	return threshold;
}


//otsu阈值
int otsu(IplImage *inputGrayImg,int u)  //u=w0*u0 + w1*u1 图像总平均灰度 wi 前(背)景像素点数占图像的比例 ui前(背)景像素点的平均灰度
{
	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*inputImg,*backImg,*backRImg,*cutImg,*dst_contours;
    int gray_mean_threshold,iteration_threshold,otsu_threshold;
    
	//load source images
	inputImg = cvLoadImage("C:\\Users\\ocean\\Desktop\\images\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);  //输入图像
	backImg = cvLoadImage("C:\\Users\\ocean\\Desktop\\images\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);   //背景图像
	backRImg = cvLoadImage("C:\\Users\\ocean\\Desktop\\images\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);  //去背景图
    cutImg = cvLoadImage("C:\\Users\\ocean\\Desktop\\images\\rice.jpg",CV_LOAD_IMAGE_GRAYSCALE);    //分割图
    dst_contours = cvLoadImage("C:\\Users\\ocean\\Desktop\\images\\rice.jpg");       // 轮廓图


    
	IplConvKernel* element=cvCreateStructuringElementEx(4,4,1,1,CV_SHAPE_ELLIPSE,0);//形态学结构指针[创建结构元素,4列4行,椭圆形】
	

    cvErode(inputImg,backImg,element,5);//腐蚀
	cvDilate(backImg,backImg,element,5);//膨胀

	// sub the background 
	cvSub(inputImg,backImg,backRImg,0);   //用原始图像inputImg减去背景图像backImg,backRImg是结果图像

	



    //阈值分割(均值阈值,迭代阈值,otsu阈值,手动设置阈值)
	// 均值阈值
    gray_mean_threshold = aver(backRImg);
    printf("灰度均值阈值:%d\n",gray_mean_threshold);
	//迭代阈值
	iteration_threshold = iteration(backRImg,gray_mean_threshold);
	printf("迭代阈值:%d\n",iteration_threshold);
	//otsu阈值
    otsu_threshold = otsu(backRImg,gray_mean_threshold);
	printf("otsu阈值:%d\n",otsu_threshold);
	//手动设置阈值
	cvThreshold(backRImg,cutImg, gray_mean_threshold,255,CV_THRESH_BINARY);
	//cvThreshold(backRImg,cutImg, iteration_threshold,255,CV_THRESH_BINARY);
	//cvThreshold(backRImg,cutImg, otsu_threshold,255,CV_THRESH_BINARY);  //cutImg是分割图像
    


	//通过再次腐蚀膨胀去除噪声,得到最终的分割图片
	cvErode(cutImg,cutImg,element,1);//腐蚀
	cvDilate(cutImg,cutImg,element,1);//膨胀




    //count the number of rice 统计米粒个数
	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); //连通域
    
	

	double tmpArea=0;
	double tmpLength=0;
	int x1,y1;
	for (;cont != NULL;cont=cont->h_next)
	{
		CvRect rect=cvBoundingRect(cont,0);
		double tmpArea1=fabs(cvContourArea(cont,CV_WHOLE_SEQ));  //获得当前米粒的面积
		double tmpLength1=cvArcLength(cont);
		if(tmpArea<tmpArea1)  //更新为最大的米粒的面积和周长
		{ 
			tmpArea=tmpArea1;
			tmpLength=tmpLength1;
			x1=rect.x;
			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",tmpArea,tmpLength);
	printf("最大面积位置坐标为:%d %d\n",x1,y1);



    for (;cont1 != NULL;cont1=cont1->h_next) //再将所有米粒遍历一次,单独为最大米粒的轮廓上色
	{
		CvRect rect=cvBoundingRect(cont1,0);
		double tmpArea1=fabs(cvContourArea(cont1,CV_WHOLE_SEQ));
		if(rect.x==x1&&y1==rect.y&&tmpArea1==tmpArea)
        //用红色在图像上绘制最大米粒的轮廓
		cvDrawContours(dst_contours,cont1,CV_RGB(255,0,0),CV_RGB(255,0,0),0,1,8,cvPoint(1,1));//在图像上绘制轮廓.
	}





	//show the result
	cvNamedWindow("inputImg");
	cvShowImage("inputImg",inputImg);
	
	cvNamedWindow("backImg");
	cvShowImage("backImg",backImg);
	
	cvNamedWindow("backRImg");
	cvShowImage("backRImg",backRImg);

	cvNamedWindow("cutImg");
	cvShowImage("cutImg",cutImg);

	
	cvNamedWindow("dst_contours");
	cvShowImage("dst_contours",dst_contours);
	
	
	
	cvWaitKey(0);
	return 0;
	
	
	
}


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值