⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 watersheddoc.cpp

📁 分水岭算法
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// WaterShedDoc.cpp : implementation of the CWaterShedDoc class
//

#include "stdafx.h"
#include "WaterShed.h"

#include "WaterShedDoc.h"
#include <queue>
using namespace std;
#include "MainFrm.h"
#include "math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MAXV 256
// Coefficient matrix for xyz and rgb spaces
static const int    XYZ[3][3] = { { 4125, 3576, 1804 },
{ 2125, 7154,  721 },
{  193, 1192, 9502 } };
static const double  RGB[3][3] = { 
	{ (float)3.2405, (float)-1.5371, (float)-0.4985 },
	{(float)-0.9693,  (float)1.8760,  (float)0.0416 },
	{ (float)0.0556, (float)-0.2040,  (float)1.0573 } };
	
	// Constants for LUV transformation 
	static const float     Xn = (float)0.9505;
	static const float     Yn = (float)1.0;
	static const float     Zn = (float)1.0888;
	static const float     Un_prime = (float)0.1978;
	static const float     Vn_prime = (float)0.4683;
	static const float     Lt = (float)0.008856;


/////////////////////////////////////////////////////////////////////////////
// CWaterShedDoc

IMPLEMENT_DYNCREATE(CWaterShedDoc, CDocument)

BEGIN_MESSAGE_MAP(CWaterShedDoc, CDocument)
	//{{AFX_MSG_MAP(CWaterShedDoc)
	ON_COMMAND(ID_WATERSHED, OnWatershed)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWaterShedDoc construction/destruction

CWaterShedDoc::CWaterShedDoc()
{
	// TODO: add one-time construction code here
	imageData = NULL;
	isImageLoaded=FALSE;
	imageName = "";
	myImageObject = NULL;
	luvData = NULL;
}

CWaterShedDoc::~CWaterShedDoc()
{
	if (imageData!=NULL)
	{
		delete [] imageData;
		imageData = NULL;
	}
	if (luvData!=NULL)
	{
		delete [] luvData;
		luvData = NULL;
	}
	
	if (myImageObject!=NULL)
	{
		delete myImageObject;
		myImageObject = NULL;
	}
}

BOOL CWaterShedDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CWaterShedDoc serialization

void CWaterShedDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/////////////////////////////////////////////////////////////////////////////
// CWaterShedDoc diagnostics

#ifdef _DEBUG
void CWaterShedDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CWaterShedDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CWaterShedDoc commands

BOOL CWaterShedDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
// 	if (!CDocument::OnOpenDocument(lpszPathName))
// 		return FALSE;
	
	// TODO: Add your specialized creation code here
	CString strPathName = lpszPathName;
	imageName = strPathName;
	while ( imageName.Find("\\", 0)>=0 && imageName!="") 
	{
		imageName.Delete(0, 1);
	} 
	
	myImageObject = new CImageObject(strPathName);
	if(myImageObject==NULL)
	{
		AfxMessageBox("Could not create image class!");
		return FALSE;
	}
	isImageLoaded = TRUE;
	
	//以下将RGB数据存入数组以备处理;
	LONG width = myImageObject->GetWidth();
	LONG height = myImageObject->GetHeight();
	dataLen = width*height*3;
	if ( imageData != NULL )
	{
		delete [] imageData;
		imageData = NULL;
	}
	imageData = new BYTE[width*height*3];
	imageWidth = width;
	imageHeight = height;
	myImageObject->LoadDIBToBuf(imageData);
	
	   //以下保存LUV数据;
	if ( luvData != NULL )
	{
		delete [] luvData;
		luvData = NULL;
	}
	luvData = new MyLUV[width*height];
	RgbtoLuvPcm(imageData, width, height, luvData);

	return TRUE;
}

void CWaterShedDoc::OnWatershed() 
{
	// TODO: Add your command handler code here

	BeginWaitCursor();

	LONG imagelen = imageWidth*imageHeight;
	FLOAT* deltar = new FLOAT[imagelen];//梯度模数组;
	FLOAT* deltasita = new FLOAT[imagelen];//梯度角度数组;
	INT*   flag = new INT[imagelen];//各点标识数组;
	INT*  gradientfre = new INT[256];//图像中各点梯度值频率;
	INT*  gradientadd = new INT[257];//各梯度起终位置;
	memset( gradientfre, 0, 256*sizeof(INT));
	memset( gradientadd, 0, 257*sizeof(INT));

	//首先得到各点梯度;
    GetGradient(imageData, imageWidth, imageHeight
		, deltar, deltasita);

	LONG temptime1 = GetTickCount();//初始时刻;
	//以下统计各梯度频率;
	MyImageGraPt*  graposarr = new MyImageGraPt[imagelen];
	LONG xstart, imagepos, deltapos;
	xstart = imagepos = deltapos = 0;
	for (INT y=0; y<imageHeight; y++)
	{
		xstart = y*imageWidth;
		for (INT x=0; x<imageWidth; x++)
		{
			deltapos = xstart + x;
			if (deltar[deltapos]>255)
			{
				deltar[deltapos] = 255;
			}
			INT tempi = (INT)(deltar[deltapos]);
			gradientfre[tempi] ++;//灰度值频率;
		}
	}

	//统计各梯度的累加概率;
	INT added = 0;
	gradientadd[0] = 0;//第一个起始位置为0;
	for (INT ii=1; ii<256; ii++)
	{
		added += gradientfre[ii-1];
		gradientadd[ii] = added;
	}
	gradientadd[256] = imagelen;//最后位置;

	memset( gradientfre, 0, 256*sizeof(INT));//清零,下面用作某梯度内的指针;
	//自左上至右下sorting....
	for (y=0; y<imageHeight; y++)
	{
		xstart = y*imageWidth;
		for (INT x=0; x<imageWidth; x++)
		{
			deltapos = xstart + x;
			INT tempi = (INT)(deltar[deltapos]);//当前点的梯度值,由于前面的步骤,最大只能为255;
			//根据梯度值决定在排序数组中的位置;
			INT tempos = gradientadd[tempi] + gradientfre[tempi];
			gradientfre[tempi] ++;//梯度内指针后移;
			graposarr[tempos].gradient = tempi;	//根据当前点的梯度将该点信息放后排序后数组中的合适位置中去;		
			graposarr[tempos].x = x;
			graposarr[tempos].y = y;
		}
	}

	LONG temptime2 = GetTickCount();//vincent泛洪前的时刻;
	INT rgnumber = 0;//分割后的区域数;
	FloodVincent(graposarr, gradientadd, 0, 255, flag, rgnumber);//Flooding;
	LONG temptime3 = GetTickCount();//vincent泛洪后的时刻;
	LONG kk0 = temptime2 - temptime1;//排序用时;
	LONG kk1 = temptime3 - temptime2;//flood用时;
	LONG allkk = temptime3 - temptime1;//总用时;
	allkk = temptime3 - temptime1;//总用时;

 //区域增长步骤
	//以下准备计算各个区域的LUV均值;
	MyRgnInfo*  rginfoarr = new MyRgnInfo[rgnumber+1];//分割后各个区的一些统计信息,第一个元素不用,图像中各点所属区域的信息存放在flag数组中;
	//清空该数组;
	for (INT i=0; i<=rgnumber; i++)
	{
		rginfoarr[i].isflag = FALSE;
		rginfoarr[i].ptcount = 0;
		rginfoarr[i].l = 0;
		rginfoarr[i].u = 0;
		rginfoarr[i].v = 0;
	}

	for (y=0; y<imageHeight; y++)
	{
		xstart = y*imageWidth;
		for (INT x=0; x<imageWidth; x++)
		{
			INT pos = xstart + x;
			INT rgid = flag[pos];//当前位置点所属区域在区统计信息数组中的位置;
			//以下将该点的信息加到其所属区信息中去;
			rginfoarr[rgid].ptcount ++;
			rginfoarr[rgid].l += luvData[pos].l;//////////////////////////////////
			rginfoarr[rgid].u += luvData[pos].u;
			rginfoarr[rgid].v += luvData[pos].v;
		}
	}
	//求出各个区的LUV均值;
	for (i=0; i<=rgnumber; i++)
	{
		rginfoarr[i].l = (FLOAT) ( rginfoarr[i].l / rginfoarr[i].ptcount );
		rginfoarr[i].u = (FLOAT) ( rginfoarr[i].u / rginfoarr[i].ptcount );
		rginfoarr[i].v = (FLOAT) ( rginfoarr[i].v / rginfoarr[i].ptcount );
	}

	//根据各区LUV均值(rginfoarr)和各区之间邻接关系(用flag计算)进行区域融合
	INT* mergearr = new INT[rgnumber+1];
	memset( mergearr, -1, sizeof(INT)*(rgnumber+1) );
	INT mergednum = 0;
	LONG temptime4 = GetTickCount();
	MergeRgs(rginfoarr, rgnumber, flag, imageWidth, imageHeight, mergearr, mergednum);
	LONG temptime5 = GetTickCount();
	LONG kk2 = temptime5 - temptime4;//合并用时;
	//确定合并后各像素点所属区域;
	for (y=0; y<(imageHeight); y++)
	{
		xstart = y*imageWidth;
		for (INT x=0; x<(imageWidth); x++)
		{
			INT pos = xstart + x;
			INT rgid = flag[pos];//该点所属区域;
			flag[pos] = FindMergedRgn(rgid, mergearr);
		}
	}
	delete [] mergearr; mergearr = NULL;

	//用各区均值代替原像素点值;
	FLOAT* luvbuff = NULL;
	luvbuff = new FLOAT[imageWidth*imageHeight*3];

	for (y=1; y<(imageHeight-1); y++)
	{
		xstart = y*imageWidth;
		for (INT x=1; x<(imageWidth-1); x++)
		{
			INT pos = xstart + x;
			INT rgid = flag[pos];//该点所属区域;
			luvData[pos].l = rginfoarr[rgid].l;//luvData用于全局保存LUV值;
			luvbuff[pos*3] = rginfoarr[rgid].l;//luvbuff用于传递参数给LuvToRgb();
			luvData[pos].u = rginfoarr[rgid].u;
			luvbuff[pos*3+1] = rginfoarr[rgid].u;
			luvData[pos].v = rginfoarr[rgid].v;
			luvbuff[pos*3+2] = rginfoarr[rgid].v;
		}
	}

	LuvToRgb(luvbuff, imageWidth, imageHeight, imageData);

	delete [] luvbuff; luvbuff = NULL;
	delete [] rginfoarr; rginfoarr = NULL;//大小等于区域总数


	//以下根据标识数组查找边界点(不管四边点以减小复杂度);
	for (y=1; y<(imageHeight-1); y++)
	{
		xstart = y*imageWidth;
		for (INT x=1; x<(imageWidth-1); x++)
		{
			INT pos = xstart + x;
			INT imagepos = pos * 3;	
			INT left = pos - 1;
			INT up = pos - imageWidth;
			INT right = pos +1;
			INT down = pos + imageWidth;
			if ( ( flag[right]!=flag[pos] )
				|| ( flag[down]!=flag[pos] ) )
			//if ( flag[pos]==0 )
			{
				imageData[imagepos] = 0;
				imageData[imagepos+1] = 0;
				imageData[imagepos+2] = 250;
			}

		}
	}

	delete [] gradientadd; gradientadd = NULL;//大小256
	delete [] gradientfre; gradientfre = NULL;//大小256
	delete [] deltasita; deltasita = NULL;//大小imagelen
	delete [] deltar;    deltar    = NULL;//大小imagelen
	delete [] graposarr; graposarr = NULL;//大小imagelen
	delete [] flag;      flag      = NULL;//大小imagelen

	RefreshImageObject();

	CMainFrame* pFrame = (CMainFrame*) AfxGetApp()->GetMainWnd();
	EndWaitCursor();
	pFrame->pImageView->Invalidate(FALSE);	
	
}

