📄 watersheddoc.cpp
字号:
// 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 + -