OpenCV入门(C++/Python)- 使用OpenCV色彩空间(七)
创始人
2024-04-20 16:52:21
0

在本教程中,了解计算机视觉中使用的流行色彩空间,并将其用于基于颜色的分割。

使用OpenCV色彩空间

  • 不同的颜色空间
    • RGB颜色空间
    • LAB颜色空间
    • YCrCB 颜色空间
    • HSV颜色空间
  • 如何使用这些颜色空间进行分割
    • 简单方法

文章内容如下:

  • 首先,我们将了解如何在OpenCV中读取图像并将其转换为不同的颜色空间,并了解每个颜色空间的不同通道为我们提供了哪些新信息。
  • 我们将应用掩码,来做一个简单的颜色分割算法,在算法中使用系统的方法来选择指定的颜色:1.正确的颜色空间。2.分割的正确阈值。

不同的颜色空间

在本节中,将介绍计算机视觉中使用的一些重要颜色空间。

通过加载一个立方体的图像。将讲解不同的颜色空间。

首先是,Opencv默认情况下,它将以BGR格式加载。我们可以使用OpenCV函数cvtColor()在不同的颜色空间之间进行转换,稍后将显示。

Python

#python
img = cv2.imread('cube.jpg')

C++

img = cv::imread('cube.jpg')

在这里插入图片描述

RGB颜色空间

RGB颜色空间具有以下属性

  • 它是一个加法颜色空间,其中颜色是通过红色、绿色和蓝色值的线性组合获得的。
  • 这三个通道与撞击表面的光量相关。

让我们将这两个图像分成R、G和B分量,并观察它们,以获得对颜色空间的更多了解。

在这里插入图片描述

LAB颜色空间

Lab颜色空间有三个通道

  1. L–亮度(强度)
  2. a–颜色成分范围从绿色到红色
  3. b–从蓝色到黄色的颜色成分

Lab颜色空间与RGB颜色空间非常不同。在RGB颜色空间中,颜色信息被分成三个通道,但相同的三个通道也编码亮度信息。但在Lab颜色空间中,L通道独立于颜色信息,仅对亮度进行编码。其他两个通道编码颜色。

它具有以下属性。

  • 感知均匀的颜色空间,近似于我们感知颜色的方式。
  • 独立于设备(捕获或显示)。
  • 在Adobe Photoshop中广泛使用。
  • 与RGB颜色空间相关的是一个复杂的变换方程。

让我们看看Lab颜色空间中的两幅图像,它们被分成三个通道。

Python

#python
LAB = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

C++

//C++
cv::cvtColor(img, LAB, cv::COLOR_BGR2LAB);

在这里插入图片描述

YCrCB 颜色空间

YCrCb颜色空间源自RGB颜色空间,具有以下三种通道。

  1. 从RGB获得的亮度经过Y–伽马校正后的分量。
  2. Cr=R–Y(红色分量距离Luminance距离)。
  3. Cb=B–Y(蓝色分量距离Luminance距离)。

此颜色空间具有以下属性。

  • 将亮度和色度分量分离到不同的通道中。
  • 主要用于电视传输的压缩(Cr和Cb成分)。

Python

#python
YCB = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)

C++

//C++
cv::cvtColor(img, YCB, cv::COLOR_BGR2YCrCb);

在这里插入图片描述

HSV颜色空间

HSV颜色空间包含以下三个通道

  • H–色调(颜色波长)。
  • S–饱和度(颜色的纯度/色调)。
  • V–值(强度)。

其中H通道可以用它来描述颜色最为直观
魔方图像的H、S和V分量如下所示。
Python

#python
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

C++

//C++
cv::cvtColor(img,hsv, cv::COLOR_BGR2HSV);

在这里插入图片描述

如何使用这些颜色空间进行分割

简单方法

现在我们已经对不同的颜色空间有了一些了解,让我们首先尝试使用它们来检测立方体中的蓝色。

在这里插入图片描述

应用阈值进行分割
从图像中所有像素,提取值接近蓝色的像素。我们可以设定一个蓝色颜色范围,来更可能获取到所有的蓝色像素

再使用opencv.inRange()函数查找这个范围内所有的像素,再使用bitwise_and运算从图像中获取这部分像素。(也就是除蓝色范围内的所有像素,其他所有内容去掉)

还要注意,为了将一个像素转换为另一个颜色空间,我们首先需要将1D矩阵转换为3D矩阵。

Python

import cv2
import  numpy as npbright = cv2.imread('data/cube.jpg')
brightLAB = cv2.cvtColor(bright, cv2.COLOR_BGR2LAB)
brightYCB = cv2.cvtColor(bright, cv2.COLOR_BGR2YCrCb)
brightHSV = cv2.cvtColor(bright, cv2.COLOR_BGR2HSV)bgr = [255, 50, 50]
thresh = 50minBGR = np.array([bgr[0] - thresh, bgr[1] - thresh, bgr[2] - thresh])
maxBGR = np.array([bgr[0] + thresh, bgr[1] + thresh, bgr[2] + thresh])maskBGR = cv2.inRange(bright,minBGR,maxBGR)
resultBGR = cv2.bitwise_and(bright, bright, mask = maskBGR)#convert 1D array to 3D, then convert it to HSV and take the first element
# this will be same as shown in the above figure [65, 229, 158]
hsv = cv2.cvtColor( np.uint8([[bgr]] ), cv2.COLOR_BGR2HSV)[0][0]minHSV = np.array([hsv[0] - thresh, hsv[1] - thresh, hsv[2] - thresh])
maxHSV = np.array([hsv[0] + thresh, hsv[1] + thresh, hsv[2] + thresh])maskHSV = cv2.inRange(brightHSV, minHSV, maxHSV)
resultHSV = cv2.bitwise_and(brightHSV, brightHSV, mask = maskHSV)#convert 1D array to 3D, then convert it to YCrCb and take the first element
ycb = cv2.cvtColor( np.uint8([[bgr]] ), cv2.COLOR_BGR2YCrCb)[0][0]minYCB = np.array([ycb[0] - thresh, ycb[1] - thresh, ycb[2] - thresh])
maxYCB = np.array([ycb[0] + thresh, ycb[1] + thresh, ycb[2] + thresh])maskYCB = cv2.inRange(brightYCB, minYCB, maxYCB)
resultYCB = cv2.bitwise_and(brightYCB, brightYCB, mask = maskYCB)#convert 1D array to 3D, then convert it to LAB and take the first element
lab = cv2.cvtColor( np.uint8([[bgr]] ), cv2.COLOR_BGR2LAB)[0][0]minLAB = np.array([lab[0] - thresh, lab[1] - thresh, lab[2] - thresh])
maxLAB = np.array([lab[0] + thresh, lab[1] + thresh, lab[2] + thresh])maskLAB = cv2.inRange(brightLAB, minLAB, maxLAB)
resultLAB = cv2.bitwise_and(brightLAB, brightLAB, mask = maskLAB)cv2.imshow("Result BGR", resultBGR)
cv2.imshow("Result HSV", resultHSV)
cv2.imshow("Result YCB", resultYCB)
cv2.imshow("Output LAB", resultLAB)
cv2.waitKey(0)
cv2.destroyAllWindows()

C++

