opencv 图片颜色识别与替换

目录

1、RGB颜色空间

2、颜色加法

2.1 普通加法(饱和与模运算)

2.2 加权加法

3、HSV颜色空间

4、制作掩膜(cv2.inRange(参数1.参数2,参数3))

5、应用掩膜(cv2.bitwise_and(参数1,参数2,参数3))

6、图片颜色替换

———————————————————————————————————————————

1、RGB颜色空间

在图像处理中,最常见的就是RGB颜色空间。RGB颜色空间是我们接触最多的颜色空间,是一种用于表示和显示彩色图像的一种颜色模型,R代表红色(Red),G代表绿色(Green),B代表蓝色(Blue),这三种颜色通过不同强度的光的组合来创建其他颜色,广泛应用于我们的生活中,比如电视、电脑显示屏等。

RGB颜色模型基于笛卡尔坐标系,如下图所示,原色值位于3个角上,二次色青色、红色和黄色位于另外三个角上,黑色位于原点处,白色位于离原点最远的角上。因为黑色在RGB三通道中表现为(0,0,0),所以映射到这里就是原点;而白色是(255,255,255),所以映射到这里就是三个坐标为最大值的点。

这里解释一下,彩色图是三通道图像,即每个像素点包含三个值,可以想象成一个像素点就是一个小盒子,里面叠放了三张不同颜色的玻璃纸,最终所折射出来的颜色就是该像素点的颜色,所以彩色图的每个像素点的颜色是由三个数值共同定义的(本人之前对这里有点疑惑所以整理笔记的时候还是顺带写一下)

但是注意:在opencv中,颜色是以BGR的形式存储的,即纯红色的像素值应该是(0,0,255)

2、颜色加法

就是两幅图或多幅图的颜色通道叠加,有多种方式,比如普通加法、加权加法、通道分离等,这里只介绍前两种。

2.1 普通加法(饱和与模运算)

有两种方法:

1、利用 opencv中的 cv2.add(参数1,参数2) 进行饱和加法,参数直接填图像或数组名

饱和加法会将运算后超过255的值进行截断使其变为255。

代码示例如下:

数组展示:

def test1():
    '''普通加法-cv2.add()'''
    img1 = np.array([[1,2,3],
                     [40,50,60]],dtype = np.uint8)
    img2 = np.array([[100,200,30],
                     [240,150,66]],dtype = np.uint8)
    img3 = cv2.add(img1,img2)
    print(img3)
    # [[101 202  33]
    # [255 200 126]]

可以看到img3的打印结果中第二行第一列的值本来是 40+240=280,但是被截断成了255。

图像展示:(注意相加的两个图像尺寸要一致)

def test2():
    '''普通加法-cv2.add() 图像展示'''
    img1=cv2.imread("./src/cao.png")
    img2 = cv2.imread("./src/pig.png")
    img3 = cv2.add(img1,img2)
    cv2.imshow("img1",img1)
    cv2.imshow("img2",img2)
    cv2.imshow("img3",img3)
    cv2.waitKey(0)

运行结果:

就是两个图像叠加在一起

2、利用numpy库里的 np.add(参数1,参数2) ,参数同样直接填图像或数组名,或者直接 用“+”进行模运算

模运算会将超过255的值与256相除然后取余。(因为 unit8 的范围是 0-255,共256个值),这种运算方式会导致亮区域变暗。

代码示例如下:

数组展示:

def test3():
    '''普通加法-numpy 数组展示'''
    img1 = np.array([[1,2,3],
                     [40,50,60]],dtype = np.uint8)
    img2 = np.array([[100,200,30],
                     [240,250,66]],dtype = np.uint8)
    img3 = np.add(img1,img2)
    print(img3)
    # [[101 202  33]
    #  [ 24 44 126]]

可以看到img3的打印结果中第二行第一列的值本来是 40+240=280,与256经过模运算后变为24,同理旁边那个值本来应该是300,与256经过模运算后变为44。

图像展示:

def test4():
    '''普通加法-np.add() 图像展示'''
    img1=cv2.imread("./src/cao.png")
    img2 = cv2.imread("./src/pig.png")
    img3 = np.add(img1,img2)
    cv2.imshow("img1",img1)
    cv2.imshow("img2",img2)
    cv2.imshow("img3",img3)
    cv2.waitKey(0)

运行结果:

可以看到效果挺奇特的,所以一般不会采用这种方法去叠加图像。

2.2 加权加法

与普通加法的区别在于两张图像的权重不同,这就会给人一种混合或者透明的感觉,API为 cv2.addWeighted(图像1,a,图像2,b,y),这里的a和b分别是两张图像各自的权重,不一定加起来要为1,最终结果会按公式 dst = a⋅img1 + b⋅img2 + y 计算并自动处理溢出,这里只介绍权重和=1的标准混合。

代码展示:

def test5():
    '''加权加法'''
    img1 = cv2.imread("./src/cao.png")
    img2 = cv2.imread("./src/pig.png")
    img3 = cv2.addWeighted(img1,0.6,img2,0.4,0)

    cv2.imshow("img1",img1)
    cv2.imshow("img2",img2)
    cv2.imshow("img3",img3)
    cv2.waitKey(0)

运行结果:

效果比之前好了很多,可以继续调整权重以达到更好的效果。

3、HSV颜色空间

HSV颜色空间指的是HSV颜色模型,这是一种与RGB颜色模型并列的颜色空间表示法。RGB颜色模型使用红、绿、蓝三原色的强度来表示颜色,是一种加色法模型,即颜色的混合是添加三原色的强度。而HSV颜色空间使用色调(Hue)、饱和度(Saturation)和亮度(Value)三个参数来表示颜色,色调H表示颜色的种类,如红色、绿色、蓝色等;饱和度表示颜色的纯度或强度,如红色越纯,饱和度就越高;亮度表示颜色的明暗程度,如黑色比白色亮度低。

HSV颜色模型是一种六角锥体模型,如下图所示:

                                               

用更直观的话来说,

  • H 决定“是什么颜色”(如红色还是蓝色)。

  • S 决定“有多浓”(如深红还是浅红)。

  • V 决定“有多亮”(如亮红还是暗红)。

然后hsv颜色空间有一张基本分量图用来表示颜色,当然这是通过实验计算出的模糊范围(此处把部分红色归为了紫色):

至于为什么有了RGB颜色空间还需要HSV,可以理解为它在处理颜色识别以及颜色分割相关任务时更优秀,具体原因这里不详解,接下来介绍使用HSV颜色空间最多的操作:制作掩膜。

当然将RGB图像转换为HSV图像的方法如下:

img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

4、制作掩膜(cv2.inRange(参数1.参数2,参数3))

掩膜(Mask)是一种在图像处理中常见的操作,它选择性地遮挡图像的某些部分,以实现特定任务的目标,通常是一个二值化图像,并且与原图像的大小相同,其中目标区域被设置为255(白色),而其他区域被设置为0(黑色),并且目标区域可以根据HSV的颜色范围进行修改。

通俗的话来说,就是拿一张与目标图像大小相同的纸,将要提取的目标颜色对应的区域变成白色,其余区域全都为黑色。 API中的参数分别为目标图像转为HSV颜色空间后的图像:img_hsv, 以及提取的目标颜色在HSV空间中的极值:color_low, color_high

使用示例如下,比如我想提取这张图像的紫色区域:

代码如下:

def test6():
    '''掩膜制作'''
    img1 = cv2.imread("./src/masktest.png")
    img1_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)#转成hsv空间

    #找出紫色在hsv空间中的范围
    color_low = np.array([125,43,46])
    color_high = np.array([155,255,255])

    img_mask = cv2.inRange(img1_hsv,color_low,color_high)#制作掩膜

    cv2.imshow("img1", img1)
    cv2.imshow("img_mask",img_mask)
    cv2.waitKey(0)

运行结果如下:

可以看到掩膜是制作成功了,但是我的目标是提取紫色区域,即新图像应该只有紫色,所以接下来还要进行一步操作就是:应用掩膜。

5、应用掩膜(cv2.bitwise_and(参数1,参数2,参数3))

参数1=参数2=img(原图),参数3=img_mask(掩膜)

API是cv2.bitwise_and(),这个方法就像“图像界的魔法剪刀”,能按掩膜精准裁剪或组合图像,但是其中的原理有点复杂,我们一步一步来:

先复习一下按位与运算:将输入数值转化为二进制并进行逐位比较,有0为0,无0为1,例如

  • 像素A: 150 → 二进制表示为 10010110

  • 像素B: 200 → 二进制表示为 11001000

  • 按位与运算结果:逐位比较 → 10000000(转化为十进制是128)

当然,A&A=A 是基本性质,因为每一位都和自己比较,保持不变。

再解释原理:参数1和参数2都是填原图,然后原图与原图进行按位与运算,当然结果是原图本身,参数3就是掩膜。至于为什么要让原图与原图进行按位与运算,是因为掩膜本身没有对原图进行任何操作的能力,它就像一张筛子只能通过控制原图与原图是否进行按位与运算,来决定结果图中哪些区域显示,哪些区域隐藏。在opencv内部就是:

  • mask=255 的地方:执行 img 和 img 的按位与运算(即保留原值)

  • mask=0 的地方:不执行,直接把输出像素置为0(黑色)

所以,不是掩膜本身去修改图像,而是在操作过程中干预了结果产生,是在原图与原图按位与计算过程中,控制哪些地方产生结果,哪些地方归零

原理理解完之后就接着我们上一步的操作提取紫色区域吧,代码如下:

def test7():
    '''应用掩膜'''
    img1 = cv2.imread("./src/masktest.png")
    img1_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)#转成hsv空间

    #找出紫色在hsv空间中的范围
    color_low = np.array([125,43,46])
    color_high = np.array([155,255,255])

    img_mask = cv2.inRange(img1_hsv,color_low,color_high)#制作掩膜

    img_bit = cv2.bitwise_and(img1,img1,mask=img_mask)#应用掩膜

    cv2.imshow("img1", img1)
    cv2.imshow("img_bit", img_bit)
    cv2.waitKey(0)

运行结果:

可以看到,此时我们已经成功提取了紫色区域。

所以现在我们有了这个方法之后,就可以对抠出来的图像做进一步操作,比如常见的颜色替换。

6、图片颜色替换

为什么有了掩膜之后就可以对指定颜色区域进行颜色替换呢,是因为由于掩膜与原图的大小相同,并且像素位置一一对应,所以我们就得到了掩膜中白色(也就是像素值=255)区域,再将其进行赋值即可,比如我想将刚刚提取的紫色区域变成蓝色,就可以这样:

def test8():
    '''图片颜色替换'''
    img1 = cv2.imread("./src/masktest.png")
    img1_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)#转成hsv空间

    #找出紫色在hsv空间中的范围
    color_low = np.array([125,43,46])
    color_high = np.array([155,255,255])

    img_mask = cv2.inRange(img1_hsv,color_low,color_high)#制作掩膜

    img_change =  img1.copy() #复制原图,增加对比
    img_change[img_mask==255]=(255,0,0)#图片颜色改变,将紫色对应区域改成蓝色

    cv2.imshow("img1", img1)
    cv2.imshow("img_change", img_change)
    cv2.waitKey(0)

运行结果:

可以看到,左边是原图,右边是修改颜色后的图像。

以上就是图片颜色识别与替换相关,下一篇是添加水印以及ROI切割。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值