📄 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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -