opencv图像处理(二)通道(这里讲清楚了16UC1)

转载自:Python学习笔记 | opencv图像处理(二)通道

Python学习笔记 | opencv图像处理(二)通道

原创 维克少  我是维克少  9月10日

1. 通道基础知识

1.1 大小、深度与通道

上一篇推送我们介绍了一个很重要的概念,叫做位深度。简单来说,一个图片的位深度决定了像素的大小,从而决定一幅图片的颜色。

上篇推送:Python学习笔记 | opencv图像处理(一)

对计算机来说,照片的尺寸和深度决定了一张照片的所有信息,然而,为了方便颜色处理,我们定义了“通道”这一概念,用于分离一个像素点的元素。例如,之前提到的RGB颜色模型,就用到了三个通道(R、G、B)。

图片

RGB模式下通道分离

例如上面的图片,左上角是原始图片。在RGB色彩模式下,每个像素点是由红绿蓝三种光混合而来的,每一个颜色占用一个通道,因此RGB模式下一共有三个通道。

我们得到了如下关系:

位深度 = 通道数 × 每个通道基本元素的字节数 × 8

RGB模式下的图片,位深度为24 bit,共有3个通道,每个通道的基本元素为1字节(B),1字节等于8比特。

RGB是一种非常常用的三通道颜色模型,在RGB的基础上,人们添加了一个控制透明度的通道Alpha,得到了RGBA颜色模型。

图片

RGBA模式下修改透明度

1.2 矩阵数据类型与图片的通道类型

假如我有一张3通道(例如RGB)24-bit位深度的照片,那么按照道理,这张照片每一个像素点的值都应当在0到255的范围内。然而,当我们对图片矩阵数据进行数学运算时,矩阵里的元素有可能会超出0到255的范围,此时,0至255的范围就会限制我们的发挥。因此,在定义我们的矩阵画布时,需要同时定义数据类型。

在OpenCV中,一张画布应该确定如下信息:

数据类型:

8U(8位无符号整数),8S(8位有符号整数),

16U(16位无符号整数),16S(16位有符号整数),

32S(32位有符号整数),32F(单精度浮点数),

64F(双精度浮点数)

通道数量:C1,C2,C3,C4(分别对应1-4个通道)

对各种数据类型进行解释:

图片数据类型取值范围矩阵数据类型(dtype)

8U

[0, 255]

np.uint8

8S

[-128, 127]

np.int8

16U

[0, 65535]

np.uint16

16S

[-32768, 32767]

np.int16

32S

[-231, 231-1]

np.int32

32F

[0.0, 1.0]

np.float32

64F

[0.0, 1.0]

np.float64

规律:

对于一个n位的二进制数:

  • 无符号整数的取值范围,二进制下n个0一直到n个1,转变为十进制,取值范围是0至2n-1

    例如:8U的取值范围是(0000 0000)2至(1111 1111)2,转化成十进制就是0至28-1,即0至255;

  • 有符号整数的取值范围相比于无符号整数,最高位由1表示负数,0表示正数,因此真正表示数字的位数为n-1,转变成十进制,取值范围为-2n-1-1至2n-1-1;同时,考虑到+0与-0在数量上没有差别,因此,原本用于表示-0的(1000 0000 0000 ... 0000)2用于表示最小数,十进制下取值范围下限加一,变成-2n-1至2n-1-1,

    例如:8U的取值范围是(1111 1111)2至(0111 1111)2,最高位表示正负号,因此转化成十进制为-27至27-1,即-128至127;

  • 单双浮点数可以理解为通俗意义上的小数,具体的编码方式可以参考技术文件IEEE 754,平时经常用到的就是32位单精度浮点数与64位双精度浮点数

上面三组数据进行排列组合,就会得出组合:

通道1通道2通道3通道4

深度0

CV_8UC1=0

CV_8UC2=8

CV_8UC3=16

CV_8UC4=24

深度1

CV_8SC1=1

CV_8SC2=9

CV_8SC3=17

CV_8SC4=25

深度2

CV_16UC1=2

CV_16UC2=10

CV_16UC3=18

CV_16UC4=26

深度3

CV_16SC1=3

CV_16SC2=11

CV_16SC3=19

CV_16SC4=27

深度4

CV_32SC1=4

CV_32SC2=12

CV_32SC3=20

CV_32SC4=28

深度5

CV_32FC1=5

CV_32FC2=13

CV_32FC3=21

CV_32FC4=29

深度6

CV_64FC1=6

CV_64FC2=14

CV_64FC3=22

CV_64FC4=30

2. 实战

我们曾经说过,OpenCV处理图片的本质,是把图片转化成矩阵,通过矩阵的运算得到新的图片。

2.1 创建空画布

首先,我们需要创建一个空的画布,最简单的方法是创建一个所有元素为0的矩阵,方法如下:

 

import numpy as np
canvas = np.zeros(shape=(400,400,3), dtype=np.uint8)# size里填入的三个数依次为宽(行数)、长(列数)、通道数(C3)# dtype规定该画布里每个数据都在0-255之间(8U)# 此时画布类型为8UC3(一般RGB颜色模型下的图片就是8UC3类型的)

此时我们可以在画布里填上任意数,试试看效果

 

draw1 = np.copy(canvas) # 在复制的图片上操作,是一个好习惯draw1[:, :, :] = 255# []是切片用法,此处用“,”分割3个维度——行,列,通道# 此处把255这个值赋给这个画布所有行,所有列,所有3个通道里的所有元素cv2.imshow('255', draw1) # 展示draw1cv2.waitKey()

