【图像算法】彩色图像分割专题六:一种基于颜色直方图的图像分割
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://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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
-------------------------------------------------------------------------------------------------------------------------------