www.pudn.com > VC20070605zghLPR.rar > PlateRecoView.cpp


// PlateRecoView.cpp : implementation of the CPlateRecoView class 
// 
 
#include "stdafx.h" 
#include "PlateReco.h" 
#include "MainFrm.h" 
#include "DlgRecoResult.h" 
 
#include "PlateRecoDoc.h" 
#include "PlateRecoView.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView 
 
IMPLEMENT_DYNCREATE(CPlateRecoView, CView) 
 
BEGIN_MESSAGE_MAP(CPlateRecoView, CView) 
	//{{AFX_MSG_MAP(CPlateRecoView) 
	ON_COMMAND(ID_LPR_platelocation, OnLPRplatelocation) 
	ON_COMMAND(ID_LPR_plate2binarycolor, OnLPRplate2binarycolor) 
	ON_COMMAND(ID_LPR_platenorm, OnLPRplatenorm) 
	ON_COMMAND(ID_LPR_platecharthinning, OnLPRplatecharthinning) 
	ON_COMMAND(ID_LPR_feature16seg, OnLPRfeature16seg) 
	ON_COMMAND(ID_LPR_platereco, OnLPRplatereco) 
	ON_COMMAND(ID_LPR_platepreprocessall, OnLPRplatepreprocessall) 
	//}}AFX_MSG_MAP 
	// Standard printing commands 
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) 
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) 
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView construction/destruction 
 
CPlateRecoView::CPlateRecoView() 
{ 
	// TODO: add construction code here 
	for(int i = 0; i < 13; i++) 
	{ 
		m_fCode13Sect[i] = 0.0; 
	} 
 
	for(int j = 0; j < 16; j++) 
	{ 
		m_fCode13Sect[j] = 0.0; 
	} 
	m_iPlateType = 0; 
} 
 
CPlateRecoView::~CPlateRecoView() 
{ 
} 
 
BOOL CPlateRecoView::PreCreateWindow(CREATESTRUCT& cs) 
{ 
	// TODO: Modify the Window class or styles here by modifying 
	//  the CREATESTRUCT cs 
 
	return CView::PreCreateWindow(cs); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView drawing 
 
void CPlateRecoView::OnDraw(CDC* pDC) 
{ 
	// 显示等待光标 
	BeginWaitCursor(); 
	 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	ASSERT_VALID(pDoc); 
	 
	// 获取DIB 
	HDIB hDIB = pDoc->GetHDIB(); 
	 
	// 判断DIB是否为空 
	if (hDIB != NULL) 
	{ 
		LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); 
		 
		// 获取DIB宽度 
		int cxDIB = (int) ::DIBWidth(lpDIB); 
		 
		// 获取DIB高度 
		int cyDIB = (int) ::DIBHeight(lpDIB); 
 
		::GlobalUnlock((HGLOBAL) hDIB); 
		 
		CRect rcDIB; 
		rcDIB.top = rcDIB.left = 0; 
		rcDIB.right = cxDIB; 
		rcDIB.bottom = cyDIB; 
		 
		CRect rcDest; 
		 
		// 判断是否是打印 
		if (pDC->IsPrinting()) 
		{ 
			// 是打印,计算输出图像的位置和大小,以便符合页面 
			 
			// 获取打印页面的水平宽度(象素) 
			int cxPage = pDC->GetDeviceCaps(HORZRES); 
			 
			// 获取打印页面的垂直高度(象素) 
			int cyPage = pDC->GetDeviceCaps(VERTRES); 
			 
			// 获取打印机每英寸象素数 
			int cxInch = pDC->GetDeviceCaps(LOGPIXELSX); 
			int cyInch = pDC->GetDeviceCaps(LOGPIXELSY); 
			 
			// 计算打印图像大小(缩放,根据页面宽度调整图像大小) 
			rcDest.top = rcDest.left = 0; 
			rcDest.bottom = (int)(((double)cyDIB * cxPage * cyInch) 
					/ ((double)cxDIB * cxInch)); 
			rcDest.right = cxPage; 
			 
			// 计算打印图像位置(垂直居中) 
			int temp = cyPage - (rcDest.bottom - rcDest.top); 
			rcDest.bottom += temp/2; 
			rcDest.top += temp/2; 
 
		} 
		else    
		// 非打印 
		{ 
			// 不必缩放图像 
			rcDest = rcDIB; 
		} 
		 
		// 输出DIB 
		::PaintDIB(pDC->m_hDC, &rcDest, pDoc->GetHDIB(), 
			&rcDIB, pDoc->GetDocPalette()); 
	} 
 
	CSize sizeTotal(1200,900); 
	SetScrollSizes(MM_TEXT, sizeTotal); 
 
	// 恢复正常光标 
	EndWaitCursor(); 
} 
void CPlateRecoView::OnInitialUpdate() 
{ 
	CScrollView::OnInitialUpdate(); 
 
	CSize sizeTotal; 
	// TODO: calculate the total size of this view 
	sizeTotal.cx =1200; 
	sizeTotal.cy =900; 
	SetScrollSizes(MM_TEXT, sizeTotal); 
 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
 
	// 指向DIB的指针 
	LPSTR lpDIB; 
	 
	// 锁定DIB 
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); 
 
	// 保存原图像大小 
	m_iWidth = ::DIBWidth(lpDIB); 
	m_iHeight = ::DIBHeight(lpDIB); 
 
