推广 热搜: LabVIEW  控制  自动化  电子  自动  软件  sci  编程  机器视觉  视觉 

《使用OpenCV开发机器视觉项目》

   日期:2018-08-22     浏览:59    评论:0    
核心提示:使用OpenCV开发机器视觉项目有以下9个章节Chapters:Ch1) Cartoonifier and Skin Changer for Android, by Shervin Emami.Ch2) Ma
 使用OpenCV开发机器视觉项目

 有以下9个章节

 

Chapters:

  • Ch1) Cartoonifier and Skin Changer for Android, by Shervin Emami.
  • Ch2) Marker-based Augmented Reality on iPhone or iPad, by Khvedchenia Ievgen.
  • Ch3) Marker-less Augmented Reality, by Khvedchenia Ievgen.
  • Ch4) Exploring Structure from Motion using OpenCV, by Roy Shilkrot.
  • Ch5) Number Plate Recognition using SVM and Neural Networks, by David Escrivá.
  • Ch6) Non-rigid Face Tracking, by Jason Saragih.
  • Ch7) 3D Head Pose Estimation using AAM and POSIT, by Daniel Lélis Baggio.
  • Ch8) Face Recognition using Eigenfaces or Fisherfaces, by Shervin Emami.
  • Ch9) Developing Fluid Wall using the Microsoft Kinect, by Naureen Mahmood.
  • Per-chapter Requirements:

    • Ch1: webcam (for desktop app), or Android development system (for Android app).
    • Ch2: iOS development system (to build an iOS app).
    • Ch3: OpenGL built into OpenCV.
    • Ch4: PCL (http://pointclouds.org/) and SSBA (http://www.inf.ethz.ch/personal/chzach/opensource.html).
    • Ch5: nothing.
    • Ch6: nothing, but requires training data for execution.
    • Ch7: nothing.
    • Ch8: webcam.
    • Ch9: Kinect depth sensor.

Screenshots:

  • Ch1) Cartoonifier and Skin Changer for Android: Ch1) Cartoo<em></em>nifier and Skin Changer for Android
  • Ch2) Marker-based Augmented Reality on iPhone or iPad: Ch2) Marker-ba<em></em>sed Augmented Reality on iPhone or iPad
  • Ch3) Marker-less Augmented Reality: Ch3) Marker-less Augmented Reality
  • Ch4) Exploring Structure from Motion using OpenCV: Ch4) Exploring Structure from Motion using OpenCV
  • Ch5) Number Plate Recognition using SVM and Neural Networks: Ch5) Number Plate Recognition using SVM and Neural Networks
  • Ch6) Non-rigid Face Tracking: Ch6) Non-rigid Face Tracking
  • Ch7) 3D Head Pose Estimation using AAM and POSIT: Ch7) 3D Head Pose Estimation using AAM and POSIT
  • Ch8) Face Recognition using Eigenfaces or Fisherfaces: Ch8) Face Recognition using Eigenfaces or Fisherfaces
  • Ch9) Developing Fluid Wall using the Microsoft Kinect: Ch9) Developing Fluid Wall using the Microsoft Kinect

     看看,他们确实涵盖了当今最热门的一些机器视觉相关项目,其中包括我喜欢的Kinect,甚至我熟悉的人脸识别、人脸跟踪、人脸朝向估计等等(这么多关于人脸的!),还包括虚拟现实之类技术,有时间也得看看。这本书可以买纸质版也可以买电子版,购买地址 PacktPub。好吧,估计一般人是买不到的,国外的书果然不便宜,$44.99

     不过书中配套的项目源码倒是都有的!https://github.com/MasteringOpenCV/code

     

第一个项目:卡通画和肤色变化初探

我在windows上尝试编译了第一个例子(他既有android平台的代码也给出了PC平台的)。以下是截图:

    第一张和第四张图片都是卡通图,第2张是evil状态的,所以有点惨不忍睹吧,第三张是素描。具体算法我还未去细读,给出下载第一个项目的VS2010地址。通过debug可以编译出可用的exe,而release尽然无法检测到摄像头以致exe无法运行,编译时注意。

   给出主要的卡通画函数实现代码:

[cpp] view plaincopy
 
 
  1.   
  2.   
  3. #include "cartoon.h"  
  4. #include "ImageUtils.h" // Handy functions for debugging OpenCV images, by Shervin Emami.  
  5.   
  6.   
  7.   
  8. // Convert the given photo into a cartoon-like or painting-like image.  
  9. // Set sketchMode to true if you want a line drawing instead of a painting.  
  10. // Set alienMode to true if you want alien skin instead of human.  
  11. // Set evilMode to true if you want an "evil" character instead of a "good" character.  
  12. // Set debugType to 1 to show where skin color is taken from, and 2 to show the skin mask in a new window (for desktop).  
  13. void cartoonifyImage(Mat srcColor, Mat dst, bool sketchMode, bool alienMode, bool evilMode, int debugType)  
  14. {  
  15.     // Convert from BGR color to Grayscale  
  16.     Mat srcGray;  
  17.     cvtColor(srcColor, srcGray, CV_BGR2GRAY);  
  18.   
  19.     // Remove the pixel noise with a good Median filter, before we start detecting edges.  
  20.     medianBlur(srcGray, srcGray, 7);  
  21.   
  22.     Size size = srcColor.size();  
  23.     Mat mask = Mat(size, CV_8U);  
  24.     Mat edges = Mat(size, CV_8U);  
  25.     if (!evilMode) {  
  26.         // Generate a nice edge mask, similar to a pencil line drawing.  
  27.         Laplacian(srcGray, edges, CV_8U, 5);  
  28.         threshold(edges, mask, 80, 255, THRESH_BINARY_INV);  
  29.         // Mobile cameras usually have lots of noise, so remove small  
  30.         // dots of black noise from the black & white edge mask.  
  31.         removePepperNoise(mask);  
  32.     }  
  33.     else {  
  34.         // Evil mode, making everything look like a scary bad guy.  
  35.         // (Where "srcGray" is the original grayscale image plus a medianBlur of size 7x7).  
  36.         Mat edges2;  
  37.         Scharr(srcGray, edges, CV_8U, 1, 0);  
  38.         Scharr(srcGray, edges2, CV_8U, 1, 0, -1);  
  39.         edges += edges2;  
  40.         threshold(edges, mask, 12, 255, THRESH_BINARY_INV);  
  41.         medianBlur(mask, mask, 3);  
  42.     }  
  43.     //imshow("edges", edges);  
  44.     //imshow("mask", mask);  
  45.   
  46.     // For sketch mode, we just need the mask!  
  47.     if (sketchMode) {  
  48.         // The output image has 3 channels, not a single channel.  
  49.         cvtColor(mask, dst, CV_GRAY2BGR);  
  50.         return;  
  51.     }  
  52.   
  53.     // Do the bilateral filtering at a shrunken scale, since it  
  54.     // runs so slowly but doesn't need full resolution for a good effect.  
  55.     Size smallSize;  
  56.     smallSize.width = size.width/2;  
  57.     smallSize.height = size.height/2;  
  58.     Mat smallImg = Mat(smallSize, CV_8UC3);  
  59.     resize(srcColor, smallImg, smallSize, 0,0, INTER_LINEAR);  
  60.   
  61.     // Perform many iterations of weak bilateral filtering, to enhance the edges  
  62.     // while blurring the flat regions, like a cartoon.  
  63.     Mat tmp = Mat(smallSize, CV_8UC3);  
  64.     int repetitions = 7;        // Repetitions for strong cartoon effect.  
  65.     for (int i=0; i<repetitions; i++) {  
  66.         int size = 9;           // Filter size. Has a large effect on speed.  
  67.         double sigmaColor = 9;  // Filter color strength.  
  68.         double sigmaSpace = 7;  // Positional strength. Effects speed.  
  69.         bilateralFilter(smallImg, tmp, size, sigmaColor, sigmaSpace);  
  70.         bilateralFilter(tmp, smallImg, size, sigmaColor, sigmaSpace);  
  71.     }  
  72.   
  73.     if (alienMode) {  
  74.         // Apply an "alien" filter, when given a shrunken image and the full-res edge mask.  
  75.         // Detects the color of the pixels in the middle of the image, then changes the color of that region to green.  
  76.         changeFacialSkinColor(smallImg, edges, debugType);  
  77.     }  
  78.   
  79.     // Go back to the original scale.  
  80.     resize(smallImg, srcColor, size, 0,0, INTER_LINEAR);  
  81.   
  82.     // Clear the output image to black, so that the cartoon line drawings will be black (ie: not drawn).  
  83.     memset((char*)dst.data, 0, dst.step * dst.rows);  
  84.   
  85.     // Use the blurry cartoon image, except for the strong edges that we will leave black.  
  86.     srcColor.copyTo(dst, mask);  
  87. }  
  88.   
  89.   
  90.   
  91. // Apply an "alien" filter, when given a shrunken BGR image and the full-res edge mask.  
  92. // Detects the color of the pixels in the middle of the image, then changes the color of that region to green.  
  93. void changeFacialSkinColor(Mat smallImgBGR, Mat bigEdges, int debugType)  
  94. {  
  95.         // Convert to Y'CrCb color-space, since it is better for skin detection and color adjustment.  
  96.         Mat yuv = Mat(smallImgBGR.size(), CV_8UC3);  
  97.         cvtColor(smallImgBGR, yuv, CV_BGR2YCrCb);  
  98.   
  99.         // The floodFill mask has to be 2 pixels wider and 2 pixels taller than the small image.  
  100.         // The edge mask is the full src image size, so we will shrink it to the small size,  
  101.         // storing into the floodFill mask data.  
  102.         int sw = smallImgBGR.cols;  
  103.         int sh = smallImgBGR.rows;  
  104.         Mat maskPlusBorder = Mat::zeros(sh+2, sw+2, CV_8U);  
  105.         Mat mask = maskPlusBorder(Rect(1,1,sw,sh));  // mask is a ROI in maskPlusBorder.  
  106.         resize(bigEdges, mask, smallImgBGR.size());  
  107.   
  108.         // Make the mask values just 0 or 255, to remove weak edges.  
  109.         threshold(mask, mask, 80, 255, THRESH_BINARY);  
  110.         // Connect the edges together, if there was a pixel gap between them.  
  111.         dilate(mask, mask, Mat());  
  112.         erode(mask, mask, Mat());  
  113.         //imshow("constraints for floodFill", mask);  
  114.   
  115.         // YCrCb Skin detector and color changer using multiple flood fills into a mask.  
  116.         // Apply flood fill on many points around the face, to cover different shades & colors of the face.  
  117.         // Note that these values are dependent on the face outline, drawn in drawFaceStickFigure().  
  118.         int const NUM_SKIN_POINTS = 6;  
  119.         Point skinPts[NUM_SKIN_POINTS];  
  120.         skinPts[0] = Point(sw/2,          sh/2 - sh/6);  
  121.         skinPts[1] = Point(sw/2 - sw/11,  sh/2 - sh/6);  
  122.         skinPts[2] = Point(sw/2 + sw/11,  sh/2 - sh/6);  
  123.         skinPts[3] = Point(sw/2,          sh/2 + sh/16);  
  124.         skinPts[4] = Point(sw/2 - sw/9,   sh/2 + sh/16);  
  125.         skinPts[5] = Point(sw/2 + sw/9,   sh/2 + sh/16);  
  126.         // Skin might be fairly dark, or slightly less colorful.  
  127.         // Skin might be very bright, or slightly more colorful but not much more blue.  
  128.         const int LOWER_Y = 60;  
  129.         const int UPPER_Y = 80;  
  130.         const int LOWER_Cr = 25;  
  131.         const int UPPER_Cr = 15;  
  132.         const int LOWER_Cb = 20;  
  133.         const int UPPER_Cb = 15;  
  134.         Scalar lowerDiff = Scalar(LOWER_Y, LOWER_Cr, LOWER_Cb);  
  135.         Scalar upperDiff = Scalar(UPPER_Y, UPPER_Cr, UPPER_Cb);  
  136.         // Instead of drawing into the "yuv" image, just draw 1's into the "maskPlusBorder" image, so we can apply it later.  
  137.         // The "maskPlusBorder" is initialized with the edges, because floodFill() will not go across non-zero mask pixels.  
  138.         Mat edgeMask = mask.clone();    // Keep an duplicate copy of the edge mask.  
  139.         for (int i=0; i<NUM_SKIN_POINTS; i++) {  
  140.             // Use the floodFill() mode that stores to an external mask, instead of the input image.  
  141.             const int flags = 4 | FLOODFILL_FIXED_RANGE | FLOODFILL_MASK_ONLY;  
  142.             floodFill(yuv, maskPlusBorder, skinPts[i], Scalar(), NULL, lowerDiff, upperDiff, flags);  
  143.             if (debugType >= 1)  
  144.                 circle(smallImgBGR, skinPts[i], 5, CV_RGB(0, 0, 255), 1, CV_AA);  
  145.         }  
  146.         if (debugType >= 2)  
  147.             imshow("flood mask", mask*120); // Draw the edges as white and the skin region as grey.  
  148.   
  149.         // After the flood fill, "mask" contains both edges and skin pixels, whereas  
  150.         // "edgeMask" just contains edges. So to get just the skin pixels, we can remove the edges from it.  
  151.         mask -= edgeMask;  
  152.         // "mask" now just contains 1's in the skin pixels and 0's for non-skin pixels.  
  153.   
  154.         // Change the color of the skin pixels in the given BGR image.  
  155.         int Red = 0;  
  156.         int Green = 70;  
  157.         int Blue = 0;  
  158.         add(smallImgBGR, Scalar(Blue, Green, Red), smallImgBGR, mask);  
  159. }  
  160.   
  161.   
  162. // Remove black dots (upto 4x4 in size) of noise from a pure black & white image.  
  163. // ie: The input image should be mostly white (255) and just contains some black (0) noise  
  164. // in addition to the black (0) edges.  
  165. void removePepperNoise(Mat &mask)  
  166. {  
  167.     // For simplicity, ignore the top & bottom row border.  
  168.     for (int y=2; y<mask.rows-2; y++) {  
  169.         // Get access to each of the 5 rows near this pixel.  
  170.         uchar *pThis = mask.ptr(y);  
  171.         uchar *pUp1 = mask.ptr(y-1);  
  172.         uchar *pUp2 = mask.ptr(y-2);  
  173.         uchar *pDown1 = mask.ptr(y+1);  
  174.         uchar *pDown2 = mask.ptr(y+2);  
  175.   
  176.         // For simplicity, ignore the left & right row border.  
  177.         pThis += 2;  
  178.         pUp1 += 2;  
  179.         pUp2 += 2;  
  180.         pDown1 += 2;  
  181.         pDown2 += 2;  
  182.         for (int x=2; x<mask.cols-2; x++) {  
  183.             uchar v = *pThis;   // Get the current pixel value (either 0 or 255).  
  184.             // If the current pixel is black, but all the pixels on the 2-pixel-radius-border are white  
  185.             // (ie: it is a small island of black pixels, surrounded by white), then delete that island.  
  186.             if (v == 0) {  
  187.                 bool allAbove = *(pUp2 - 2) && *(pUp2 - 1) && *(pUp2) && *(pUp2 + 1) && *(pUp2 + 2);  
  188.                 bool allLeft = *(pUp1 - 2) && *(pThis - 2) && *(pDown1 - 2);  
  189.                 bool allBelow = *(pDown2 - 2) && *(pDown2 - 1) && *(pDown2) && *(pDown2 + 1) && *(pDown2 + 2);  
  190.                 bool allRight = *(pUp1 + 2) && *(pThis + 2) && *(pDown1 + 2);  
  191.                 bool surroundings = allAbove && allLeft && allBelow && allRight;  
  192.                 if (surroundings == true) {  
  193.                     // Fill the whole 5x5 block as white. Since we know the 5x5 borders  
  194.                     // are already white, just need to fill the 3x3 inner region.  
  195.                     *(pUp1 - 1) = 255;  
  196.                     *(pUp1 + 0) = 255;  
  197.                     *(pUp1 + 1) = 255;  
  198.                     *(pThis - 1) = 255;  
  199.                     *(pThis + 0) = 255;  
  200.                     *(pThis + 1) = 255;  
  201.                     *(pDown1 - 1) = 255;  
  202.                     *(pDown1 + 0) = 255;  
  203.                     *(pDown1 + 1) = 255;  
  204.                 }  
  205.                 // Since we just covered the whole 5x5 block with white, we know the next 2 pixels  
  206.                 // won't be black, so skip the next 2 pixels on the right.  
  207.                 pThis += 2;  
  208.                 pUp1 += 2;  
  209.                 pUp2 += 2;  
  210.                 pDown1 += 2;  
  211.                 pDown2 += 2;  
  212.             }  
  213.             // Move to the next pixel.  
  214.             pThis++;  
  215.             pUp1++;  
  216.             pUp2++;  
  217.             pDown1++;  
  218.             pDown2++;  
  219.         }  
  220.     }  
  221. }  
  222.   
  223.   
  224. // Draw an anti-aliased face outline, so the user knows where to put their face.  
  225. // Note that the skin detector for "alien" mode uses points around the face based on the face  
  226. // dimensions shown by this function.  
  227. void drawFaceStickFigure(Mat dst)  
  228. {  
  229.     Size size = dst.size();  
  230.     int sw = size.width;  
  231.     int sh = size.height;  
  232.   
  233.     // Draw the face onto a color image with black background.  
  234.     Mat faceOutline = Mat::zeros(size, CV_8UC3);  
  235.     Scalar color = CV_RGB(255,255,0);   // Yellow  
  236.     int thickness = 4;  
  237.     // Use 70% of the screen height as the face height.  
  238.     int faceH = sh/2 * 70/100;  // "faceH" is actually half the face height (ie: radius of the ellipse).  
  239.     // Scale the width to be the same nice shape for any screen width (based on screen height).  
  240.     int faceW = faceH * 72/100; // Use a face with an aspect ratio of 0.72  
  241.     // Draw the face outline.  
  242.     ellipse(faceOutline, Point(sw/2, sh/2), Size(faceW, faceH), 0, 0, 360, color, thickness, CV_AA);  
  243.     // Draw the eye outlines, as 2 half ellipses.  
  244.     int eyeW = faceW * 23/100;  
  245.     int eyeH = faceH * 11/100;  
  246.     int eyeX = faceW * 48/100;  
  247.     int eyeY = faceH * 13/100;  
  248.     // Set the angle and shift for the eye half ellipses.  
  249.     int eyeA = 15; // angle in degrees.  
  250.     int eyeYshift = 11;  
  251.     // Draw the top of the right eye.  
  252.     ellipse(faceOutline, Point(sw/2 - eyeX, sh/2 - eyeY), Size(eyeW, eyeH), 0, 180+eyeA, 360-eyeA, color, thickness, CV_AA);  
  253.     // Draw the bottom of the right eye.  
  254.     ellipse(faceOutline, Point(sw/2 - eyeX, sh/2 - eyeY - eyeYshift), Size(eyeW, eyeH), 0, 0+eyeA, 180-eyeA, color, thickness, CV_AA);  
  255.     // Draw the top of the left eye.  
  256.     ellipse(faceOutline, Point(sw/2 + eyeX, sh/2 - eyeY), Size(eyeW, eyeH), 0, 180+eyeA, 360-eyeA, color, thickness, CV_AA);  
  257.     // Draw the bottom of the left eye.  
  258.     ellipse(faceOutline, Point(sw/2 + eyeX, sh/2 - eyeY - eyeYshift), Size(eyeW, eyeH), 0, 0+eyeA, 180-eyeA, color, thickness, CV_AA);  
  259.   
  260.     // Draw the bottom lip of the mouth.  
  261.     int mouthY = faceH * 53/100;  
  262.     int mouthW = faceW * 45/100;  
  263.     int mouthH = faceH * 6/100;  
  264.     ellipse(faceOutline, Point(sw/2, sh/2 + mouthY), Size(mouthW, mouthH), 0, 0, 180, color, thickness, CV_AA);  
  265.   
  266.     // Draw anti-aliased text.  
  267.     int fontFace = FONT_HERSHEY_COMPLEX;  
  268.     float fontScale = 1.0f;  
  269.     int fontThickness = 2;  
  270.     putText(faceOutline, "Put your face here", Point(sw * 23/100, sh * 10/100), fontFace, fontScale, color, fontThickness, CV_AA);  
  271.     //imshow("faceOutline", faceOutline);  
  272.   
  273.     // Overlay the outline with alpha blending.  
  274.     addWeighted(dst, 1.0, faceOutline, 0.7, 0, dst, CV_8UC3);  
  275. }  
 
打赏
 
更多>同类编程
0相关评论

推荐图文
推荐编程
点击排行

网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报