【图像算法】彩色图像分割专题六:一种基于颜色直方图的图像分割

【图像算法】彩色图像分割专题六:一种基于颜色直方图的图像分割

     SkySeraph Jun 14th 2011  HQU

Email:zgzhaobo@gmail.com    QQ:452728574

Latest Modified Date:Jun 14th 2011 HQU

一 原理及说明:

1   首先RGB转HSV,在HSV空间下,对颜色分量H和S分别通过直方图,手动取范围进行分割。 关于RGB转HSV参考:http://www.cnblogs.com/skyseraph/archive/2011/05/05/2038317.html

2   关于颜色直方图相关资料:

http://www.opencv.org.cn/index.php/%E5%9B%BE%E5%83%8F%E9%A2%9C%E8%89%B2%E5%88%86%E5%B8%83%E7%9B%B4%E6%96%B9%E5%9B%BE

http://blog.csdn.net/foolpanda1168/archive/2010/12/15/6078463.aspx

http://www.cnblogs.com/xrwang/archive/2010/02/04/howtousehistogram.html

http://blog.csdn.net/yanqingan/archive/2010/06/14/5670951.aspx

 二 核心源码:

①响应函数

/////////////////////////////////////////////////////////////////////////////
void CColorSegDlg::OnHistDlgSeg() 
//直方图分割(H/S分量)
{
	//  验证
	if(!(ToDisplayCtr1))
	{
		MessageBox("Please Load Pic!");
		return;
	}	

	//  定义工作位图
	IplImage* src;
	src = ToDisplayCtr1;
	
	IplImage* imgH = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1); 
	IplImage* imgS = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1); 

	//  源图像信息
	int width = src->width;
	int height = src->height;
	int channel = src->nChannels;
	
	//  色彩空间转化
	int i,j; 
	double R,G,B,H,S,V;
	for(j=0;j<height;j++)
	{
		for(i=0;i<width;i++)
		{
			B = ((uchar*)(src->imageData + j*src->widthStep))[i*channel];
			G = ((uchar*)(src->imageData + j*src->widthStep))[i*channel+1];
			R = ((uchar*)(src->imageData + j*src->widthStep))[i*channel+2];
			pMyColorSpace.RGB2HSV(R,G,B,H,S,V);
			H = (360*H)/(2*PI);		// 弧度制[0,2pi]转换为角度[0,360]
			H = (250*H)/(360);		//[0,250] -- [0,360]
			S = S*255;
			((uchar*)(imgH->imageData + j*imgH->widthStep))[i*imgH->nChannels] = (uchar)H;	
			((uchar*)(imgS->imageData + j*imgS->widthStep))[i*imgS->nChannels] = (uchar)S;
		}
	}
	
	//  处理
	pMyThreshold.HistDlgSegment(imgH);
	pMyThreshold.HistDlgSegment(imgS);

	cvReleaseImage(&imgH);
	cvReleaseImage(&imgS);
	
}

②函数模块

/////////////////////////////////////////////////////////////////////////////////
// **直方图分割**
// 06/10/2011
// Copyright:	@skyseraph  zgzhaobo@gmail.com
// Version:	6/10/2011 zhaobo
/////////////////////////////////////////////////////////////////////////////////
void MyThreshold::HistDlgSegment(IplImage* img)
{
	if(img->nChannels != 1)
	{
		AfxMessageBox("It's not a SigleChannelPic!");
		return;
	}

	//=====================输入图像信息====================//
	int imgWidth = img->width;				
	int imgHeight = img->height;				
	int imgDepth = img->depth;				
	int imgChannels = img->nChannels;			
	int imgSize = img->imageSize;				
	int imgStep = img->widthStep/sizeof(uchar);
	uchar* imgData  = (uchar *)img->imageData;	
	int imgLen = imgWidth*imgHeight;			

	//保存像素范围
	int m_lowerLimit,m_upperLimit;

	//指向灰度级的数据指针
	int *pArray;
	//分配内存
	pArray = new int[256];
	//初始化内存
	for(int i =0 ;i <256 ;i++)
	{
		pArray[i] = 0;
	}

	//总的象素个数
	int   Total;
	Total = imgWidth *  imgHeight ;

	//调用函数获得每一级灰度级的值
	HuiDuTongJi(img,pArray);

	//
	HistDlg m_dlg;
	m_dlg.pArray = pArray;
	m_dlg.m_total = Total;

   
	if(m_dlg.DoModal() == IDOK)
	{
		//获得分割的上限和下限
		if(m_dlg.m_lowerLimit > m_dlg.m_upperLimit)
		{
			m_lowerLimit  = m_dlg.m_upperLimit;
			m_upperLimit =  m_dlg.m_lowerLimit;
		}
		else
		{   
			m_lowerLimit  = m_dlg.m_lowerLimit;
			m_upperLimit =  m_dlg.m_upperLimit;
		}
		//阈值分割
		HistThreshold(img,m_lowerLimit,m_upperLimit);
	}
	
	delete[]m_dlg;
	delete []pArray;
}