/* 
	CScrollView::OnInitialUpdate(); 
 
 
	CSize sizeTotal(1000,600);//::DIBWidth(lpDIB), ::DIBHeight(lpDIB)); 
	SetScrollSizes(MM_TEXT, sizeTotal); 
	 
	CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd; 
	ASSERT_KINDOF(CMainFrame, pAppFrame); 
	CRect rc; 
	pAppFrame->GetClientRect(&rc); 
	if (rc.Width() >= sizeTotal.cx && rc.Height() >= sizeTotal.cy && 
		(sizeTotal.cx>0 || sizeTotal.cy>0)) 
		ResizeParentToFit(FALSE); 
*/ 
} 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView printing 
 
BOOL CPlateRecoView::OnPreparePrinting(CPrintInfo* pInfo) 
{ 
	// 设置总页数为一。 
	pInfo->SetMaxPage(1); 
	 
	// default preparation 
	return DoPreparePrinting(pInfo); 
} 
 
 
void CPlateRecoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) 
{ 
	// TODO: add extra initialization before printing 
} 
 
void CPlateRecoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) 
{ 
	// TODO: add cleanup after printing 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView diagnostics 
 
#ifdef _DEBUG 
void CPlateRecoView::AssertValid() const 
{ 
	CView::AssertValid(); 
} 
 
void CPlateRecoView::Dump(CDumpContext& dc) const 
{ 
	CView::Dump(dc); 
} 
 
CPlateRecoDoc* CPlateRecoView::GetDocument() // non-debug version is inline 
{ 
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPlateRecoDoc))); 
	return (CPlateRecoDoc*)m_pDocument; 
} 
#endif //_DEBUG 
 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView message handlers 
 
LRESULT CPlateRecoView::OnDoRealize(WPARAM wParam, LPARAM) 
{ 
	ASSERT(wParam != NULL); 
 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	 
	// 判断DIB是否为空 
	if (pDoc->GetHDIB() == NULL) 
	{ 
		// 直接返回 
		return 0L; 
	} 
	 
	// 获取Palette 
	CPalette* pPal = pDoc->GetDocPalette(); 
	if (pPal != NULL) 
	{ 
		// 获取MainFrame 
		CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd; 
		ASSERT_KINDOF(CMainFrame, pAppFrame); 
		 
		CClientDC appDC(pAppFrame); 
 
		// All views but one should be a background 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) 
				pDoc->UpdateAllViews(NULL); 
			appDC.SelectPalette(oldPalette, TRUE); 
		} 
		else 
		{ 
			TRACE0("\tCCh1_1View::OnPaletteChanged中调用SelectPalette()失败!\n"); 
		} 
	} 
	 
	return 0L; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CPlateRecoView message handlers 
 
void CPlateRecoView::OnLPRplatelocation()  
{ 
	// TODO: Add your command handler code here 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	 
	// 指向DIB的指针 
	LPSTR	lpDIB; 
 
	// 指向DIB象素指针 
	LPSTR   lpDIBBits; 
	 
	// 锁定DIB 
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); 
	 
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的边缘检测,其它的可以类推) 
	if (::DIBNumColors(lpDIB) != 256) 
	{ 
		// 提示用户 
		MessageBox("目前只支持256色位图的运算!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
 
		// 解除锁定 
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
		 
		// 返回 
		return; 
	} 
 
	// 找到DIB图像象素起始位置 
	lpDIBBits = ::FindDIBBits(lpDIB); 
 
	// 指向缓存图像的指针 
	LPSTR	lpDst1; 
	LPSTR	lpDst2; 
	 
	// 指向缓存DIB图像的指针 
	LPSTR	lpNewDIBBits1; 
	HLOCAL	hNewDIBBits1; 
	LPSTR	lpNewDIBBits2; 
	HLOCAL	hNewDIBBits2; 
 
	int *pPlateLine1,*pPlateLine2; 
 
	// 获取车牌位置信息 
	int *pPlatePosition; 
 
 
	//循环变量 
	long i; 
	long j; 
 
	for(i=0;i<40;i++) 
		m_iPlateLine[i]=0; 
 
	// 指向源图像象素的指针 
    unsigned char * lpSrc; 
	// 阈值 
	BYTE	bThre; 
	// 各个灰度值的计数 
	LONG lCount[256]; 
 
	int temp1,temp2,iOldLeixin1,iOldLeixin2,iNum1,iNum2,iGrayCore1,iGrayCore2,iMeanGray; 
 
	// 参数对话框 
	//CDlgBinary  myDlgBinary; 
 
 
	// 暂时分配内存,以保存新图像 
	hNewDIBBits1 = LocalAlloc(LHND, m_iWidth * m_iHeight); 
 
	if (hNewDIBBits1 == NULL) 
	{ 
		// 分配内存失败 
		return; 
	} 
	 
	// 锁定内存 
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); 
 
	// 暂时分配内存,以保存新图像 
	hNewDIBBits2 = LocalAlloc(LHND, m_iWidth * m_iHeight); 
 
	if (hNewDIBBits2 == NULL) 
	{ 
		// 分配内存失败 
		return; 
	} 
	 
	// 锁定内存 
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); 
	 
    // 拷贝源图像到缓存图像中 
	lpDst1 = (char *)lpNewDIBBits1; 
	memcpy(lpNewDIBBits1, lpDIBBits, m_iWidth * m_iHeight); 
	lpDst2 = (char *)lpNewDIBBits2; 
	memcpy(lpNewDIBBits2, lpDIBBits,  m_iWidth * m_iHeight); 
	// 复制经过模板运算后的图像到源图像 
//	memcpy(lpDIBBits, lpNewDIBBits1,  m_iWidth * m_iHeight); 
 
	// 更改光标形状 
	BeginWaitCursor(); 
 
////////////////////////////////////////////////////////	 
	// 水平差分 
	if (DifferDIB(lpDIBBits, WIDTHBYTES(::DIBWidth(lpDIB) * 8), ::DIBHeight(lpDIB))) 
	{ 
		 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
 
		// 更新视图 
		pDoc->UpdateAllViews(NULL); 
	} 
	else 
	{ 
		// 提示用户 
		MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
	} 
 
//////////////////////////////////////////////////////// 
	// 调用HprojectDIB()函数对DIB进行水平投影 
	if (pPlateLine1 = HDifferProjDIB4(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB))) 
	{ 
		for(int i=0;i<40;i++) 
		{ 
			m_iPlateLine[i]=*pPlateLine1; 
			pPlateLine1++; 
		} 
		 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
 
		// 更新视图 
		pDoc->UpdateAllViews(NULL); 
	} 
	else 
	{ 
		// 提示用户 
		MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
	} 
 
