At present in the field of face recognition, the use of a webcam is common, but access to the webcam and face recognition SDK has a certain threshold, which is described in this article GuoHong soft facial recognition SDK access process, the paper focuses on web CAM for video streaming (red frame) and processing process, the following content is for reference only.
There are many webcams on the market at present, take Haikang camera as an example. Hikon SDK contains many interfaces, which are difficult to access. Here only the interfaces related to obtaining video frames are introduced.
1. Basic process of Hikon SDK access
A. Initialize and authenticate the login
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;
}
Copy the code
B. Create a thread and register the callback function
thread videoThread(&HCNetCamera::getCameraPreview, this);
videoThread.detach();
bool HCNetCamera::getCameraPreview()
{
NET_DVR_CLIENTINFO ClientInfo;
ClientInfo.lChannel = 1; //Channel number Indicates the device Channel number
ClientInfo.hPlayWnd = NULL; // The window is empty, the device SDK does not decode, only fetch stream
ClientInfo.lLinkMode = 0; //Main Stream
ClientInfo.sMultiCastIP = NULL;
// Preview stream fetching
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;
}
Copy the code
C. Use the callback interface to obtain real-time video frame data
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; // The same stream does not need to call the open stream interface more than once
}
if(! PlayM4_GetPort(&g_cameraPort)) {break;
}
if(! PlayM4_OpenStream(g_cameraPort, pBuffer, dwBufSize,1024 * 1024))
{
dRet = PlayM4_GetLastError(g_cameraPort);
break;
}
// Sets the decoder callback function
if(! PlayM4_SetDecCallBack(g_cameraPort, DecCBFun)) { dRet = PlayM4_GetLastError(g_cameraPort);break;
}
// Open video decoding
if(! PlayM4_Play(g_cameraPort,NULL))
{
dRet = PlayM4_GetLastError(g_cameraPort);
break;
}
dRet = PlayM4_GetLastError(g_cameraPort);
break;
case NET_DVR_STREAMDATA: // Video stream data
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; }}Copy the code
// Decode the callback video to YUV data (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);
// Image format conversion
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);// Get all RGB images}}}Copy the code
D. The application layer obtains video frames. In order to simplify operations, only the current frame is obtained; You can also use thread-safe queues
int HCNetCamera::getFrame(Mat& image)
{
lock_guard<mutex> locker(g_CameraMutex);
if (g_curRGBImage && g_curRGBImage->imageData)
{
image = g_curRGBImage;
return 0;
}
return - 1;
}
// The following is part of the thread function, mainly to take the frame, and then carry out face detection
{
lock_guard<std::mutex> locker(g_CameraMutex);
int ret = m_camera->getFrame(curFrame);
if (ret == - 1)
{
continue;
}
}
ftProcessor->faceDetect(curFrame);
Copy the code
2. Basic image format conversion
Currently, Hongsoft SDK supports the following image data formats:
Opencv is generally used in the actual development process. The default image data format of OpencV is BGR24, while the hikang camera video encoding format I use is H264, and the video frame data format is YV12. Therefore, it is necessary to convert YV12 to BGR24, and how to convert it to other formats supported by Rainbow soft SDK will also be explained. Mainly refer to [2], the following code is for reference only.
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; }}}Copy the code
b.YV12 To I420
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);
}
Copy the code
c.YV12 To NV21
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; }}Copy the code
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; }}Copy the code
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; }}Copy the code
Rainbow soft free SDK download: ai.arcsoft.com.cn/third/mobil…
[1] Rainbow soft AI face recognition SDK access – performance optimization (multithreading) [2] Image combat – image format conversion [3] Microsoft official analysis image format [4] article read YUV sampling and format