opencv颜色跟踪以及人脸检测的小工具
图:
dll:
##########################################################################
.h
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #pragma once 2 #ifndef _CVV_H 3 #define _CVV_H 4 5 #include <opencv2/opencv.hpp> 6 #include<opencv2/core/core.hpp> 7 #include <opencv2/video/tracking.hpp> 8 #include <opencv2/objdetect/objdetect.hpp> 9 #include <opencv2/highgui/highgui.hpp> 10 #include <opencv2/highgui/highgui_c.h> 11 #include <opencv2/imgproc/imgproc.hpp> 12 #include "windows.h" 13 #include "dshow.h" 14 #include <comutil.h> 15 #include <string> 16 #include <iostream> 17 18 #define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0) 19 20 //图像信息 21 typedef struct 22 { 23 int width; 24 int height; 25 int depth; 26 int ch; 27 int size; 28 }IMGINFO; 29 30 //视频信息 31 typedef struct 32 { 33 double _width; 34 double _height; 35 double _frameRate; 36 double _totalFrames; 37 }_VIDEOINFO; 38 39 //位置信息 40 typedef struct 41 { 42 int width; 43 int height; 44 int x; 45 int y; 46 int r; 47 int facenum; 48 }POSITIONINFO; 49 50 //Object 51 typedef struct 52 { 53 int x; 54 int y; 55 int w; 56 int h; 57 }TRACKOBJECT; 58 59 //HSV参数 60 typedef struct 61 { 62 int hmin, hmax, smin, smax, vmin, vmax; 63 }HSVPARAMS; 64 65 //Mat->img 66 uint8_t *pBmpArray; 67 68 #endif // !_CVV_H
.cpp
1 #include "stdafx.h" 2 #include "cvv.h" 3 4 #pragma comment(lib, "strmiids.lib") 5 #pragma comment(lib, "quartz.lib") 6 #pragma comment(lib, "comsuppw.lib") 7 8 using namespace std; 9 using namespace cv; 10 11 //cap 12 VideoCapture cap; 13 Mat frame; 14 15 /****************************************************************************************/ 16 //tracking 17 Rect trackWindow; 18 UINT8 trackingEnable = 1; 19 bool trackingInit = false; 20 bool backprojMode = false; 21 bool selectObject = false;//用来判断是否选中,当鼠标左键按下时为true,左键松开时为false 22 int trackObject = 0; 23 bool showHist = true; 24 Point origin;//选中的起点 25 Rect selection;//选中的区域 26 //int vmin = 10, vmax = 256, smin = 30;//图像掩膜需要的边界常数 27 int 28 vmin = 130, 29 vmax = 256, 30 smin = 150;//图像掩膜需要的边界常数 31 32 //创建Mat变量,frame, hsv, hue, mask, hist, histimg, backproj;其中histimg初始化为200*300的零矩阵 33 Mat hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj; 34 //直方图所需常量 35 int hsize; 36 //.. 37 float hranges[] = { 0,180 }; 38 const float* phranges = hranges; 39 40 /****************************************************************************************/ 41 //face 42 UINT8 faceDetectEnable = 1; 43 CascadeClassifier cascade; 44 double scale = 2.2; 45 BOOL tryflip = false; 46 47 48 /* 49 input: Mat -> img 50 output: bmp_size 51 return: bmp_buffer pointer. (need to free by USER) 52 http://blog.chinaunix.net/uid-27875-id-5784597.html 53 */ 54 static uint8_t * _convertMat_toBMP(Mat *img, /*int *bmp_size,*/ IMGINFO * info=NULL) 55 { 56 //uint8_t *pBmpArray = NULL; 57 //======建立位图信息 =========== 58 int width, height, depth, channel; 59 width = img->cols; 60 height = img->rows; 61 depth = img->depth(); 62 channel = img->channels(); 63 64 info->width = width; 65 info->height = height; 66 info->depth = depth; 67 info->ch = channel; 68 69 //printf("w=%d h=%d d=%d c=%d\n", width, height, depth, channel); 70 71 int bits; 72 //int colors; 73 uint8_t idx; 74 bits = (8 << (depth / 2)) * channel; 75 76 #if 0 77 if (bits > 8) 78 colors = 0; 79 else 80 colors = 1 << bits; //now, bits must be 8; so color = 256 81 #endif 82 83 if (bits == 24) 84 bits = 32; 85 86 //待存储图像数据每行字节数为4的倍数 87 int lineByte = (width * bits / 8 + 3) / 4 * 4; 88 89 int colorTablesize = 0; 90 if (bits == 8) { // 256 色位图, // 设置灰阶调色板 91 colorTablesize = 256 * sizeof(RGBQUAD); 92 } 93 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 94 DWORD bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height; 95 //bitmap 文件 buffer 96 pBmpArray = (uint8_t *)malloc(bfSize); 97 memset(pBmpArray, 0, bfSize); 98 //*bmp_size = bfSize; 99 100 info->size = bfSize; 101 102 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 103 BITMAPFILEHEADER *fileHead = (BITMAPFILEHEADER *)pBmpArray; // sizeof(BITMAPFILEHEADER) = 14; 104 fileHead->bfType = 0x4D42; //bmp类型 105 //bfSize是图像文件4个组成部分之和 106 fileHead->bfSize = bfSize; 107 //bfOffBits是图像文件前3个部分所需空间之和 108 fileHead->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize; 109 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 110 //位图的头 111 BITMAPINFOHEADER *head = (BITMAPINFOHEADER *)(&pBmpArray[sizeof(BITMAPFILEHEADER)]); // sizeof(BITMAPINFOHEADER) = 40; 112 head->biSize = 40; 113 head->biWidth = width; 114 head->biHeight = height; 115 head->biPlanes = 1; 116 head->biBitCount = bits; //表示颜色用到的位数 117 head->biCompression = 0; //0:不压缩(用BI_RGB表示) 118 head->biSizeImage = lineByte*height; //图像数据站的字节数 119 head->biXPelsPerMeter = 0; 120 head->biYPelsPerMeter = 0; 121 head->biClrUsed = 0; 122 head->biClrImportant = 0; 123 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 124 RGBQUAD *VgaColorTab = (RGBQUAD *)(&pBmpArray[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)]); 125 if (bits == 8) { // 256 色位图, // 设置灰阶调色板 126 for (idx = 0; idx<256; idx++) { 127 VgaColorTab[idx].rgbRed = VgaColorTab[idx].rgbGreen = VgaColorTab[idx].rgbBlue = idx; 128 } 129 } 130 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 131 //======颠倒数据 132 //======Mat 中从上往下存,而 bitmap 中从下往上存。 都是从左往右,并 且 bitmap 每一个点多占一个保留字节,默认 255 133 unsigned char *m_pDibBits = pBmpArray + fileHead->bfOffBits;//存储图像中的数据,从下向上,从左向右 //x行 * Y列 134 int x, y; 135 unsigned char * bmpdata; 136 unsigned char * imgData = img->data; 137 138 if (bits == 8) 139 { 140 //把 imgData 中的第一行复制到 m_pDibBits 的最后一行 , 依次颠倒 141 for (x = 0; x<height; x++) 142 { 143 bmpdata = m_pDibBits + (height - 1 - x)*width; 144 memcpy(bmpdata, imgData, width); 145 imgData = imgData + width; 146 } 147 } 148 else if (bits == 32) 149 { 150 //把 imgData 中的第一行复制到 m_pDibBits 的最后一行 , 依次颠倒 151 for (x = 0; x<height; x++) 152 { 153 bmpdata = m_pDibBits + (height - 1 - x)*width * 4; 154 for (y = 0; y<width; y++) 155 { 156 memcpy(bmpdata, imgData, 3); 157 bmpdata[3] = 255; 158 bmpdata = bmpdata + 4; 159 imgData = imgData + 3; 160 } 161 } 162 } 163 164 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 165 return pBmpArray; 166 } 167 168 //灰度化 169 static void _toGray(Mat * img) 170 { 171 cvtColor(*img, *img, COLOR_BGR2GRAY); 172 } 173 174 //https://www.cnblogs.com/zhaobinyouth/p/11672434.html 175 static vector<string> _getDevices() { 176 177 //COM Library Initialization 178 //comInit(); 179 180 vector<string> list; 181 182 ICreateDevEnum *pDevEnum = NULL; 183 IEnumMoniker *pEnum = NULL; 184 int deviceCounter = 0; 185 CoInitialize(NULL); 186 187 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 188 CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, 189 reinterpret_cast<void**>(&pDevEnum)); 190 191 192 if (SUCCEEDED(hr)) 193 { 194 // Create an enumerator for the video capture category. 195 hr = pDevEnum->CreateClassEnumerator( 196 CLSID_VideoInputDeviceCategory, 197 &pEnum, 0); 198 199 if (hr == S_OK) { 200 201 //printf("SETUP: Looking For Capture Devices\n"); 202 IMoniker *pMoniker = NULL; 203 204 while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { 205 206 IPropertyBag *pPropBag; 207 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, 208 (void**)(&pPropBag)); 209 210 if (FAILED(hr)) { 211 pMoniker->Release(); 212 continue; // Skip this one, maybe the next one will work. 213 } 214 215 // Find the description or friendly name. 216 VARIANT varName; 217 VariantInit(&varName); 218 hr = pPropBag->Read(L"Description", &varName, 0); 219 220 if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0); 221 222 if (SUCCEEDED(hr)) 223 { 224 225 hr = pPropBag->Read(L"FriendlyName", &varName, 0); 226 227 int count = 0; 228 char tmp[255] = { 0 }; 229 //int maxLen = sizeof(deviceNames[0]) / sizeof(deviceNames[0][0]) - 2; 230 while (varName.bstrVal[count] != 0x00 && count < 255) 231 { 232 tmp[count] = (char)varName.bstrVal[count]; 233 count++; 234 } 235 236 list.push_back(tmp); 237 //deviceNames[deviceCounter][count] = 0; 238 239 //if (!silent) DebugPrintOut("SETUP: %i) %s\n", deviceCounter, deviceNames[deviceCounter]); 240 } 241 242 pPropBag->Release(); 243 pPropBag = NULL; 244 245 pMoniker->Release(); 246 pMoniker = NULL; 247 248 deviceCounter++; 249 } 250 251 pDevEnum->Release(); 252 pDevEnum = NULL; 253 254 pEnum->Release(); 255 pEnum = NULL; 256 } 257 258 //if (!silent) DebugPrintOut("SETUP: %i Device(s) found\n\n", deviceCounter); 259 } 260 261 //comUnInit(); 262 263 return list; 264 265 } 266 267 static void _trackingColor(Mat &img, POSITIONINFO * _pinfo = NULL) 268 { 269 if (trackingEnable == 0) 270 {//开始跟踪 271 cvtColor(img, hsv, CV_BGR2HSV);//将BGR转换成HSV格式,存入hsv中,hsv是3通道 272 273 if (trackObject) 274 { 275 int _vmin = vmin, _vmax = vmax; 276 277 //inRange用来检查元素的取值范围是否在另两个矩阵的元素取值之间,返回验证矩阵mask(0-1矩阵) 278 //这里用于制作掩膜板,只处理像素值为H:0~180,S:smin~256, V:vmin~vmax之间的部分。mask是要求的,单通道 279 inRange(hsv, Scalar(0, smin, MIN(_vmin, _vmax)), 280 Scalar(256, 256, MAX(_vmin, _vmax)), mask); 281 282 int ch[] = { 0, 0 }; 283 //type包含通道信息,例如CV_8UC3,而深度信息depth不包含通道信息,例如CV_8U. 284 hue.create(hsv.size(), hsv.depth());//hue是单通道 285 mixChannels(&hsv, 1, &hue, 1, ch, 1);//将H分量拷贝到hue中,其他分量不拷贝。 286 287 if (trackObject < 0) 288 { 289 //roi为选中区域的矩阵,maskroi为0-1矩阵 290 Mat roi(hue, selection), maskroi(mask, selection); 291 //绘制色调直方图hist,仅限于用户选定的目标矩形区域 292 calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges); 293 normalize(hist, hist, 0, 255, CV_MINMAX);//必须是单通道,hist是单通道。归一化,范围为0-255 294 295 trackWindow = selection; 296 trackObject = 1;//trackObject置1,接下来就不需要再执行这个if块了 297 298 histimg = Scalar::all(0);//用于显示直方图 299 //计算每个直方的宽度 300 int binW = histimg.cols / hsize;//hsize为16,共显示16个 301 Mat buf(1, hsize, CV_8UC3);// 302 303 for (int i = 0; i < hsize; i++) 304 //直方图每一项的颜色是根据项数变化的 305 buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180. / hsize), 255, 255); 306 cvtColor(buf, buf, CV_HSV2BGR); 307 //量化等级一共有16个等级,故循环16次,画16个直方块 308 for (int i = 0; i < hsize; i++) 309 { 310 int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows / 255);//获取直方图每一项的高 311 //画直方图。opencv中左上角为坐标原点 312 rectangle(histimg, Point(i*binW, histimg.rows), 313 Point((i + 1)*binW, histimg.rows - val), 314 Scalar(buf.at<Vec3b>(i)), -1, 8); 315 } 316 } 317 //根据直方图hist计算整幅图像的反向投影图backproj,backproj与hue相同大小 318 calcBackProject(&hue, 1, 0, hist, backproj, &phranges); 319 //计算两个矩阵backproj、mask的每个元素的按位与,返回backproj 320 backproj &= mask; 321 //调用最核心的camshift函数 322 //TermCriteria是算法完成的条件 323 324 RotatedRect trackBox; 325 int Iteration = meanShift(backproj, trackWindow, 326 TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1)); 327 if (Iteration != 0 && trackWindow.x >= 0 && trackWindow.y >= 0) { 328 trackBox = CamShift(backproj, trackWindow, 329 TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1)); 330 331 } 332 else 333 { 334 Point cp(trackWindow.x + cvRound(trackWindow.width * 0.5), trackWindow.y + cvRound(trackWindow.height * 0.5)); 335 circle(img, cp, 100, Scalar(255, 255, 0)); 336 } 337 338 int xpos = trackWindow.x + cvRound(trackWindow.width * 0.5); 339 int ypos = trackWindow.y + cvRound(trackWindow.height * 0.5); 340 341 //返回跟踪位置 342 _pinfo->width = trackWindow.width; 343 _pinfo->height = trackWindow.height; 344 _pinfo->x = xpos; 345 _pinfo->y = ypos; 346 347 if (trackWindow.area() <= 1) 348 { 349 int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5) / 6; 350 trackWindow = Rect(trackWindow.x - r, trackWindow.y - r, 351 trackWindow.x + r, trackWindow.y + r) & 352 Rect(0, 0, cols, rows); 353 } 354 355 if (backprojMode)//转换显示方式,将backproj显示出来 356 cvtColor(backproj, img, CV_GRAY2BGR); 357 //画出椭圆,第二个参数是一个矩形,画该矩形的内接圆 358 if (trackBox.size.width > 0 && trackBox.size.height > 0) 359 ellipse(img, trackBox, Scalar(255, 255, 0), 1, CV_AA); 360 361 } 362 363 } 364 else 365 {//停止跟踪 366 //位置初始化 367 _pinfo->x = -1; 368 _pinfo->y = -1; 369 } 370 371 if (selectObject && selection.width > 0 && selection.height > 0) 372 { 373 Mat roi(img, selection); 374 bitwise_not(roi, roi); 375 } 376 } 377 378 static void _faceDetect(Mat img, POSITIONINFO * _pinfo = NULL) //人脸检测,返回人脸数量 379 { 380 if (faceDetectEnable == 0) 381 { 382 double t = 0; 383 vector<Rect> faces, faces2; 384 const static Scalar colors[] = 385 { 386 Scalar(255,0,0), 387 Scalar(255,128,0), 388 Scalar(255,255,0), 389 Scalar(0,255,0), 390 Scalar(0,128,255), 391 Scalar(0,255,255), 392 Scalar(0,0,255), 393 Scalar(255,0,255) 394 }; 395 Mat gray, smallImg; 396 397 cvtColor(img, gray, COLOR_BGR2GRAY); 398 double fx = 1 / scale; 399 resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT); 400 equalizeHist(smallImg, smallImg); 401 402 cascade.detectMultiScale(smallImg, faces, 403 1.1, 2, 0 404 //|CASCADE_FIND_BIGGEST_OBJECT 405 //|CASCADE_DO_ROUGH_SEARCH 406 | CASCADE_SCALE_IMAGE, 407 Size(30, 30)); 408 if (tryflip) 409 { 410 flip(smallImg, smallImg, 1); 411 cascade.detectMultiScale(smallImg, faces2, 412 1.1, 2, 0 413 //|CASCADE_FIND_BIGGEST_OBJECT 414 //|CASCADE_DO_ROUGH_SEARCH 415 | CASCADE_SCALE_IMAGE, 416 Size(30, 30)); 417 for (vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r) 418 { 419 faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height)); 420 } 421 } 422 423 //获取人脸数量 424 _pinfo->facenum = faces.size(); 425 426 for (size_t i = 0; i < faces.size(); i++) 427 { 428 Rect r = faces[i]; 429 Mat smallImgROI; 430 Point center; 431 Scalar color = colors[i % 8]; 432 //int radius; 433 int x, y, w, h, cx, cy; 434 435 double aspect_ratio = (double)r.width / r.height; 436 if (0.75 < aspect_ratio && aspect_ratio < 1.3) 437 { 438 x = cvRound(r.x * scale); 439 y = cvRound(r.y * scale); 440 w = cvRound(r.width * scale); 441 h = cvRound(r.height * scale); 442 443 cx = cvRound(x + w * 0.5); 444 cy = cvRound(y + h * 0.5); 445 446 _pinfo->x = x; 447 _pinfo->y = y; 448 _pinfo->width = w; 449 _pinfo->height = h; 450 451 //center.x = cvRound((r.x + r.width*0.5)*scale); 452 //center.y = cvRound((r.y + r.height*0.5)*scale); 453 //radius = cvRound((r.width + r.height)*0.25*scale); 454 //circle(img, center, radius, color, 3, 8, 0); 455 456 Rect rect(x, y, w, h); 457 rectangle(img, rect, Scalar(255, 255, 0), 1, LINE_8, 0); 458 } 459 else 460 rectangle(img, Point(cvRound(r.x*scale), cvRound(r.y*scale)), 461 Point(cvRound((r.x + r.width - 1)*scale), cvRound((r.y + r.height - 1)*scale)), 462 color, 3, 8, 0); 463 smallImgROI = smallImg(r); 464 } 465 466 } 467 468 } 469 470 /*********************************释放资源*********************************************/ 471 void __cdecl cv_frameRelease() 472 { 473 //free(pBmpArray); 474 delete pBmpArray; 475 } 476 477 void __cdecl cv_capRelease() 478 { 479 if (cap.isOpened()) 480 { 481 cap.release(); 482 frame.release(); 483 } 484 } 485 486 /**************************************************************************************/ 487 488 SAFEARRAY* __cdecl cv_listDevices() 489 { 490 vector<string> list = _getDevices(); 491 size_t deviceCounts = list.size(); 492 493 SAFEARRAY* r; 494 SAFEARRAYBOUND b; 495 b.lLbound = 0; 496 b.cElements = deviceCounts; 497 r = SafeArrayCreate(VT_BSTR, 1, &b); 498 499 BSTR bstrText; 500 char *ch = NULL; 501 502 for (LONG i = 0; i < deviceCounts; i++) 503 { 504 String s = list[i]; 505 size_t len = s.length(); 506 ch = new char[len]; 507 strcpy(ch, s.c_str()); 508 bstrText = _com_util::ConvertStringToBSTR(list[i].c_str()); 509 SafeArrayPutElement(r, &i, SysAllocString(bstrText)); 510 } 511 512 return r; 513 } 514 515 uint8_t * __cdecl cv_loadImage(char * path, IMGINFO * _iinfo, POSITIONINFO * _pinfo) 516 { 517 Mat image = imread(path); 518 519 cout << "loading..." << endl; 520 521 if (!image.data) 522 { 523 return 0; 524 } 525 else 526 { 527 _faceDetect(image, _pinfo); 528 return _convertMat_toBMP(&image.clone(), _iinfo); 529 } 530 } 531 532 int __cdecl cv_openCamera(long id, int w, int h, IMGINFO * info) 533 { 534 cap.open(id); 535 536 cap.set(CAP_PROP_FRAME_WIDTH, w); 537 cap.set(CAP_PROP_FRAME_HEIGHT, h); 538 539 if (!cap.isOpened()) 540 return -1; 541 542 return 0; 543 } 544 545 int __cdecl cv_getVideoParams(_VIDEOINFO * info) 546 { 547 if (!cap.isOpened()) 548 { 549 return -1; 550 } 551 else 552 { 553 info->_width = cap.get(CAP_PROP_FRAME_WIDTH); 554 info->_height = cap.get(CAP_PROP_FRAME_HEIGHT); 555 info->_frameRate = cap.get(CAP_PROP_FPS); 556 info->_totalFrames = cap.get(CAP_PROP_FRAME_COUNT); 557 } 558 559 return 0; 560 } 561 562 uint8_t * __cdecl cv_getVideoStream(IMGINFO * info, POSITIONINFO * _pinfo = NULL) 563 { 564 565 if (cap.isOpened()) 566 { 567 cap >> frame; 568 if (frame.empty()) 569 return 0; 570 571 /****/ 572 _trackingColor(frame, _pinfo); 573 574 /****/ 575 _faceDetect(frame, _pinfo); 576 577 _convertMat_toBMP(&frame, info); 578 } 579 580 if (pBmpArray != NULL) 581 return pBmpArray; 582 return 0; 583 } 584 585 int __cdecl cv_setSelection(UINT8 enable, TRACKOBJECT * obj = NULL) 586 { 587 if (enable == 0) 588 { 589 //开始设置选区 590 selectObject = true; 591 selection.empty(); 592 trackWindow.empty(); 593 } 594 else 595 { 596 //选区设置完成 597 selection.x = obj->x; 598 selection.y = obj->y; 599 selection.width = obj->w; 600 selection.height = obj->h; 601 602 //选区有效,重新计算直方图 603 if (selection.width > 0 && selection.height > 0) 604 { 605 hsize = 16; 606 trackObject = -1; 607 } 608 else 609 { 610 return -1; 611 } 612 613 selectObject = false; 614 } 615 616 return 0; 617 618 } 619 620 void __cdecl cv_setHsvParams(HSVPARAMS * hsv) 621 { 622 vmin = hsv->vmin; 623 vmax = hsv->vmax; 624 smin = hsv->smin; 625 } 626 627 void __cdecl cv_trackObject(UINT8 enable) 628 { 629 trackingEnable = enable; 630 } 631 632 int __cdecl cv_faceDetect(UINT8 enable, const char * _path) 633 { 634 if (enable == 0) 635 { 636 if (cascade.empty()) 637 { 638 //加载分类器 639 if (!cascade.load(_path)) 640 { 641 return -1; //分类器加载失败 642 } 643 else 644 { 645 faceDetectEnable = enable; 646 } 647 } 648 else 649 { 650 faceDetectEnable = enable; 651 } 652 } 653 else 654 { 655 faceDetectEnable = enable; 656 } 657 658 return 0; 659 } 660 661 void __cdecl cv_setFaceParams(double _scale, BOOL _tryflip) 662 { 663 scale = _scale; 664 tryflip = _tryflip; 665 }
##########################################################################
dll调用类
##########################################################################
CvHelper.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Runtime.InteropServices; 7 using System.Drawing; 8 using System.Drawing.Imaging; 9 using System.IO; 10 using System.Threading; 11 12 namespace CvHelper 13 { 14 public class Cv 15 { 16 protected static IntPtr ipr; 17 18 protected enum SWITCHCONFIG:sbyte 19 { 20 ENABLE = 0, 21 DISABLE = 1 22 }; 23 24 //图像信息 25 [StructLayout(LayoutKind.Sequential)] 26 public struct ImageInfo 27 { 28 //[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 29 //public string ShowContent; 30 31 public int width; 32 public int height; 33 public int depth; 34 public int ch; 35 public int size; 36 37 }; 38 39 //视频信息 40 public struct VideoInfo 41 { 42 public double width; 43 public double height; 44 public double frameRate; 45 public double totalFrames; 46 }; 47 48 //位置信息 49 public struct PositionInfo 50 { 51 public int width; 52 public int height; 53 public int x; //中心x 54 public int y; //中心y 55 public int r; //未使用 56 public int facenum; //图片人脸数量//暂放位置信息中 57 } 58 59 //选区 60 public struct SelectObject 61 { 62 public int x, y, w, h; 63 } 64 65 //hsv参数 66 public struct HsvParams 67 { 68 public int hmin, hmax, smin, smax, vmin, vmax; 69 } 70 71 //设备信息 72 public struct DeviceInfo 73 { 74 public long id; 75 public string name; 76 } 77 78 protected static ImageInfo iifo = new ImageInfo(); 79 protected static VideoInfo vifo = new VideoInfo(); 80 protected static PositionInfo pifo = new PositionInfo(); 81 public static SelectObject sobj = new SelectObject(); 82 public static HsvParams phsv = new HsvParams(); 83 protected static byte[] frame; //帧 84 protected static bool isSelect = false; 85 86 public ImageInfo curImgInfo { get { return iifo; } } 87 public static VideoInfo curVideoInfo { get { return vifo; } } 88 public PositionInfo curPosInfo { get { return pifo; } } 89 public static bool isCapOpen { get; private set; } 90 91 //DLL 92 protected const string cv_dll = @"\x64\Debug\cv.dll"; 93 //cascade 94 protected static string cascade = System.Windows.Forms.Application.StartupPath + @"\data\haarcascade_frontalface_alt.xml"; 95 96 //IMPORT DLL 97 //获取设备列表 98 [DllImport(cv_dll, EntryPoint = "cv_listDevices", CallingConvention = CallingConvention.Cdecl)] 99 [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] 100 protected static extern string[] cv_listDevices(); 101 102 //加载图片 103 [DllImport(cv_dll, EntryPoint = "cv_loadImage", CallingConvention = CallingConvention.Cdecl)] 104 protected static extern IntPtr cv_loadImage(string path, ref ImageInfo info, ref PositionInfo pinfo); 105 106 //打开摄像头 107 [DllImport(cv_dll, EntryPoint = "cv_openCamera", CallingConvention = CallingConvention.Cdecl)] 108 protected static extern int cv_openCamera(long id, int w, int h); //设备号//宽度//高度 109 110 //获取视频参数 111 [DllImport(cv_dll, EntryPoint = "cv_getVideoParams", CallingConvention = CallingConvention.Cdecl)] 112 protected static extern int cv_getVideoParams(ref VideoInfo info); 113 114 //获取视频 115 [DllImport(cv_dll, EntryPoint = "cv_getVideoStream", CallingConvention = CallingConvention.Cdecl)] 116 protected static extern IntPtr cv_getVideoStream(ref ImageInfo info, ref PositionInfo _info); 117 118 //颜色跟踪 119 [DllImport(cv_dll, EntryPoint = "cv_setSelection", CallingConvention = CallingConvention.Cdecl)] 120 protected static extern int cv_setSelection(sbyte enable, ref SelectObject sobj); //设置选区//开始//结束 121 [DllImport(cv_dll, EntryPoint = "cv_trackObject", CallingConvention = CallingConvention.Cdecl)] 122 protected static extern void cv_trackObject(sbyte enable); //跟踪 cv_setHsvParams 123 [DllImport(cv_dll, EntryPoint = "cv_setHsvParams", CallingConvention = CallingConvention.Cdecl)] 124 protected static extern void cv_setHsvParams(ref HsvParams hsv); //hsv参数调整 125 126 //人脸识别 127 [DllImport(cv_dll, EntryPoint = "cv_faceDetect", CallingConvention = CallingConvention.Cdecl)] 128 protected static extern int cv_faceDetect(sbyte enable, string cascade); 129 [DllImport(cv_dll, EntryPoint = "cv_setFaceParams", CallingConvention = CallingConvention.Cdecl)] 130 protected static extern void cv_setFaceParams(double scale, bool tryflip); 131 132 //资源释放 133 [DllImport(cv_dll, EntryPoint = "cv_frameRelease", CallingConvention = CallingConvention.Cdecl)] 134 protected static extern void cv_frameRelease(); 135 [DllImport(cv_dll, EntryPoint = "cv_capRelease", CallingConvention = CallingConvention.Cdecl)] 136 protected static extern void cv_capRelease(); 137 138 //定义委托 139 public delegate void VideoStreamDelegate(Bitmap bmp); 140 public static VideoStreamDelegate VideoStreamReceived; 141 142 public delegate void PositionDelegate(int x, int y, int facenum); 143 public static PositionDelegate PosDataReceived; 144 145 public delegate void CascadeLoadDelegate(bool succ); 146 public static CascadeLoadDelegate CascadeLoadProcess; 147 148 protected static System.Threading.Thread videoStreamThread = null; 149 150 //线程处理 151 protected static void VideoStreamHandler() 152 { 153 for (;;) 154 { 155 try 156 { 157 ipr = cv_getVideoStream(ref iifo, ref pifo); 158 159 if (ipr != IntPtr.Zero && isCapOpen) 160 { 161 VideoStreamReceived?.Invoke(BytesToBmp(ipr)); 162 PosDataReceived?.Invoke(pifo.x, pifo.y, pifo.facenum); 163 } 164 else 165 { 166 break; 167 } 168 } 169 catch 170 { 171 ; 172 } 173 174 Thread.CurrentThread.Join(10); 175 //Thread.Sleep(10); 176 } 177 178 cv_capRelease(); 179 isCapOpen = false; 180 videoStreamThread.Abort(); 181 } 182 183 protected static void VideoStreamThreadInit() 184 { 185 if (isCapOpen) 186 { 187 videoStreamThread = new System.Threading.Thread(VideoStreamHandler); 188 videoStreamThread.Start(); 189 } 190 } 191 192 /// <summary> 193 /// 转Bitmap 194 /// </summary> 195 /// <param name="path"></param> 196 protected static Bitmap BytesToBmp(IntPtr _ipr) 197 { 198 if (iifo.size == 0) 199 { 200 return null; 201 } 202 else 203 { 204 frame = new byte[iifo.size]; 205 frame = CvImage.getData(ipr, iifo.size); 206 cv_frameRelease();//资源释放 207 return CvImage.BytesToBitmap(frame); 208 } 209 } 210 211 /// <summary> 212 /// 获取摄像头设备列表 213 /// </summary> 214 /// <returns></returns> 215 public static List<DeviceInfo> GetDeviceList() 216 { 217 //先断开摄像头 218 CloseCamera(); 219 220 DeviceInfo device = new DeviceInfo(); 221 List<DeviceInfo> deviceList = new List<DeviceInfo>(); 222 223 long i = 0; 224 225 foreach (string name in cv_listDevices()) 226 { 227 device.id = i; 228 device.name = name; 229 i++; 230 231 deviceList.Add(device); 232 } 233 234 return deviceList; 235 236 } 237 238 /// <summary> 239 /// 加载图片 240 /// </summary> 241 /// <param name="path"></param> 242 /// <returns></returns> 243 public static Bitmap LoadImage(string path) 244 { 245 if (path == "") 246 return null; 247 248 //先断开摄像头 249 CloseCamera(); 250 251 ipr = cv_loadImage(path, ref iifo, ref pifo); 252 253 if(ipr != IntPtr.Zero) 254 PosDataReceived?.Invoke(pifo.x, pifo.y, pifo.facenum); 255 256 return BytesToBmp(ipr); 257 } 258 259 /// <summary> 260 /// 打开摄像头 261 /// </summary> 262 /// <param name="id"></param> 263 /// <returns></returns> 264 public static bool OpenCamera(long id, int w, int h) 265 { 266 if (cv_openCamera(id, w, h) != 0) 267 { 268 Console.WriteLine("摄像头打开失败"); 269 isCapOpen = false; 270 return false; 271 } 272 else 273 { 274 Console.WriteLine("摄像头打开成功"); 275 isCapOpen = true; 276 277 VideoStreamThreadInit(); 278 return true; 279 } 280 281 } 282 283 //获取视频参数 284 public static VideoInfo GetVideoInfo() 285 { 286 if (isCapOpen) 287 { 288 cv_getVideoParams(ref vifo); 289 } 290 291 return vifo; 292 } 293 294 //关闭摄像头 295 public static void CloseCamera() 296 { 297 if (isCapOpen) 298 { 299 isCapOpen = false; 300 } 301 } 302 303 public static string GetBase64(Bitmap bmp) 304 { 305 return CvImage.ImgToBase64String(bmp); 306 } 307 308 /*******************************************************************************/ 309 //设置选区 310 public static void SelectTrackObjectStart() 311 { 312 if (isCapOpen && isSelect) 313 { 314 cv_setSelection((sbyte)SWITCHCONFIG.ENABLE, ref sobj); 315 } 316 else 317 { 318 Console.WriteLine("请开启跟踪"); 319 } 320 } 321 322 public static int SelectTrackObjectEnd() 323 { 324 int r = -1; 325 if (isSelect) 326 { 327 r = cv_setSelection((sbyte)SWITCHCONFIG.DISABLE, ref sobj); 328 } 329 330 return r; 331 } 332 333 //设置hsv参数 334 public static void SetHsvParams() 335 { 336 if (isSelect) 337 { 338 cv_setHsvParams(ref phsv); 339 } 340 } 341 342 //跟踪 343 public static bool TrackingStart() 344 { 345 if (isCapOpen) 346 { 347 cv_trackObject((sbyte)SWITCHCONFIG.ENABLE); //启用 348 isSelect = true; 349 return true; 350 } 351 else 352 { 353 isSelect = false; 354 return false; 355 } 356 } 357 358 public static void TrackingStop() 359 { 360 cv_trackObject((sbyte)SWITCHCONFIG.DISABLE); //关闭 361 isSelect = true; 362 } 363 364 //人脸检测 365 public static void FaceDetectEnable() 366 { 367 Task.Run(() => 368 { 369 if (cv_faceDetect((sbyte)SWITCHCONFIG.ENABLE, cascade) == 0) 370 { 371 Console.WriteLine("分类器加载完成"); 372 CascadeLoadProcess?.Invoke(true); 373 } 374 else 375 { 376 CascadeLoadProcess?.Invoke(false); 377 } 378 }); 379 } 380 381 public static void FaceDetectDisable() 382 { 383 Task.Run(()=> { 384 cv_faceDetect((sbyte)SWITCHCONFIG.DISABLE, cascade); 385 }); 386 } 387 388 public static void FaceSetScale(double scale, bool tryflip) 389 { 390 cv_setFaceParams(scale, tryflip); 391 } 392 393 public static int GetFaceNum() 394 { 395 return pifo.facenum; 396 } 397 398 399 400 401 } 402 403 class CvImage 404 { 405 //转base64 406 public static string ImgToBase64String(Bitmap bmp) 407 { 408 try 409 { 410 MemoryStream ms = new MemoryStream(); 411 bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 412 byte[] arr = new byte[ms.Length]; 413 ms.Position = 0; 414 ms.Read(arr, 0, (int)ms.Length); 415 ms.Close(); 416 return Convert.ToBase64String(arr); 417 } 418 catch (Exception ex) 419 { 420 return null; 421 } 422 } 423 424 public static byte[] getData(IntPtr pData, int len) 425 { 426 try 427 { 428 byte[] data = new byte[len]; 429 Marshal.Copy(pData, data, 0, len); 430 return data; 431 } 432 catch (Exception ex) 433 { 434 return null; 435 } 436 } 437 438 439 public static Bitmap BytesToBitmap(byte[] Bytes) 440 { 441 MemoryStream stream = null; 442 try 443 { 444 stream = new MemoryStream(Bytes); 445 return new Bitmap((Image)new Bitmap(stream)); 446 } 447 catch (ArgumentNullException ex) 448 { 449 throw ex; 450 } 451 catch (ArgumentException ex) 452 { 453 throw ex; 454 } 455 finally 456 { 457 stream.Close(); 458 } 459 } 460 461 } 462 }
##########################################################################
源码地址:
链接:https://pan.baidu.com/s/1yj9Bk9_g0i8FSVBOLP34YQ
提取码:9my8