void CWaterShedDoc::GetGradient(BYTE *image, INT width, INT height, FLOAT *deltar, FLOAT *deltasita)
{
	//下面计算各像素在水平和垂直方向上的梯度,边缘点梯度计为0;
	INT* deltaxarr;
	INT* deltayarr;
	INT grawidth = width;
	INT graheight = height;
	INT deltacount = grawidth * graheight;
	deltaxarr = new INT[deltacount];
	deltayarr = new INT[deltacount];
	
    //暂不计算边缘点;
	for (INT y=1; y<graheight-1; y++)
	{
		for (INT x=1; x<grawidth-1; x++)
		{
			INT inarrpos = ((y)*width + (x))*3 + 1;//在输入块中的位置;
			INT deltaarrpos = y*grawidth + x;//在梯度数组中的位置;
			//卷积计算;
			deltaxarr[deltaarrpos] = (INT) ( (
				image[((y-1)*width + (x+1))*3 + 1] //右上
				+ image[((y)*width + (x+1))*3 + 1] //右
				+ image[((y+1)*width + (x+1))*3 + 1] //右下
				- image[((y-1)*width + (x-1))*3 + 1] //左上
				- image[((y)*width + (x-1))*3 + 1] //左
				- image[((y+1)*width + (x-1))*3 + 1] ) / 3 );//左下
			deltayarr[deltaarrpos] = (INT) ( ( 
				image[((y-1)*width + (x+1))*3 + 1] //右上
				+ image[((y-1)*width + (x))*3 + 1] //上
				+ image[((y-1)*width + (x-1))*3 + 1] //左上
				- image[((y+1)*width + (x-1))*3 + 1] //左下
				- image[((y+1)*width + (x))*3 + 1] //下
				- image[((y+1)*width + (x+1))*3 + 1]) / 3 );//右下
		}
	}
	
	//边缘赋为其内侧点的值;
	for (y=0; y<graheight; y++)
	{
		INT x1 = 0;
		INT pos1 = y*grawidth + x1;
		deltaxarr[pos1] = deltaxarr[pos1+1];
		deltayarr[pos1] = deltayarr[pos1+1];
		INT x2 = grawidth-1;
		INT pos2 = y*grawidth + x2;
		deltaxarr[pos2] = deltaxarr[pos2-1];
		deltayarr[pos2] = deltayarr[pos2-1];
	}
	for (INT x=0; x<grawidth; x++)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -