教程汇总:python基础入门系列
通过之前的章节(四、OpenCV颜色空间——HSV颜色模型),我们已经初步认识了HSV颜色空间的特性与优势,现在就来看两个典型的应用实例,颜色分割提取 与 颜色替换。
通过HSV颜色空间的操作我们可以准确的对指定颜色进行分割图像,这也是后续图像处理中会用到的一种预处理手段。
下面我们就结合一个实例来看HSV颜色分割的应用:
如下图是一个穿有红色上衣的人,我们要把衣服部分的图分割出来:
通过前面几个章节的讲解我们能够想到,可以通过观察h分量的直方图来确定这个上衣红色的取值范围,以作为我们分割的界限标准。上代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt
#通过OpenCV读取图片信息
img = cv2.imread('RedShirt.jpg')
# BGR图转为HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 提取hsv中H通道数据
h = hsv[:, :, 0].ravel()
# 直方图显示
plt.hist(h, 180, [0, 180])
plt.show()
得到直方图如下:
根据HSV颜色空间模型可知 红色的颜色分布在0或180附近,直方图中170到180部分出现了大量数据,由此可以确定红色的H分量上下限为170-180,至于SV的界限可以先给个30-255的初始值,具体可以在提取掩模的时候调整确定。
下面通过HSV的红色界限生成mask掩模。上代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt
#通过OpenCV读取图片信息
img = cv2.imread('RedShirt.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 提取hsv中H通道数据
# h = hsv[:, :, 0].ravel()
#
# plt.hist(h, 180, [0, 180])
# plt.show()
cv2.imshow("img", img)
# HSV 的下界限
lower_red = np.array([170,30,30])
# HSV 的上界限
upper_red = np.array([180,255,255])
# 通过上下限提取范围内的掩模mask
mask = cv2.inRange(hsv, lower_red, upper_red)
cv2.imshow("mask", mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下图:
可以发现,答题衣服轮廓对上了,但是有些细节不够完美,比如胳膊两侧还有些白点,这时候就要分析了,胳膊侧边的颜色更接近暗红颜色,所以可以通过提高V值的下限来滤除掉。通过不断调整测试我设定的V值在100-255。
但是发现右侧的白点已经无法通过V的调整来去除了,这个时候我们还可以采取另一种方法,对于mask这种二值化图处理,可以采用膨胀腐蚀的手段来消除独立的白点或黑点。上代码:
import cv2
import numpy as np
#通过OpenCV读取图片信息
img = cv2.imread('RedShirt.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.imshow("img", img)
# HSV 的下界限
lower_red = np.array([170,30,90])
# HSV 的上界限
upper_red = np.array([180,255,255])
# 通过上下限提取范围内的掩模mask
mask = cv2.inRange(hsv, lower_red, upper_red)
cv2.imshow("mask", mask)
# 腐蚀与膨胀处理
# 定义
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))#定义结构元素的形状和大小
#腐蚀图像
eroded = cv2.erode(mask,kernel)
#显示腐蚀后的图像
cv2.imshow("Eroded Image",eroded)
# #膨胀图像
dilated = cv2.dilate(eroded,kernel)
#显示膨胀后的图像
cv2.imshow("Dilated Image",dilated)
img2 = cv2.bitwise_and(img, img, mask=dilated)
cv2.imshow("img2", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
生成mask之后我们先是用腐蚀方法去除掉周边的孤立白点,但同样的衣服轮廓的白色区域边界也会被腐蚀变小,这时候可以用反向操作膨胀在填充回原来的大小
这样我们优化好的mask掩模就做好了,可以采用OpenCV的图像位运算cv2.bitwise_and()
把原图与mask进行位与得到衣服的抠图:
通过上面的操作我们已经可以准确的分割出我们指定的颜色了,在次基础上就可以对他的颜色进行更改了,比如改成黄色,这个同样也是要在HSV颜色空间操作的,不过这次就不需要对mask进行膨胀腐蚀优化了。
import cv2
import numpy as np
def nothing(x):
pass
#通过OpenCV读取图片信息
img = cv2.imread('RedShirt.jpg')
cv2.imshow("img", img)
lower_red = np.array([170,30,30])
upper_red = np.array([180,255,255])
cv2.namedWindow('img2')
cv2.createTrackbar('H','img2',140,180,nothing)
cv2.createTrackbar('S','img2',100,180,nothing)
cv2.createTrackbar('V','img2',117,180,nothing)
rows,cols,channels = img.shape
while(1):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_red, upper_red)
#将制定像素点的数据设置为0, 要注意的是这三个参数对应的值是Blue, Green, Red。
h = cv2.getTrackbarPos('H', 'img2')
s = cv2.getTrackbarPos('S', 'img2')
v = cv2.getTrackbarPos('V', 'img2')
for r in range(rows):
for c in range(cols):
if mask[r, c] == 255:
hsv.itemset((r, c, 0), hsv.item(r, c, 0) -h)
hsv.itemset((r, c, 1), hsv.item(r, c, 1) +90-s)
hsv.itemset((r, c, 2), hsv.item(r, c, 2) +90-v)
img2 = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
#将图像进行输出,使用show()也是可以显示的。
cv2.imshow("img2", img2)
k = cv2.waitKey(1)&0xFF
if k == 27: #esc exit
break
#cv2.waitKey(0)
cv2.destroyAllWindows()
通过滑动H滑条我们就可以更改衣服的颜色了,同样调节SV滑条也可以更改饱和度与明度。