图片

如图,所有像素全部转变成了白色

当然,这个矩阵里的每个数据都应当在0到255之间,但如果我们直接给矩阵赋一个超出该范围的值,结果会怎么样呢?

 

draw2 = np.copy(canvas) # 在复制的图片上操作,是一个好习惯draw2[:, :, :] = 256# 此处把256这个值赋给这个画布所有行,所有列,所有3个通道里的所有元素cv2.imshow('256', draw1) # 展示draw2cv2.waitKey()

图片

所有像素全部转变成了黑色

发现得到了一张黑色的图片,这是为什么呢?

当运算结果超出机器数所能表示的范围,机器就会溢出(spillover),比如说,对(1111 1111)2即(255)10加1时,数据应当变为(1 0000 0000)2,但是uint8下仅仅可以保留8个bit,因此溢出的第九位会被舍去,变成(0000 0000)2,也就是10进制下的0。这样256被解读成了0,画布变成了黑色(0,0,0)。

总之,空的画布在OpenCV的主要作用在于暂时储存需要修改的部分并且进行运算操作,下面将展示一些常用的通道操作。

2.2 通道切分

此时我们可以利用numpy的切片工具,对canvas的局部进行操作。

 

import numpy as npimport cv2
img = cv2.imread('阳光猫猫头.png', cv2.IMREAD_COLOR)# 矩阵方法r = np.copy(img)[:, :, 2]g = np.copy(img)[:, :, 1]b = np.copy(img)[:, :, 0]# 注:OpenCV默认的通道顺序并非RGB,而是BGR# OpenCV的内置方法b, g, r = cv2.split(img)

此时我们单独观察R,G,B三个通道

 

cv2.imshow('R', r)cv2.imshow('G', g)cv2.imshow('B', b)cv2.waitKey()

图片

RGB灰度图

我们获得了三个通道的灰度图,这个操作在经常用于磨皮,在图像识别中也经常用此方法压缩信息、提取特征。

2.3 通道修改与合并

观察发现,此时这只猫猫头整体红色系偏强,蓝色系偏弱,我们希望对此调整,红色减弱,蓝色增强。

 

import cv2import numpy
img = cv2.imread('阳光猫猫头.png', cv2.IMREAD_COLOR)# 使用OpenCV的内置方法切割通道b, g, r = cv2.split(img)r_new = r - 20 # 红色全部下降20b_new = b + 20 # 蓝色全部上升20# 注意不要用太大的数字,否则数据会溢出,得到奇怪的效果# 不过很建议大家尝试一下

调整完通道以后,我们还需要重新合并图像

 

# 矩阵方法img_new = np.zeros(img.shape, np.uint8)img_new[:, :, 0] = b_newimg_new[:, :, 1] = gimg_new[:, :, 2] = r_new# 图像方法img_new = cv2.merge([b_new, g, r_new])# 输出cv2.imwrite('阳光猫猫头_2.png', img_new)

图片

原图(左)与修改后(右)对比

回顾

  1. 为了方便操作,我们会把一张图片分成几个通道进行处理

  2. 图片里的每个元素,都有自己的取值范围,数据处理时,要注意数据是否会出现溢出的情况

  3. 创建空画布

    • np.zeros(shape, dtype)      # 纯黑画布

    • np.ones(shape, dtype) * 255      # 纯白画布

  4. 分离通道

    • 矩阵法(切片工具)

    • 图像法  cv2.split(img)

  5. 合并通道

    • 矩阵法(对空画布赋值)

    • 图像法  cv2.merge([b, r, g])

参考资料

  1. OpenCV——像素数据类型总结 [https://www.cnblogs.com/farewell-farewell/p/5914685.html]

  2. 32 位的有符号整数的取值范围以及数值溢出 [https://blog.csdn.net/sytyp111/article/details/115170758]

  3. 百度百科——IEEE 754 [https://baike.baidu.com/item/IEEE%20754]

  4. float32与float64 [https://blog.csdn.net/linkequa/article/details/107722310]

  • 9
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
OpenCV是一个开源的计算机视觉库,用于图像和视频处理。它提供了丰富的功能和算法,可以用于图像的读取、显示、处理、分析和识别等任务。OpenCV基于C++实现,同时也提供了Python等其他编程语言的接口,其中OpenCV-PythonOpenCVPython API,结合了OpenCV C++ API和Python语言的最佳特性。\[1\]\[2\] 在使用OpenCV进行图像处理时,可以利用其提供的各种模块和函数来实现不同的功能。例如,可以使用OpenCV图像处理模块来进行图像的滤波、边缘检测、图像变换等操作。同时,OpenCV还提供了一些特征提取的算法,如SIFT和SURF等,可以用于图像的特征点检测和匹配。如果要使用这些特征提取算法,需要安装相应的扩展库,如opencv-contrib-python。\[3\] 总之,OpenCV是一个功能强大的图像处理库,可以用于各种图像处理任务,包括图像的读取、显示、处理、分析和特征提取等。通过使用OpenCV的各种模块和函数,可以实现对图像的各种操作和处理。 #### 引用[.reference_title] - *1* *2* *3* [图像处理 OpenCV简介](https://blog.csdn.net/mengxianglong123/article/details/125850218)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值