/////////////////////////////////////////////////////////////////////////////////
void MyThreshold::HuiDuTongJi(IplImage* img,int *pArray)
//图像的灰度统计
{
	if(img->nChannels != 1)
	{
		AfxMessageBox("It's not a SigleChannelPic!");
		return;
	}	
	
	//=====================循环变量====================//
	int i,j;
	//=====================输入图像信息====================//
	int imgWidth = img->width;			
	int imgHeight = img->height;			
	int imgDepth = img->depth;			
	int imgChannels = img->nChannels;			
	int imgSize = img->imageSize;			
	int imgStep = img->widthStep/sizeof(uchar); 
	uchar* imgData  = (uchar *)img->imageData;	
	int imgLen = imgWidth*imgHeight;				//
     
	//统计灰度级
	for(i = 0 ; i< imgHeight ; i++)
	{
		for(j = 0; j< imgWidth ; j++)
		{ 
			pArray[imgData[i*imgStep+j*imgChannels]]++;
		}
	}
}
/////////////////////////////////////////////////////////////////////////////////
//参数:
//	   m_lowerLimit //阈值下限
//	   m_upperLimit //阈值上限
/////////////////////////////////////////////////////////////////////////////////
void MyThreshold::HistThreshold(IplImage* img, int m_lowerLimit, int m_upperLimit)
//灰度直方图阈值分割
{
	//=====================循环变量====================//
	int i,j,k;
	//=====================输入图像信息====================//
	int imgWidth = img->width;			
	int imgHeight = img->height;			
	int imgDepth = img->depth;			
	int imgChannels = img->nChannels;			
	int imgSize = img->imageSize;			
	int imgStep = img->widthStep/sizeof(uchar); 
	uchar* imgData  = (uchar *)img->imageData;	
	int imgLen = imgWidth*imgHeight;				//			//

	IplImage* dst = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);

	for(i = 0 ;i < imgHeight; i++)
	{
		for(j =0 ; j <imgWidth ; j++)
		{
			for(k = 0; k<imgChannels;k++)
			{
				//当灰度值不在范围之内时灰度值付为0,否则为255
				if( imgData[i*imgStep+j*imgChannels+k] <m_lowerLimit || imgData[i*imgStep+j*imgChannels+k] > m_upperLimit)
				{
					(((uchar *)(dst->imageData))[i*imgStep+j*imgChannels+k]) = 255;				
				}
				else 
				{
					(((uchar *)(dst->imageData))[i*imgStep+j*imgChannels+k]) = 0;
				
				}
			}
		}	
	}

	cvNamedWindow("src");
	cvShowImage("src",img);
	cvNamedWindow("dst");
	cvShowImage("dst",dst);

	
	cvSaveImage(".\\dst.jpg",dst);
	cvSaveImage(".\\src.jpg",img);

	cvWaitKey(0);
	cvDestroyAllWindows();
	cvReleaseImage(&dst);
}
/////////////////////////////////////////////////////////////////////////////////

三 效果:

①H下:

原图及H直方图:

H单通道图像:

H直方图分割结果:

②S下

原图及S直方图:

S单通道图像:

S直方图分割结果:

 

More in  http://skyseraph.com/2011/08/27/CV/图像算法专题/ 

 

-------------------------------------------------------------------------------------------------------------------------------

Author:         SKySeraph

Email/GTalk: zgzhaobo@gmail.com    QQ:452728574

From:         http://www.cnblogs.com/skyseraph/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

 -------------------------------------------------------------------------------------------------------------------------------


作者:skyseraph
出处:http://www.cnblogs.com/skyseraph/
更多精彩请直接访问SkySeraph个人站点:http://skyseraph.com//
Email/GTalk: zgzhaobo@gmail.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @ 2011-06-14 22:58  SkySeraph  阅读(10482)  评论(2编辑  收藏  举报