海康威视SDK车牌号识别调试

海康威视SDK车牌号识别调试

使用海康官方SDK调试门禁车牌号识别,MFC开发

一、WEB登录设备

首次使用设备需激活,输入说明书写的默认ip地址,用户名admin,修改密码。

进入设备的配置界面,我这里车牌识别方式改为视频识别。

进入预览界面就可以查看视频是否打开成功。

二、环境配置

新建自己的MFC项目,基于对话框项目,运行。
将SDK中库文件中的所有文件和文件夹统一放到你项目中输出有exe的地方。

新建include放头文件。

pApIOFf.png

配置项目的属性,

pApoIhT.jpg
pApo5NV.jpg
pApoT9U.jpg
pApo4A0.jpg

项目的目录结构

pApT3bn.jpg

在HKMFCcard.h中加入
#include "HCNetSDK.h"

三、开发

1.界面设计

pApRMPH.jpg

两个PictureControl分别显示场景图和车牌小图,两个本文框显示状态信息,中间本文框显示车牌号,两个按钮远程开关道闸暂时未开发

2.流程

设备注册 –>> 打开布防 –>> 检测到车牌 –>> 进入回调函数 –>> 抓拍识别 –>> 保存数据 –>> 界面显示

全局变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int iNum = 0;
NET_DVR_SETUPALARM_PARAM struSetupParam = { 0 };
``````

#### 3.设备注册

在HKMFcard.cpp中初始化<br>
`NET_DVR_Init(); // init DVR`

打开软件进行设备注册,将此过程放在了`OnInitDialog()`中。
```c++
//---------------------------------------
//注册设备

//登录参数,包括设备地址、登录用户、密码等
LONG lUserID = -1;
NET_DVR_USER_LOGIN_INFO struLoginInfo = { 0 };
struLoginInfo.bUseAsynLogin = 0; //同步登录方式
strcpy(struLoginInfo.sDeviceAddress, "192.168.11.111"); //设备IP地址
struLoginInfo.wPort = 8000; //设备服务端口
strcpy(struLoginInfo.sUserName, "admin"); //设备登录用户名
strcpy(struLoginInfo.sPassword, "11111111"); //设备登录密码

//设备信息, 输出参数
NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = { 0 };

lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
if (lUserID < 0)
{
/*printf("Login failed, error code: %d\n", NET_DVR_GetLastError());*/
m_textLogin.SetWindowTextA("登录失败");
NET_DVR_Cleanup();
return 0;
}
m_textLogin.SetWindowTextA("登录成功");

4.报警布防

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//---------------------------------------
//报警布防

//设置报警回调函数
/*注:多台设备对接时也只需要调用一次设置一个回调函数,不支持不同设备的事件在不同的回调函数里面返回*/
NET_DVR_SetDVRMessageCallBack_V50(0, cbMessageCallback, NULL);

//启用布防

struSetupParam.dwSize = sizeof(NET_DVR_SETUPALARM_PARAM);
struSetupParam.byLevel = 1; //布防优先级:0- 一等级(高),1- 二等级(中)
struSetupParam.byAlarmInfoType = 1; //上传报警信息类型: 0- 老报警信息(NET_DVR_PLATE_RESULT), 1- 新报警信息(NET_ITS_PLATE_RESULT)

LONG lHandle = NET_DVR_SetupAlarmChan_V41(lUserID, &struSetupParam);
if (lHandle < 0)
{
//printf("NET_DVR_SetupAlarmChan_V41 failed, error code: %d\n", NET_DVR_GetLastError());
m_textBufang.SetWindowTextA("布防失败");
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return 0;
}
m_textBufang.SetWindowTextA("布防成功");

cbMessageCallback 回调函数,当检测到有车牌号时调用此函数。

5.回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void CALLBACK cbMessageCallback(LONG lCommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void* pUser)
{
HWND hWnd = FindWindow(NULL, _T("车牌号识别系统"));
//以下代码仅供参考,实际应用中不建议在该回调函数中直接处理数据保存文件,
//例如可以使用消息的方式(PostMessage)在消息响应函数里进行处理。

switch (lCommand)
{
case COMM_UPLOAD_PLATE_RESULT:
{

NET_DVR_PLATE_RESULT struPlateResult = { 0 };
memcpy(&struPlateResult, pAlarmInfo, sizeof(struPlateResult));

if (hWnd != NULL)
{
SendMessage(hWnd, WM_SAVE_DATA, (WPARAM)((void *)struPlateResult), 0);
}

break;
}
case COMM_ITS_PLATE_RESULT:
{
NET_ITS_PLATE_RESULT struITSPlateResult = { 0 };
memcpy(&struITSPlateResult, pAlarmInfo, sizeof(struITSPlateResult));


if (/*AfxGetMainWnd()->m_hWnd*/hWnd != NULL)
{
SendMessage(hWnd, WM_SAVE_DATA, (WPARAM)(&struITSPlateResult), 0);
}
break;
}
default:
break;
}

return;
}

使用SendMessage传出消息。

1)宏定义

自定义消息
#define WM_SAVE_DATA (WM_USER + 100) //自定义消息

2)创建映射
1
2
3
4
5
6
7
8
BEGIN_MESSAGE_MAP(CHKMFCcardDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_SAVE_DATA, &CHKMFCcardDlg::OnSaveData)
ON_BN_CLICKED(IDC_BUTTON1, &CHKMFCcardDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

3)数据处理OnSaveData及显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//数据的存储与显示
LRESULT CHKMFCcardDlg::OnSaveData(WPARAM wParam, LPARAM lParam)
{
// 在这里处理数据保存操作
// 例如,将 lParam 解释为指向数据的指针
char filename[100];
FILE *fSnapPic = NULL;
FILE *fSnapPicPlate = NULL;

//NET_ITS_PLATE_RESULT* struITSPlateResult = reinterpret_cast<NET_ITS_PLATE_RESULT*>(lParam);
NET_ITS_PLATE_RESULT* struITSPlateResult = (NET_ITS_PLATE_RESULT*)(wParam);
//NET_ITS_PLATE_RESULT struITSPlateResult = wParam;
// 进行数据保存操作
if (struSetupParam.byAlarmInfoType == 1)
{
int i = 0;
for (i = 0; i < struITSPlateResult->dwPicNum; i++)
{
if (i >= sizeof(struITSPlateResult->struPicInfo) / sizeof(struITSPlateResult->struPicInfo[0])) {
break;
}
//printf("车牌号: %s\n", struITSPlateResult->struPlateInfo.sLicense);//车牌号
m_card.SetWindowTextA(struITSPlateResult->struPlateInfo.sLicense);

switch (struITSPlateResult->struPlateInfo.byColor)//车牌颜色
{
case VCA_BLUE_PLATE:
printf("车辆颜色: 蓝色\n");
break;
case VCA_YELLOW_PLATE:
printf("车辆颜色: 黄色\n");
break;
case VCA_WHITE_PLATE:
printf("车辆颜色: 白色\n");
break;
case VCA_BLACK_PLATE:
printf("车辆颜色: 黑色\n");
break;
default:
break;
}

//保存场景图
if ((struITSPlateResult->struPicInfo[i].dwDataLen != 0) && (struITSPlateResult->struPicInfo[i].byType == 1) || (struITSPlateResult->struPicInfo[i].byType == 2))
{
if (struITSPlateResult->struPicInfo[i].pBuffer != NULL) {
sprintf(filename, "testITSpic%d_%d.jpg", iNum, i);
fSnapPic = fopen(filename, "wb");

fwrite(struITSPlateResult->struPicInfo[i].pBuffer, struITSPlateResult->struPicInfo[i].dwDataLen, 1, fSnapPic);

iNum++;

fclose(fSnapPic);

ShowImage(filename, 1);
}

}
//车牌小图片
if ((struITSPlateResult->struPicInfo[i].dwDataLen != 0) && (struITSPlateResult->struPicInfo[i].byType == 0))
{

if (struITSPlateResult->struPicInfo[i].pBuffer != NULL)
{
sprintf(filename, "testPicPlate%d_%d.jpg", iNum, i);
fSnapPicPlate = fopen(filename, "wb");
fwrite(struITSPlateResult->struPicInfo[i].pBuffer, struITSPlateResult->struPicInfo[i].dwDataLen, 1, fSnapPicPlate);
iNum++;
fclose(fSnapPicPlate);
ShowImage(filename, 0);
}

}
//其他信息处理......
}
// 释放内存
//delete[] struITSPlateResult;

}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void CHKMFCcardDlg::ShowImage(const CString& filename, int type)
{

float cx, cy, dx, dy, k, t;//跟控件的宽和高以及图片宽和高有关的参数
CRect rect;//用于获取图片控件的宽和高
CImage q;//为cimage图片类创建一个对象
q.Load(filename);//构造函数的形参是所加载图片的路径
cx = q.GetWidth();
cy = q.GetHeight();//获取图片的宽 高
k = cy / cx;//获得图片的宽高比

CWnd *pWnd = NULL;
if (type == 1)
{
pWnd = GetDlgItem(IDC_BigPic);//获取控件句柄
}
else
{
pWnd = GetDlgItem(IDC_SmallPic);//获取控件句柄
}

pWnd->GetClientRect(&rect);//获取Picture Control控件的客户区
dx = rect.Width();
dy = rect.Height();//获得控件的宽高比
t = dy / dx;//获得控件的宽高比
if (k >= t)
{

rect.right = floor(rect.bottom / k);
rect.left = (dx - rect.right) / 2;
rect.right = floor(rect.bottom / k) + (dx - rect.right) / 2;
}
else
{
rect.bottom = floor(k*rect.right);
rect.top = (dy - rect.bottom) / 2;
rect.bottom = floor(k*rect.right) + (dy - rect.bottom) / 2;
}

CDC *pDc = NULL;
pDc = pWnd->GetDC();//获取picture control的DC
int ModeOld = SetStretchBltMode(pDc->m_hDC, STRETCH_HALFTONE);//设置指定设备环境中的位图拉伸模式

//GetDlgItem(IDC_BigPic)->ShowWindow(FALSE);
//GetDlgItem(IDC_BigPic)->ShowWindow(TRUE);
GetDlgItem(IDC_SmallPic)->ShowWindow(FALSE);
GetDlgItem(IDC_SmallPic)->ShowWindow(TRUE);
q.StretchBlt(pDc->m_hDC, rect, SRCCOPY);//显示函数
SetStretchBltMode(pDc->m_hDC, ModeOld);
ReleaseDC(pDc);//释放指针空间
}

四、源代码

HKMCcard.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

// HKMFCcard.h : PROJECT_NAME 应用程序的主头文件
//

#pragma once

#ifndef __AFXWIN_H__
#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h" // 主符号
#include "HCNetSDK.h"

#define WM_SAVE_DATA (WM_USER + 100) //自定义消息


// CHKMFCcardApp:
// 有关此类的实现,请参阅 HKMFCcard.cpp
//

class CHKMFCcardApp : public CWinApp
{
public:
CHKMFCcardApp();

// 重写
public:
virtual BOOL InitInstance();

// 实现

DECLARE_MESSAGE_MAP()
};

extern CHKMFCcardApp theApp;

HKMCcard.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

// HKMFCcard.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "HKMFCcard.h"
#include "HKMFCcardDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CHKMFCcardApp

BEGIN_MESSAGE_MAP(CHKMFCcardApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CHKMFCcardApp 构造

CHKMFCcardApp::CHKMFCcardApp()
{
// 支持重新启动管理器
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CHKMFCcardApp 对象

CHKMFCcardApp theApp;


// CHKMFCcardApp 初始化

BOOL CHKMFCcardApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。 否则,将无法创建窗口。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它设置为包括所有要在应用程序中使用的
// 公共控件类。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);

CWinApp::InitInstance();


AfxEnableControlContainer();

// 创建 shell 管理器,以防对话框包含
// 任何 shell 树视图控件或 shell 列表视图控件。
CShellManager *pShellManager = new CShellManager;

// 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("山东力山特智能科技股份有限公司"));

NET_DVR_Init(); // init DVR
CHKMFCcardDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: 在此放置处理何时用
// “确定”来关闭对话框的代码
}
else if (nResponse == IDCANCEL)
{
// TODO: 在此放置处理何时用
// “取消”来关闭对话框的代码
}
else if (nResponse == -1)
{
TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");
TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
}

// 删除上面创建的 shell 管理器。
if (pShellManager != NULL)
{
delete pShellManager;
}

// 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
// 而不是启动应用程序的消息泵。
return FALSE;
}


HKMFCcardDlg.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

// HKMFCcardDlg.h : 头文件
//

#pragma once
#include "afxwin.h"
#include "afxcmn.h"

// CHKMFCcardDlg 对话框
class CHKMFCcardDlg : public CDialogEx
{
// 构造
public:
CHKMFCcardDlg(CWnd* pParent = NULL); // 标准构造函数

// 对话框数据
enum { IDD = IDD_HKMFCCARD_DIALOG };

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持


// 实现
protected:
HICON m_hIcon;
void ShowImage(const CString& filename, int type);

// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg LRESULT OnSaveData(WPARAM wParam, LPARAM lParam);

DECLARE_MESSAGE_MAP()
public:

afx_msg void OnBnClickedButton1();

CStatic m_textLogin;
CStatic m_textBufang;
CStatic m_bigPic;
CStatic m_smallPic;
CStatic m_card;
};

HMFCcardDlg.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515

// HKMFCcardDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "HKMFCcard.h"
#include "HKMFCcardDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

int iNum = 0;
NET_DVR_SETUPALARM_PARAM struSetupParam = { 0 };
void CALLBACK cbMessageCallback(LONG lCommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void* pUser)
{

#if 1
HWND hWnd = FindWindow(NULL, _T("车牌号识别系统"));
//以下代码仅供参考,实际应用中不建议在该回调函数中直接处理数据保存文件,
//例如可以使用消息的方式(PostMessage)在消息响应函数里进行处理。

switch (lCommand)
{
case COMM_UPLOAD_PLATE_RESULT:
{
//NET_DVR_PLATE_RESULT struPlateResult = { 0 };
//memcpy(&struPlateResult, pAlarmInfo, sizeof(struPlateResult));
NET_DVR_PLATE_RESULT *struPlateResult = { 0 };
memcpy(struPlateResult, pAlarmInfo, sizeof(*struPlateResult));


if (hWnd != NULL)
{
SendMessage(hWnd, WM_SAVE_DATA, (WPARAM)((void *)struPlateResult), 0);
}

break;
}
case COMM_ITS_PLATE_RESULT:
{
NET_ITS_PLATE_RESULT struITSPlateResult = { 0 };
memcpy(&struITSPlateResult, pAlarmInfo, sizeof(struITSPlateResult));


if (/*AfxGetMainWnd()->m_hWnd*/hWnd != NULL)
{
SendMessage(hWnd, WM_SAVE_DATA, (WPARAM)(&struITSPlateResult), 0);
}
break;
}
default:
break;
}
#else
int i = 0;
char filename[100];
FILE *fSnapPic = NULL;
FILE *fSnapPicPlate = NULL;

//以下代码仅供参考,实际应用中不建议在该回调函数中直接处理数据保存文件,
//例如可以使用消息的方式(PostMessage)在消息响应函数里进行处理。

switch (lCommand)
{
case COMM_UPLOAD_PLATE_RESULT:
{
NET_DVR_PLATE_RESULT struPlateResult = { 0 };
memcpy(&struPlateResult, pAlarmInfo, sizeof(struPlateResult));
printf("车牌号: %s\n", struPlateResult.struPlateInfo.sLicense);//车牌号

switch (struPlateResult.struPlateInfo.byColor)//车牌颜色
{
case VCA_BLUE_PLATE:
printf("车辆颜色: 蓝色\n");
break;
case VCA_YELLOW_PLATE:
printf("车辆颜色: 黄色\n");
break;
case VCA_WHITE_PLATE:
printf("车辆颜色: 白色\n");
break;
case VCA_BLACK_PLATE:
printf("车辆颜色: 黑色\n");
break;
default:
break;
}

//场景图
if (struPlateResult.dwPicLen != 0 && struPlateResult.byResultType == 1)
{
sprintf(filename, "testpic_%d.jpg", iNum);
fSnapPic = fopen(filename, "wb");
fwrite(struPlateResult.pBuffer1, struPlateResult.dwPicLen, 1, fSnapPic);
iNum++;
fclose(fSnapPic);
}
//车牌图
if (struPlateResult.dwPicPlateLen != 0 && struPlateResult.byResultType == 1)
{
sprintf(filename, "testPicPlate_%d.jpg", iNum);
fSnapPicPlate = fopen(filename, "wb");
fwrite(struPlateResult.pBuffer1, struPlateResult.dwPicLen, 1, fSnapPicPlate);
iNum++;
fclose(fSnapPicPlate);
}

//其他信息处理......
break;
}
case COMM_ITS_PLATE_RESULT:
{
NET_ITS_PLATE_RESULT struITSPlateResult = { 0 };
memcpy(&struITSPlateResult, pAlarmInfo, sizeof(struITSPlateResult));

for (i = 0; i < struITSPlateResult.dwPicNum; i++)
{
printf("车牌号: %s\n", struITSPlateResult.struPlateInfo.sLicense);//车牌号

switch (struITSPlateResult.struPlateInfo.byColor)//车牌颜色
{
case VCA_BLUE_PLATE:
printf("车辆颜色: 蓝色\n");
break;
case VCA_YELLOW_PLATE:
printf("车辆颜色: 黄色\n");
break;
case VCA_WHITE_PLATE:
printf("车辆颜色: 白色\n");
break;
case VCA_BLACK_PLATE:
printf("车辆颜色: 黑色\n");
break;
default:
break;
}

//保存场景图
if ((struITSPlateResult.struPicInfo[i].dwDataLen != 0) && (struITSPlateResult.struPicInfo[i].byType == 1) || (struITSPlateResult.struPicInfo[i].byType == 2))
{
sprintf(filename, "testITSpic%d_%d.jpg", iNum, i);
fSnapPic = fopen(filename, "wb");
fwrite(struITSPlateResult.struPicInfo[i].pBuffer, struITSPlateResult.struPicInfo[i].dwDataLen, 1, fSnapPic);
iNum++;
fclose(fSnapPic);
}
//车牌小图片
if ((struITSPlateResult.struPicInfo[i].dwDataLen != 0) && (struITSPlateResult.struPicInfo[i].byType == 0))
{
sprintf(filename, "testPicPlate%d_%d.jpg", iNum, i);
fSnapPicPlate = fopen(filename, "wb");
fwrite(struITSPlateResult.struPicInfo[i].pBuffer, struITSPlateResult.struPicInfo[i].dwDataLen, 1, fSnapPicPlate);
iNum++;
fclose(fSnapPicPlate);
}
//其他信息处理......
}
break;
}
default:
break;
}

return;

#endif
return;
}

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();

// 对话框数据
enum { IDD = IDD_ABOUTBOX };

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现
protected:
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)

END_MESSAGE_MAP()


// CHKMFCcardDlg 对话框


CHKMFCcardDlg::CHKMFCcardDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CHKMFCcardDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

void CHKMFCcardDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LOGIN, m_textLogin);
DDX_Control(pDX, IDC_BUFANG, m_textBufang);
DDX_Control(pDX, IDC_BigPic, m_bigPic);
DDX_Control(pDX, IDC_SmallPic, m_smallPic);
DDX_Control(pDX, IDC_CARD, m_card);
}

BEGIN_MESSAGE_MAP(CHKMFCcardDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_SAVE_DATA, &CHKMFCcardDlg::OnSaveData)
ON_BN_CLICKED(IDC_BUTTON1, &CHKMFCcardDlg::OnBnClickedButton1)
END_MESSAGE_MAP()


// CHKMFCcardDlg 消息处理程序

BOOL CHKMFCcardDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码
m_textLogin.SetWindowTextA("登录无状态");
m_textBufang.SetWindowTextA("布防无状态");

//---------------------------------------
//注册设备

//登录参数,包括设备地址、登录用户、密码等
LONG lUserID = -1;
NET_DVR_USER_LOGIN_INFO struLoginInfo = { 0 };
struLoginInfo.bUseAsynLogin = 0; //同步登录方式
strcpy(struLoginInfo.sDeviceAddress, "192.168.1.64"); //设备IP地址
struLoginInfo.wPort = 8000; //设备服务端口
strcpy(struLoginInfo.sUserName, "admin"); //设备登录用户名
strcpy(struLoginInfo.sPassword, "lst686868"); //设备登录密码

//设备信息, 输出参数
NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = { 0 };

lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
if (lUserID < 0)
{
/*printf("Login failed, error code: %d\n", NET_DVR_GetLastError());*/
m_textLogin.SetWindowTextA("登录失败");
NET_DVR_Cleanup();
return 0;
}
m_textLogin.SetWindowTextA("登录成功");

//---------------------------------------
//报警布防

//设置报警回调函数
/*注:多台设备对接时也只需要调用一次设置一个回调函数,不支持不同设备的事件在不同的回调函数里面返回*/
NET_DVR_SetDVRMessageCallBack_V50(0, cbMessageCallback, NULL);

//启用布防

struSetupParam.dwSize = sizeof(NET_DVR_SETUPALARM_PARAM);
struSetupParam.byLevel = 1; //布防优先级:0- 一等级(高),1- 二等级(中)
struSetupParam.byAlarmInfoType = 1; //上传报警信息类型: 0- 老报警信息(NET_DVR_PLATE_RESULT), 1- 新报警信息(NET_ITS_PLATE_RESULT)

LONG lHandle = NET_DVR_SetupAlarmChan_V41(lUserID, &struSetupParam);
if (lHandle < 0)
{
//printf("NET_DVR_SetupAlarmChan_V41 failed, error code: %d\n", NET_DVR_GetLastError());
m_textBufang.SetWindowTextA("布防失败");
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return 0;
}
m_textBufang.SetWindowTextA("布防成功");


return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}

void CHKMFCcardDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。

void CHKMFCcardDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}

}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CHKMFCcardDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}



void CHKMFCcardDlg::OnBnClickedButton1()
{

}



//数据的存储与显示
LRESULT CHKMFCcardDlg::OnSaveData(WPARAM wParam, LPARAM lParam)
{
// 在这里处理数据保存操作
// 例如,将 lParam 解释为指向数据的指针
char filename[100];
FILE *fSnapPic = NULL;
FILE *fSnapPicPlate = NULL;

//NET_ITS_PLATE_RESULT* struITSPlateResult = reinterpret_cast<NET_ITS_PLATE_RESULT*>(lParam);
NET_ITS_PLATE_RESULT* struITSPlateResult = (NET_ITS_PLATE_RESULT*)(wParam);
//NET_ITS_PLATE_RESULT struITSPlateResult = wParam;
// 进行数据保存操作
if (struSetupParam.byAlarmInfoType == 1)
{
int i = 0;
for (i = 0; i < struITSPlateResult->dwPicNum; i++)
{
if (i >= sizeof(struITSPlateResult->struPicInfo) / sizeof(struITSPlateResult->struPicInfo[0])) {
break;
}
//printf("车牌号: %s\n", struITSPlateResult->struPlateInfo.sLicense);//车牌号
m_card.SetWindowTextA(struITSPlateResult->struPlateInfo.sLicense);

switch (struITSPlateResult->struPlateInfo.byColor)//车牌颜色
{
case VCA_BLUE_PLATE:
printf("车辆颜色: 蓝色\n");
break;
case VCA_YELLOW_PLATE:
printf("车辆颜色: 黄色\n");
break;
case VCA_WHITE_PLATE:
printf("车辆颜色: 白色\n");
break;
case VCA_BLACK_PLATE:
printf("车辆颜色: 黑色\n");
break;
default:
break;
}

//保存场景图
if ((struITSPlateResult->struPicInfo[i].dwDataLen != 0) && (struITSPlateResult->struPicInfo[i].byType == 1) || (struITSPlateResult->struPicInfo[i].byType == 2))
{
if (struITSPlateResult->struPicInfo[i].pBuffer != NULL) {
sprintf(filename, "testITSpic%d_%d.jpg", iNum, i);
fSnapPic = fopen(filename, "wb");

fwrite(struITSPlateResult->struPicInfo[i].pBuffer, struITSPlateResult->struPicInfo[i].dwDataLen, 1, fSnapPic);

iNum++;

fclose(fSnapPic);

ShowImage(filename, 1);
}

}
//车牌小图片
if ((struITSPlateResult->struPicInfo[i].dwDataLen != 0) && (struITSPlateResult->struPicInfo[i].byType == 0))
{

if (struITSPlateResult->struPicInfo[i].pBuffer != NULL)
{
sprintf(filename, "testPicPlate%d_%d.jpg", iNum, i);
fSnapPicPlate = fopen(filename, "wb");
fwrite(struITSPlateResult->struPicInfo[i].pBuffer, struITSPlateResult->struPicInfo[i].dwDataLen, 1, fSnapPicPlate);
iNum++;
fclose(fSnapPicPlate);
ShowImage(filename, 0);
}

}
//其他信息处理......
}
// 释放内存
//delete[] struITSPlateResult;

}
return 0;
}


void CHKMFCcardDlg::ShowImage(const CString& filename, int type)
{

float cx, cy, dx, dy, k, t;//跟控件的宽和高以及图片宽和高有关的参数
CRect rect;//用于获取图片控件的宽和高
CImage q;//为cimage图片类创建一个对象
q.Load(filename);//构造函数的形参是所加载图片的路径
cx = q.GetWidth();
cy = q.GetHeight();//获取图片的宽 高
k = cy / cx;//获得图片的宽高比

CWnd *pWnd = NULL;
if (type == 1)
{
pWnd = GetDlgItem(IDC_BigPic);//获取控件句柄
}
else
{
pWnd = GetDlgItem(IDC_SmallPic);//获取控件句柄
}

pWnd->GetClientRect(&rect);//获取Picture Control控件的客户区
dx = rect.Width();
dy = rect.Height();//获得控件的宽高比
t = dy / dx;//获得控件的宽高比
if (k >= t)
{

rect.right = floor(rect.bottom / k);
rect.left = (dx - rect.right) / 2;
rect.right = floor(rect.bottom / k) + (dx - rect.right) / 2;
}
else
{
rect.bottom = floor(k*rect.right);
rect.top = (dy - rect.bottom) / 2;
rect.bottom = floor(k*rect.right) + (dy - rect.bottom) / 2;
}

CDC *pDc = NULL;
pDc = pWnd->GetDC();//获取picture control的DC
int ModeOld = SetStretchBltMode(pDc->m_hDC, STRETCH_HALFTONE);//设置指定设备环境中的位图拉伸模式

//GetDlgItem(IDC_BigPic)->ShowWindow(FALSE);
//GetDlgItem(IDC_BigPic)->ShowWindow(TRUE);
GetDlgItem(IDC_SmallPic)->ShowWindow(FALSE);
GetDlgItem(IDC_SmallPic)->ShowWindow(TRUE);
q.StretchBlt(pDc->m_hDC, rect, SRCCOPY);//显示函数
SetStretchBltMode(pDc->m_hDC, ModeOld);
ReleaseDC(pDc);//释放指针空间
}

五、改进

1.添加用户管理
2.历史记录,数据库中添加图片字段,点击查看
3.实时记录
4.用户的操作记录
5.图片备份,时间久了存到备份盘中
6.添加录入数据库中没有的车牌号
7.添加车牌号对比之后自动开关门
8.接受库管传来的车辆信息
9.将车牌信息传递给库管

海康威视SDK车牌号识别调试
http://zanderchan666.github.io/2024/08/13/海康威视车牌识别调试/
作者
Zander
发布于
2024年8月13日
许可协议