📄 watershed.cpp
字号:
//处理待进队的新点
if(pushPoint.x!=-1&&pushPoint.y!=-1){
*(pMarker+pushPoint.y*linebyte+pushPoint.x)=j;
edgeFlg=0;
contourFlg=0;
//判断该新点是否边缘点或轮廓点
for(k=0;k<8;k++){
neighborPoint.x=pushPoint.x+direct[k][0];
neighborPoint.y=pushPoint.y+direct[k][1];
//邻域点不在图像内,则跳过
if(neighborPoint.y<0||neighborPoint.y>height-1
||neighborPoint.x<0||neighborPoint.x>width-1)
continue;
mark=*(pMarker+neighborPoint.y*linebyte+neighborPoint.x);
if( mark==0 ){
edgeFlg=1;
}
if( mark!=j && mark!=objectCount+1 &&mark!=0){
contourFlg=1;
}
}
if(flag_contour){//不同类间加分水岭线的标志(叠坝)
if(contourFlg)
*(pMarker+pushPoint.y*width+pushPoint.x)=objectCount+1;
}
if(edgeFlg){
if(minGradient<i){
if(IsOverflow(i,j)){
CString str;
str.Format("%d",minGradient);
CString str1="第"+ str + "个队溢出!";
::MessageBox(0,str1,MB_OK,0);
return;
}
Push(i,j,pushPoint);
}
else{
if(IsOverflow(minGradient,j)){
CString str;
str.Format("%d",minGradient);
CString str1="第"+ str + "个队溢出!";
::MessageBox(0,str1,MB_OK,0);
return;
}
Push(minGradient,j,pushPoint);
}
}
}
//处理刚才出队的点,若该点仍然是边缘点,则重新进队
edgeFlg=0;
contourFlg=0;
//判断被弹出点是否边缘点且非轮廓
for(k=0;k<8;k++){
neighborPoint.x=popPoint.x+direct[k][0];
neighborPoint.y=popPoint.y+direct[k][1];
//邻域点不在图像范围内,则跳过
if(neighborPoint.y<0||neighborPoint.y>height-1
||neighborPoint.x<0||neighborPoint.x>width-1)
continue;
mark=*(pMarker+neighborPoint.y*linebyte+neighborPoint.x);
if( mark==0 ){
edgeFlg=1;
}
if( mark!=j && mark!=objectCount+1 &&mark!=0){
contourFlg=1;
}
}
if(flag_contour){//不同类间加分水岭线的标志(叠坝)
if(contourFlg) //轮廓线标志
*(pMarker+popPoint.y*linebyte+popPoint.x)=objectCount+1;
}
if(edgeFlg){
if(IsOverflow(i,j)){
CString str;
str.Format("%d",minGradient);
CString str1="第"+ str + "个队溢出!";
::MessageBox(0,str1,MB_OK,0);
return;
}
Push(i,j,popPoint);
}
}//while end
}// for(j) end
}//for(i) end
}
/***********************************************************************
* 函数名称:
* GenerateMarkerByPos()
*
*函数参数:
* unsigned char* pMarker -图像的标记图
* int width -图像的宽
* int height -图像的高
* CPoint position[] -指定种子点数组
* int objectCount -分类数
*
*返回值:
* 无
*
*说明:给定种子点数组position及分类数objectCount,产生标记图pMarker
***********************************************************************/
void Watershed::GenerateMarkerByPos(unsigned char* pMarker, int width,
int height, CPoint position[], int objectCount)
{
//每行像素字节数
int linebyte=(width+3)/4*4;
//初始化标记图置0,0代表未作标记的点(等待生长的点)
memset(pMarker, 0, linebyte*height);
//循环变量
int k;
//将第k个指定点置成标记k,
for(k=0;k<objectCount;k++){
*(pMarker+position[k].y*linebyte+position[k].x)=k+1;
}
}
/***********************************************************************
* 函数名称:
* Sobel()
*
*函数参数:
* unsigned char* imgBuf -图像数据
* int width -图像的宽
* int height -图像的高
* unsigned char *gradient -梯度图
*
*返回值:
* 无
*
*说明:给定图像数据,进行sobel变换,得到的梯度图存入gradient缓冲区,此处
* 没有调用前面ImgSegment类中的Sobel(),是为了Watershed类的集成性,便
* 于代码移植
***********************************************************************/
void Watershed::Sobel(unsigned char *imgBuf, int width, int height,
unsigned char *gradient)
{
//每行像素字节数
int linebyte=(width+3)/4*4;
//梯度图像缓冲区初始化置0。
memset(gradient, 0, linebyte*height);
//循环变量,图像的坐标
int i, j;
//中间变量
int x, y, t;
for(i=1;i<height-1; i++){
for(j=1; j<width-1; j++){
//x方向梯度
x=*(imgBuf+(i+1)*linebyte+j-1)+2**(imgBuf+(i+1)*linebyte+j)
+*(imgBuf+(i+1)*linebyte+j+1) -*(imgBuf+(i-1)*linebyte+j-1)
-2**(imgBuf+(i-1)*linebyte+j)-*(imgBuf+(i-1)*linebyte+j+1);
//y方向梯度
y=*(imgBuf+(i+1)*linebyte+j-1)+2**(imgBuf+i*linebyte+j-1)
+*(imgBuf+(i-1)*linebyte+j)-*(imgBuf+(i+1)*linebyte+j+1)
-2**(imgBuf+i*linebyte+j+1)-*(imgBuf+(i-1)*linebyte+j+1);
//梯度
t=sqrt(x*x+y*y);
if(t>255) t=255;
*(gradient+i*linebyte+j)=t;
}
}
}
/***********************************************************************
* 函数名称:
* WatershedSegment()
*
*函数参数:
* CPoint position[] -种子点数组
* int classCount -分类数
* int contourFlg -标志性变量,1为叠坝(加轮廓线),0为不叠坝(不加轮廓线)
*
*返回值:
* 无
*
*说明:给定种子点及分类数,对输入图像进行水域分割函数
***********************************************************************/
void Watershed::WatershedSegment(CPoint position[], int classCount, int contourFlg)
{
//释放m_pImgDataOut指向的图像数据空间
if(m_pImgDataOut!=NULL){
delete []m_pImgDataOut;
m_pImgDataOut=NULL;
}
//释放颜色表空间
if(m_lpColorTableOut!=NULL){
delete []m_lpColorTableOut;
m_lpColorTableOut=NULL;
}
//输出图像为标记图像的输出,此处为灰度类型
m_nBitCountOut=m_nBitCount;
m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);
if(m_nColorTableLengthOut!=0){
m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
memcpy(m_lpColorTableOut,m_lpColorTable,
sizeof(RGBQUAD)*m_nColorTableLengthOut);
}
//输出图像的宽高,与输入图像相等
m_imgWidthOut=m_imgWidth;
m_imgHeightOut=m_imgHeight;
int lineByte=(m_imgWidth*m_nBitCountOut/8+3)/4*4;
m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];
//queueLng表示队列的长度,为节省空间,其值为图像像素总数的1/16,实际处理中队
//列最长还可能远远小于本程序设定的值,或者采用指针方式实现队列更为合理
queueLng=m_imgWidth*m_imgHeight/16;
//标记数
objectCount=classCount;
//循环变量
int i, j;
//申请队列缓冲区
for(i=0;i<256;i++){
for(j=0;j<4;j++)
queue[i][j]=new CPoint[queueLng];
}
//通过指定点参数产生标记,此时m_pImgDataOut内是初始标记图
GenerateMarkerByPos(m_pImgDataOut, m_imgWidth, m_imgHeight,
position, objectCount);
//申请缓冲区,存放sobel变换梯度图
unsigned char *sobelBuf=new unsigned char[lineByte*m_imgHeight];
Sobel(m_pImgData, m_imgWidth, m_imgHeight, sobelBuf);
//水域变换,变换后m_pImgDataOut内存放的是水域生长以后的标记图,即分割结果
WatershedTrans(sobelBuf, m_pImgDataOut, m_imgWidth, m_imgHeight,contourFlg);
//标记图按一定比例显示
for(i=0;i<m_imgHeight;i++){
for(j=0;j<m_imgWidth;j++){
if(*(m_pImgDataOut+i*lineByte+j)==objectCount+1)
*(m_pImgDataOut+i*lineByte+j)=255;
else
*(m_pImgDataOut+i*lineByte+j)=
(*(m_pImgDataOut+i*lineByte+j)-1)*255/objectCount;
}
}
//清除梯度图缓冲区
delete []sobelBuf;
//清除队列缓冲区
if(queueLng!=0){
for(i=0;i<256;i++){
for(j=0;j<4;j++){
//释放队列缓冲区
delete []queue[i][j];
}
}
queueLng=0;
}
}
/*
//用直方图方法生成标记图,threshInterval阈值段数组
void Watershed::calculateMarker(unsigned char* pImgBuf, unsigned char* pMarker, int width,int height, int threshInterval[], int objectCount)
{
//每行像素字节数
int linebyte=(width+3)/4*4;
//初始化标记图置0,0代表未作标记的点(等待生长的点)
memset(pMarker, 0, linebyte*height);
//循环变量
int i,j,k;
unsigned char t;
for(i=0;i<height;i++){
for(j=0;j<width;j++){
for(k=0;k<objectCount;k++){
//坐标为(i,j)像素的指针
t=*(pImgBuf+i*linebyte+j);
if(t>=threshInterval[k*2+0] && t<threshInterval[k*2+1])//第k类目标灰度区间
*(pMarker+i*linebyte+j)=k+1;
}
}
}
}
void Watershed::WatershedSegment1(int threshInterval[], int classCount, int contourFlg)
{
if(classCount<2||classCount>3){
::MessageBox(0,"分类数只能是2或3",MB_OK,0);
return;
}
//释放m_pImgDataOut指向的图像数据空间
if(m_pImgDataOut!=NULL){
delete []m_pImgDataOut;
m_pImgDataOut=NULL;
}
//释放颜色表空间
if(m_lpColorTableOut!=NULL){
delete []m_lpColorTableOut;
m_lpColorTableOut=NULL;
}
//输出图像为标记图象的输出,此处为灰度类型
m_nBitCountOut=8;
m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);
if(m_nColorTableLengthOut!=0){
m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
for(int i=0; i<m_nColorTableLengthOut;i++){
m_lpColorTableOut[i].rgbBlue=i;
m_lpColorTableOut[i].rgbGreen=i;
m_lpColorTableOut[i].rgbRed=i;
m_lpColorTableOut[i].rgbReserved=0;
}
}
//输出图像的宽高,与输入图像相等
m_imgWidthOut=m_imgWidth;
m_imgHeightOut=m_imgHeight;
int lineByte=(m_imgWidth*m_nBitCountOut/8+3)/4*4;
m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];
//进队的像素是每个区域的边缘像素,边缘像素的数目要小于区域的像素数
//而图像又被分成classCount个目标类,因此每个队列的最长远小于图像像素的总数
//maxQueueBufLng用来作为申请队列缓冲区大小的依据,为节省空间,此处maxQueueBufLng的值为图像像素总数除以16
//实际处理中队列最长还可能远远小于本程序设定的值
maxQueueBufLng=m_imgWidth*m_imgHeight/16;
//标记数
objectCount=classCount;
//循环变量
int i, j;
//申请队列缓冲区
for(i=0;i<256;i++){
for(j=0;j<4;j++)
queue[i][j]=new CPoint[maxQueueBufLng];
}
//通过指定点参数产生标记图,此时m_pImgDataOut是初始标记图
calculateMarker(m_pImgData, m_pImgDataOut, m_imgWidth, m_imgHeight, threshInterval, objectCount);
//申请缓冲区,存放梯度图
unsigned char *sobelBuf=new unsigned char[lineByte*m_imgHeight];
//计算sobel梯度图
sobel(m_pImgData, m_imgWidth, m_imgHeight, sobelBuf);
//水域变换
waterShed(sobelBuf, m_pImgDataOut, m_imgWidth, m_imgHeight,contourFlg);
//显示
for(i=0;i<m_imgHeight;i++){
for(j=0;j<m_imgWidth;j++){
if(*(m_pImgDataOut+i*lineByte+j)==objectCount+1)
*(m_pImgDataOut+i*lineByte+j)=255;
else
*(m_pImgDataOut+i*lineByte+j)=
(*(m_pImgDataOut+i*lineByte+j)-1)*255/objectCount;
}
}
//清除梯度缓冲区
delete []sobelBuf;
//清除队列缓冲区
if(maxQueueBufLng!=0){
for(i=0;i<256;i++){
for(j=0;j<4;j++){
//申请队列缓冲区
delete []queue[i][j];
}
}
maxQueueBufLng=0;
}
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -