📄 locateview.cpp
字号:
// LocateView.cpp : implementation of the CLocateView class
//
#include "stdafx.h"
#include "Locate.h"
#include "LocateDoc.h"
#include "LocateView.h"
#include "MainFrm.h"
#include "DIBAPI.h"
#include "DibAlgo.h"
#include "EdgeContour.h"
#include "DlgHistShow.h"
#include "SetParamtDlg.h"
#include <afxtempl.h>
#include <fstream.h>
#include <math.h>
#include <conio.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CLocateView
IMPLEMENT_DYNCREATE(CLocateView, CView)
BEGIN_MESSAGE_MAP(CLocateView, CView)
//{{AFX_MSG_MAP(CLocateView)
ON_COMMAND(ID_IMAGE_TOGRAY, OnImageToGray)
ON_COMMAND(ID_GRAY_TOSTRE, OnStretch)
ON_COMMAND(ID_GRAY_TOTHRE, OnThreshold)
ON_COMMAND(ID_GRAY_TOTEMP, OnTemplate)
ON_COMMAND(ID_MEDIAN_TOFILTER, OnMedianFilter)
ON_COMMAND(ID_IMAGE_TOPROJECT, OnFiltrate)
ON_COMMAND(ID_TEMP_TOSUBRECT, OnSubrect)
ON_COMMAND(ID_IMAGE_OPEN, OnImageOpen)
ON_COMMAND(ID_GRAY_EQUA, OnGrayEqualize)
ON_COMMAND(ID_VIEW_HIST, OnViewHist)
ON_COMMAND(ID_IMAGE_SAVE, OnImageSave)
ON_COMMAND(ID_OPTION_PARAM, OnOptionParam)
ON_COMMAND(ID_FIRST,OnFirst)
ON_COMMAND(ID_MIDDLE,OnMiddle)
ON_COMMAND(ID_LAST,OnLast)
ON_COMMAND(ID_RESULT,OnResult)
//}}AFX_MSG_MAP
// Standard printing commands
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLocateView construction/destruction
CLocateView::CLocateView()
{
m_hDIB = NULL;
m_palDIB = NULL;
m_lMaxDist = 20; // 最大允许的跳变点间距
m_lMinDotNum = 10; // 最小允许的每行跳变点数
m_nMaxOffset = 100; // 同一区域两行最左端允许相差的最大距离
m_nMaxGap = 4; // 同一区域最多允许的间断行数
m_nMinHeight = 20; // 车牌照的最小高度
m_nMinWidth = 100; // 车牌照的最小宽度
}
CLocateView::~CLocateView()
{
if (m_hDIB != NULL)
{
::GlobalFree((HGLOBAL) m_hDIB);
}
if (m_palDIB != NULL) // 判断调色板是否存在
{
delete m_palDIB;
}
}
/////////////////////////////////////////////////////////////////////////////
// CLocateView drawing
void CLocateView::OnDraw(CDC* pDC)
{
// 显示等待光标
BeginWaitCursor();
// 判断DIB是否为空
if (m_hDIB != NULL)
{
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
// 获取DIB宽度
int cxDIB = (int) ::DIBWidth(lpDIB);
// 获取DIB高度
int cyDIB = (int) ::DIBHeight(lpDIB);
::GlobalUnlock((HGLOBAL) m_hDIB);
CRect rcDIB;
rcDIB.top = rcDIB.left = 0;
rcDIB.right = cxDIB;
rcDIB.bottom = cyDIB;
// 输出DIB
::PaintDIB(pDC->m_hDC, &rcDIB, m_hDIB , &rcDIB, GetViewPalette());
}
// 恢复正常光标
EndWaitCursor();
}
/////////////////////////////////////////////////////////////////////////////
// CLocateView diagnostics
#ifdef _DEBUG
void CLocateView::AssertValid() const
{
CView::AssertValid();
}
void CLocateView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CLocateDoc* CLocateView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLocateDoc)));
return (CLocateDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CLocateView message handlers
// 打开车牌照片
void CLocateView::OnImageOpen()
{
CString strPhotoPath; // 照片文件路径
char fullPath[100];
char dir[100];
CFileDialog dlg(TRUE,NULL,NULL,0,"JPEG 文件 (*.jpg)|*.jpg||",this);
GetModuleFileName(AfxGetInstanceHandle(), fullPath ,100);
_splitpath(fullPath,NULL,dir,NULL,NULL);
dlg.m_ofn.lpstrInitialDir=dir;
if (dlg.DoModal() != IDOK)
{
return;
}
strPhotoPath = dlg.GetPathName();
// 调用JpgVsBmp.dll中提供的JPG=>BMP的功能
HINSTANCE hInst = ::LoadLibrary("JpgVSbmp.dll");
if( hInst == NULL )
{
AfxMessageBox("缺少JpgVSbmp.dll文件!");
return;
}
typedef bool(__stdcall CHANGE)(LPCTSTR,LPCTSTR,int);
CHANGE* pFunc = (CHANGE *)::GetProcAddress(hInst,"JpgToBmp");
pFunc(strPhotoPath, "Temp.bmp", 24);
::FreeLibrary(hInst);
// 从磁盘载入bmp文件
CFile file;
file.Open("Temp.bmp", CFile::modeRead);
m_hDIB = ::ReadDIBFile(file);
if (m_hDIB != NULL)
{
Invalidate();
}
file.Close();
CFile::Remove("Temp.bmp");
}
// 保存车牌照片为bmp文件
void CLocateView::OnImageSave()
{
CFileDialog dlg(FALSE,NULL,NULL,0,"BMP 文件 (*.bmp)|*.bmp||",this);
if (dlg.DoModal() != IDOK)
{
return;
}
CString strBMPPath = dlg.GetPathName();
CFile file;
file.Open(strBMPPath, CFile::modeCreate|CFile::modeWrite);
::SaveDIB(m_hDIB,file);
file.Close();
}
// 灰度化
void CLocateView::OnImageToGray()
{
if (m_hDIB == NULL)
return;
Copy(); // 在处理之前先保存原来的图像
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
ConvertToGrayScale(lpDIB);
::GlobalUnlock((HGLOBAL) m_hDIB);
Invalidate();
CStatusBar* pStatus=(CStatusBar*)
AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
pStatus->SetPaneText(0,"灰度化处理");
}
// 直方图均衡化
void CLocateView::OnGrayEqualize()
{
if (m_hDIB == NULL)
return;
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
LPSTR lpDIBBits = FindDIBBits(lpDIB);
int lWidth = DIBWidth(lpDIB);
int lHeight = DIBHeight(lpDIB);
InteEqualize(lpDIBBits,lWidth,lHeight);
::GlobalUnlock((HGLOBAL) m_hDIB);
Invalidate();
}
// 灰度拉伸
void CLocateView::OnStretch()
{
if (m_hDIB == NULL)
return;
// 点1坐标
BYTE bX1;
BYTE bY1;
// 点2坐标
BYTE bX2;
BYTE bY2;
// 锁定DIB
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
// 找到DIB图像象素起始位置
LPSTR lpDIBBits = ::FindDIBBits(lpDIB);
//(重要)
bX1 = 100;
bY1 = 1;
bX2 = 150;
bY2 = 255;
BeginWaitCursor();
// 调用GrayStretch()函数进行灰度拉伸
GrayStretch(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bX1, bY1, bX2, bY2);
Invalidate();
// 解除锁定
::GlobalUnlock((HGLOBAL) m_hDIB);
EndWaitCursor();
}
// 阈值变换(二值化)
void CLocateView::OnThreshold()
{
}
// 模板变换
void CLocateView::OnTemplate()
{
if (m_hDIB == NULL)
return;
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);//获得当前位图
LPSTR lpDIBBits = ::FindDIBBits(lpDIB);
int w = ::DIBWidth(lpDIB);
int h = ::DIBHeight(lpDIB);
//用自定义的模板消弱背景干扰
Template(lpDIB);
// ::RobertDIB(lpDIBBits,w,h);
Invalidate();
::GlobalUnlock((HGLOBAL) m_hDIB);
}
// 中值滤波
void CLocateView::OnMedianFilter()
{
LPSTR lpDIB; // 指向DIB的指针
LPSTR lpDIBBits; // 指向DIB象素指针
int iFilterH; // 滤波器的高度
int iFilterW; // 滤波器的宽度
int iFilterMX; // 中心元素的X坐标
int iFilterMY; // 中心元素的Y坐标
// 锁定DIB
if (m_hDIB == NULL)
return;
lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
if(::DIBNumColors(lpDIB) != 256) //不是256色位图不作任何处理
{
return ;
}
// 找到DIB图像象素起始位置
lpDIBBits = ::FindDIBBits(lpDIB);
// 初始化变量值(重要)
iFilterH = 3;
iFilterW = 3;
iFilterMX = 1;
iFilterMY = 1;
BeginWaitCursor();
// 调用MedianFilter()函数中值滤波
if (MedianFilter(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB),
iFilterH, iFilterW, iFilterMX, iFilterMY))
{
Invalidate();
}
else
{
MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
}
// 解除锁定
::GlobalUnlock((HGLOBAL) m_hDIB);
EndWaitCursor();
CStatusBar* pStatus=(CStatusBar*)
AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
pStatus->SetPaneText(0,"去噪音处理");
}
// 核心代码: 筛选可能存在拍照的区域
void CLocateView::OnFiltrate()
{
if (m_hDIB == NULL)
return;
long lRows = 0; // 有效的行数
long L,K; // 用于迭代的行列号
long lDist; // 跳变点的间距
CPoint s[1000]; // 某一段跳变点的起始坐标
CPoint e[1000]; // 某一段跳变点的终止坐标
long r[1000]; // 每行的跳变点数
LPSTR lpDIB = (LPSTR)::GlobalLock((HGLOBAL)m_hDIB);
LPSTR lpDIBBits = ::FindDIBBits(lpDIB);
long lWidth = ::DIBWidth(lpDIB);
long lHeight = ::DIBHeight(lpDIB);
long lLineBytes = WIDTHBYTES(lWidth * 8);
#define VALUE(i,j) (*((unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j))
BOOL* lFlag = new BOOL[lHeight]; // 记录每一行是否存在有效跳边点段
memset(lFlag,0,sizeof(BOOL)*lHeight);
for(L = 0; L < lHeight; L++)
{
for (K = 0,lDist = -1; K < lWidth; K++)
{
// 跳过黑色点
while (VALUE(L,K) == 0)
{
K++;
if (lDist >= 0)
{
lDist++;
}
}
if (lDist == -1)
{
s[lRows] = e[lRows] = CPoint(L,K);
r[lRows] = 1;
lDist = 0;
}
else if (lDist >= 0 && lDist <= m_lMaxDist)
{
e[lRows].y = K;
r[lRows]++;
lDist = 0;
}
else if (lDist > m_lMaxDist && r[lRows] < m_lMinDotNum)
{
s[lRows].y = K;
e[lRows].y = K;
r[lRows] = 0;
lDist = 0;
}
else if (lDist > m_lMaxDist && r[lRows] >= m_lMinDotNum)
{
lRows++;
break;
}
}// end for K
}// end for L
CPoint pts[1000],pte[1000];
for (int i = 0; i < lRows; i++)
{
lFlag[s[i].x] = TRUE; // 该行有效
pts[s[i].x] = s[i];
pte[s[i].x] = e[i];
// for (int col = s[i].y; col < e[i].y; col++)
// VALUE(s[i].x,col) = 255;
}
::GlobalUnlock((HGLOBAL)GetHDIB());
//////////////////////////////////////////////////////////////////////////
CArray<group,group> grpArray; // 存放候选区域
int nDist = -1;
int nCurS;
int nCurE;
for (i = 0; i < lHeight; i++)
{
if (lFlag[i] == FALSE)
{
if (nDist != -1) // 为-1的时候不考虑,只管跳过
{
nCurE = i;
while (lFlag[i] == FALSE && i < lHeight)
{
i++;
nDist++;
}
if (nDist > m_nMaxGap) // 之间的行间距太大
{
if ((nCurE - nCurS) > m_nMinHeight)
{
group grpTemp;
grpTemp.s = nCurS;
grpTemp.e = nCurE;
grpArray.Add(grpTemp);
}
nDist = -1; // 重新置为-1
}
else
{
nCurE = i;
}
}
}
else // TRUE
{
if (nDist == -1) // 这一行将要成为一个区域的起始行
{
nCurS = nCurE = i;
nDist = 0;
}
else
{
// 求当前的跳变点左端离起始行的跳变点左端距离
if (abs(pts[i].y - pts[nCurS].y) > m_nMaxOffset)
{
nCurE = i; // 一段结束
if ((nCurE - nCurS) > m_nMinHeight)
{
group grpTemp;
grpTemp.s = nCurS;
grpTemp.e = nCurE;
grpArray.Add(grpTemp);
}
nDist = -1;
}
else
{
nCurE = i;
nDist = 0;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
CArray<CRect,CRect> rcArray;
for (i = 0; i < grpArray.GetSize(); i++)
{
for (int j = grpArray[i].s; j <= grpArray[i].e; j++)
{
if (lFlag[j] == TRUE)
{
for (int col = pts[j].y; col < pte[j].y; col++)
VALUE(pts[j].x,col) = 255;
}
}
CRect rcTemp;
double left = 0,right = 0;
int lines = 0;
for (j = grpArray[i].s; j <= grpArray[i].e; j++)
{
if (lFlag[j] == TRUE)
{
left += pts[j].y;
right += pte[j].y;
lines++;
}
}
rcTemp.left = long(left / lines);
rcTemp.right = long(right / lines);
rcTemp.top = grpArray[i].s;
rcTemp.bottom = grpArray[i].e;
if (rcTemp.Width() > rcTemp.Height() && rcTemp.Width() > m_nMinWidth
&& rcTemp.Height() > m_nMinHeight)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -