OpenCV的HSV颜色空间在无人车中颜色识别的应用

RGB属于三基色空间,是大家最为熟悉的,看到的任何一种颜色都可以由三基色进行混合而成。然而一般对颜色空间的图像进行有效处理都是在HSV空间进行的,HSV(色调Hue,饱和度Saturation,亮度Value)是根据颜色的直观特性创建的一种颜色空间, 也称六角锥体模型

 

在OpenCV中HSV颜色空间的取值范围=> H:[0, 180],S:[0, 255],V:[0, 255]H色调越小越接近于红色,越高越接近于蓝色,这种表达方式也要比单纯使用红色来表示红色更加准确;S饱和度越小颜色越淡,越大颜色越浓;V亮度越小就越暗,越大越明亮。注意观察上面图片颜色的变化!
之所以选择HSV,是因为H代表的色调基本上可以确定某种颜色,再结合饱和度和亮度信息判断大于某一个阈值。而RGB 由三个分量构成, 需要判断每种分量的贡献比例。HSV空间的识别的范围更广,使用起来更方便。

1、实例演示

 我们来看一个实例,拿一包蓝色外包装的宽窄香烟,识别并跟踪颜色。

1.1、颜色识别跟踪

由于本人台式机没有安装摄像头,这里使用无人车上面的摄像头,其获取摄像头视频的方法与OpenCV有点点区别,也差不多,毕竟是在OpenCV的基础上来的。

from jetbotmini import Camera
from jetbotmini import bgr8_to_jpeg
import cv2
import numpy as np
import traitlets
import ipywidgets.widgets as widgets
from IPython.display import display# 目标颜色,这里设置为蓝色数组
color_lower = np.array([100,43,46])
color_upper = np.array([124, 255, 255])
# 相机实例
camera = Camera.instance(width=720, height=720)
# 显示控件(视频也是图片的连续帧)
color_image = widgets.Image(format='jpeg', width=500, height=400)
display(color_image)# 实时识别颜色并反馈到上面的控件里
while 1:frame = camera.value # (720, 720, 3) (H,W,C)frame = cv2.resize(frame, (400, 400)) # (400, 400, 3)frame = cv2.GaussianBlur(frame,(5,5),0) # 高斯滤波(5, 5)表示高斯矩阵的长与宽都是5,标准差为0hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)#将BGR转成HSVmask=cv2.inRange(hsv,color_lower,color_upper)mask=cv2.erode(mask,None,iterations=2) # 进行腐蚀操作,去除边缘毛躁mask=cv2.dilate(mask,None,iterations=2) # 进行膨胀操作mask=cv2.GaussianBlur(mask,(3,3),0)cnts=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2] # 轮廓if len(cnts)>0:cnt = max(cnts,key=cv2.contourArea) # 轮廓面积(color_x,color_y),color_radius=cv2.minEnclosingCircle(cnt) # 外接圆的位置信息if color_radius > 10:# 圆圈标注cv2.circle(frame,(int(color_x),int(color_y)),int(color_radius),(255,0,255),2)color_image.value = bgr8_to_jpeg(frame) # 转成图片传入Image组件

可以看到,粉红色的圆圈,在追踪画面中的蓝色。其中摄像头的用法与widgets中有很多的web交互组件,有兴趣的可以查阅:无人车的摄像头的实时捕获图片以及widgets小部件的相关操作

这段代码的意思就比较清晰了,实例化摄像头,将每一帧图像中按照不同颜色的HSV色域空间进行分类标记出来,通过 cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) 先将BGR(这里读取到的图片是BGR而不是RGB)转换成HSV,将掩码mask和原图片进行按位与操作,找到颜色后,在颜色的轮廓上画出圆形(最小外接圆)进行标注。 如果在环境光充足的情况下,识别效果不太理想的话,我们可以在死循环里面的进行手动的更改一些参数的设置。

1.2、cv2.inRange

接下来对上述代码中的一些函数进行解释
在做mask的时候,mask=cv2.inRange(hsv,color_lower,color_upper) 这个就是低于下边界数组和高于上边界数组的值为0黑色,介于之间的为255白色,属于单通道。我们来看代码直观了解下: 

import cv2
import matplotlib.pyplot as pltimg_cv2 = cv2.imread('test.jpg')
hsv = cv2.cvtColor(img_cv2, cv2.COLOR_BGR2HSV)
lowerb = np.array([20, 20, 20])
upperb = np.array([200, 200, 200])# 黑白单通道(H,W)
mask = cv2.inRange(hsv, lowerb, upperb)
cv2.imshow('Display', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()plt.subplot(1,2,1); plt.imshow(img_cv2,aspect='auto');plt.axis('off');plt.title('BGR')
plt.subplot(1,2,2); plt.imshow(mask,aspect='auto');plt.axis('off');plt.title('mask')
plt.show()

 如下图BGR和mask:

 

1.3、cv2.erode和cv2.dilate

腐蚀操作,属于图像形态学,跟字面意思一样,进行腐蚀,我们可以查看下这个函数的帮助:
erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) -> dst
src原图跟目标图dst的大小是一样的,然后这里的kernel核的大小决定腐蚀的大小,可选。代码测试下:

import cv2
import numpy as npimage = cv2.imread('test.jpg')
kernel = np.ones((5, 5), np.uint8)
image = cv2.erode(image, None)
cv2.imshow('erode', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

其中这里的 image = cv2.erode(image, None) 第二个kernel参数可以指定也可以不指定,指定之后image = cv2.erode(image, kernel),以及修改kernel 中的大小看下效果:

实质也是做卷积运算,对于不是1的操作内的数置0,只有全为1才为1。作用如同代码中的注释,用来去掉边缘一些噪声毛刺等。cv2.dilate膨胀函数,这个可以看成是腐蚀函数的反向操作,腐蚀之后就是黑色部分扩大,膨胀函数就是缩小。

1.4、cv2.GaussianBlur

高斯模糊也是用来去噪的,我们来看下对一张图片加了高斯噪声之后,再通过这个函数来做个去噪的效果,主要针对高斯噪声: 

import cv2  as cv
import numpy as npdef myShow(name,img):cv.imshow(name,img)cv.waitKey(0)cv.destroyAllWindows()
# 加高斯噪声
def addGauss(img,mean=0,val=0.01):img = img / 255gauss = np.random.normal(mean,val**0.05,img.shape)img = img + gaussreturn imgimg = cv.imread('gauss.png')
img1 = addGauss(img)
myShow('img1',img1)img2 = cv.GaussianBlur(img1,(3,3),0)
myShow('img2',img2)

这里我将原图和加了高斯噪声与降噪处理的三张图放在了一起,如下图:

1.5、cv2.findContours和drawContours 

查找轮廓函数findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy 是在二值图像中检测,所以我们先将其转成灰度图片,通过threshold转成二值图片。
最后我们将轮廓画出来,使用 drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image
我们来看下代码的实现:

import cv2
import numpy as npimage = cv2.imread('test.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
image = cv2.drawContours(image,contours,-1,(255,0,0),2)#cv2.imshow('erode',binary)
cv2.imshow('erode',image)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

cv2.RETR_EXTERNAL:检测外轮廓,忽略轮廓内部的结构。
cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩阵轮廓只需 4 个点来保存轮廓信息。
cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻两个点的像素位置差不超过1

1.6、HSV颜色取值 

这里使用的是蓝色来示例,如果想要其他颜色呢?在HSV中的取值情况是怎么样的,如下图:

 

2、OpenCV知识点

这里用的很多的是OpenCV的一些知识,我们来熟悉下常用的,比如读取图片转成灰色图片。 

2.1、读取和显示图片 

import cv2img = cv2.imread('test.jpg', 0)
cv2.imshow("image",img)
# 如果注释下面的等待按键和释放窗口资源,会出现“窗口未响应”的状态,不能正常显示图片
cv2.waitKey()
cv2.destroyAllWindows()

 当然如果没有安装这个视觉库的话,报错:ModuleNotFoundError: No module named 'cv2'

安装命令:pip install opencv-python -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com 

读取图片cv2.imread()的时候,第二个参数为0,表示灰度模式,也可以使用cv2.IMREAD_GRAYSCALE 代替0
其他数字表示如下:
1表示彩色图片cv2.IMREAD_GRAYSCALE
2表示不修改模式包括通道cv2.IMREAD_UNCHANGED 

2.2、读取和保存图片

img = cv2.imread('test.jpg', 0)
cv2.imwrite('new.jpg', img)

这样就将以灰度模式读取的图片,通过cv2.imwrite写入的方式,保存为了一张新的图片。

2.3、读取和显示视频 

同样的,我们来看下视频的效果,通俗理解就是视频不断的读取里面的每帧(图片) 

import cv2cap = cv2.VideoCapture('test.mp4')
print(cap.read()[1].shape) # (1080, 1920, 3)

 这样就读取了视频的一帧,返回值是一个元组,如果读取整个视频呢?我们一起来看下:

import cv2cap = cv2.VideoCapture('test.mp4')
if (cap.isOpened() == False):print('不能打开视频文件')
else:fps = cap.get(cv2.CAP_PROP_FPS) # 参数可直接使用5代替print('每帧速度:', fps,'FPS') # 每帧速度: 29.97002997002997 FPSf_count = cap.get(cv2.CAP_PROP_FRAME_COUNT) # 7print('总帧数: ', f_count) #总帧数:  3394.0while(cap.isOpened()):ret, frame = cap.read()if ret == True:cv2.imshow('Frame',frame)key = cv2.waitKey(20)# 按q键退出if key == ord('q'):breakelse:break# 注意释放资源
cap.release()
cv2.destroyAllWindows()

这样就跟显示图片一样,显示视频了。其中cv2.waitKey(20)表示在连续帧之间等待20毫秒,那这个数值越大,等待时长越大,可以看到视频的播放就变得比较慢了。
当然更关键的是用来获取摄像头监控的视频。

# 参数 0 表示设备的默认摄像头,当设备有多个摄像头时可以改变参数选择
cap = cv2.VideoCapture(0)

当然有些外接摄像头的ID可能不是0,我们可以使用遍历来获取到:

import cv2
ID = 0
while(1):cap = cv2.VideoCapture(ID)ret, frame = cap.read()if ret == False:ID += 1else:print(ID)break

 2.4、多张图片合成视频

将一个目录里面的图片写入到视频中,方法跟前面差不多,不过需要注意的是,合成视频的图片尺寸必须一致,也就是说如果目录里面的图片大小各不相同的话,单纯的直接写入视频会失败,所以这里需要将图片裁剪成一样,利用插值法来操作:

import cv2
import os
path ='imgs'
size = (600,400) # (W,H)
fps = 1
#fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
fourcc = cv2.VideoWriter_fourcc(*'XVID')
video = cv2.VideoWriter('hi.avi',fourcc,fps,size)for item in os.listdir(path):if item.lower().endswith('.jpg'):img = cv2.imread(os.path.join(path,item))img1 = cv2.resize(img, size, interpolation=cv2.INTER_CUBIC)print(img1.shape) # (H,W,C)video.write(img1)
video.release()
cv2.destroyAllWindows()

其中interpolation参数指定的插值法:

INTER_NEAREST:最邻近插值法
INTER_LINEAR:双线性插值,默认
INTER_CUBIC:4x4像素邻域内的双立方插值
INTER_LANCZOS4:8x8像素邻域内的Lanczos插值

2.5、直线、矩形、圆圈等形状

一些常见的形状,在实际应用中很常见,这里列举如下:

2.5.1、直线

cv2.line(img, startPoint, endPoint, color, thickness)
startPoint	:起始位置像素坐标
endPoint:结束位置像素坐标
color:绘制的颜色
thickness:绘制的线条宽度

2.5.2、圆圈

cv2.circle(img, centerPoint, radius, color, thickness)
img:需要绘制的目标图像对象
centerPoint:绘制的圆的圆心位置像素坐标
radius:绘制的圆半径
color:绘制的颜色
thickness:绘制的线条宽度(thickness 是负数,表示圆被填充)

2.5.3、矩形

cv2.rectangle(img, point1, point2, color, thickness)
img:需要绘制的目标图像对象
point1:左上顶点位置像素坐标
point2:右下顶点位置像素坐标
color:绘制的颜色
thickness:绘制的线条宽度

2.5.4、文本

cv2.putText(img, text, point, font, size, color, thickness)
img:需要绘制的目标图像对象
text:绘制的文字
point:左上顶点位置像素坐标
font:绘制的文字格式
size:绘制的文字大小
color:绘制使用的颜色
thickness:绘制的线条宽度

2.5.5、图片缩放

cv2.resize(InputArray src, OutputArray dst, Size, fx, fy, interpolation)
InputArray src:输入图片
OutputArray dst:输出图片
Size:输出图片尺寸
fx, fy:沿x轴,y轴的缩放系数
interpolation:插值方法

3、bgr8_to_jpeg

其中最后在图片组件中需要显示图片的时候,我们需要将每帧的图像反馈到图片组件里面,然后每帧的图像是BGR,而图像组件格式为jpeg,所以需要做一个转换。
bgr8_to_jpeg这个函数就是将图像编码到内存缓冲区中,实质是一个imencode函数的封装,对图像做压缩处理
函数源码是:

def bgr8_to_jpeg(value, quality=75):return bytes(cv2.imencode('.jpg', value)[1])

里面的imencode函数如下:

imencode(ext, img[, params]) -> retval, buf
ext:定义输出格式的文件扩展名
img:要写入的图像
buf:输出缓冲区调整大小,以适应压缩图像

快速查看函数源码或不方便查看源文件的情况:

import inspect
print(inspect.getsource(bgr8_to_jpeg))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/29156.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【技巧】Maven重复依赖分析查找

【技巧】Maven重复依赖分析查找 遇到奇葩的错误可以考虑是不是依赖冲突了 比如同一段代码 再这个项目中好好的 另一个项目中不能用等 idea安装插件 maven helper 打开pom文件 输入要查找的依赖 将不用的排除掉 右键排除即可

Pandas Groupby:在Python中汇总、聚合和分组数据

GroupBy是一个非常简单的概念。我们可以创建一个类别分组,并对这些类别应用一个函数。这是一个简单的概念,但它是一种在数据科学中广泛使用的非常有价值的技术。在真实的的数据科学项目中,您将处理大量数据并一遍又一遍地尝试,因此…

旅游卡小程序软件招商加盟代理

旅游卡小程序软件招商加盟代理 我国人民生活水平的提高,旅游业成为了人们生活中必不可少的一部分。旅游卡小程序软件作为旅游行业的重要组成部分,也日益受到人们的关注。如今,旅游卡小程序软件招商加盟代理已经成为了一个热门的投资创业项…

⛳ Java数组

Java数组的目录 ⛳ Java数组🎨 一,一维数组👣 1.1,概念📢 1.2,基本用法1,语法格式2,代码 💻 1.3,内存结构📝 1.4,练习 🎁 …

芯片验证板卡设计方案:基于VU440T的多核处理器多输入芯片验证板卡

基于VU440T的多核处理器多输入芯片验证板卡 一、板卡概述 基于XCVU440-FLGA2892的多核处理器多输入芯片验证板卡为实现网络交换芯片的验证,包括四个FMC接口、DDR、GPIO等,板卡用于完成甲方的芯片验证任务,多任务功能验证。 …

GO语言Metex

Mutex互斥锁 type Mutex struct{state int32 // 0表示未加锁 1表示加锁,原子操作sema uint32 // 信号量,用作等待队列 } Mutex正常模式: 尝试加锁的G会先自旋几次,若获不到锁,则加入等待队列. 正常模式下,自选和等待队列的一起竞争 因为G频繁的挂起…

后端(五):JVM

目录 JVM 中的内存区域划分 JVM 的类加载机制 1. 加载 2. 验证 3. 准备 4. 解析 5. 初始化 JVM 中的垃圾回收策略 找,确认垃圾 1. 引用计数 2. 可达行分析 释放”垃圾“对象 1. 标记清除 2. 复制算法 3. 标记整理 分代算法 JVM也就是我们俗称的八股…

WEB阶段_CSSJS篇(附代码笔记)

&#xff08;一&#xff09;、使用DIVCSS布局首页 1、HTML的块标记 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><div>div1</div><div>div2</div><…

查看IP地址方法(电脑IP地址方法)

查看IP地址方法 如何识别win7还是win10系统&#xff1f; &#xff08;一&#xff09;Win7系统电脑导航栏如下&#xff1a; &#xff08;二&#xff09;Win10系统电脑导航栏如下&#xff1a; 一、win7系统查看IP地址 方法一&#xff1a;查看网络设置 点击电脑导航栏最右下…

ASEMI快恢复二极管MUR20100CTR在电子工程中的应用

编辑-Z 随着电子技术的日益发展&#xff0c;各种电子元件的使用场景与需求也在逐步扩大。今天&#xff0c;我们将聚焦于一款广泛应用于各类电路的二极管——MUR20100CTR&#xff0c;来详细解读其性能特征及应用。 一、MUR20100CTR二极管的主要特性 MUR20100CTR是一款极高性能的…

Redis远程字典服务

目录 前言 1.NoSQL 1.1NOSQL和关系型数据库比较 1.2非关系型数据库的优势 1.3关系型数据库的优势 ​编辑 2.主流的NOSQL产品 键值(Key-Value)存储数据库 列存储数据库 文档型数据库 图形(Graph)数据库 3.Redis简介 redis的应用场景 4.命令操作 4.1字符串类型 s…

A7二极管-ASEMI迷你封装整流管A7二极管

编辑&#xff1a;ll A7二极管-ASEMI迷你封装整流管A7二极管 型号&#xff1a;A7二极管 品牌&#xff1a;ASEMI 封装&#xff1a;SOD-123 正向电流&#xff1a;1A 反向耐压&#xff1a;1000V 芯片大小&#xff1a;60MIL 芯片个数&#xff1a;1 引脚数量&#xff1a;2 …