虹軟人臉識別SDK在網路攝像頭中的實際應用
阿新 • • 發佈:2019-08-12
市面上目前有很多款網路攝像頭,以海康攝像頭為例。海康SDK包含很多介面,接入有一定難度,這裡只介紹獲取視訊幀相關的介面。
1.海康SDK接入基本流程
a.初始化並登入驗證
NET_DVR_Init(); NET_DVR_DEVICEINFO_V30 struDeviceInfo = { 0 }; long lUserID = NET_DVR_Login_V30(m_cameraIp, m_cameraPort, m_cameraUser, m_cameraPwd, &struDeviceInfo); if (lUserID < 0) { NET_DVR_Cleanup(); return false; }
b.建立執行緒並註冊回撥函式
thread videoThread(&HCNetCamera::getCameraPreview, this); videoThread.detach(); bool HCNetCamera::getCameraPreview() { NET_DVR_CLIENTINFO ClientInfo; ClientInfo.lChannel = 1; //Channel number 裝置通道號 ClientInfo.hPlayWnd = NULL; //視窗為空,裝置SDK不解碼只取流 ClientInfo.lLinkMode = 0; //Main Stream ClientInfo.sMultiCastIP = NULL; //預覽取流 g_realHandle = NET_DVR_RealPlay_V30(g_cameraUserId, &ClientInfo, fRealDataCallBack, NULL, TRUE); if (g_realHandle < 0) { qDebug() << "NET_DVR_RealPlay_V30 failed! Error number: " << NET_DVR_GetLastError(); return false; } return true; }
c.使用回撥介面,獲取實時的視訊幀資料
void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser) { UNREFERENCED_PARAMETER(lRealHandle); UNREFERENCED_PARAMETER(pUser); DWORD dRet = 0; BOOL inData = FALSE; switch (dwDataType) { case NET_DVR_SYSHEAD: if (g_cameraPort >= 0) { break; //同一路碼流不需要多次呼叫開流介面 } if (!PlayM4_GetPort(&g_cameraPort)) { break; } if (!PlayM4_OpenStream(g_cameraPort, pBuffer, dwBufSize, 1024 * 1024)) { dRet = PlayM4_GetLastError(g_cameraPort); break; } //設定解碼回撥函式 if (!PlayM4_SetDecCallBack(g_cameraPort, DecCBFun)) { dRet = PlayM4_GetLastError(g_cameraPort); break; } //開啟視訊解碼 if (!PlayM4_Play(g_cameraPort, NULL)) { dRet = PlayM4_GetLastError(g_cameraPort); break; } dRet = PlayM4_GetLastError(g_cameraPort); break; case NET_DVR_STREAMDATA: //視訊流資料 default: inData = PlayM4_InputData(g_cameraPort, pBuffer, dwBufSize); while (!inData) { Sleep(10); inData = PlayM4_InputData(g_cameraPort, pBuffer, dwBufSize); dRet = PlayM4_GetLastError(g_cameraPort); OutputDebugString(L"PlayM4_InputData failed \n"); } break; } } //解碼回撥 視訊為YUV資料(YV12) void CALLBACK DecCBFun(long port, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, long nReserved1, long nReserved2) { UNREFERENCED_PARAMETER(nReserved1); UNREFERENCED_PARAMETER(nReserved2); UNREFERENCED_PARAMETER(nSize); UNREFERENCED_PARAMETER(port); //影象格式轉換 if (pFrameInfo->nType == T_YV12) { { lock_guard<mutex> locker(g_CameraMutex); Utils_ns::ImageUtils_ns::YV12ToBGR24_FFMPEG((unsigned char*)pBuf, (unsigned char*)g_curRGBImage->imageData, pFrameInfo->nWidth, pFrameInfo->nHeight);//得到全部RGB影象 } } }
d.應用層獲取視訊幀,這裡為了簡化操作,只獲取了當前幀;大家也可以使用執行緒安全佇列來處理
int HCNetCamera::getFrame(Mat& image)
{
lock_guard<mutex> locker(g_CameraMutex);
if (g_curRGBImage && g_curRGBImage->imageData)
{
image = g_curRGBImage;
return 0;
}
return -1;
}
//以下是執行緒函式的一部分,主要是取幀,然後進行人臉檢測
{
lock_guard<std::mutex> locker(g_CameraMutex);
int ret = m_camera->getFrame(curFrame);
if (ret == -1)
{
continue;
}
}
ftProcessor->faceDetect(curFrame);
2.基本影象格式轉換
目前虹軟SDK支援以下幾種影象資料格式:
在實際開發過程中一般使用opencv,opencv預設的影象資料格式是BGR24,而我使用的海康攝像頭視訊編碼格式是H264,視訊幀資料格式是YV12,因此需要將YV12轉換為BGR24 ,同時也會說明下怎麼轉換為虹軟SDK支援的其它格式,主要參考了[2],以下的程式碼僅供參考。
a.YV12 To BGR24
void yv12ToBGR24(unsigned char* yv12, unsigned char* bgr24, int width, int height)
{
unsigned char* y_yv12 = yv12;
unsigned char* v_yv12 = yv12 + width*height;
unsigned char* u_yv12 = yv12 + width*height + width*height / 4;
unsigned char* b = bgr24;
unsigned char* g = bgr24 + 1;
unsigned char* r = bgr24 + 2;
int yIndex, uIndex, vIndex;
for (int i = 0; i < height; ++i)
{
for (int j = 0; j < width; ++j)
{
yIndex = i * width + j;
vIndex = (i / 2) * (width / 2) + (j / 2);
uIndex = vIndex;
*b = (unsigned char)(y_yv12[yIndex] + 1.732446 * (u_yv12[vIndex] - 128));
*g = (unsigned char)(y_yv12[yIndex] - 0.698001 * (u_yv12[uIndex] - 128) - 0.703125 * (v_yv12[vIndex] - 128));
*r = (unsigned char)(y_yv12[yIndex] + 1.370705 * (v_yv12[uIndex] - 128));
b += 3;
g += 3;
r += 3;
}
}
b.YV12 To I42
void yv12ToI420(unsigned char yv12, unsigned char i420, int width, int height)
{unsigned char* y_yv12 = yv12;
unsigned char* v_yv12 = yv12 + width*height;
unsigned char* u_yv12 = yv12 + width*height + width*height / 4;
unsigned char* y_i420 = i420;
unsigned char* u_i420 = i420 + width*height;
unsigned char* v_i420 = i420 + width*height + width*height / 4;
memcpy(i420, yv12, width*height);
memcpy(v_i420, v_yv12, width*height / 4);
memcpy(u_i420, u_yv12, width*height / 4);
}
c.YV12 To NV2
void yv12ToNV21(unsigned char yv12, unsigned char nv21, int width, int height)
{unsigned char* y_yv12 = yv12;
unsigned char* v_yv12 = yv12 + width*height;
unsigned char* u_yv12 = yv12 + width*height + width*height / 4;
unsigned char* y_nv21 = nv21;
unsigned char* v_nv21 = nv21 + width*height;
unsigned char* u_nv21 = nv21 + width*height + 1;
memcpy(nv21, yv12, width*height);
for (int i = 0; i < width*height / 4; ++i)
{
*v_nv21 = *v_yv12;
*u_nv21 = *u_yv12;
v_nv21 += 2;
u_nv21 += 2;
++v_yv12;
++u_yv12;
}
}
d.YV12 To NV12
void yv12ToNV12(unsigned char yv12, unsigned char nv12, int width, int height)
{unsigned char* y_yv12 = yv12;
unsigned char* v_yv12 = yv12 + width*height;
unsigned char* u_yv12 = yv12 + width*height + width*height / 4;
unsigned char* y_nv12 = nv12;
unsigned char* u_nv12 = nv12 + width*height;
unsigned char* v_nv12 = nv12 + width*height + 1;
memcpy(nv12, yv12, width*height);
for (int i = 0; i < width*height / 4; ++i)
{
*v_nv12 = *v_yv12;
*u_nv12 = *u_yv12;
v_nv12 += 2;
u_nv12 += 2;
++v_yv12;
++u_yv12;
}
}
e.YV12 To YUYV
void yv12ToYUYV(unsigned char yv12, unsigned char yuyv, int width, int height)
{unsigned char* y_yv12 = yv12;
unsigned char* v_yv12 = yv12 + width*height;
unsigned char* u_yv12 = yv12 + width*height + width*height / 4;
unsigned char* y_yuyv = yuyv;
unsigned char* u_yuyv = yuyv + 1;
unsigned char* v_yuyv = yuyv + 3;
for (int i = 0; i < width; ++i)
{
for (int j = 0; j < height; ++j)
{
*y_yuyv = *y_yv12;
y_yuyv += 2;
++y_yv12;
}
}
for (int j = 0; j < height / 2; ++j)
{
for (int i = 0; i < width / 2; ++i)
{
*u_yuyv = *u_yv12;
*(u_yuyv + width * 2) = *u_yv12;
u_yuyv += 4;
++u_yv12;
*v_yuyv = *v_yv12;
*(v_yuyv + width * 2) = *v_yv12;
v_yuyv += 4;
++v_yv12;
}
u_yuyv += width * 2;
v_yuyv += width * 2;
}
}
虹軟免費的sdk下載: https://ai.arcsoft.com.cn/third/mobile.html?oschina
參考:
[1] 虹軟AI 人臉識別SDK接入 — 效能優化篇(多執行緒)
[2] 影象實戰 - 影象格式轉換
[3] 微軟官方解析影象格式
[4]一文讀懂 YUV