opencv颜色跟踪以及人脸检测的小工具

图:

dll:

##########################################################################

.h

 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
View Code

 

.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

posted @ 2019-12-28 23:49  Yan327  阅读(412)  评论(0编辑  收藏  举报