//////////////////////////////////////////////////////// 
	int iLineNumber=0; 
	for(iLineNumber=0;iLineNumber<40;iLineNumber++) 
	{ 
	//////////////////////////////////////////////////////// 
		// 复制原图象 
		memcpy(lpDIBBits, lpNewDIBBits1,  m_iWidth * m_iHeight); 
 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
 
		// 更新视图 
		pDoc->UpdateAllViews(NULL); 
 
//		AfxMessageBox("又一次"); 
 
	//////////////////////////////////////////////////////// 
        // 边缘检测 
		pPlateLine2 = &m_iPlateLine[iLineNumber]; 
		// 调用SobelDIB()函数对DIB进行边缘检测 
		if (PlateDIB1(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB),pPlateLine2)) 
		{ 
			 
			// 设置脏标记 
			pDoc->SetModifiedFlag(TRUE); 
 
			// 更新视图 
			pDoc->UpdateAllViews(NULL); 
		} 
		else 
		{ 
			// 提示用户 
			MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
		} 
 
	//////////////////////////////////////////////////////// 
		// 二值化 
 
		// 重置计数为0 
		for (i = 0; i < 256; i ++) 
		{ 
			// 清零 
			lCount[i] = 0; 
		} 
		 
		// 图像每行的字节数 
		LONG lLineBytes; 
		 
		// 计算图像每行的字节数 
		lLineBytes = WIDTHBYTES(m_iWidth * 8); 
		 
		// 计算各个灰度值的计数 
		for (i = 0; i < m_iHeight; i ++) 
		{ 
			for (j = 0; j < m_iWidth; j ++) 
			{ 
				lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; 
				 
				// 计数加1 
				lCount[*(lpSrc)]++; 
			} 
		} 
 
		// 计算平均灰度值 
		iMeanGray = 0; 
		for(i = 1; i < 255; i++) 
		{ 
			iMeanGray += i * lCount[i]; 
		} 
		iMeanGray = (int)iMeanGray / (m_iHeight * m_iWidth); 
 
		// 初始的类心,可任意设定 
		iGrayCore1 = (int)(iMeanGray/2); 
		iGrayCore2 = (int)(iMeanGray+(255-iMeanGray)/2); 
 
 
 
		do  // K-均值聚类分析 
		{ 
			iNum1 = 0; 
			iNum2 = 0; 
			temp1 = 0; 
			temp2 = 0; 
			iOldLeixin1 = iGrayCore1; 
			iOldLeixin2 = iGrayCore2; 
 
			for(i = 0; i < m_iHeight; i++) 
			{ 
				for(j = 0; j < m_iWidth; j++) 
				{ 
					lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; 
					if(abs(iGrayCore1-*lpSrc)<=abs(iGrayCore2-*lpSrc)) 
					{ 
						temp1 += *lpSrc; 
						iNum1++; 
					} 
					else 
					{ 
						temp2 += *lpSrc; 
						iNum2++; 
					} 
				} 
			} 
			iGrayCore1 = (int)(temp1/iNum1); 
			iGrayCore2 = (int)(temp2/iNum2); 
		}while((iGrayCore1!=iOldLeixin1)||(iGrayCore2!=iOldLeixin2)); 
			 
 
		 
		bThre  = iGrayCore2+30; 
		 
		// 删除对话框 
	//	delete myDlgBinary;	 
		 
		// 更改光标形状 
		BeginWaitCursor(); 
		 
		// 调用ThresholdTrans()函数进行阈值变换 
		ThresholdTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bThre); 
		 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
		 
		// 更新视图 
		pDoc->UpdateAllViews(NULL); 
 
	/////////////////////////////////////////////////////// 
		// 提取车牌 
		// 缩放后图像的宽度和高度 
		LONG	lNewWidth = 140; 
		LONG	lNewHeight = 40; 
		 
		// 缩放后图像的宽度(lNewWidth',必须是4的倍数) 
		LONG	lNewLineBytes; 
				 
		// 创建新DIB 
		HDIB hNewDIB = NULL; 
			 
		// 指向缩放图像的指针 
		LPSTR	lpNewDIB ; 
		 
		// 指向BITMAPINFO结构的指针(Win3.0) 
		LPBITMAPINFOHEADER lpbmi; 
		 
		// 指向BITMAPCOREINFO结构的指针 
		LPBITMAPCOREHEADER lpbmc; 
		 
		// 计算新图像每行的字节数 
		lNewLineBytes = WIDTHBYTES(lNewWidth * 8); 
		 
		// 更改光标形状 
		BeginWaitCursor(); 
 
		// 找到DIB图像象素起始位置 
		lpDIBBits = ::FindDIBBits(lpDIB); 
 
		pPlatePosition = RowscanDIB3 (lpDIBBits,lpNewDIBBits1,::DIBWidth(lpDIB), ::DIBHeight(lpDIB), pPlateLine2); 
 
		for(i=0;i<5;i++) 
		{ 
			m_iPlatePosition[i] = *pPlatePosition; 
			pPlatePosition++; 
		} 
 
		if(m_iPlatePosition[0]==1) 
		{ 
//			AfxMessageBox("找到了!"); 
 
			// 显示车牌位置信息 
	//		CDlgShowPlate dlgShowPlate; 
	//		dlgShowPlate.m_iTop   = ::DIBHeight(lpDIB) - m_iPlatePosition[0]; 
	//		dlgShowPlate.m_iLow   = ::DIBHeight(lpDIB) - m_iPlatePosition[1]; 
	//		dlgShowPlate.m_iLeft  = m_iPlatePosition[2]; 
	//		dlgShowPlate.m_iRight = m_iPlatePosition[3]; 
 
	//		dlgShowPlate.DoModal(); 
 
			// 分配内存,以保存新DIB 
			hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); 
			 
			// 判断是否内存分配失败 
			if (hNewDIB != NULL) 
			{ 
				lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hNewDIB); 
				 
				// 复制DIB信息头、调色板和车牌图像 
				memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB) + lNewLineBytes * lNewHeight); 
					 
				// 获取指针 
				lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; 
				lpbmc = (LPBITMAPCOREHEADER)lpNewDIB; 
				 
				// 更新DIB中图像的高度和宽度 
				if (IS_WIN30_DIB(lpNewDIB)) 
				{ 
					// 对于Windows 3.0 DIB 
					lpbmi->biWidth = lNewWidth; 
					lpbmi->biHeight = lNewHeight; 
				} 
				else 
				{ 
					// 对于其它格式的DIB 
					lpbmc->bcWidth = (unsigned short) lNewWidth; 
					lpbmc->bcHeight = (unsigned short) lNewHeight; 
				} 
					 
	//			TRACE("\n*******%d*******\n",m_iPlatePosition[0]); 
 
				// 替换DIB,同时释放旧DIB对象 
				pDoc->ReplaceHDIB(hNewDIB); 
 
				// 更新DIB大小和调色板 
				pDoc->InitDIBData(); 
 
				// 设置脏标记 
				pDoc->SetModifiedFlag(TRUE); 
 
				// 更新视图 
				pDoc->UpdateAllViews(NULL); 
			} 
		}		 
		else 
		{ 
			// 提示用户 
//			AfxMessageBox("这次没找到!"); 
		} 
	 
		if( (m_iPlateLine[iLineNumber+2]>=0)||((m_iPlatePosition[0]==1))) 
			break; 
	} 
 
 
 
	// 释放内存 
	LocalUnlock(hNewDIBBits1); 
	LocalFree(hNewDIBBits1); 
 
	LocalUnlock(hNewDIBBits2); 
	LocalFree(hNewDIBBits2); 
	 
	// 解除锁定 
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
 
	// 恢复光标 
	EndWaitCursor();		 
	 
} 
 
void CPlateRecoView::OnLPRplate2binarycolor()  
{ 
	// TODO: Add your command handler code here 
	// 二值化 
	 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	 
	// 指向DIB的指针 
	LPSTR	lpDIB; 
	 
	// 指向DIB象素指针 
	LPSTR   lpDIBBits; 
	 
	// 参数对话框 
	//CDlgBinary  myDlgBinary; 
	 
	// 阈值 
	BYTE	bThre; 
	 
	// 锁定DIB 
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); 
	 
	// 找到DIB图像象素起始位置 
	lpDIBBits = ::FindDIBBits(lpDIB); 
	 
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的阈值变换,其它的可以类推) 
	if (::DIBNumColors(lpDIB) != 256) 
	{ 
		// 提示用户 
		MessageBox("目前只支持256色位图的阈值变换!", "系统提示" ,  
			MB_ICONINFORMATION | MB_OK); 
		 
		// 解除锁定 
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
		 
		// 返回 
		return; 
	} 
 
 
	// 各个灰度值的计数 
	LONG lCount[256]; 
 
	int temp1,temp2,iOldLeixin1,iOldLeixin2,iNum1,iNum2,iGrayCore1,iGrayCore2,iMeanGray; 
	// 指向源图像象素的指针 
 
	unsigned char * lpSrc; 
	 
	// 循环变量 
	LONG i; 
	LONG j; 
 
 
	// 重置计数为0 
	for (i = 0; i < 256; i ++) 
	{ 
		// 清零 
		lCount[i] = 0; 
	} 
	 
	// 车牌图像的长、宽 
	int iWidth; 
	int iHeight; 
 
	iWidth = ::DIBWidth(lpDIB); 
	iHeight = ::DIBHeight(lpDIB); 
 
	// 图像每行的字节数 
	LONG lLineBytes; 
	 
	// 计算图像每行的字节数 
	lLineBytes = WIDTHBYTES(iWidth * 8); 
	 
	// 计算各个灰度值的计数 
	for (i = 0; i < iHeight; i ++) 
	{ 
		for (j = 0; j < iWidth; j ++) 
		{ 
			lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; 
			 
			// 计数加1 
			lCount[*(lpSrc)]++; 
		} 
	} 
 
	// 计算平均灰度值 
	iMeanGray = 0; 
	for(i = 1; i < 255; i++) 
	{ 
		iMeanGray += i * lCount[i]; 
	} 
	iMeanGray = (int)iMeanGray / (iHeight * iWidth); 
 
    // 初始的类心,可任意设定 
	iGrayCore1 = (int)(iMeanGray/2); 
	iGrayCore2 = (int)(iMeanGray+(255-iMeanGray)/2); 
 
 
 
	do  // K-均值聚类分析 
	{ 
		iNum1 = 0; 
		iNum2 = 0; 
		temp1 = 0; 
		temp2 = 0; 
		iOldLeixin1 = iGrayCore1; 
		iOldLeixin2 = iGrayCore2; 
 
		for(i = 0; i < iHeight; i++) 
		{ 
			for(j = 0; j < iWidth; j++) 
			{ 
				lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; 
				if(abs(iGrayCore1-*lpSrc)<=abs(iGrayCore2-*lpSrc)) 
				{ 
					temp1 += *lpSrc; 
					iNum1++; 
				} 
				else 
				{ 
					temp2 += *lpSrc; 
					iNum2++; 
				} 
			} 
		} 
		iGrayCore1 = (int)(temp1/iNum1); 
		iGrayCore2 = (int)(temp2/iNum2); 
	}while((iGrayCore1!=iOldLeixin1)||(iGrayCore2!=iOldLeixin2)); 
		 
 
	// 初始化变量值 
	//myDlgBinary.m_bThre = iGrayCore2-20; 
 
	/* 显示对话框,提示用户设定阈值 
	if (myDlgBinary.DoModal() != IDOK) 
	{ 
		// 返回 
		return; 
	}*/ 
	 
	// 获取用户设定的阈值 
	bThre = 112; //myDlgBinary.m_bThre; 
	 
	// 删除对话框 
	//delete myDlgBinary;	 
	 
	// 更改光标形状 
	BeginWaitCursor(); 
	 
	// 调用ThresholdTrans()函数进行阈值变换 
	ThresholdTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bThre); 
	 
	// 设置脏标记 
	pDoc->SetModifiedFlag(TRUE); 
	 
	// 更新视图 
	pDoc->UpdateAllViews(NULL); 
	 
	// 解除锁定 
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
	 
	// 恢复光标 
	EndWaitCursor();	 
} 
 
void CPlateRecoView::OnLPRplatenorm()  
{ 
	// TODO: Add your command handler code here 
	// 字符归一化 
	 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	 
	// 指向DIB的指针 
	LPSTR	lpDIB; 
	 
	// 指向DIB象素指针 
	LPSTR   lpDIBBits; 
	LPSTR   lpNewDIBBits2; 
	 
 
	// 字符归一化后的新的高度与宽度 
	int iNewWidth; 
	int iOldHeight; 
	int iNewHeight; 
	int* pNewHeight; 
	int iTemp; 
	 
 
	// 锁定DIB 
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); 
 
	iNewWidth = ::DIBWidth(lpDIB);	 
	iOldHeight = ::DIBHeight(lpDIB); 
 
	// 找到DIB图像象素起始位置 
	lpDIBBits = ::FindDIBBits(lpDIB); 
	 
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的阈值变换,其它的可以类推) 
	if (::DIBNumColors(lpDIB) != 256) 
	{ 
		// 提示用户 
		MessageBox("目前只支持256色位图的阈值变换!", "系统提示" ,  
			MB_ICONINFORMATION | MB_OK); 
		 
		// 解除锁定 
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
		 
		// 返回 
		return; 
	} 
 
	// 更改光标形状 
	BeginWaitCursor(); 
	pNewHeight = RowscanDIB4(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB)); 
 
	iTemp = *pNewHeight; 
	pNewHeight++; 
	iNewHeight = *pNewHeight; 
	iNewHeight = abs(iNewHeight - iTemp); 
 
 
	// 缩放后图像的宽度(lNewWidth',必须是4的倍数) 
	LONG	lNewLineBytes; 
			 
	// 创建新DIB 
	HDIB hNewDIB = NULL; 
		 
	// 指向缩放图像的指针 
	LPSTR	lpNewDIB ; 
 
	// 指向缩放图像的指针 
	LPSTR   lpNewDIB2; 
	 
	// 指向BITMAPINFO结构的指针(Win3.0) 
	LPBITMAPINFOHEADER lpbmi; 
	 
	// 指向BITMAPCOREINFO结构的指针 
	LPBITMAPCOREHEADER lpbmc; 
 
	// 计算新图像每行的字节数 
	lNewLineBytes = WIDTHBYTES(iNewWidth * 8); 
	 
 
	// 分配内存,以保存新DIB 
	hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * iNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); 
	 
	// 判断是否内存分配失败 
	if (hNewDIB != NULL) 
	{ 
		lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hNewDIB); 
		 
		// 复制DIB信息头、调色板和车牌图像 
		memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB) + lNewLineBytes * iNewHeight); 
			 
		// 获取指针 
		lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; 
		lpbmc = (LPBITMAPCOREHEADER)lpNewDIB; 
		 
		// 更新DIB中图像的高度和宽度 
		if (IS_WIN30_DIB(lpNewDIB)) 
		{ 
			// 对于Windows 3.0 DIB 
			lpbmi->biWidth = iNewWidth; 
			lpbmi->biHeight = iNewHeight; 
		} 
		else 
		{ 
			// 对于其它格式的DIB 
			lpbmc->bcWidth = (unsigned short) iNewWidth; 
			lpbmc->bcHeight = (unsigned short) iNewHeight; 
		} 
			 
//			TRACE("\n*******%d*******\n",m_iPlatePosition[0]); 
 
		// 替换DIB,同时释放旧DIB对象 
		pDoc->ReplaceHDIB(hNewDIB); 
 
		// 更新DIB大小和调色板 
		pDoc->InitDIBData(); 
 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
 
		// 更新视图 
