本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的、不同方法的处理,以达到对图像进行去噪、锐化等一系列的操作。同时,希望观看本专栏的小伙伴可以理解到OpenCv进行图像处理的强大哦,如有转载,请注明出处(原文链接和作者署名),感谢各位小伙伴啦!
前文参考:
《OpenCv视觉之眼》Python图像处理一 :Opencv-python的简介及Python环境搭建
《OpenCv视觉之眼》Python图像处理二 :Opencv图像读取、显示、保存基本函数原型及使用
上次博客,我们介绍了OpneCv图像读取、显示、保存函数原型和基本使用方法,并介绍了程序工作者常用的图像显示函数,本次博客,林君学长将介绍初步使用OpenCv进行基本的图像处理,包括图像属性获取、修改像素、像素移植、图像通道的理解等,并且,深入介绍图像通道B\G\R的颜色显示原理,通过原理了解OpenCv,相信是每一位做图像处理的一个必要技能,赶快了解原理吧。有不正确的地方,记得提醒林君学长进行改正啦!
提示:本片文章需要重点理解的是 三、图像通道 的理解,因此,小伙伴在对第三部分的理解时候,最好是结合学长的代码,然后自己书写代码进行理解,可以加深对B\G\R通道颜色形成的理解哦!
既然是图像属性,首先我们得了解什么是图像属性,一张图像包括哪些属性?只有当了解以上两个问题,才能进行对于的图像操作,OpenCv对于图像的操作,本质上可以理解为对图像属性的相关操作,达到我们需要的目的,接下来,我们一起看下图像包括的属性有哪些吧!
1)、什么是图像属性?
图像属性:一张图片的特性,不同的图片有不同的特性,但总体来讲,只有以下基本属性:像素、分辨率、大小、颜色、位深、色调、饱和度、亮度、色彩通道、图像的层次
2)、图像属性种类
通过以上,我们可以知道,图像属性种类共分为10个基本属性,接下来,依次进行属性介绍吧!
图像的像素数目(Pixeldimensions),是指在位图图像的宽度和高度方向上含有的像素数目。一幅图像在显示器上的显示效果由像素数目和显示器的设定共同决定。
图像的分辨率是指单位打印长度上的图像像素的数目,表示图像数字信息的数量或密度,它决定了图像的清晰程度。在同样大小的面积上,图像的分辨率越高,则组成图像的像素点越多,像素点越小,图像的清晰度越高。例如,一幅分辨率为72dpi的1×1英寸的图像,它包含的像素数目为5184,而一幅分辨率为300dpi的同样大小的图像,它包含的像素数目则为90000。由于高分辨率的图像在单位面积上含有更多的像素,所以在打印时能够比低分辨率的图像更好地表现图像的细节和微妙的颜色变化。
对于那些在扫描时采用低分辨率得到的图像,不能通过提高分辨率的方法来提高图像的质量,因为这种方法仅仅是将一个像素的信息扩展成了几个像素的信息,并没有从根本上增加像素的数量。另外,在ImageReady中,图像的分辨率是不能更改的,这是因为ImageReady是专门用来处理在线媒体的图像的,而不是Photoshop
那样用来处理打印的图像的。
设定图像的分辨率时,应该考虑所制作的图像的最终发布媒体,如果制作的图像是用于在线媒体,只需要使用图像的分辨率和典型的显示器的分辨率(72dpi或96dpi)相匹配即可;如果制作的是打印图像,采用过低的分辨率会使打印出来的图像显得粗糙,而采用过高的分辨率,则会使图像的像素比打印装置所能够提供的像素小,导致文件的增大和打印时间的延长。而且,对于分辨率过高的图像,打印设备未必能够正常工作。
图像文件的大小首先决定了图像文件所需的磁盘存储空间,它一般以字节(byte)来度量,其计算公式为:字节数=(位图高×位图宽×图像深度)/8从计算公式可以看出来,图像文件的大小与像素数目直接相关。虽然含有较多像素的图像在打印时能够更好地表现图像的细节,但是它们需要更大的存储空间,并且编辑和打印的时间相对地要长一些。例如,一幅分辨率为200dpi的1×1英寸的图像,它包含的像素数目是分辨率为100dpi的1×1英寸的图像的4倍,其大小自然也是后者的4倍。所以,设定图像的分辨率时应综合考虑图像的质量和大小,找到它们的最佳结合点。Photoshop所能够支持的最大图像文件是2GB,最大的像素数目是30000×30000像素,这就对打印大小和图像的分辨率产生了一定的限制。例如,一幅100×100英寸的图像,它能够得到的最大分辨率是300dpi(300像素/100英寸)
图像颜色是指一幅图像中所具有的最多的颜色种类,通过图像处理软件,可以很容易地改变三原色的比例,混合成任意一种颜色。
图像深度也称图像的位深,是指描述图像中每个像素的数据所占的位数。图像的每一个像素对应的数据通常可以是1位(bit)或多位字节,用于存放该像素的颜色、亮度等信息,数据位数越多,对应的图像颜色种类越多。
色调就是各种图像色8彩模式下图像的原色(例如,RGB模式的图像的原以为R、G、B3种)的明暗度,色调的调整也就是对明暗度的调整。色调的范围为0—255,总共包括256种色调。例如,灰度模式的就是将白色到黑色间连续划分为256个色调,即由白到灰、再由灰到黑。同样的道理,在RGB模式中则代表了各原色的明暗度,即红、绿、蓝3种原色的明暗度,将红色加深色就成为了深红色。
饱和度是指图像颜色的深度,它表明了色彩的纯度,决定于物体反射或投射的特性。饱和度用与色调成一定比便的灰度数量来表示,取值范围通常为0%(饱和度最低)–100%(饱和度最高)。调整图像的饱和度也就是调整图像的色度,当将一幅图像的饱和度降低到0%时,就会变成为一个灰色的图偈,增加饱和度应付增加其色调。例如调整彩色电视机的饱和度,用户可以选择观看黑白或彩色的电视节目。对白、黑、灰度色彩的图像而言,它们是没有饱和度的。
亮度是指图像色彩的明暗程度,是人眼对物本明暗强度的感觉,取值为0%–100%
图像的色彩通道 图像三原色按不同的比例进行混合可以产生许多种颜色,保存每一种原色信息及对其可进行调整处理所提供的方式或途径就是相应颜色的色彩通道。根据应用种类的不同,原色的种类也不同,如在印刷一中以4个印版来印刷,每个印版分别印刷青色(Cyan)、品红(Magenta)、黄色(Yellow)、黑色(Black),一个通道就相当于印刷中的一个印版,每个通道保存一种颜色的数据。CMYK图像有青色、品红、黄色、黑色4种颜色的通道和一个CMYK通道。
图像的层次在计算机设计系统中,为更便捷有效地处理图像素材,通常将它们置于不同的层中,而图像可看作是由若干层图像叠加而成的。利用图像处理软件,可对每层做单独处理,而不是影响其他层的图像内容。在新建一个图像文件时,系统会自动为其建立一个背景层,该层相当于一块画布,可在上面做贴图、绘画及其他图像处理工作。若一个图像有多个图层,则每个图层均具有相同的像素、通道数及格式。
然而,在我们对图像处理的过程中,我们使用到的图像属性无非就是图像尺寸(高和宽)和图像通道数,对于彩色图像来说,为3通道,对于灰度图像来说,通常为单通道,接下来看看如何通过python代码实现对图像属性的获取吧!
1)、获取图像尺寸和通道数
#导入图像处理库opencv
import cv2
#读取图像
img=cv2.imread("my.jpg")
#获取图像尺寸和通道数
h,w,channel=img.shape
#打印获取的数据
print(h,w,channel)
#导入图像处理库opencv
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取图像
img=cv2.imread("my.jpg")
#获取图像尺寸和通道数
h,w=img.shape[0:2]
#打印获取的数据
print(h,w)
ROI兴趣区域是对图像像素的一种基本处理方式,你可以理解为一张图片中你喜欢的部分通过裁剪像素的方式获取出来,然后进行显示,具体方法如下所示
1)、感兴趣区域:机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI。在Halcon、OpenCV、Matlab等机器视觉软件上常用到各种算子(Operator)和函数来求得感兴趣区域ROI,并进行图像的下一步处理。
2)、ROI有什么用?
ROI属于IVE技术的一种,IVE指的是Intelligent video encoding, 即智能视频编码, IVE技术可以根据客户要求对视频进行智能编码,并在不损失图像质量的前提下,优化视频编码性能,最终降低网络带宽占用率和减少存储空间。
在监控画面中,有些监控区域是不需要被监控或无关紧要,例如天空,墙壁, 草地等等监控对象,普通网络监控摄像机对整个区域进行视频编码(压缩)并传输,这样就给网络带宽和视频存储带来了压力。而ROI智能视频编码技术却很好的解决了这个问题,ROI功能的摄像机可以让用户选择画面中感兴趣的区域,启用ROI功能后,重要的或者移动的区域将会进行高质量无损编码, 而对那些不移动,不被选择的区域降低其码率和图像质量,进行标准清晰度视频压缩,甚至是不传输这部分区域视频,达到节省网络带宽占用和视频存储空间。
#导入图像处理库opencv
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取图像
img=cv2.imread("my.jpg")
img= cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#获取图像高度200:400,宽度200:500区域的图像
img1=img[200:400,200:500]
#图像格式转换
#显示图像
titles = ['原图', '陈一月的ROI区域'] #标题
images = [img, img1] #图像对比显示
for i in range(2):
plt.subplot(1,2,i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
以上方式,直接截取像素对应区域位置然后进行显示,获取一张图像中你喜欢的部分
对于ROI区域的获取在生活中一种照片常用的方法就是为图片添加水印,将自己喜欢的水印图片找好,然后添加到你需要设置的图片上面去,这就是ROI区域移植,通过如下Python代码进行了解吧!
1)、自身图像ROI兴趣区域移植
#导入图像处理库opencv
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取图像
img=cv2.imread("my.jpg")
img= cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#获取图像高度200:400,宽度200:500区域的图像
img1=img[200:400,300:500]
img[:200,:200]=img1 #ROI区域移植到原图上面左上角
#显示图像
titles = ['ROI移植', '陈一月的ROI区域'] #标题
images = [img, img1] #图像对比显示
for i in range(2):
plt.subplot(1,2,i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
#导入图像处理库opencv
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取第一张图像
img=cv2.imread("my.jpg")
img= cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#读取第二张图像
img1=cv2.imread("house.jpg")
img1= cv2.cvtColor(img1,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#获取第二图像高度200:400,宽度200:500区域的图像
img1=img1[200:400,300:500]
img[:200,:200]=img1 #将第二张图像ROI区域移植到第一张图像上面左上角
#显示图像
titles = ['图像水印添加', '水印'] #标题
images = [img, img1] #图像对比显示
for i in range(2):
plt.subplot(1,2,i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
对于图像通道的考虑,一般来讲只会考虑彩色图片,也就是2通道图像,对于单通道的灰度图我们不进行考虑;查询资料我们可以知道,彩色图像的色彩为三基色B\G\R通过不同的比例混合而成,在图像像素中用[0-255表示]表示B\G\R颜色的深浅。下面,我们将分别获取不同的通道,然后理解三通道所表示的含义。
Python中对于通道的获取通过直接对像素数组进行操作实现,如
1)、B、G、R通道获取
#导入图像处理库opencv
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取第一张图像
img=cv2.imread("my.jpg")
#3通道获取
B=img[:,:,0]
G=img[:,:,1]
R=img[:,:,2]
#打印3通道
print('B',B)
print('G',G)
print('R',R)
#转显示格式的目的是因为我们opencv读取图像是以BGR格式读取,而matplotlib显示图像是以RBG格式显示,因此,我们需要通过以下函数进行格式转换,该函数后面会讲到哦!
B= cv2.cvtColor(B,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
G= cv2.cvtColor(G,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
R= cv2.cvtColor(R,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#显示图像
titles = ['B通道', 'G通道','R通道'] #标题
images = [B, G,R] #图像对比显示
for i in range(3):
plt.subplot(1,3,i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
2)、当然,除了可以通过对像素数组操作的方法,我们该可以通过split()函数拆分通道,拆分通道代码如下所示:
B, G, R = cv2.split(img)
通过以上方式获得的3通道图像和第一种方式是一样的,因此具体选择什么方法和个人爱好有关!
上面我们介绍了如何对3通道图像进行通道拆分,既然有拆分就一定有合并,opencv中通道的合并主要通过cv2.merge([B, G, R]) 函数实现,其中的参数变为BGR通道
1)、通道合并代码如下所示:
#导入图像处理库opencv
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取第一张图像
img=cv2.imread("my.jpg")
#3通道获取
B=img[:,:,0]
G=img[:,:,1]
R=img[:,:,2]
#通道合并
img1=cv2.merge([B, G, R])
img1=cv2.cvtColor(img1,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
plt.imshow(img1)
plt.title('通道合并')
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
可能到这里,很多小伙伴还不能理解BGR为什么代表蓝色、绿色和红色,接下来,我们提取出图像中B\G\R三通道不同的颜色,让小伙伴看一下B\G\R为什么说表示的就是三基色,方便大家理解原理
1)、B(Blue)、G(Green)、R(Red)三基色显示
#导入图像处理库opencv
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取第一张图像
img=cv2.imread("my.jpg")
#获取图像高和宽
h,w=img.shape[0:2]
'''
对蓝色通道处理,
'''
#获取通道B-蓝色
B=img[:,:,0]
#将另外两通道设为0
G=np.zeros((h,w),dtype=img.dtype)
R=np.zeros((h,w),dtype=img.dtype)
#合并通道,只保留蓝色通道,其他通道置为0
img1=cv2.merge([B, G, R])
'''
对绿色通道处理,
'''
#获取通道G-绿色
B1=np.zeros((h,w),dtype=img.dtype)
#将另外两通道设为0
G1=img[:,:,1]
R1=np.zeros((h,w),dtype=img.dtype)
#合并通道,只保留绿色通道,其他通道置为0
img2=cv2.merge([B1, G1, R1])
'''
对红色通道处理,
'''
#获取通道R-红色
B2=np.zeros((h,w),dtype=img.dtype)
#将另外两通道设为0
G2=np.zeros((h,w),dtype=img.dtype)
R2=img[:,:,2]
#合并通道,只保留红色通道,其他通道置为0
img3=cv2.merge([B2, G2, R2])
img1= cv2.cvtColor(img1,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
img2= cv2.cvtColor(img2,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
img3= cv2.cvtColor(img3,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#显示图像
titles = ['B通道', 'G通道','R通道'] #标题
images = [img1, img2,img3] #图像对比显示
for i in range(3):
plt.subplot(1,3,i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
2)、当我们将各个通道像素提取,然后分别将其他两通道像素设置为0,只单独保留需要显示通道的像素,然后我们便可以看到3基色的颜色表示,通过对以上三基色进行颜色比例的混合,就会得到其他的各种颜色,颜色混合比例就是3基色组合一起的像素比例;
3)、这里我们需要理解的是,对于一个有三通道的像素来说(例如:[127,234,158]),其中127表示蓝色的深浅度,越接近255颜色越深,给我们的视觉感受就是越蓝,越接近于0颜色越浅,蓝色也就越淡,但值得注意的是,0-255这里表示的是颜色等级,127属于里面颜色等级的第128级(从0开始),也就是说,还是蓝色,只是给我们人眼的视觉感受不一样,呈现出的蓝色深浅度不同而已;同理,234表示的就是绿色等级、158表示的就是红色等级。
4)、但是,让我们把上面三种颜色组合到一起之后,也就是[127,234,158],给我们的视觉颜色可能就是其他颜色了,这就是B\G\R像素混合比例,混合后形成其他颜色;例如我们知道的红蓝配紫色,代码中像素则可以表示为有红色和蓝色两种基色,将绿色设置为0,如:[127,0,158],这里表示的是紫色范畴,因为紫色颜色也具有深浅嘛,也就是说,紫色的深浅通过调整蓝色通道B和红色通道R的像素值,如下代码所示:
#导入图像处理库opencv
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取第一张图像
img=cv2.imread("my.jpg")
#获取图像高和宽
h,w=img.shape[0:2]
#自定义空白图像,和原图像尺寸一样,用于保存红蓝配后的紫色
img1=np.zeros((h,w,3),dtype=img.dtype)
for i in range(h):
for j in range(w):
img1[i,j][0]=img[i,j][0] #B蓝色通道保留
img1[i,j][1]= 0 #绿色通道,设置为0
img1[i,j][2]=img[i,j][2] #红色通道保留
img= cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
img1= cv2.cvtColor(img1,cv2.COLOR_BGR2RGB)#BGR转换为RGB显示格式
#显示图像
titles = ['原图', '红蓝配紫色'] #标题
images = [img, img1] #图像对比显示
for i in range(2):
plt.subplot(1,2,i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.axis('off')#关闭坐标轴 设置为on则表示开启坐标轴
plt.show()#显示图像
5)、那么为了将紫色设置为最深的颜色,该怎么办呢?及全部都为紫色,则我们可以将红色通道R和蓝色通道B全部设置为255,这样得到的紫色便是最深效果,核心代码如下所示:
for i in range(h):
for j in range(w):
img1[i,j][0]=255 #B蓝色通道保留
img1[i,j][1]= 0 #绿色通道,设置为0
img1[i,j][2]=255 #红色通道保留
相信到这里,很多小伙伴就明白了B\G\R所属的意义了吧,其实还是很简单的,理解Opencv中颜色显示原理,即图像颜色显示的原理,对后面图像处理有非常大的意义,同时也是OpenCv图像处理的入门基础,小伙伴们一定要理解呀!
以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!
真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血。这是怎样的哀痛者和幸福者?然而造化又常常为庸人设计,以时间的流驶,来洗涤旧迹,仅使留下淡红的血色和微漠的悲哀。在这淡红的血色和微漠的悲哀中,又给人暂得偷生,维持着这似人非人的世界。我不知道这样的世界何时是一个尽头! -----鲁迅
陈一月的又一天编程岁月^ _ ^