图像基本操作:
1.访问,修改图片像素点值
2.获取图片宽、高、通道数等属性
3.了解感兴趣区域ROI
4.分离和合并图像通道
5.颜色空间转换,如BGR↔Gray,BGR↔HSV等
6.追踪视频中特定颜色的物体
7.OpenCV函数:cv2.cvtColor(),cv2.inRange()
获取和修改图片像素点值
import cv2
img = cv2.imread('lena.jpg')
px = img[100, 90]
print(px) # [103 98 197]
#只获取蓝色blue通道的值
px_blue = img[100, 90, 0]
print(px_blue) # 103
#修改像素的值
img[100, 90] = [255, 255, 255]
print(img[100, 90]) # [255 255 255]
1.首先,读图
2.通过行列的坐标来获取某像素点的值,
对于彩色图,结果是B,G,R三个值的列表;
对于灰度图或单通道图,只有一个值
img[y, x]
行对应y,列对应x——即行在前,列在后
注:这步操作只有内存中的img像素点值改变,
因为没有保存,所以原图并没有更改。
图片属性
img.shape
获取图像的形状,
图片是彩色,返回一个包含行数(高度)、列数(宽度)和通道数的元组,
灰度图只返回行数和列数:
print(img.shape) # (263, 247, 3)
# 形状中包括行数、列数和通道数
height, width, channels = img.shape
# img是灰度图的话:height, width = img.shape
img.dtype
获取图像数据类型:
print(img.dtype) # uint8
注:多数错误是因为数据类型不对导致的
img.size
获取图像总像素数:
print(img.size) # 263*247*3=194883
ROI
ROI:Region of Interest,感兴趣区域
目的:节省计算量,提高运行速度
截取ROI:指定图片的范围即可
# 截取脸部ROI
face = img[100:200, 115:188]
cv2.imshow('face', face)
cv2.waitKey(0)
通道分割和合并
彩色图的BGR三个通道是可分开单独访问:cv2.split()
也可将单独的三个通道合并成一副图像:cv2.merge()
b, g, r = cv2.split(img)
img = cv2.merge((b, g, r))
split()比较耗时,更高效的方式是用numpy中的索引,如提取B通道:
b = img[:, :, 0]
cv2.imshow('blue', b)
cv2.waitKey(0)
颜色空间转换
import cv2
img = cv2.imread('lena.jpg')
# 转换为灰度图
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('img', img)
cv2.imshow('gray', img_gray)
cv2.waitKey(0)
cv2.cvtColor()
用来进行颜色模型转换,
参数1:要转换的图片,
参数2:转换模式,
COLOR_BGR2GRAY表示BGR→Gray,
可用以下代码显示所有转换模式:
flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
print(flags)
注:颜色转换是数学运算,
如灰度化最常用的:gray=R*0.299+G*0.587+B*0.114
视频中特定颜色物体追踪
HSV:一个常用于颜色识别的模型,相比BGR更易区分颜色,转换模式用COLOR_BGR2HSV表示
注:OpenCV中色调H范围为[0,179],饱和度S是[0,255],明度V是[0,255]。
虽然H的理论数值是0°~360°,但8位图像像素点的最大值是255,
所以OpenCV中除以了2,某些软件可能使用不同的尺度表示,
所以同其他软件混用时,要归一化
例
实现使用HSV来只显示视频中蓝色物体
1.捕获视频中的一帧
2.从BGR转换到HSV
3.提取蓝色范围的物体
4.只显示蓝色物体
import numpy as np
capture = cv2.VideoCapture(0)
# 蓝色范围,不同光照条件下不一样,可灵活调整
lower_blue = np.array([100, 110, 110])
upper_blue = np.array([130, 255, 255])
while(True):
# 1.捕获视频中一帧
ret, frame = capture.read()
# 2.从BGR转换到HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 3.inRange():介于lower/upper之间为白色,其余黑色
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# 4.只保留原图中蓝色部分
res = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
cv2.imshow('res', res)
if cv2.waitKey(1) == ord('q'):
break
bitwise_and()函数先忽视
问:蓝色HSV值上下限lower和upper范围如何得到?
答:把标准蓝色的BGR值用cvtColor()转换
blue = np.uint8([[[255, 0, 0]]])
hsv_blue = cv2.cvtColor(blue, cv2.COLOR_BGR2HSV)
print(hsv_blue) # [[[120 255 255]]]
根据结果调整蓝色范围
小结
1.img[y,x]:获取/设置像素点值,
img.shape:图片的形状(行数、列数、通道数)
img.dtype:图像的数据类型
img.size:图像总像素数
2.img[y1:y2,x1:x2]:进行ROI截取,
cv2.split()/cv2.merge():通道分割/合并
更推荐的获取单通道方式:b = img[:, :, 0]
BGR012
3.cv2.cvtColor():用来进行颜色空间转换,常用BGR↔Gray,BGR↔HSV
4.HSV颜色模型常用于颜色识别
要想知道某种颜色在HSV下的值,可将它的BGR值用cvtColor()转换得到
练习
1.打开lena.jpg,将帽子部分(高:25120,宽:50220)的红色通道截取出来并显示
import cv2
img = cv2.imread('lena.jpg')
# 帽子ROI的红色通道
hat_r = img[25:120, 50:220, 2]
cv2.imshow('hat', hat_r)
cv2.waitKey(0)
2.尝试在视频中同时提取红色、蓝色、绿色的物体
import cv2
import numpy as np
# HSV中
# Blue:[[[120 255 255]]]
# Green:[[[ 60 255 255]]]
# Red:[[[ 0 255 255]]]
capture = cv2.VideoCapture(0)
# 蓝色的范围
lower_blue = np.array([100, 110, 110])
upper_blue = np.array([130, 255, 255])
# 绿色的范围
lower_green = np.array([40, 90, 90])
upper_green = np.array([70, 255, 255])
# 红色的范围
lower_red = np.array([160, 120, 120])
upper_red = np.array([179, 255, 255])
while(True):
# 1.捕获视频中的一帧
ret, frame = capture.read()
# 2.从BGR转换到HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask_blue = cv2.inRange(hsv, lower_blue, upper_blue)
mask_green = cv2.inRange(hsv, lower_green, upper_green)
mask_red = cv2.inRange(hsv, lower_red, upper_red)
# 3.将所有的mask相加,就可以同时显示了
mask = mask_blue + mask_green + mask_red
# 4.保留原图中的三种颜色部分
res = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
cv2.imshow('res', res)
if cv2.waitKey(1) == ord('q'):
break
效果如图