基于SEETAFACE2和红外MLX90640的人脸识别系统

一、背景

 去年8月,中科视拓发布了SEETAFACE2了,楼主花了十天,结合前期的基于MLX90640的开发基础,把SEETAFACE2作为引擎,构建一个即可温度检测,又可识别人脸的系统,打法下无聊的在家休养时光。中科的SEETA1若干年前楼主用过,总体来说,SEETA1测试效果差是公开的,识别率比公布的97%差距很大。这次,对于seetaface2到底效果好不好,真是拭目以待。

二、SEETAFACE2的编译

网上有很多的seetaface2怎么编译的例子,楼主感觉没有写的那么复杂,下面就把步骤简单说下:

(1) 下载opencv-4.1.0-vc14_vc15.exe,由于我的开发环境刚好是VS2017(vc15),就没有自己编译opencv,直接把opencv改了下名字,放到c:\\下面了,接下来要用的就是VC15下的LIB/DLL拷贝了.

基于SEETAFACE2和红外MLX90640的人脸识别系统_第1张图片

(2)配置下环境变量,把opencv相关路径放进去

基于SEETAFACE2和红外MLX90640的人脸识别系统_第2张图片

(3)下载cmake,安装好,设好路径,设置好opencv, 依次config, generate, open project, 设置如下所示:

基于SEETAFACE2和红外MLX90640的人脸识别系统_第3张图片

(4)接下来,编译seeta2,生成相关的lib 和dll,要注意的是,默认的编译方式是x32,要改成64的,编译完成后,就可以在D:\....\SEETA2\SeetaFace2-master\build\x64\Release里找到相关的DLL和LIB。

基于SEETAFACE2和红外MLX90640的人脸识别系统_第4张图片

三、串口程序的编写

(1)改了下代码,用VC加入了serial port 的支持;

#ifdef __OPEN_IR_SENSORS_DRIVER__
	g_Comm1.setbandrate(115200);
	g_Comm1.setportno("COM7");
	if (g_Comm1.Init() == COMM_FAIL)
	{
		CString strMsg = _T("子系统通讯口驱动失败!");
		AfxMessageBox(strMsg);
		LOG_PRINT(ERROR_LEVEL3, "%s\n", strMsg);
		return;
	}
	DWORD dwReadCookie;
	g_bReadStart = true;
	HANDLE hReadThread = CreateThread(NULL, 0, DriverReadProc, (LPVOID)this->m_hWnd, 0, &dwReadCookie);
#endif

(2)把MLX90640的数据读了出来,并转换成图像MAT。

Mat Array2Mat(int a[], const char *str)
{
	Mat M(24, 32, CV_8UC1);
	for (int i = 0; i < M.rows; ++i) 
	{
		uchar *p = M.ptr(i);
		for (int j = 0; j < M.cols; ++j)
			p[j] = a[i*32 + j];
	}

	return M;
}

//红外数据获取线程
DWORD WINAPI DriverReadProc(LPVOID pParam)
{
	HWND hWnd = (HWND)pParam;

	int index = 0;
	while (g_bReadStart)
	{
		unsigned char data_out[MAX_BUFFER_SIZE];
		DWORD  dwLength = 0;
		memset(data_out, 0, MAX_BUFFER_SIZE * sizeof(unsigned char));
		g_Comm1.ReadPort(data_out, &dwLength);
		if (dwLength > 0)
		{
			if (dwLength >= 2 && data_out[0] == 0x5A && data_out[1] == 0x5A)
			{
				index = 0;
			}

			if (dwLength >= 1543)
			{
				WORD tempdata[768];
				for (int i = 0; i < 768; i++)
				{
					tempdata[i] = (WORD)(data_out[2 * i + 5] * 256 + data_out[2 * i + 4]);
				}

				long mean = 0;
				long max = 0;
				long min = 0;
				int maxi = 0;
				for (int i = 0; i < 768; i++)
				{
					mean += tempdata[i];
					if (tempdata[i] > max)
					{
						max = tempdata[i];
						maxi = i;
					}
					if (tempdata[i] < min) min = tempdata[i];
				}

				::EnterCriticalSection(&g_csTempDataLock);
				memcpy(g_tempdata, tempdata, 768 * sizeof(WORD));
				::LeaveCriticalSection(&g_csTempDataLock);

				mean = mean / 768;

				long scale = 0;
				if ((max - mean) > (mean - min))
					scale = max - mean;
				else scale = mean - min;

				int imgdata[768];
				for (int j = 0; j < 768; j++)
				{
					imgdata[j] = (ushort)((tempdata[j] - mean)*255.0 / scale);
				}

				g_MATIR = Array2Mat(imgdata, "ssss");

				index = 0;
			}
		}

		Sleep(10);
	}

(3)调整算法,把热红外的温度数据图像合成到实时视频里。如下图红色的效果:

基于SEETAFACE2和红外MLX90640的人脸识别系统_第5张图片

代码如下:

#ifdef __OPEN_IR_SENSORS_DRIVER__
		//显示红外动态画面
		Mat m = g_MATIR.clone();
		Mat mdest, mdest3;
		int width = static_cast(m.cols * 5);
		int height = static_cast(m.rows * 5);
		resize(m, mdest, cv::Size(width, height));
		mdest3 = convertTo3Channels(mdest);
		Mat imageROI;
		imageROI = frameD(cv::Rect(frame.cols-mdest3.cols, frame.rows-mdest3.rows, mdest3.cols, mdest3.rows));
		cv::addWeighted(imageROI, 1.0, mdest3, 0.5, 0, imageROI);
#endif

通过这种方式,就可以把红外合成到实时视频里了。

四、监控管理程序

(1)人脸图库,通过图片把需要识别的人底片加进去。

基于SEETAFACE2和红外MLX90640的人脸识别系统_第6张图片

(2)测试,把摄像头对准水果机,开启爱奇艺,开始追剧,发现识别效果还是不错的。

(3)查询,可以查询识别出来的陌生人和熟人。

(4)监控程序就不多解释了。

 

五 、总结

总体来说,SEETA2效果还是不错的,小规模应用问题应该不是很大,DETECT/LANDMARKER速度应该是不错的,但是识别速度有点慢了,I5处理器在0.5秒左右;人脸识别系统和MLX90640配合起来,算是对32*24的红外传感器在上位软件上的极大的提升吧。另外就是,侧脸的识别率的确有点低,这一缺点经过验证是存在的,希望对大家有所帮助。

 

 

你可能感兴趣的:(基于SEETAFACE2和红外MLX90640的人脸识别系统)