本博客是记录作者生成一些图片遮罩的经验,介绍了使用cv2.inRange()获取图片黑白遮罩的方式。
一、基于cv2.inRange()函数
opencv-python库中直接提供了一个可以同时针对多通道实现二值化功能的cv2.inRange()函数。我们演示如何使用该函数生成黑白遮罩。
1、获取黑白遮罩的演示
导入相关包:
import cv2
import numpy as np
import matplotlib.pyplot as plt
(1)读取输入图片
input = cv2.imread('./Image000.png') # BGR色彩模式
(2)获取黑白遮罩
lower = np.array([0, 0, 17]) # 最低阈值
upper = np.array([179, 255, 255]) # 最高阈值
hsv = cv2.cvtColor(input, cv2.COLOR_BGR2HSV) # BGR色彩空间转换为HSV色彩空间
mask = cv2.inRange(hsv, lower, upper) # 将图片二值化
可以发现获取黑白遮罩的函数中最关键的是设定两个阈值数组lower和upper,这两个怎么设定呢?可以使用下文第2节给出的小工具调节。
(3)获取图片和遮罩的交集
output = cv2.bitwise_and(input, input, mask=mask)
(4)显示所有图片
# 显示窗口
fig = plt.figure(figsize=(12, 4), tight_layout=True) # tight_layout设置自动填充
fig.canvas.set_window_title('测试窗口') # 设置窗口
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用中文字符
plt.rcParams['axes.unicode_minus'] = False # 显示负数的负号
# 转换色彩空间
rgb_img = cv2.cvtColor(input, cv2.COLOR_BGR2RGB) # BGR色彩空间转换为RGB色彩空间
rgb_output = cv2.cvtColor(output, cv2.COLOR_BGR2RGB) # BGR色彩空间转换为RGB色彩空间
# 显示子窗口
ax = fig.add_subplot(131)
ax.set_title('原始图片')
ax.imshow(rgb_img)
ax = fig.add_subplot(132)
ax.set_title('黑白遮罩')
ax.imshow(mask,cmap=plt.cm.gray)
ax = fig.add_subplot(133)
ax.set_title('合并图片')
ax.imshow(rgb_output)
plt.show()
最终效果如下:
2、选定黑白遮罩阈值的工具
我们的工具的所有功能封装在一个名为inRangeHelper的Python类中,
首先我们使用初始化一个cv2库自带的API创建一个可以调节参数的简易窗口:
def __init__(self):
# 创建一个窗口图片
self.wndname = 'image'
cv2.namedWindow(self.wndname)
# 对颜色变化创建轨迹栏目
cv2.createTrackbar('HMin', self.wndname, 0, 179, self._nothing) # Hue is from 0-179 for Opencv
cv2.createTrackbar('HMax', self.wndname, 0, 179, self._nothing)
cv2.createTrackbar('SMin', self.wndname, 0, 255, self._nothing)
cv2.createTrackbar('SMax', self.wndname, 0, 255, self._nothing)
cv2.createTrackbar('VMin', self.wndname, 0, 255, self._nothing)
cv2.createTrackbar('VMax', self.wndname, 0, 255, self._nothing)
# 设置默认HSV空间的最大值
cv2.setTrackbarPos('HMax', self.wndname, 179)
cv2.setTrackbarPos('SMax', self.wndname, 255)
cv2.setTrackbarPos('VMax', self.wndname, 255)
# 初始化HSV空间最大、最小值
self.img_tempPars = [0,0,0,0,0,0]
self.parsName = ['HMin','SMin','VMin','HMax','SMax','VMax']
def _nothing(self,x):
pass
接着定义运行函数:
def run(self,img_path = './Image000.png'):
# 读取输入图片
img = cv2.imread(img_path)
waitTime = 33
# 循环渲染窗口
while (True):
# 获取轨迹栏的当前位置
try:
curPars = [cv2.getTrackbarPos(name, self.wndname) for name in self.parsName]
except:
print("窗口已关闭!")
break
# 设置显示的HSV最大最小值
lower = np.array(curPars[:3])
upper = np.array(curPars[3:])
# 创建HSV图像,并根据最低、最高阈值进行阈值化
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
output = cv2.bitwise_and(img, img, mask=mask)
# 展示输出图像
cv2.imshow('mask', mask)
cv2.imshow('output', output)
# 判断当前参数是否发生变化
for cur,temp in zip(curPars,self.img_tempPars):
if cur!=temp:
print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (
curPars[0], curPars[1], curPars[2], curPars[3], curPars[4], curPars[5]))
self.img_tempPars = curPars
# 等待33毫秒或者按下q键退出循环
if cv2.waitKey(waitTime) & 0xFF == ord('q'):
break
# 关闭所有窗口
cv2.destroyAllWindows()
运行该工具:
tool = inRangeHelper()
tool.run()
显示效果如下: