📄 imageview.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 + -