//		pDoc->UpdateAllViews(NULL); 
	} 
 
	LocalUnlock(lpDIB); 
	LocalFree(lpDIB); 
 
	// 创建新DIB 
	HDIB hNewDIB2 = NULL; 
	 
	// 更改光标形状 
	BeginWaitCursor(); 
 
	float fXZoomRatio = 1.0; 
	float fYZoomRatio; 
 
	fYZoomRatio = (float)iOldHeight / (float)::DIBHeight(lpNewDIB); 
	 
	// 调用ZoomDIB()函数转置DIB 
	hNewDIB2 = (HDIB) ZoomDIB(lpNewDIB, fXZoomRatio, fYZoomRatio); 
 
 
 
	// 判断缩放是否成功 
	if (hNewDIB2 != NULL) 
	{ 
		 
		// 替换DIB,同时释放旧DIB对象 
		pDoc->ReplaceHDIB(hNewDIB2); 
 
		// 更新DIB大小和调色板 
		pDoc->InitDIBData(); 
		 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
 
	    lpNewDIB2 =  (char * )::GlobalLock((HGLOBAL) hNewDIB2);	 
		 
		// 重新设置滚动视图大小 
		SetScrollSizes(MM_TEXT, pDoc->GetDocSize()); 
 
		// 更新视图 
//		pDoc->UpdateAllViews(NULL); 
	} 
	else 
	{ 
		// 提示用户 
		MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
	} 
 
	LocalUnlock(lpNewDIB); 
	LocalFree(lpNewDIB);	 
 
 
	// 找到DIB图像象素起始位置 
	lpNewDIBBits2 = ::FindDIBBits(lpNewDIB2); 
 
	// 调用ThresholdTrans()函数进行阈值变换 
	if(CharacterUnit(lpNewDIBBits2, ::DIBWidth(lpNewDIB2), ::DIBHeight(lpNewDIB2)) != TRUE) 
	{ 
		return; 
	} 
 
	// 设置脏标记 
	pDoc->SetModifiedFlag(TRUE); 
 
	// 更新视图 
	pDoc->UpdateAllViews(NULL); 
 
	// 解除锁定 
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
	 
	// 恢复光标 
	EndWaitCursor();		 
} 
 
void CPlateRecoView::OnLPRplatecharthinning()  
{ 
	// TODO: Add your command handler code here 
 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	 
	// 指向DIB的指针 
	LPSTR lpDIB; 
	 
	// 指向DIB象素指针 
	LPSTR    lpDIBBits; 
	 
	// 线性变换的斜率 
	FLOAT fA; 
	 
	// 线性变换的截距 
	FLOAT fB; 
	 
	// 反色操作的线性变换的方程是-x + 255 
	fA = -1.0; 
	fB = 255.0; 
	 
	// 锁定DIB 
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); 
 
	// 找到DIB图像象素起始位置 
	lpDIBBits = ::FindDIBBits(lpDIB); 
	 
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的反色,其它的可以类推) 
	if (::DIBNumColors(lpDIB) != 256) 
	{ 
		// 提示用户 
		MessageBox("目前只支持256色位图的反色!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
		 
		// 解除锁定 
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
		 
		// 返回 
		return; 
	} 
	 
	// 更改光标形状 
	BeginWaitCursor(); 
	 
	// 调用LinerTrans()函数反色 
	LinerTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), fA, fB); 
	 
	// 设置脏标记 
	pDoc->SetModifiedFlag(TRUE); 
	 
	// 更新视图 
//	pDoc->UpdateAllViews(NULL); 
	 
	// 解除锁定 
//	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
 
	// 恢复光标 
//	EndWaitCursor();	 
 
	// 找到DIB图像象素起始位置 
//	lpDIBBits = ::FindDIBBits(lpDIB); 
	 
	// 调用ThiningDIB()函数对DIB进行闭运算 
	if (ThiningDIB(lpDIBBits, WIDTHBYTES(::DIBWidth(lpDIB) * 8), ::DIBHeight(lpDIB))) 
	{ 
		 
		// 设置脏标记 
		pDoc->SetModifiedFlag(TRUE); 
 
		// 更新视图 
		pDoc->UpdateAllViews(NULL); 
	} 
	else 
	{ 
		// 提示用户 
		MessageBox("分配内存失败或者图像中含有0和255之外的像素值!", "系统提示" , MB_ICONINFORMATION | MB_OK); 
	} 
	 
	// 解除锁定 
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
 
	// 恢复光标 
	EndWaitCursor();		 
} 
 
 
void CPlateRecoView::OnLPRfeature16seg()  
{ 
	// TODO: Add your command handler code here 
	// 基于13段投影法的特征提取 
	// 获取文档 
	CPlateRecoDoc* pDoc = GetDocument(); 
	 
	// 指向DIB的指针 
	LPSTR	lpDIB; 
	 
	// 指向DIB象素指针 
	LPSTR    lpDIBBits; 
	 
	// 锁定DIB 
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); 
	 
	// 找到DIB图像象素起始位置 
	lpDIBBits = ::FindDIBBits(lpDIB); 
 
	// 用于传递13段投影编码表 
	float* pCode16Section; 
	float fCode16Sect[6][16]; 
 
	FILE *fpPlateCharData; 
	char *pPlateCharDataFileName = "识别数据_16段映射.txt "; 
 
	LONG i,j; 
	 
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的沃尔什-哈达玛变换,其它的可以类推) 
	if (::DIBNumColors(lpDIB) != 256) 
	{ 
		// 提示用户 
		MessageBox("目前只支持256色位图的沃尔什-哈达玛变换!", "系统提示" , 
			MB_ICONINFORMATION | MB_OK); 
		 
		// 解除锁定 
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
		 
		// 返回 
		return; 
	} 
 
    pCode16Section = CharExtract16Sect(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB)); 
 
