zoukankan      html  css  js  c++  java
  • 【图像算法】彩色图像分割专题六:一种基于颜色直方图的图像分割

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

         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/

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

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

  • 相关阅读:
    转:sql语句中GROUP BY 和 HAVING和使用 count()
    shell中的大括号和小括号
    转:关于rename命令ubuntu下的用法
    Linux批量重命名
    STL 源代码剖析 算法 stl_algo.h -- partition
    HDU 5091 线段树扫描线
    IBM 中国研究院面试经历
    当人手一部智能手机时 庞大的数据中心们已死
    Treap的读书笔记2
    【JUnit4.10源码分析】5 Statement
  • 原文地址:https://www.cnblogs.com/skyseraph/p/2081042.html
Copyright © 2011-2022 走看看