知识点

- RGB色彩空间

是我们最常用的色彩空间,且与设备无关。

- HSV色彩空间

对于一些直方图相关的图像处理和算法,将其转到HSV色彩空间,通常会取得较好的效果。

- YUV色彩空间

一种跟设备有关的色彩空间。

- YCrCb色彩空间

常用作皮肤检测,根据一些颜色的统计模型,通常会取得较好的效果。

API知识点

  • 色彩空间转换 cvtColor

  • 提取指定色彩范围区域 inRange
    image.png
    注:关于 HSV 各通道在 OpenCV 中取值范围的确定

上图清晰的列出来不同的颜色在HSV色彩空间的最小值和最大值。利用这个取值范围,我们便可以实现一些好玩的应用。

例如,绿色在HSV色彩空间的取值范围是(35, 43, 46)—(77, 255, 255)。通过inRange函数,可以很方便的将人物和绿幕背景分离出来。再通过像素的逻辑操作与或非,便可以实现更换背景的效果~~

C++代码

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. using namespace std;
  4. using namespace cv;
  5. void day09() {
  6. Mat src = imread("E:\\_Image\\OpenCVTest\\tinygreen.jpg");
  7. if (src.empty()) {
  8. cout << "could not load image.." << endl;
  9. return;
  10. }
  11. imshow("src", src);
  12. Mat hsv, mask, mask_not, people;
  13. cvtColor(src, hsv, COLOR_BGR2HSV);
  14. // 获取背景蒙版,即绿幕部分为白,前景人物部分为黑
  15. inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);
  16. imshow("mask", mask);
  17. // 蒙版取非,即前景人物部分为白色
  18. bitwise_not(mask, mask_not);
  19. imshow("mask_not", mask_not);
  20. // 利用蒙版,将人物部分抠出
  21. bitwise_and(src, src, people, mask_not);
  22. imshow("people", people);
  23. // 取一张背景图,并截取与mask相同尺寸的部分
  24. Mat scene = imread("E:\\_Image\\OpenCVTest\\scene.jpg");
  25. Mat dstScene(scene, Rect(0, 0, people.cols, people.rows));
  26. imshow("dstScene", dstScene);
  27. // 利用蒙版,在背景图中扣掉待填充的人物蒙版部分
  28. Mat sceneBackground, finalImage;
  29. bitwise_and(dstScene, dstScene, sceneBackground, mask);
  30. imshow("sceneBackground", sceneBackground);
  31. // 或操作,将人物融入背景图中
  32. bitwise_or(sceneBackground, people, finalImage);
  33. imshow("final", finalImage);
  34. waitKey(0);
  35. }

Python代码

  1. import cv2 as cv
  2. # 查看版本
  3. print(cv.__version__)
  4. # 读取显示图像
  5. src = cv.imread("E:/_Image/OpenCVTest/tinygreen.jpg")
  6. cv.imshow("bgr", src)
  7. # RGB to HSV
  8. hsv = cv.cvtColor(src, cv.COLOR_BGR2HSV)
  9. cv.imshow("hsv", hsv)
  10. # RGB to YUV
  11. yuv = cv.cvtColor(src, cv.COLOR_BGR2YUV)
  12. cv.imshow("yuv", yuv)
  13. # RGB to YUV
  14. ycrcb = cv.cvtColor(src, cv.COLOR_BGR2YCrCb)
  15. cv.imshow("ycrcb", ycrcb)
  16. # 获取背景蒙版,即绿幕部分为白,前景人物部分为黑
  17. mask = cv.inRange(hsv, (35, 43, 46), (77, 255, 255))
  18. cv.imshow("mask", mask)
  19. # 蒙版取非,即前景人物部分为白色
  20. mask_not = cv.bitwise_not(mask)
  21. cv.imshow("mask_not", mask_not)
  22. # 利用蒙版,将人物部分抠出
  23. people = cv.bitwise_and(src, src, mask=mask_not)
  24. cv.imshow("people", people)
  25. # 取一张背景图,并截取与mask相同尺寸的部分
  26. scene = cv.imread("E:/_Image/OpenCVTest/scene.jpg")
  27. dstScene = scene[:people.shape[0], :people.shape[1], :]
  28. cv.imshow("dstScene", dstScene)
  29. # 利用蒙版,在背景图中扣掉待填充的人物蒙版部分
  30. sceneBackground = cv.bitwise_and(dstScene, dstScene, mask=mask)
  31. cv.imshow("sceneBackground", sceneBackground)
  32. # 或操作,将人物融入背景图中
  33. finalImage = cv.bitwise_or(sceneBackground, people)
  34. cv.imshow("finalImage", finalImage)
  35. # 等待键盘输入 释放内存
  36. cv.waitKey(0)
  37. cv.destroyAllWindows()

Javascript代码

  1. <template>
  2. <div>
  3. <p>色彩空间的转换及应用</p>
  4. <p id="status">OpenCV.js is loading...</p>
  5. <div class="inputoutput">
  6. <img id="imageSrc" src="imgs/tinygreen.jpg" />
  7. <img id="imageSrc2" src="imgs/scene.jpg" />
  8. </div>
  9. <div class="inputoutput">
  10. <canvas id="canvasOutput"></canvas>
  11. <div class="caption">canvasOutput</div>
  12. </div>
  13. </div>
  14. </template>
  15. <script>
  16. export default {
  17. name: "day09",
  18. mounted() {
  19. this.init();
  20. },
  21. destoryed() {},
  22. data() {
  23. return {
  24. mats: [],
  25. };
  26. },
  27. methods: {
  28. init() {
  29. setTimeout(() => {
  30. if (window.cv) {
  31. this.onOpenCvReady(window.cv);
  32. } else {
  33. this.init();
  34. }
  35. }, 500);
  36. },
  37. onOpenCvReady(cv) {
  38. document.getElementById("status").innerHTML = "OpenCV.js is ready.";
  39. // 官方文档链接:https://docs.opencv.org/4.5.0/db/d64/tutorial_js_colorspaces.html
  40. let src = this.createMat(cv, 1, { name: "imageSrc" });
  41. // 转化到 HSV 色彩空间
  42. let hsv = this.createMat(cv, 2);
  43. cv.cvtColor(src, hsv, cv.COLOR_RGB2HSV);
  44. // 获取背景蒙版,即绿幕部分为白,前景人物部分为黑
  45. let mask = this.createMat(cv, 2);
  46. let low = this.createMat(cv, 3, {
  47. rows: src.rows,
  48. cols: src.cols,
  49. type: cv.CV_8UC3,
  50. initValue: [35, 43, 46, 255],
  51. });
  52. let high = this.createMat(cv, 3, {
  53. rows: src.rows,
  54. cols: src.cols,
  55. type: cv.CV_8UC3,
  56. initValue: [77, 255, 255, 255],
  57. });
  58. cv.inRange(hsv, low, high, mask);
  59. // 蒙版取非,即前景人物部分为白色
  60. let mask_not = this.createMat(cv, 2);
  61. cv.bitwise_not(mask, mask_not);
  62. // 利用蒙版,将人物部分抠出
  63. let people = this.createMat(cv, 2);
  64. cv.bitwise_and(src, src, people, mask_not);
  65. // 取一张背景图,并截取与mask相同尺寸的部分
  66. let scene = this.createMat(cv, 1, { name: "imageSrc2" });
  67. let rect = new cv.Rect(0, 0, people.cols, people.rows);
  68. let dstScene = this.createMat(cv, 2);
  69. dstScene = scene.roi(rect);
  70. // 利用蒙版,在背景图中扣掉待填充的人物蒙版部分
  71. let sceneBackground = this.createMat(cv, 2);
  72. cv.bitwise_and(dstScene, dstScene, sceneBackground, mask);
  73. // 或操作,将人物融入背景图中
  74. let finalImage = this.createMat(cv, 2);
  75. cv.bitwise_or(sceneBackground, people, finalImage);
  76. // 显示图像
  77. cv.imshow("canvasOutput", finalImage);
  78. // 销毁所有 mat
  79. this.destoryAllMats();
  80. },
  81. createMat(cv, type, ops) {
  82. switch (type) {
  83. case 1:
  84. if (ops && ops.name) {
  85. let mat = cv.imread(ops.name);
  86. this.mats.push(mat);
  87. return mat;
  88. }
  89. break;
  90. case 2: {
  91. let mat = new cv.Mat();
  92. this.mats.push(mat);
  93. return mat;
  94. }
  95. case 3:
  96. if (ops && ops.rows && ops.cols && ops.type && ops.initValue) {
  97. let mat = new cv.Mat(ops.rows, ops.cols, ops.type, ops.initValue);
  98. this.mats.push(mat);
  99. return mat;
  100. }
  101. break;
  102. default:
  103. break;
  104. }
  105. },
  106. destoryAllMats() {
  107. this.mats.forEach((item) => {
  108. item.delete();
  109. });
  110. },
  111. },
  112. };
  113. </script>
  114. <style lang="scss" scoped>
  115. </style>

image.png