//C++ code
cv::Vec3b bgrPixel(255, 50, 50);
// Create Mat object from vector since cvtColor accepts a Mat object
Mat3b bgr (bgrPixel);//Convert pixel values to other color spaces.
Mat3b hsv,ycb,lab;
cvtColor(bgr, ycb, COLOR_BGR2YCrCb);
cvtColor(bgr, hsv, COLOR_BGR2HSV);
cvtColor(bgr, lab, COLOR_BGR2Lab);
//Get back the vector from Mat
Vec3b hsvPixel(hsv.at(0,0));
Vec3b ycbPixel(ycb.at(0,0));
Vec3b labPixel(lab.at(0,0));int thresh = 50;cv::Scalar minBGR = cv::Scalar(bgrPixel.val[0] - thresh, bgrPixel.val[1] - thresh, bgrPixel.val[2] - thresh)
cv::Scalar maxBGR = cv::Scalar(bgrPixel.val[0] + thresh, bgrPixel.val[1] + thresh, bgrPixel.val[2] + thresh) cv::Mat maskBGR, resultBGR;
cv::inRange(bright, minBGR, maxBGR, maskBGR);
cv::bitwise_and(bright, bright, resultBGR, maskBGR);cv::Scalar minHSV = cv::Scalar(hsvPixel.val[0] - thresh, hsvPixel.val[1] - thresh, hsvPixel.val[2] - thresh)
cv::Scalar maxHSV = cv::Scalar(hsvPixel.val[0] + thresh, hsvPixel.val[1] + thresh, hsvPixel.val[2] + thresh) cv::Mat maskHSV, resultHSV;
cv::inRange(brightHSV, minHSV, maxHSV, maskHSV);
cv::bitwise_and(brightHSV, brightHSV, resultHSV, maskHSV);cv::Scalar minYCB = cv::Scalar(ycbPixel.val[0] - thresh, ycbPixel.val[1] - thresh, ycbPixel.val[2] - thresh)
cv::Scalar maxYCB = cv::Scalar(ycbPixel.val[0] + thresh, ycbPixel.val[1] + thresh, ycbPixel.val[2] + thresh) cv::Mat maskYCB, resultYCB;
cv::inRange(brightYCB, minYCB, maxYCB, maskYCB);
cv::bitwise_and(brightYCB, brightYCB, resultYCB, maskYCB);cv::Scalar minLAB = cv::Scalar(labPixel.val[0] - thresh, labPixel.val[1] - thresh, labPixel.val[2] - thresh)
cv::Scalar maxLAB = cv::Scalar(labPixel.val[0] + thresh, labPixel.val[1] + thresh, labPixel.val[2] + thresh) cv::Mat maskLAB, resultLAB;
cv::inRange(brightLAB, minLAB, maxLAB, maskLAB);
cv::bitwise_and(brightLAB, brightLAB, resultLAB, maskLAB);cv2::imshow("Result BGR", resultBGR)
cv2::imshow("Result HSV", resultHSV)
cv2::imshow("Result YCB", resultYCB)
cv2::imshow("Output LAB", resultLAB)

在这里插入图片描述

我们也可以设计一个GUI,通过人工调节颜色的范围来观察图像中的变化,获取想要的 颜色

python代码如下:

import cv2
import numpy as np
import os#定义HSV滑块的值
def empty(a):h_min = cv2.getTrackbarPos("Hue Min","TrackBars")h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")v_min = cv2.getTrackbarPos("Val Min", "TrackBars")v_max = cv2.getTrackbarPos("Val Max", "TrackBars")print(h_min, h_max, s_min, s_max, v_min, v_max)return h_min, h_max, s_min, s_max, v_min, v_max#图片拼接,将4张图片拼接到一起
def stackImages(scale,imgArray):rows = len(imgArray)cols = len(imgArray[0])rowsAvailable = isinstance(imgArray[0], list)width = imgArray[0][0].shape[1]height = imgArray[0][0].shape[0]if rowsAvailable:for x in range ( 0, rows):for y in range(0, cols):if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)else:imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv2.cvtColor( imgArray[x][y], cv2.COLOR_GRAY2BGR)imageBlank = np.zeros((height, width, 3), np.uint8)hor = [imageBlank]*rowshor_con = [imageBlank]*rowsfor x in range(0, rows):hor[x] = np.hstack(imgArray[x])ver = np.vstack(hor)else:for x in range(0, rows):if imgArray[x].shape[:2] == imgArray[0].shape[:2]:imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)else:imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)hor= np.hstack(imgArray)ver = horreturn verroot = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
path = os.path.join(root,'data/cube.jpg')
cv2.namedWindow("TrackBars")
# 创建一个窗口,放置6个滑动条rackBars")
cv2.resizeWindow("TrackBars",640,240)
cv2.createTrackbar("Hue Min","TrackBars",0,179,empty)
cv2.createTrackbar("Hue Max","TrackBars",19,179,empty)
cv2.createTrackbar("Sat Min","TrackBars",110,255,empty)
cv2.createTrackbar("Sat Max","TrackBars",240,255,empty)
cv2.createTrackbar("Val Min","TrackBars",153,255,empty)
cv2.createTrackbar("Val Max","TrackBars",255,255,empty)while True:img = cv2.imread(path)imgHSV = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)# 调用回调函数,获取滑动条的值h_min = cv2.getTrackbarPos("Hue Min","TrackBars")h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")v_min = cv2.getTrackbarPos("Val Min", "TrackBars")v_max = cv2.getTrackbarPos("Val Max", "TrackBars")h_min, h_max, s_min, s_max, v_min, v_max = empty(0)lower = np.array([h_min,s_min,v_min])upper = np.array([h_max,s_max,v_max])# 获得指定颜色范围内的掩码mask = cv2.inRange(imgHSV,lower,upper)# 对原图图像进行按位与的操作,掩码区域保留imgResult = cv2.bitwise_and(img,img,mask=mask)# cv2.imshow("Original",img)# cv2.imshow("HSV",imgHSV)# cv2.imshow("Mask", mask)# cv2.imshow("Result", imgResult)imgStack = stackImages(0.6,([img,imgHSV],[mask,imgResult]))cv2.imshow("Stacked Images", imgStack)cv2.waitKey(1)

在这里插入图片描述

相关内容

热门资讯

【MySQL】锁 锁 文章目录锁全局锁表级锁表锁元数据锁(MDL)意向锁AUTO-INC锁...
【内网安全】 隧道搭建穿透上线... 文章目录内网穿透-Ngrok-入门-上线1、服务端配置:2、客户端连接服务端ÿ...
GCN的几种模型复现笔记 引言 本篇笔记紧接上文,主要是上一篇看写了快2w字,再去接入代码感觉有点...
数据分页展示逻辑 import java.util.Arrays;import java.util.List;impo...
Redis为什么选择单线程?R... 目录专栏导读一、Redis版本迭代二、Redis4.0之前为什么一直采用单线程?三、R...
【已解决】ERROR: Cou... 正确指令: pip install pyyaml
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
Lock 接口解读 前置知识点Synchronized synchronized 是 Java 中的关键字,...
Win7 专业版安装中文包、汉... 参考资料:http://www.metsky.com/archives/350.htm...
3 ROS1通讯编程提高(1) 3 ROS1通讯编程提高3.1 使用VS Code编译ROS13.1.1 VS Code的安装和配置...
大模型未来趋势 大模型是人工智能领域的重要发展趋势之一,未来有着广阔的应用前景和发展空间。以下是大模型未来的趋势和展...
python实战应用讲解-【n... 目录 如何在Python中计算残余的平方和 方法1:使用其Base公式 方法2:使用statsmod...
学习u-boot 需要了解的m... 一、常用函数 1. origin 函数 origin 函数的返回值就是变量来源。使用格式如下...
常用python爬虫库介绍与简... 通用 urllib -网络库(stdlib)。 requests -网络库。 grab – 网络库&...
药品批准文号查询|药融云-中国... 药品批文是国家食品药品监督管理局(NMPA)对药品的审评和批准的证明文件...
【2023-03-22】SRS... 【2023-03-22】SRS推流搭配FFmpeg实现目标检测 说明: 外侧测试使用SRS播放器测...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
初级算法-哈希表 主要记录算法和数据结构学习笔记,新的一年更上一层楼! 初级算法-哈希表...
进程间通信【Linux】 1. 进程间通信 1.1 什么是进程间通信 在 Linux 系统中,进程间通信...
【Docker】P3 Dock... Docker数据卷、宿主机与挂载数据卷的概念及作用挂载宿主机配置数据卷挂载操作示例一个容器挂载多个目...