知识点
- RGB色彩空间
是我们最常用的色彩空间,且与设备无关。
- HSV色彩空间
对于一些直方图相关的图像处理和算法,将其转到HSV色彩空间,通常会取得较好的效果。
- YUV色彩空间
一种跟设备有关的色彩空间。
- YCrCb色彩空间
常用作皮肤检测,根据一些颜色的统计模型,通常会取得较好的效果。
API知识点
色彩空间转换 cvtColor
提取指定色彩范围区域 inRange

注:关于 HSV 各通道在 OpenCV 中取值范围的确定
上图清晰的列出来不同的颜色在HSV色彩空间的最小值和最大值。利用这个取值范围,我们便可以实现一些好玩的应用。
例如,绿色在HSV色彩空间的取值范围是(35, 43, 46)—(77, 255, 255)。通过inRange函数,可以很方便的将人物和绿幕背景分离出来。再通过像素的逻辑操作与或非,便可以实现更换背景的效果~~
C++代码
#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;void day09() {Mat src = imread("E:\\_Image\\OpenCVTest\\tinygreen.jpg");if (src.empty()) {cout << "could not load image.." << endl;return;}imshow("src", src);Mat hsv, mask, mask_not, people;cvtColor(src, hsv, COLOR_BGR2HSV);// 获取背景蒙版,即绿幕部分为白,前景人物部分为黑inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);imshow("mask", mask);// 蒙版取非,即前景人物部分为白色bitwise_not(mask, mask_not);imshow("mask_not", mask_not);// 利用蒙版,将人物部分抠出bitwise_and(src, src, people, mask_not);imshow("people", people);// 取一张背景图,并截取与mask相同尺寸的部分Mat scene = imread("E:\\_Image\\OpenCVTest\\scene.jpg");Mat dstScene(scene, Rect(0, 0, people.cols, people.rows));imshow("dstScene", dstScene);// 利用蒙版,在背景图中扣掉待填充的人物蒙版部分Mat sceneBackground, finalImage;bitwise_and(dstScene, dstScene, sceneBackground, mask);imshow("sceneBackground", sceneBackground);// 或操作,将人物融入背景图中bitwise_or(sceneBackground, people, finalImage);imshow("final", finalImage);waitKey(0);}
Python代码
import cv2 as cv# 查看版本print(cv.__version__)# 读取显示图像src = cv.imread("E:/_Image/OpenCVTest/tinygreen.jpg")cv.imshow("bgr", src)# RGB to HSVhsv = cv.cvtColor(src, cv.COLOR_BGR2HSV)cv.imshow("hsv", hsv)# RGB to YUVyuv = cv.cvtColor(src, cv.COLOR_BGR2YUV)cv.imshow("yuv", yuv)# RGB to YUVycrcb = cv.cvtColor(src, cv.COLOR_BGR2YCrCb)cv.imshow("ycrcb", ycrcb)# 获取背景蒙版,即绿幕部分为白,前景人物部分为黑mask = cv.inRange(hsv, (35, 43, 46), (77, 255, 255))cv.imshow("mask", mask)# 蒙版取非,即前景人物部分为白色mask_not = cv.bitwise_not(mask)cv.imshow("mask_not", mask_not)# 利用蒙版,将人物部分抠出people = cv.bitwise_and(src, src, mask=mask_not)cv.imshow("people", people)# 取一张背景图,并截取与mask相同尺寸的部分scene = cv.imread("E:/_Image/OpenCVTest/scene.jpg")dstScene = scene[:people.shape[0], :people.shape[1], :]cv.imshow("dstScene", dstScene)# 利用蒙版,在背景图中扣掉待填充的人物蒙版部分sceneBackground = cv.bitwise_and(dstScene, dstScene, mask=mask)cv.imshow("sceneBackground", sceneBackground)# 或操作,将人物融入背景图中finalImage = cv.bitwise_or(sceneBackground, people)cv.imshow("finalImage", finalImage)# 等待键盘输入 释放内存cv.waitKey(0)cv.destroyAllWindows()
Javascript代码
<template><div><p>色彩空间的转换及应用</p><p id="status">OpenCV.js is loading...</p><div class="inputoutput"><img id="imageSrc" src="imgs/tinygreen.jpg" /><img id="imageSrc2" src="imgs/scene.jpg" /></div><div class="inputoutput"><canvas id="canvasOutput"></canvas><div class="caption">canvasOutput</div></div></div></template><script>export default {name: "day09",mounted() {this.init();},destoryed() {},data() {return {mats: [],};},methods: {init() {setTimeout(() => {if (window.cv) {this.onOpenCvReady(window.cv);} else {this.init();}}, 500);},onOpenCvReady(cv) {document.getElementById("status").innerHTML = "OpenCV.js is ready.";// 官方文档链接:https://docs.opencv.org/4.5.0/db/d64/tutorial_js_colorspaces.htmllet src = this.createMat(cv, 1, { name: "imageSrc" });// 转化到 HSV 色彩空间let hsv = this.createMat(cv, 2);cv.cvtColor(src, hsv, cv.COLOR_RGB2HSV);// 获取背景蒙版,即绿幕部分为白,前景人物部分为黑let mask = this.createMat(cv, 2);let low = this.createMat(cv, 3, {rows: src.rows,cols: src.cols,type: cv.CV_8UC3,initValue: [35, 43, 46, 255],});let high = this.createMat(cv, 3, {rows: src.rows,cols: src.cols,type: cv.CV_8UC3,initValue: [77, 255, 255, 255],});cv.inRange(hsv, low, high, mask);// 蒙版取非,即前景人物部分为白色let mask_not = this.createMat(cv, 2);cv.bitwise_not(mask, mask_not);// 利用蒙版,将人物部分抠出let people = this.createMat(cv, 2);cv.bitwise_and(src, src, people, mask_not);// 取一张背景图,并截取与mask相同尺寸的部分let scene = this.createMat(cv, 1, { name: "imageSrc2" });let rect = new cv.Rect(0, 0, people.cols, people.rows);let dstScene = this.createMat(cv, 2);dstScene = scene.roi(rect);// 利用蒙版,在背景图中扣掉待填充的人物蒙版部分let sceneBackground = this.createMat(cv, 2);cv.bitwise_and(dstScene, dstScene, sceneBackground, mask);// 或操作,将人物融入背景图中let finalImage = this.createMat(cv, 2);cv.bitwise_or(sceneBackground, people, finalImage);// 显示图像cv.imshow("canvasOutput", finalImage);// 销毁所有 matthis.destoryAllMats();},createMat(cv, type, ops) {switch (type) {case 1:if (ops && ops.name) {let mat = cv.imread(ops.name);this.mats.push(mat);return mat;}break;case 2: {let mat = new cv.Mat();this.mats.push(mat);return mat;}case 3:if (ops && ops.rows && ops.cols && ops.type && ops.initValue) {let mat = new cv.Mat(ops.rows, ops.cols, ops.type, ops.initValue);this.mats.push(mat);return mat;}break;default:break;}},destoryAllMats() {this.mats.forEach((item) => {item.delete();});},},};</script><style lang="scss" scoped></style>

