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

📄 imageview.cpp

📁 K均值聚类算法 C++实现的K均值聚类算法。
💻 CPP
字号:
// ImageView.cpp : implementation of the CImageView class
//

#include "stdafx.h"
#include "DERSImg.h"
#include "Kmean.h"
#include "ImageDoc.h"
#include "ImageView.h"
#include "MainFrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CImageView

IMPLEMENT_DYNCREATE(CImageView, CScrollView)

BEGIN_MESSAGE_MAP(CImageView, CScrollView)
	//{{AFX_MSG_MAP(CImageView)
	ON_COMMAND(ID_KMEAN, OnKmean)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CImageView construction/destruction

CImageView::CImageView()
{
	m_fRatio.x = 1.0;
	m_fRatio.y = 1.0;
}

CImageView::~CImageView()
{
}

BOOL CImageView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CImageView drawing

void CImageView::OnDraw(CDC* pDC)
{
	CImageDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here	
	HDIB hDIB = pDoc->m_pDib->GetHandle();
	if (hDIB != NULL)
	{
		//锁定DIB
		LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
		//指向DIB象素指针
		LPSTR lpDIBBits = ::FindDIBBits(lpDIB);
		//原图象信息头结构
		BITMAPINFO* lpbmi = (BITMAPINFO*)lpDIB;
		
		//原图的长和宽
		int cxDIB = (int) ::DIBWidth(lpDIB);         // Size of DIB - x
		int cyDIB = (int) ::DIBHeight(lpDIB);        // Size of DIB - y
		
		//解除锁定
		::GlobalUnlock((HGLOBAL) hDIB);
		
		//设定显示矩形区域的大小
		CRect rcDIB;
		rcDIB.top = rcDIB.left = 0;
		rcDIB.right = cxDIB;
		rcDIB.bottom = cyDIB;
		CRect rcDest;
		if (pDC->IsPrinting())   // printer DC
		{
			// get size of printer page (in pixels)
			int cxPage = pDC->GetDeviceCaps(HORZRES);
			int cyPage = pDC->GetDeviceCaps(VERTRES);
			// get printer pixels per inch
			int cxInch = pDC->GetDeviceCaps(LOGPIXELSX);
			int cyInch = pDC->GetDeviceCaps(LOGPIXELSY);
			
			//
			// Best Fit case -- create a rectangle which preserves
			// the DIB's aspect ratio, and fills the page horizontally.
			//
			// The formula in the "->bottom" field below calculates the Y
			// position of the printed bitmap, based on the size of the
			// bitmap, the width of the page, and the relative size of
			// a printed pixel (cyInch / cxInch).
			//
			rcDest.top = rcDest.left = 0;
			rcDest.bottom = (int)(((double)cyDIB * cxPage * cyInch)
				/ ((double)cxDIB * cxInch));
			rcDest.right = cxPage;
		}
		else   // not printer DC
		{
			rcDest.top = rcDest.left = 0;
			rcDest.bottom = (LONG)(m_fRatio.x*rcDIB.bottom);
			rcDest.right  = (LONG)(m_fRatio.y*rcDIB.right);		
		}
		CSize sizeTotal(rcDest.right,
			rcDest.bottom);	
		SetScrollSizes(MM_TEXT, sizeTotal);
		::PaintDIB(pDC->m_hDC, &rcDest, pDoc->m_pDib->GetHandle(),
			&rcDIB, pDoc->m_pDib->GetPalette());	
	}
}

void CImageView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
	CImageDoc* pDoc = GetDocument();
	
	CSize sizeTotal(pDoc->m_pDib->GetWidth(),pDoc->m_pDib->GetHeight());
	SetScrollSizes(MM_TEXT,sizeTotal);
	
	CMainFrame* pAppFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
	ASSERT_KINDOF(CMainFrame,pAppFrame);
	CRect rect;
	pAppFrame->GetClientRect(&rect);
	if(rect.Width() >= sizeTotal.cx && rect.Height() >= sizeTotal.cy &&
		sizeTotal.cx > 0 || sizeTotal.cy > 0)
		ResizeParentToFit(FALSE);
}