//	TRACE("\n"); 
	for(i=0;i<6;i++) 
	{ 
		for(j=0;j<16;j++) 
		{ 
			fCode16Sect[i][j] = *pCode16Section; 
			m_fCode16Sect[i][j] = fCode16Sect[i][j]; 
			pCode16Section++; 
		} 
//		TRACE("\t%f",m_fCode13Sect[i]); 
	} 
 
	if((fpPlateCharData = fopen(pPlateCharDataFileName,"w+"))==NULL) 
	{ 
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!"); 
		return; 
	} 
	int q1=0; 
	// 将提取出的各字符的特征量存成文件 
 
	// 将指针移到文件头 
	fseek(fpPlateCharData,0l,SEEK_SET); 
	for(i = 0; i < 6; i++) 
	{ 
		for(j = 0; j < 16; j++) 
		{ 
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]); 
			fprintf(fpPlateCharData,"%10f",fCode16Sect[i][j]); 
		} 
		fprintf(fpPlateCharData,"\n",""); 
		if(i==5) 
			fprintf(fpPlateCharData,"\n",""); 
	} 
	fclose(fpPlateCharData); 
//	TRACE("\n"); 
 
	// 解除锁定 
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); 
 
	// 更改光标形状 
	BeginWaitCursor();	 
} 
 
void CPlateRecoView::OnLPRplatereco()  
{ 
	OnLPRfeature16seg(); 
 
	CPlateRecoDoc* pDoc = GetDocument(); 
 
	float* pReco16Section; 
 
//	CString strRecoChars,strTemp; 
 
	CDlgRecoResult myDlgRecoResult; 
 
	pReco16Section = &m_fCode16Sect[0][0]; 
 
	// 字符识别 
	m_cRecoChar[0] = BPReco16SectionLetter(pReco16Section); 
 
	pReco16Section = &m_fCode16Sect[1][0]; 
	if(m_iPlateType==0) 
	{	 
		m_cRecoChar[1] = BPReco16SectionLetter(pReco16Section); 
	} 
	else 
	{ 
		m_cRecoChar[1] = BPReco16SectionNumber(pReco16Section); 
	} 
//	strTemp.Format("%c",m_cRecoChar[0]); 
	pReco16Section = &m_fCode16Sect[2][0]; 
	m_cRecoChar[2] = BPReco16SectionNumber(pReco16Section); 
 
	pReco16Section = &m_fCode16Sect[3][0]; 
	m_cRecoChar[3] = BPReco16SectionNumber(pReco16Section); 
 
	pReco16Section = &m_fCode16Sect[4][0]; 
	m_cRecoChar[4] = BPReco16SectionNumber(pReco16Section); 
 
	pReco16Section = &m_fCode16Sect[5][0]; 
	m_cRecoChar[5] = BPReco16SectionNumber(pReco16Section); 
 
 
	 
	myDlgRecoResult.m_cRecoChar[0]= m_cRecoChar[0]; 
	myDlgRecoResult.m_cRecoChar[1]= m_cRecoChar[1]; 
	myDlgRecoResult.m_cRecoChar[2]= m_cRecoChar[2]; 
	myDlgRecoResult.m_cRecoChar[3]= m_cRecoChar[3]; 
	myDlgRecoResult.m_cRecoChar[4]= m_cRecoChar[4]; 
	myDlgRecoResult.m_cRecoChar[5]= m_cRecoChar[5]; 
 
 
	myDlgRecoResult.DoModal(); 
 
	delete myDlgRecoResult; 
 
	return;		 
} 
 
void CPlateRecoView::OnLPRplatepreprocessall()  
{ 
	OnLPRplatelocation();  
	OnLPRplate2binarycolor(); 
	OnLPRplatenorm(); 
	OnLPRplatecharthinning(); 
 
}