#停车场管理系统
前段时间因为课程要求,所以做了一个停车场管理系统,主要为mfc+oracle+opencv,简单来说,也就是可视化界面+数据库连接+车牌识别。
在继续阅读下去的同时,我先声明,这里我的车牌识别由于时间的问题,是调用了别人的接口,所以想研究车牌识别的同学可以跳转下这边详细的车牌识别.好了废话不多说,进入教程。
##0.摘要
本项目采用C++编程实现停车场管理系统,其主要功能包括:车辆入库、出库、车辆计费、信息查询、权限管理、摄像头调用与拍照等。课题可分为三个个模块:界面显示、车牌识别、数据库操作。界面使用MFC编程绘制,通过账号密码登录,可显示管理员-游客等不同权限的功能界面,其中管理员可对车辆信息处理,选择车辆入库时,程序调用摄像头拍照进行车牌识别,自动记录车牌信息与入库时间;当对车辆信息查询时,程序连接Oracle数据库并进行数据读取,返回信息至List控件中显示;摄像头的调用与拍照通过opencv视觉库实现,车牌识别系统基于EasyPR工程实现,通过形态学操作、梯度计算、阈值分割等实现车牌定位,使用NN训练实现字符识别等,数据库的访问与信息存储通过微软提供的ADO接口对oracle进行数据操作。
查询显示的车辆数据存于oracle中的,车辆入库与出库时的车牌号码是通过车牌识别得来的。
MFC工程建立在VS2012中,下面来看看工程全貌和流程图。
看起来有点小复杂,其实跟着慢慢来也还可以。
##1.C++连接数据库
毕竟我们是数据库课设,所以首先讲解下如何连接oracle。
工具如下:
使用ADO的话必须要导入它的库,这语句放到头文件.h中
//导入ADO库
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF", "adoEOF")
###1.2将DBOperation.h与DBOperation.c加入MFC工程中
DBOperiation.h
#pragma once
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF", "adoEOF")
class CDBOperation
{
public:
//初始化数据库操作需要的对象
CDBOperation(void);
~CDBOperation(void);
//连接至数据库
bool ConnToDB(char *ConnectionString, char *UserID, char *Password);
//数据库操作函数
//查询操作 删除以及添加
_RecordsetPtr ExecuteWithResSQL(const char *);
//bool ExecuteNoResSQL(const char *);//delete and add
private:
void PrintErrorInfo(_com_error &);
private:
//初始化数据库连接、命令、记录集
_ConnectionPtr CreateConnPtr();
_CommandPtr CreateCommPtr();
_RecordsetPtr CreateRecsetPtr();
private:
//数据库连接需要的连接、命令操作对象
_ConnectionPtr m_pConnection;
_CommandPtr m_pCommand;
};
DBOperation.c
#include "stdafx.h"
#include "DBOperation.h"
CDBOperation::CDBOperation(void)
{
CoInitialize(NULL);
m_pConnection = CreateConnPtr();
m_pCommand = CreateCommPtr();
}
CDBOperation::~CDBOperation(void)
{
//m_pCommand->Close();
m_pConnection->Close();
}
bool CDBOperation::ConnToDB(char *ConnectionString, char *UserID, char *Password)
{
if (NULL == m_pConnection)
{
printf("Failed to create connection\n");
return false;
}
try
{
HRESULT hr = m_pConnection->Open(ConnectionString, UserID, Password, NULL);
if (TRUE == FAILED(hr))
{
return false;
}
m_pCommand->ActiveConnection = m_pConnection;
return true;
}
catch(_com_error &e)
{
PrintErrorInfo(e);
return false;
}
}
_RecordsetPtr CDBOperation::ExecuteWithResSQL(const char *sql)
{
//已经在连接至数据库的时候进行判断了
//if (NULL == m_pCommand || 0 == m_pConnection->State)
//{
// printf("Failed to create command OR the state of connection is zero\n");
// return NULL;
//}
//char *query = new char;
//strcpy(query, sql);
try
{
m_pCommand->CommandText = _bstr_t(sql);
_RecordsetPtr pRst = m_pCommand->Execute(NULL, NULL, adCmdText);
return pRst;
//_variant_t ra;
//_RecordsetPtr pRst = m_pConnection->Execute((_bstr_t)query, &ra, adCmdText);
}
catch(_com_error &e)
{
PrintErrorInfo(e);
return NULL;
}
}
//bool CDBOperation::ExecuteNoResSQL(const char *sql)
//{
// //if (NULL == m_pCommand || 0 == m_pConnection->State)
// //{
// // printf();
// //}
// try
// {
// char *query = NULL;
// strcpy(query, sql);
// m_pCommand->CommandText = (_bstr_t)query;
//
// }
//}
void CDBOperation::PrintErrorInfo(_com_error &e)
{
printf("Error infomation are as follows\n");
printf("ErrorNo: %d\nError Message:%s\nError Source:%s\nError Description:%s\n", e.Error(), e.ErrorMessage(), (LPCTSTR)e.Source(), (LPCTSTR)e.Description());
}
_ConnectionPtr CDBOperation::CreateConnPtr()
{
HRESULT hr;
_ConnectionPtr connPtr;
hr = connPtr.CreateInstance(__uuidof(Connection));
if (FAILED(hr) == TRUE)
{
return NULL;
}
return connPtr;
}
_CommandPtr CDBOperation::CreateCommPtr()
{
HRESULT hr;
_CommandPtr commPtr;
hr = commPtr.CreateInstance(__uuidof(Command));
if (FAILED(hr) == TRUE)
{
return NULL;
}
return commPtr;
}
_RecordsetPtr CDBOperation::CreateRecsetPtr()
{
HRESULT hr;
_RecordsetPtr recsetPtr;
hr = recsetPtr.CreateInstance(__uuidof( Command));
if (FAILED(hr) ==TRUE)
{
return NULL;
}
return recsetPtr;
}
###1.3连接oracle
CDBOperation dbOper;
bool bConn = dbOper.ConnToDB("Provider=MSDAORA;Persist Security Info=True;Data Source=xe", "system", "123456");
if (false == bConn)
{
MessageBox("连接数据库出现错误");
return;
}
如果你是oracle完整版的,记得将Provider=MSDAORA改成Provider=OraOLEDB。
代码中的xe是数据库的SID,system是用户名,123456是密码,请记得修改。
###1.4进行增删改查
//执行插入操作
sprintf_s(sql, "insert into CARINFO(CARLICENCE, CARTYPE, TIMECARIN,TIMECAROUT,CARFEE) values('%s', %s, sysdate, null, 0)",carInlien,carIntype);
//这里的dbOper是连接数据库时得的变量,不清楚可以看下连接数据库的代码
pRst = dbOper.ExecuteWithResSQL(sql);
//这里的CARINFO是oracle中的一张表,实际上增删改查都是通过将sql语句转换为字符串(这里使用sprintf_s转化,不懂可以查下这个函数),随后再通过ExecuteWithResSQL执行。
//执行更新操作
sprintf_s(sql, "update CARINFO set CARFEE = (trunc(abs((TIMECARIN - TIMECAROUT)*24))*(select FEE from FEESTAND where CARINFO.CARTYPE = FEESTAND.CARTYPE)) where CARLICENCE = '%s'",carOutLience);
pRst = dbOper.ExecuteWithResSQL(sql);
//执行查找操作
sprintf_s(sql, "select * from FEESTAND");
pRst = dbOper.ExecuteWithResSQL(sql);
while (!pRst->adoEOF)
{
carInfoList.InsertItem(i, (LPSTR)(LPCSTR)_bstr_t(pRst->GetCollect(_variant_t("CARTYPE"))));
carInfoList.SetItemText(i, 1,(LPSTR)(LPCSTR)_bstr_t(pRst->GetCollect(_variant_t("FEE"))));
i++;
pRst->MoveNext();
}
//查询返回的是一个指针,通过不断遍历它,(LPSTR)(LPCSTR)_bstr_t(pRst->GetCollect(_variant_t("CARTYPE")))可以获得每条数据属性值为"CARTYPE"的值
//删除同理,写出sql语言,转化为字符串,进行执行
##2.可视化界面的编写
MFC中的对话框分为了模态对话框与非模态对话框,具体区别可以百度搜搜看,下面讲解一个子界面的创建至显示过程。
Dlg2 dlg2;
dlg2.DoModal();
那么点击父窗口按钮时,就会弹出子对话框.
如果需要创建非模态对话框,则需调用Create函数与ShowWindow函数
TestDlg *test = new TestDlg;
test -> Create(ID,母窗口or this)
test -> ShowWindow(SW_SHOW)
###2.2编辑控件中数据的获取
对应编辑框控件添加变量后,使用如下代码即可:
UpdataDate(True)
//读出编辑框中的值改为该控件变量的值
UpdataDate(False)
//将该控件变量的值写入编辑框
###2.3List控件的数据显示
这位博主写的特别清楚,可以看下这里,这边就不多提了。
##3.车牌识别
原本想自己写一个车牌识别的,但由于时间的问题,最后只能去调用EasyPR的接口,MFC工程是使用VS2012写的,但EasyPR只支持VS2013且需要配置opencv一些的库,于是下了个2013绿色版,下载了EasyPR懒人版(无须配置opencv,可在EasyPR github中下载到,具体链接)。由于界面与识别代码因版本的原因只能作为两个程序,于是采用文件的方式进行数据传递。车牌识别代码每次识别完后将结果存入某个文件,姑且称为’cardInfo.txt’,每次车辆入库或出库子窗口初始化时就去读取’cardInfo.txt’,并将车牌号显示于编辑框中。
其实是可以在MFC工程调用车牌识别的程序的,使用即可WinExec("D:\\EasyPR1\\demo.exe", SW_SHOW);
只是我的工程还是有问题,程序跑不起来,所以我还是采用手动的方式让车牌识别程序运行。有点无奈啊~~。
晚一些时候再传代码上来吧
https://github.com/fengqian-wei/park-manage-system
https://download.csdn.net/download/qq_34771697/10372014
补上数据库设计:
E-R图:概念设计
逻辑设计:由E-R图可得出以下关系模式
1.停放车辆信息表(车牌号、车辆类型、入库时间、出库时间、停车费)
主键为:车牌号、入库时间 外键为:车辆类型
2.停车管理员表(姓名、职工号、性别、年龄) 主键为:职工号
3.收费标准表(车辆类型、每小时收取费用) 主键为:车辆类型)
以下为每个表的具体设计:
请注意以下问题:
1、该工程用的数据库为oracle32位,开发时VS用的是2012。
2、跑前请确保已安装OPENCV库,并在VS内配置好依赖库,具体opencv配置可参考如下:
https://blog.csdn.net/poem_qianmo/article/details/19809337
3、满足以上条件基本上可以将工程跑起来,运行过程中可能会涉及连接数据库出错,请检查数据库服务是否开启,可尝试用sql developer连接测试。