【图像算法】彩色图像分割专题六:一种基于颜色直方图的图像分割
SkySeraph Jun 14th 2011 HQU
Email:[email protected] 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: @zhaobo [email protected] // 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直方图分割结果:
-------------------------------------------------------------------------------------------------------------------------------
Author: SKySeraph
Email/GTalk: [email protected] QQ:452728574
From: http://www.cnblogs.com/skyseraph/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
-------------------------------------------------------------------------------------------------------------------------------