每过几天就去看看OpenCV.org的更新,今天突然发现了一个有趣的东西。http://opencv.org/mastering-opencv-with-practical-computer-vision-projects.html。弄opencv的人出版了一个Mastering OpenCV with Practical Computer Vision Projects的书,也就是用OpenCV开发的一切有意思的项目。

使用OpenCV开发机器视觉项目

有以下9个章节

Chapters:

Screenshots:

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

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

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

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

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

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

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

使用OpenCV开发机器视觉项目相关推荐

  1. 大恒相机开发(大恒SDK+opencv开发)笔记1

    大恒相机开发(大恒SDK+opencv开发 一.项目简介 在大三上学期做过人脸识别的开发,刚好下学期老师手中有相机的项目,然后项目就到了我手上,下面是我开发这个项目的一些经历,进程还在调试中.笔记会按 ...

  2. 一位编程15年的大佬:我的OpenCV开发高手成长之路

    01 个人经历 15年编程经验的码农,从最初自己写算法开发,到后来使用OpenCV框架开发,2016年跟随深度学习的脚步开始使用深度学习来解决视觉问题,书籍<Java数字图像处理-编程技巧与应用 ...

  3. Mac平台下Opencv开发环境搭建

    OpenCV(Open Source Computer Vision Library),是一个开源的跨平台的计算机视觉库,它实现了图像处理和计算机视觉领域的很多通用算法,可以在多种计算机平台上运行,支 ...

  4. android搭建opencv开发环境,Android Studio搭建opencv开发环境

    文章不配图片,阅读需要有Android开发基础并熟悉Android Studio. 一.搭建基于Java开发环境 以下内容介绍如何搭建基于Java jni的opencv开发环境. 1.准备工作 从op ...

  5. java opencv安装路径_Java搭建opencv开发环境

    由本菜13历经4天才搭建的好的Java OpenCv开发环境带来 . PS:不保证过程都是必须的,必要的. 反正我自己成功了... 嘿嘿嘿. 官方网站 SourceForge 点击FilesFiles ...

  6. OpenCV开发团队开源计算机视觉标注工具CVAT

    OpenCV开发团队开源计算机视觉标注工具Computer Vision Annotation Tool (CVAT) 同时支持图像和视频的标注,最大特点是专业!专业团队做的专业水准的工具! (关注& ...

  7. 海康威视摄像机的实时读取篇一(OpenCV开发环境配置)

    利用海康SDK+OpenCV,实现海康摄像机图像实时读取.篇一介绍环境配置及相关注意事项. OpenCV开发环境配置 1.下载opencv-2.4.11(其他版本配置过程相似),下载完成后,双击文件会 ...

  8. 新书推荐 |《OpenCV 4计算机视觉项目实战(原书第2版)》

    新书推荐 <OpenCV 4计算机视觉项目实战(原书第2版)> 长按二维码 了解及购买 一本使用OpenCV进行计算机视觉应用开发的实践,指南不仅介绍OpenCV基础知识,还详细讲解各种实 ...

  9. VS2022永久配置OpenCV开发环境

    在VS2022中配置opencv开发环境 本文通过在VS2022中添加并配置项目属性表,实现Opencv永久配置.在不更改opencv文件位置的前提下,只需要在新的项目中添加配置好的项目属性表即可快速 ...

最新文章

  1. YARN-2.7.3-源码分析系列2:启动脚本原理的分析
  2. 话里话外:按单制造(MTO II)企业的资源瓶颈是怎么形成的?
  3. call_user_fun()函数的使用
  4. python中文软件-Python
  5. apache 提示You don't have permission to access /test.php on this server.怎样解决
  6. iOS中的armv6、armv7、armv7s
  7. Codeforces Round #618 (Div. 2)-C. Anu Has a Function
  8. 2019年用于自动化的5个最佳Java测试框架
  9. python数据结构与算法
  10. CSDN开发者周刊 TDengine:专为物联网订制的大数据平台 YugaByte DB:高性能的分布式ACID事务数据库
  11. 【Android学习笔记】【Android学习资源】GitHub上史上最全的Android开源项目分类汇总
  12. 常用Windows快捷键大全
  13. jsp + servlet 复习(C01)
  14. 锐文科技发布基于国产FPGA的智能网卡芯片
  15. 周易六十四卦——地风升卦
  16. 【设计模式】:单例设计模式深究
  17. iOS疯狂讲解之手势识别器
  18. 大数据分析工程师大纲
  19. 工资重要还是五险一金重要
  20. NR CSI(三) CQI

热门文章

  1. 【笔记】2010-11-25记录
  2. 如何运行Perl和查看帮助
  3. OVS DPDK--virtqueue(十七)
  4. java中 菜单的触发事件_javaweb ajax+div实现左边菜单右边内容时点击菜单应该触发事件但是右边没反应...
  5. OMAP-L138核心板
  6. [K/3Cloud] KSQL 关联表更新字段Update语法
  7. nagios出现乱码
  8. 配置内网邮件和外网邮件互发
  9. Linux编程简介——动态链接库
  10. Centos 5.8 安装KVM虚拟机学习笔记