/////////////////////////////////////////////////////////////////////////////
// CImageView printing

BOOL CImageView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CImageView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CImageView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CImageView diagnostics

#ifdef _DEBUG
void CImageView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CImageView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CImageDoc* CImageView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CImageDoc)));
	return (CImageDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CImageView message handlers

void CImageView::OnRealizePal(WPARAM wParam, LPARAM lParam)
{
	ASSERT(wParam != NULL);
	CImageDoc* pDoc = GetDocument();
	
	if(pDoc->m_pDib->IsEmpty())
		return;
	
	CPalette* pPal = pDoc->m_pDib->GetPalette();
	if(pPal != NULL)
	{
		CWnd* pAppFrame = AfxGetApp()->m_pMainWnd;
		
		CClientDC appDC(pAppFrame);
		//All views but one should be a backgroud palette.
		//wParam contains a handle to the active view,so the selectPalette
		//bForceBackground flag is FALSE only if wParam == m_hWnd(this view)
		CPalette* oldPalette = appDC.SelectPalette(pPal,((HWND)wParam) != m_hWnd);
		
		if(oldPalette != NULL)
		{
			UINT  nColorsChanged = appDC.RealizePalette();
			if(nColorsChanged >0)
				GetDocument()->UpdateAllViews(NULL);
			appDC.SelectPalette(oldPalette,TRUE);
		}
		else
		{
			TRACE0("\tSelectPalette failed!\n");
		}
	}
	
}



void CImageView::OnKmean() 
{
	// TODO: Add your command handler code here
	CString strSource = _T("");
	CString strResult = _T("");
	int N=1;
	//获取参数
	CKMEAN dlg;
	if (dlg.DoModal() == IDOK)
	{
		strSource = dlg.m_in;
		strResult = dlg.m_out;
		N = dlg.m_class;
	}

	//打开源影像文件
	HANDLE hSource = CreateFile(strSource,GENERIC_READ,
								FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,
								OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (hSource == INVALID_HANDLE_VALUE)
	{
		AfxMessageBox("Failed to open the result file!");
		return;
	}

	//读取源影像的文件头
	DWORD dwRead = 0;
	BITMAPFILEHEADER bmfH;
	ReadFile(hSource,&bmfH,sizeof(BITMAPFILEHEADER),&dwRead,NULL);
	if (dwRead != sizeof(BITMAPFILEHEADER))
		return;
	if (bmfH.bfType != 0x4d42) // 'BM'
		return;

	//读取源影像的信息头并获取相关影像信息
	BITMAPINFOHEADER bmiH;
	ReadFile(hSource,&bmiH,sizeof(BITMAPINFOHEADER),&dwRead,NULL);
	if (dwRead != sizeof(BITMAPINFOHEADER))
		return;
	int nHeight = bmiH.biHeight; //影像高度
	int nWidth = bmiH.biWidth;   //影像宽度
	int nLineW = WIDTHBYTES(nWidth*bmiH.biPlanes*bmiH.biBitCount); //影像行宽度
	
	//开辟临时内存
	int nBlkSize = nHeight*nLineW;
	BYTE* pData = new BYTE[nHeight*nLineW];
	if (pData == NULL)
		return;

	//读取影像数据到临时开辟的内存中
	SetFilePointer(hSource,bmfH.bfOffBits,NULL,FILE_BEGIN);   //移动文件指针到数据块区
	ReadFile(hSource,pData,nBlkSize,&dwRead,NULL);
	if (dwRead != (DWORD)nBlkSize)
		return;
//--------------------调用分类函数--------------------------------------------
	if (!Kmean(pData,bmiH.biBitCount,nHeight,nWidth,nLineW,N))
		return;
//------------------------------------------------------------------------------
	//写结果影像
	BYTE* pInfo = new BYTE[bmfH.bfOffBits];
	if (pInfo == NULL)
		return;
	SetFilePointer(hSource,0,NULL,FILE_BEGIN);
	ReadFile(hSource,pInfo,bmfH.bfOffBits,&dwRead,NULL);
	if (dwRead != bmfH.bfOffBits)
		return;	

	HANDLE hResult = ::CreateFile(strResult,GENERIC_READ|GENERIC_WRITE,
		FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,NULL);
	if (hResult == INVALID_HANDLE_VALUE)
	{
		AfxMessageBox("Failed to create the result file!");
		return;
	}
	DWORD dwWrite = 0;
	//写文件信息
	WriteFile(hResult,pInfo,bmfH.bfOffBits,&dwWrite,NULL);
	if (dwWrite != bmfH.bfOffBits)
		return;
	//写文件数据
	WriteFile(hResult,pData,nBlkSize,&dwWrite,NULL);
	if (dwWrite != (DWORD)nBlkSize)
		return;

	//删除临时开辟的内存
	delete[] pData;
	pData = NULL;
	delete[] pInfo;
	pInfo = NULL;
	
	//关闭文件句柄
	CloseHandle(hSource);
	CloseHandle(hResult);

}

BOOL CImageView::Kmean(BYTE *pData, int nCount, int nHeight, int nWidth, int nLineW, int nClass)
{

	if(nCount!=24)
	{
		MessageBox("非24位色位图,请从新选择彩色图象!");
		return false;
	}


	//--颜色表------------------------------------------
	MYRGBQUAD COLORTAB[10]; 
	COLORTAB[0].rgbBlue=0;     COLORTAB[0].rgbRed=255;   COLORTAB[0].rgbGreen=0;  
	COLORTAB[1].rgbBlue=255;   COLORTAB[1].rgbRed=0;     COLORTAB[1].rgbGreen=0;  
	COLORTAB[2].rgbBlue=0;     COLORTAB[2].rgbRed=0;     COLORTAB[2].rgbGreen=255;  
	COLORTAB[3].rgbBlue=255;   COLORTAB[3].rgbRed=255;   COLORTAB[3].rgbGreen=0;  
	COLORTAB[4].rgbBlue=255;   COLORTAB[4].rgbRed=0;     COLORTAB[4].rgbGreen=255;  
	COLORTAB[5].rgbBlue=0;     COLORTAB[5].rgbRed=255;   COLORTAB[5].rgbGreen=255;  
	COLORTAB[6].rgbBlue=0;     COLORTAB[6].rgbRed=0;     COLORTAB[6].rgbGreen=0;  
	COLORTAB[7].rgbBlue=127;   COLORTAB[7].rgbRed=127;   COLORTAB[7].rgbGreen=127;  
	COLORTAB[8].rgbBlue=56;    COLORTAB[8].rgbRed=126;   COLORTAB[8].rgbGreen=200;   
	COLORTAB[8].rgbBlue=255;    COLORTAB[8].rgbRed=255;   COLORTAB[8].rgbGreen=255;  



	//---------------------------------------------
	//转换指针类型
	MYRGBQUAD* allData=(MYRGBQUAD*) pData;

	int N=nClass;
	//----聚类中心
	MYRGBQUAD* cc=new MYRGBQUAD[N];//分N类

	//初始化
	for(long w=0;w<N;w++)
	{
//		cc[w].rgbBlue=w*256/N+128/N;//(均匀的灰度)
//		cc[w].rgbGreen=w*256/N+128/N;
//		cc[w].rgbRed=w*256/N+128/N;
		cc[w].rgbBlue=COLORTAB[w].rgbBlue;
		cc[w].rgbGreen=COLORTAB[w].rgbGreen;
		cc[w].rgbRed=COLORTAB[w].rgbRed;
	}

	//为每个类别开辟储存空间和计数变量
	MYCLASS* Classpace=new MYCLASS[N];
	count=0;


	//每类的象素数
	long* c=new long[N];
	CImageView::Digui(allData,nHeight*nWidth,cc,Classpace,N,c);

    //为每类赋色彩
	for(int i=0;i<N;i++)
	{
		for(w=0;w<c[i];w++)
		{
		/*	//用最接近每类的颜色代替
			allData[(Classpace[i].data[w])].rgbBlue=cc[i].rgbBlue;
			allData[(Classpace[i].data[w])].rgbRed=cc[i].rgbRed;
			allData[(Classpace[i].data[w])].rgbGreen=cc[i].rgbGreen;
		*/	//用色彩表中颜色代替
			allData[(Classpace[i].data[w])].rgbBlue=COLORTAB[i].rgbBlue;
			allData[(Classpace[i].data[w])].rgbRed=COLORTAB[i].rgbRed;
			allData[(Classpace[i].data[w])].rgbGreen=COLORTAB[i].rgbGreen;
		}
	}






	return TRUE;

}

void CImageView::Digui(MYRGBQUAD *allData, long ca, MYRGBQUAD *cc, MYCLASS *Classpace, int n,long* c)
{
	count++;//记次

	for(int j=0;j<n;j++)
		c[j]=0;
	//计算到中心距离,并分类
	long min;
	for(long i=0;i<ca;i++)
	{
		min=99999999;
		for(j=0;j<n;j++)
		{
			if(min>((allData[i].rgbBlue-cc[j].rgbBlue)*(allData[i].rgbBlue-cc[j].rgbBlue)+(allData[i].rgbGreen-cc[j].rgbGreen)*(allData[i].rgbGreen-cc[j].rgbGreen)+(allData[i].rgbRed-cc[j].rgbRed)*(allData[i].rgbRed-cc[j].rgbRed)))
			{
				min=((allData[i].rgbBlue-cc[j].rgbBlue)*(allData[i].rgbBlue-cc[j].rgbBlue)+(allData[i].rgbGreen-cc[j].rgbGreen)*(allData[i].rgbGreen-cc[j].rgbGreen)+(allData[i].rgbRed-cc[j].rgbRed)*(allData[i].rgbRed-cc[j].rgbRed));
				Classpace[j].data[(c[j])]=i;
				c[j]++;
			}
		}


	}




	//重新计算重心
	bool nflag;//用来标记是否收敛,true为收敛
	MYRGBQUAD* dd=new MYRGBQUAD[n];//复制原聚类中心
	float ARR=0.8f;//确定收敛的范围
	for(j=0;j<n;j++)
	{
		dd[j].rgbRed=cc[j].rgbRed;
		dd[j].rgbGreen=cc[j].rgbGreen;
		dd[j].rgbBlue=cc[j].rgbBlue;
	}

	long r,g,b;
	long ttt=0;
	nflag=true;
	for(j=0;j<n;j++)
	{
		r=0,g=0,b=0;
		for(i=0;i<c[j];i++)
		{
			ttt=Classpace[j].data[(i)];
			r=r+allData[ttt].rgbRed;
			g=g+allData[ttt].rgbGreen;
			b=b+allData[ttt].rgbBlue;	
		}

		cc[j].rgbRed=(unsigned char)(r/c[j]);
		cc[j].rgbGreen=(unsigned char)(g/c[j]);
		cc[j].rgbBlue=(unsigned char)(b/c[j]);
//判断
		if((cc[j].rgbBlue>ARR*dd[j].rgbBlue||cc[j].rgbBlue<dd[j].rgbBlue/ARR)||
			(cc[j].rgbRed>ARR*dd[j].rgbRed||cc[j].rgbRed<dd[j].rgbRed/ARR)||
			(cc[j].rgbGreen>ARR*dd[j].rgbGreen||cc[j].rgbGreen<dd[j].rgbGreen/ARR))
			nflag=false;


	}


//跌代或终止
//	if(false)
//	if(count<3)
	if((!nflag)&&(count<20))
		CImageView::Digui(allData,ca,cc,Classpace,n,c);
	else
		return;



}

⌨️ 快捷键说明

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