📄 dlgclusterpatternrecog.cpp
字号:
// TODO: Add your control notification handler code here
int i;
UpdateData(TRUE);
if(m_nClassNumber>MAXIMIZE_CLASSNUM)
{
m_nClassNumber=MAXIMIZE_CLASSNUM;
UpdateData(FALSE);
}
//设置初始聚类中心
if(m_bFirst)
{
m_arrClusterCenterBackup.SetSize(m_nClassNumber);
SetInitialClusterCenter(m_arrClusterCenterBackup);
m_bFirst=false;
}
//调整初始分类中心
m_arrClusterCenter.RemoveAll();
m_arrClusterCenter.SetSize(m_nClassNumber);
SetInitialClusterCenter(m_arrClusterCenter);
// int nMin=min(m_arrClusterCenterBackup.GetSize(),m_nClassNumber);
// for(i=0;i<nMin;i++)
// { //优化,可以加快下次迭代收敛的速度
// m_arrClusterCenter[i]=m_arrClusterCenterBackup[i];
// }
//调整分类中心的备份
m_arrClusterCenterBackup.RemoveAll();
m_arrClusterCenterBackup.SetSize(m_nClassNumber);
// for(i=0;i<m_nClassNumber;i++)
// {
// m_arrClusterCenterBackup[i]=m_arrClusterCenter[i];
// }
//设定/修改分类矩阵
m_matrixClassTag.Init(m_lImagePixelNumber,m_nClassNumber);
((CButton*)GetDlgItem(IDC_BUTTON_PR_RECOGNIZE))->EnableWindow(TRUE);
//绘制坐标轴及像素点坐标
Draw2DimetionAxis(m_lpTabDC,m_nWhichColorNoUse);
//随机产生各种分类的颜色
tagRGBVal rgb;
m_arrCenterColor.RemoveAll();
m_arrCenterColor.SetSize(m_nClassNumber);
double tmp;
for (int j=0;j<m_nClassNumber;j++)
{
srand( (unsigned)time( NULL ) );
rgb.R=rand() % 255;
for(i=0;i<1000;i++) tmp=sqrt(sin(1.0));
srand( (unsigned)time( NULL ) );
rgb.G=rand() % 255;
for(i=0;i<1000;i++) tmp=sqrt(sin(1.0));
srand( (unsigned)time( NULL ) );
rgb.B=rand() % 255;
for(i=0;i<1000;i++) tmp=sqrt(sin(1.0));
m_arrCenterColor.SetAt(j,rgb);
}
return;
}
//设置聚类中心的初始值
bool CDlgClusterPatternRecog::SetInitialClusterCenter(RGBValArray& arrClusterCenter)
{
int nCenterNumber=arrClusterCenter.GetSize();
if(nCenterNumber<=0)
return FALSE;
//这里随机指定聚类中心
tagRGBVal rgb;
// BYTE R,G,B;
CImageSysZLF01App * lpCurrentApp=(CImageSysZLF01App *)AfxGetApp();
CImageSysZLF01Doc * pDoc=lpCurrentApp->GetCurDocument();
HDIB hDIB=pDoc->GetHDIB();
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
int cxDIB = (int) ::DIBWidth(lpDIB);
int cyDIB = (int) ::DIBHeight(lpDIB);
int x,y;
for(int i=0;i<nCenterNumber;i++)
{
//随机方式
if(m_lCenterInitialMethod==CLUSTERING_INITIAL_CENTER_RANDOM)
{
srand( (unsigned)time( NULL ) );
x=rand() % m_nImageShowWidth;
srand( (unsigned)time( NULL ) );
y=rand() % m_nImageShowHeight;
}
else
{
//顺序产生
// x=cxDIB/2-i;y=cyDIB/2-1;
x=i;y=1;
}
GetPrimitiveImageColorValue(x*y, rgb);
// rgb.R=rgb.G=rgb.B=0;
arrClusterCenter.SetAt(i,rgb);
}
return true;
}
//聚类算法: K-平均值
//识别、更新显示
void CDlgClusterPatternRecog::OnButtonPrRecognize()
{
long i,j;
int nClass; //类别
long lNumber; //一类中的样本点数
int nTag;
int K=1; //当前迭代的步数
double RSS=MAXIMIZE_RSS; //误差平方和
tagRGBVal rgb;//当前颜色值
tagSumOfDistance sumrgb; //一类样本的和
long x,y,z;//计算误差平方和用
CString str;
// 显示等待光标
BeginWaitCursor();
for(K=1;K<=m_nIterativeNumber;K++)
{
if(RSS<=(double)m_nThreshold)
{
break;
}
//判断每个元素的所属类别
for(i=0;i<m_lImagePixelNumber;i++)
{
GetPrimitiveImageColorValue(i,rgb);
nClass=JudgeSampleClass(rgb);
//修改类别矩阵
for(j=0;j<m_nClassNumber;j++)
{
m_matrixClassTag.SetElement(i,j,0);
}
m_matrixClassTag.SetElement(i,nClass,1);
}
//绘制识别后的图象
//1:修改用于显示的图象
ModifyImageWithClassInfo();
//2:绘制新图
DrawRecognizedImage();
m_nCurrentIterate=K;
UpdateData(FALSE);
GetDlgItem(IDC_EDIT4)->SendMessage(WM_PAINT);
//修改聚类中心
//1: 保存上一步的聚类中心
for(i=0;i<m_nClassNumber;i++)
{
m_arrClusterCenterBackup[i]=m_arrClusterCenter[i];
}
//2: 计算新聚类中心
for(j=0;j<m_nClassNumber;j++)
{
sumrgb.X=0;sumrgb.Y=0;sumrgb.Z=0;
lNumber=1;
for(i=0;i<m_lImagePixelNumber;i++)
{
nTag=int(m_matrixClassTag.GetElement(i,j));
if(nTag==1)
{
GetPrimitiveImageColorValue(i,rgb);
sumrgb.X=sumrgb.X+(double)rgb.R;
sumrgb.Y=sumrgb.Y+(double)rgb.G;
sumrgb.Z=sumrgb.Z+(double)rgb.B;
lNumber++;
}
}
//计算中心
rgb.R=(BYTE)(sumrgb.X/lNumber);
rgb.G=(BYTE)(sumrgb.Y/lNumber);
rgb.B=(BYTE)(sumrgb.Z/lNumber);
m_arrClusterCenter[j]=rgb;
}
//更新坐标图中聚类中心的位置
DrawClusterCnterWhenUpdate();
//计算误差平方和
RSS=0;
for(j=0;j<m_nClassNumber;j++)
{
x=m_arrClusterCenter[j].R-m_arrClusterCenterBackup[j].R;
y=m_arrClusterCenter[j].G-m_arrClusterCenterBackup[j].G;
z=m_arrClusterCenter[j].B-m_arrClusterCenterBackup[j].B;
RSS=RSS+sqrt(pow(x,2)+pow(y,2)+pow(z,2));
}
} //主循环结束
//绘制坐标图中聚类中心的分类信息
DrawCCenterDisplayInfo();
if(K>=m_nIterativeNumber)
{
AfxMessageBox("循环到达上限,未收敛!");
}
if(RSS<=(double)m_nThreshold)
{
str.Format("迭代收敛! 迭代次数K=%d",K);
AfxMessageBox(str);
}
// 恢复正常光标
EndWaitCursor();
}
//从原始图象取得颜色值
void CDlgClusterPatternRecog::GetPrimitiveImageColorValue(long Index, tagRGBVal& rgb)
{
CImageSysZLF01App * lpCurrentApp=(CImageSysZLF01App *)AfxGetApp();
CImageSysZLF01Doc * pDoc=lpCurrentApp->GetCurDocument();
LPSTR lImagePrimitive=pDoc->m_pPrimitiveImage;
LPSTR lpDBitsData=FindDIBBits(lImagePrimitive);
LPSTR lpSrc=lpDBitsData+Index*3;
//注意读取得顺序! zlf 050329
rgb.B=(BYTE)*lpSrc;
rgb.G=(BYTE)*(lpSrc+1);
rgb.R=(BYTE)*(lpSrc+2);
// rgb.R=(BYTE)*lpSrc;
// rgb.G=(BYTE)*(lpSrc+1);
// rgb.B=(BYTE)*(lpSrc+2);
}
//判断样本的所属类别
int CDlgClusterPatternRecog::JudgeSampleClass(tagRGBVal rgb)
{
long Dis; //度量
double minDis;//最小度量
int i;
int ThisClass;
minDis=MAXIMIZE_DISTANCE;
for(i=0;i<m_nClassNumber;i++)
{
Dis=GetTwoSamplePointDistance(rgb,m_arrClusterCenter[i]);
if(Dis<minDis)
{
minDis=Dis;
ThisClass=i;
}
}
return ThisClass;
}
//得到两个样本点之间的距离
long CDlgClusterPatternRecog::GetTwoSamplePointDistance(tagRGBVal P1, tagRGBVal P2)
{
//欧氏距离
long x,y,z;
long Dis;
x=P1.R-P2.R;
y=P1.G-P2.G;
z=P1.B-P2.B;
Dis=(LONG)sqrt(pow(x,2)+pow(y,2)+pow(z,2));
return Dis;
}
//修改用于显示用的图象
void CDlgClusterPatternRecog::ModifyImageWithClassInfo()
{
tagRGBVal rgb;
int i,j;
int nTag;
//取得每个类的代表颜色
//这里取聚类中心的颜色
for(i=0;i<m_lImagePixelNumber;i++)
{
for(j=0;j<m_nClassNumber;j++)
{
nTag=int(m_matrixClassTag.GetElement(i,j));
if(nTag==1)
{
rgb=m_arrClusterCenter[j];
//用得到的颜色值修改
SetImageColorValue(i,rgb);
break;
}
}
}
}
void CDlgClusterPatternRecog::SetImageColorValue(long Index, tagRGBVal rgb)
{
LPSTR lpSrc=m_lImageData+Index*3;
//注意读取得顺序!
*lpSrc =rgb.B;
*(lpSrc+1)=rgb.G;
*(lpSrc+2)=rgb.R;
// *lpSrc =rgb.R;
// *(lpSrc+1)=rgb.G;
// *(lpSrc+2)=rgb.B;
}
//绘制识别后的图象
void CDlgClusterPatternRecog::DrawRecognizedImage()
{
CPaintDC dc(this); // device context for painting
CImageSysZLF01App * lpCurrentApp=(CImageSysZLF01App *)AfxGetApp();
CImageSysZLF01Doc * pDoc=lpCurrentApp->GetCurDocument();
ASSERT_VALID(pDoc);
// 获取DIB
HDIB hDIB = pDoc->GetHDIB();
// 判断DIB是否为空
// 判断DIB是否为空
if (hDIB != NULL)
{
//获取: DIB宽度,高度
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
int cxDIB = (int) ::DIBWidth(lpDIB);
int cyDIB = (int) ::DIBHeight(lpDIB);
::GlobalUnlock((HGLOBAL) hDIB);
CRect rcDIB=CRect(0,0,cxDIB,cyDIB);
::PaintDIB((HDC)dc.m_hDC, &m_rectImage, pDoc->GetHDIB(),&rcDIB, pDoc->GetDocPalette());
}
this->GetActiveWindow()->InvalidateRect(&m_rectImage,TRUE);
}
void CDlgClusterPatternRecog::OnButtonPrRestore()
{
// TODO: Add your control notification handler code here
CImageSysZLF01App * lpCurrentApp=(CImageSysZLF01App *)AfxGetApp();
CImageSysZLF01Doc * pDoc=lpCurrentApp->GetCurDocument();
pDoc->RestorePrimitiveImage();
//绘制原图像
DrawRecognizedImage();
}
//绘制数据点
void CDlgClusterPatternRecog::DrawDataPoint(CDC *pDC, int nWhichNoUse)
{
int NN=5; //数据间隔
CImageSysZLF01App * lpCurrentApp=(CImageSysZLF01App *)AfxGetApp();
CImageSysZLF01Doc * pDoc=lpCurrentApp->GetCurDocument();
LPSTR lpBitsData=::FindDIBBits(pDoc->GetDIBPtr(pDoc->GetHDIB()));
// 创建画笔对象_红色
CPen* pPenRed = new CPen;
pPenRed->CreatePen(PS_SOLID,2,RGB(0,0,255));
// 选中当前红色画笔,并保存以前的画笔
CGdiObject* pOldPen = pDC->SelectObject(pPenRed);
//绘制坐标点
BYTE xv,yv;
int i;
int X0,Y0;
X0=m_ptFigureXY0.x;
Y0=m_ptFigureXY0.y;
pDC->SelectObject(pPenRed);
switch (nWhichNoUse)
{
case COLOR_RED:
for(i=0;i<m_nImageShowHeight*m_nImageShowWidth;i=i+3*NN) //这里的3表示当前图像为24位真彩!!!
{
xv=*(lpBitsData+i +COLOR_GREEN); //Green
yv=*(lpBitsData+i +COLOR_BLUE); //Blue
pDC->MoveTo(X0+xv,Y0-yv);
pDC->LineTo(X0+xv,Y0-yv);
}
break;
case COLOR_GREEN:
for(i=0;i<m_nImageShowHeight*m_nImageShowWidth;i=i+3*NN)
{
xv=*(lpBitsData+i +COLOR_RED); //Red
yv=*(lpBitsData+i +COLOR_BLUE); //Blue
pDC->MoveTo(X0+xv,Y0-yv);
pDC->LineTo(X0+xv,Y0-yv);
}
break;
case COLOR_BLUE:
for(i=0;i<m_nImageShowHeight*m_nImageShowWidth;i=i+3*NN)
{
xv=*(lpBitsData+i +COLOR_RED); //Red
yv=*(lpBitsData+i +COLOR_GREEN); //Green
pDC->MoveTo(X0+xv,Y0-yv);
pDC->LineTo(X0+xv,Y0-yv);
}
}
// 恢复以前的画笔
pDC->SelectObject(pOldPen);
// 删除新的画笔
delete pPenRed;
}
//绘制聚类中心的移动轨迹
void CDlgClusterPatternRecog::DrawClusterCnterWhenUpdate()
{
CPen* pPen = new CPen;
// CPen* pOldPen= new CPen;
// pDC->SelectObject(pOldPen);
tagRGBVal rgbpre,rgbthis;//前一次迭代中心,后一次迭代中心
BYTE xv,yv;
int X0,Y0;
X0=m_ptFigureXY0.x;
Y0=m_ptFigureXY0.y;
CDC* pDC=m_lpTabDC;
for(int i=0;i<m_nClassNumber;i++)
{
rgbpre=m_arrClusterCenterBackup[i];
rgbthis=m_arrClusterCenter[i];
pPen->CreatePen(PS_SOLID,2,RGB(m_arrCenterColor[i].R,m_arrCenterColor[i].G,m_arrCenterColor[i].B));
pDC->SelectObject(pPen);
switch (m_nWhichColorNoUse)
{
case COLOR_RED:
xv=rgbpre.G; //Green
yv=rgbpre.B; //Blue
pDC->MoveTo(X0+xv,Y0-yv);
xv=rgbthis.G; //Green
yv=rgbthis.B; //Blue
pDC->LineTo(X0+xv,Y0-yv);
break;
case COLOR_GREEN:
xv=rgbpre.R; //Green
yv=rgbpre.B; //Blue
pDC->MoveTo(X0+xv,Y0-yv);
xv=rgbthis.R; //Green
yv=rgbthis.B; //Blue
pDC->LineTo(X0+xv,Y0-yv);
break;
case COLOR_BLUE:
xv=rgbpre.R; //Green
yv=rgbpre.G; //Blue
pDC->MoveTo(X0+xv,Y0-yv);
xv=rgbthis.R; //Green
yv=rgbthis.G; //Blue
pDC->LineTo(X0+xv,Y0-yv);
}//END SWITCH
pPen->DeleteObject();
}
delete pPen;
}
//绘制坐标图中聚类中心的分类信息
void CDlgClusterPatternRecog::DrawCCenterDisplayInfo()
{
tagRGBVal rgbthis;
BYTE xv,yv;
int X0,Y0;
CString str;
X0=m_ptFigureXY0.x;
Y0=m_ptFigureXY0.y;
CDC* pDC=m_lpTabDC;
for(int i=0;i<m_nClassNumber;i++)
{
rgbthis=m_arrClusterCenter[i];
switch (m_nWhichColorNoUse)
{
case COLOR_RED:
xv=rgbthis.G; //Green
yv=rgbthis.B; //Blue
str.Format("%d",i+1);
pDC->TextOut(X0+xv,Y0-yv,str);
break;
case COLOR_GREEN:
xv=rgbthis.G;
yv=rgbthis.B;
str.Format("%d",i+1);
pDC->TextOut(X0+xv,Y0-yv,str);
break;
case COLOR_BLUE:
xv=rgbthis.G;
yv=rgbthis.B;
str.Format("%d",i+1);
pDC->TextOut(X0+xv,Y0-yv,str);
}//end switch
}
}
void CDlgClusterPatternRecog::OnRadioRandom()
{
// TODO: Add your control notification handler code here
if(m_lCenterInitialMethod==CLUSTERING_INITIAL_CENTER_RANDOM)
return;
m_lCenterInitialMethod=CLUSTERING_INITIAL_CENTER_RANDOM;
((CButton*)GetDlgItem(IDC_BUTTON_PR_RECOGNIZE))->EnableWindow(FALSE);
}
void CDlgClusterPatternRecog::OnRadioSequent()
{
// TODO: Add your control notification handler code here
if(m_lCenterInitialMethod==CLUSTERING_INITIAL_CENTER_SEQUENT)
return;
m_lCenterInitialMethod=CLUSTERING_INITIAL_CENTER_SEQUENT;
((CButton*)GetDlgItem(IDC_BUTTON_PR_RECOGNIZE))->EnableWindow(FALSE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -