百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

【地表最全】零基础!计算机视觉OpenCV从入门到入土(二)

toyiye 2024-06-21 11:55 11 浏览 0 评论

三.图像运算

1.图像加法运算

1.1加号运算符


对于+号运算,当对图像a,图像b进行加法求和时,遵循以下规则:
当某位置像素相加得到的数值小于255时,该位置数值为两图像该位置像素相加之和
当某位置像素相加得到的数值大于255时,该位置数值为两像素该位置像素相加之和对256取模

In [ ]

img1=np.array([[200,100,200],[100,200,100],[0,200,50]],dtype=np.uint8)
img2=np.array([[200,100,200],[100,200,100],[0,200,50]],dtype=np.uint8)
print("img1=")
print(img1)
print("img2=")
print(img2)
print("img1+img2=")
print(img1+img2) #可以发现相加大于255的位置对256取模
img1=
[[200 100 200]
 [100 200 100]
 [  0 200  50]]
img2=
[[200 100 200]
 [100 200 100]
 [  0 200  50]]
img1+img2=
[[144 200 144]
 [200 144 200]
 [  0 144 100]]

In [ ]

lena=cv2.imread("例.jpg")
lena_double=lena+lena
lena=cv2.cvtColor(lena_double,cv2.COLOR_BGR2RGB)
pylab.imshow(lena_double) #有点吓人QAQ
<matplotlib.image.AxesImage at 0x7f98b832b890>

<Figure size 432x288 with 1 Axes>

1.2 cv2.add()函数


对于cv2.add()运算,当对图像a,图像b进行加法求和时,遵循以下规则:
当某位置像素相加得到的数值小于255时,该位置数值为两图像该位置像素相加之和
当某位置像素相加得到的数值大于255时,该位置数值为255

In [ ]

img1=np.array([[200,100,200],[100,200,100],[0,200,50]],dtype=np.uint8)
img2=np.array([[200,100,200],[100,200,100],[0,200,50]],dtype=np.uint8)
print("img1=")
print(img1)
print("img2=")
print(img2)
print("cv2.add(img1,img2)=")
print(cv2.add(img1,img2)) #可以发现相加大于255的位置对256取模
img1=
[[200 100 200]
 [100 200 100]
 [  0 200  50]]
img2=
[[200 100 200]
 [100 200 100]
 [  0 200  50]]
cv2.add(img1,img2)=
[[255 200 255]
 [200 255 200]
 [  0 255 100]]

In [ ]

lena=cv2.imread("例.jpg")
lena_double=cv2.add(lena,lena)
lena=cv2.cvtColor(lena_double,cv2.COLOR_BGR2RGB)
pylab.imshow(lena_double) #有点吓人QAQ
<matplotlib.image.AxesImage at 0x7f98b854aa50>

<Figure size 432x288 with 1 Axes>

2.图像加权运算


所谓图像加权和,就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来,可以用公式表示为dst=saturate(src1×α+src×β+γ)

In [ ]

img1=np.ones((3,4),dtype=np.uint8)*100
img2=np.ones((3,4),dtype=np.uint8)*10
gamma=3
img3=cv2.addWeighted(img1,0.6,img2,5,gamma)
print(img3)
[[113 113 113 113]
 [113 113 113 113]
 [113 113 113 113]]

In [ ]

lena=cv2.imread("例.jpg")
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
dollar=cv2.imread("美元.jpg")
dollar=cv2.cvtColor(dollar,cv2.COLOR_BGR2RGB)
lena_face=lena[50:400,700:1000] #提取lena的脸
dollar_face=dollar[200:550,400:700] #提取美元的脸
result=cv2.addWeighted(lena_face,0.5,dollar_face,0.5,10) #对两张脸加权求和
dollar[200:550,400:700]=result
pylab.imshow(dollar)
cv2.imwrite("lena与dollar融合.jpg",dollar)
True

<Figure size 432x288 with 1 Axes>

3.位平面分解


二进制位平面分解技术(BBD)
对于任何一个非负的整数都可以被一个二进制序列所表示,数学公式如下所示:


对于一般灰度图像而言,其灰度值通常是一个0到255之间的十进制数,那么每一个像素都可以由8位二进制序列唯一表示。因此,BBD可以将灰度图像拆分成8个二进制平面。第一个位平面是由灰度图像中每一个像素的二进制表示的所有第一位所组成的,如下图我们展示了将一个lena图分解成八张位平面子图的效果。


下图展示了将lena图分解后,各个平面图的样子,其中(a)为lena的原图,从(b)到(i)展示了从最低位平面到最高位平面,其中我们可以很明显发现第八张子图(i)最接近lena的原图,这也就说明了在组成一张图的过程中,高位的图往往起到了更加关键的作用。

In [ ]

lena = cv2.imread(r"例.jpg", 0)
pylab.imshow(lena)
r, c = lena.shape[0], lena.shape[1]
x = np.zeros((r, c, 8), dtype = np.uint8)
for i in range(8):
    x[:, :, i] = 2 ** i
r = np.zeros((r, c, 8), dtype = np.uint8)
for i in range(8):
    r[:, :, i] = cv2.bitwise_and(lena, x[:, :, i])
    mask = r[:, :, i] > 0
    r[mask] = 255
    pylab.gray()
    pylab.subplot(3, 3, i+1)
    pylab.imshow(r[:, :, i])
    pylab.axis('off')  # 去掉坐标轴
    pylab.title(str(i+1))
pylab.show()

<Figure size 432x288 with 8 Axes>

四.色彩空间转换


颜色空间按照基本结构可以分两大类:基色颜色空间 和 色、亮分离颜色空间。
前者的典型是 RGB,还包括 CMY、CMYK、CIE XYZ 等;后者包括 YCC/YUV、Lab、以及一批“色相类颜色空间”。

CIE XYZ 是定义一切颜色空间的基准,很奇妙的是,它即属于基色颜色空间,也属于色、亮分离颜色空间,是贯穿两者的枢纽。色、亮分离颜色空间中的子类型“色相类颜色空间”,是把颜色分成一个表亮属性,和两个表色属性,其中有一个表色属性是色相,而色相以外的两个属性可以选用不同的变量来定义,而色相的概念不变,因此就构成一族共同使用色相属性,另加表亮属性和表色属性各一个组成的颜色空间,它们是颜色空间中的一个家族,暂且统称为 HSB 颜色空间。RGB和CMY颜色模型都是面向硬件的,而HSV(HueSaturation Value)颜色模型是面向用户的。

补充:
色光三原色 RGB:吸收俩种,反射自身颜色;在屏幕上显示的图像,就是RGB模式表现的
色料三原色CMY:反射两种,吸收一种颜色;在印刷品上看到的图像,就是CMYK模式表现的

RGB



颜色范围

R(Red:红)、G(Green:绿)、B(Blue:蓝) A(Alpha 透明度)

RGB的每个元素在计算机内存中占用1个字节,1个字节等于8个bit位,所以RGB每个元素的取值范围为:0~256(2的8次方)

存储类型

(1)RGB555:16位的RGB格式,各分量都用5位表示,剩下的一位不用。

高字节 -> 低字节(根据内存大小端) XRRRRRGGGGGBBBBB(X代表不用)

(2)RGB565:16位的RGB格式,但是R占用5位,G占用6位,B占用5位。

(3)RGB24:24位的RGB格式,各分量占用8位,取值范围为0-255。

(4)RGB32:32位的RGB格式,各分量占用8位,剩下的8位作Alpha通道或者不用。

(5)RGB222:8位的RGB格式,各分量占用2bit位,剩下的2bit位不用!

......

单通道与多通道

单通道:俗称灰度图,每个像素点只能有一个值表示颜色,它的像素值在0到255之间,0是黑色,255是白色,中间值是一些不同等级的灰色,可以说灰度是黑与白之间的过渡色!

多通道:RGB三原色,每个像素点有三个字节来表示(RGB),分别最大取值范围是0-255,可以组合成千万种颜色。

HSV




HSV(Hue, Saturation, Value)是根据颜色的直观特性由A.R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model),HSV模型的三维表示从RGB立方体演化而来。设想从RGB沿立方体对角线的白色顶点向黑色顶点观察,就可以看到立方体的六边形外形。六边形边界表示色彩,水平轴表示纯度,明度沿垂直轴测量。与RGB系统相比,更加接近于人们的经验和描述彩色感觉时所用的方式。也称HSB (B指brightness) 是艺术家们常用的。

HSV模型对应于画家配色的方法。画家用改变色浓和 色深的方法从某种纯色获得不同色调的颜色,在一种纯色中加入白色以改变色浓,加入黑色以改变色深,同时加入不同比例的白色,黑色即可获得各种不同的色调。
色调H(Hue):用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。
饱和度S(Saturation):取值范围为0.0~1.0,值越大,颜色越饱和。用距V轴的距离来度量
明度V(Value):取值范围为0(黑色)~1(白色)。轴V=0端为黑色,轴V=1端为白色。

CMYK/CMYK彩色空间

CMY模式是指采用青色(Cyan)、品红色(Magenta)、黄色(Yellow)3种基本颜色按一定比例合成颜色的方法,是一种依靠反光显色的色彩模式。在CMY模型中,显示的色彩不是直接来自于光线的色彩,而是光线被物体吸收掉一部分之后反射回来的剩余光线所产生的。因此,光线都被吸收时显示为黑色(减色法),当光线完全被反射时显示为白色(加色法)。

从理论上来说,只需要CMY三种油墨等比例混合在一起就会得到黑色,但是因为目前制造工艺水平的限制,制造出来的油墨纯度都不够高,CMY相加的结果实际只是一种暗红色。所以往往还会加入黑色(black)油墨,这就是CMYK色彩混合模式的由来。CMYK又称为印刷色彩模式。

RGB模式是一种发光的色彩模式。比如在一间黑暗的房间里,你可以看到投射在墙壁上的光斑;CMY(K)是一种依靠反光的色彩模式。在黑暗房间里你是无法阅读报纸的,我们之所以能够看到报纸上的内容是因为有光照射到报纸上,再反射到我们的眼中。
C=255-R C - Cyan 青 〈互补色〉 R - Red 红
M=255-G M - Magenta 品红 〈互补色〉 G - Green 绿
Y=255-B Y - Yellow 黄 〈互补色〉 B - Blue 蓝


该方程证明了从一个涂满纯净青色颜料的表面反射回的光不包含红色。



YCbCr/YUV彩色空间




YUV(亦称YCrCb)彩色空间广泛用于数字视频。在这种格式中,亮度信息用单独的分量Y来表示,彩色信息是用两个色差分量Cb和Cr来存储的。分量Cb是蓝色分量与参考值的差,分量Cr是红色分量与参考值的差。 亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V)
YUV主要用于优化彩色视频信号的传输,使其向后相容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。

其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面─色调与饱和度,分别用Cr和CB来表示。其中,Cr反映了GB输入信号红色部分与RGB信号亮度值之间的差异。而CB反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。 采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。


1.获得特定颜色


在HSV色彩空间中,H通道(饱和度Hue通道)对应不同的颜色。或者换个角度理解,颜色的差异主要体现在H通道值的不同上。所以,通过对H通道值进行筛选,便能够筛选出特定的颜色。例如,在一幅HSV凸显中,如果通过控制仅仅将H通道内值为240(在OPenCV内被调整为120)的像素显示出来,那么图像中就会仅仅显示蓝色的部分。
需要注意的是,在实际提取颜色时,往往不是提取一个特定的值,而是提取一个颜色区间。
蓝色:值分布范围为[110,100,100]和[130,255,255]之间
绿色:值分布范围为[50,100,100]和[70,255,255]之间
红色:值分布范围为[0,100,100]和[10,255,255]之间
下面分离特定颜色

In [ ]

#分离蓝色
opencv=cv2.imread("OpenCV.jpg") #读取opencv图片
hsv=cv2.cvtColor(opencv,cv2.COLOR_BGR2HSV) #获得hsv色彩空间图片
opencv=cv2.cvtColor(opencv,cv2.COLOR_BGR2RGB) #将bgr转换成rgb,方便后续pylab展示(如果在本地使用cv2的imshow可忽略)
minBlue=np.array([110,50,50]) #设置蓝色空间的下限
maxBlue=np.array([130,255,255]) #设置蓝色空间的上限
mask=cv2.inRange(hsv,minBlue,maxBlue) #确定蓝色区域
blue=cv2.bitwise_and(opencv,opencv,mask=mask) #通过掩码控制的按位与运算确定蓝色区域
pylab.imshow(blue)
<matplotlib.image.AxesImage at 0x7f98b0494410>

<Figure size 432x288 with 1 Axes>

In [ ]

sky = cv2.imread('sky.jpg')
sk1 =  cv2.cvtColor(sky, cv2.COLOR_BGR2RGB)
pylab.subplot(1,2,1)
pylab.imshow(sk1)
lower_blue = np.array([15, 60, 60])
upper_blue = np.array([130, 255, 255]) #去除云
pylab.subplot(1,2,2)
hsv=cv2.cvtColor(sky,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(hsv,lower_blue,upper_blue)
res=cv2.bitwise_and(sky,sky,mask=mask)
cv2.imwrite("res.jpg",res)
res = cv2.cvtColor(res, cv2.COLOR_BGR2RGB)
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f98b0499090>

<Figure size 432x288 with 2 Axes>


2.Alpha通道

一、Alpha通道的概念与功能
在计算机图形学中,一个RGB颜色模型的真彩图形,用由红、绿、蓝三个色彩信息通道合成的,每个通道用了8位色彩深度,共计24位,包含了所有彩色信息。为实现图形的透明效果,采取在图形文件的处理与存储中附加上另一个8位信息的方法,这个附加的代表图形中各个素点透明度的通道信息就被叫做Alpha通道。
Alpha通道使用8位二进制数,就可以表示256级灰度,即256级的透明度。白色(值为255)的Alpha像素用以定义不透明的彩色像素,而黑色(值为0)的Alpha通道像素用以定义透明像素,介于黑白之间的灰度(值为30-255)的Alpha像素用以定义不同程度的半透明像素。因而通过一个32位总线的图形卡来显示带Alpha通道的图形,就可能呈现出透明或半透明的视觉效果。

In [ ]

lena=cv2.imread("例.jpg")
img=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
bgra=cv2.cvtColor(lena,cv2.COLOR_BGR2BGRA)
cv2.imwrite("bgra.jpg",bgra)
b,g,r,a=cv2.split(bgra)
a[:,:]=125
bgra125=cv2.merge([b,g,r,a])
cv2.imwrite("bgra125.jpg",bgra125)
img1=cv2.cvtColor(bgra125,cv2.COLOR_BGRA2RGBA)
a[:,:]=0
bgra0=cv2.merge([b,g,r,a])
cv2.imwrite("bgra0.jpg",bgra0)
img2=cv2.cvtColor(bgra0,cv2.COLOR_BGRA2RGBA)
pylab.subplot(1,3,1)
pylab.imshow(img)
pylab.subplot(1,3,2)
pylab.imshow(img1)
pylab.subplot(1,3,3)
pylab.imshow(img2)
<matplotlib.image.AxesImage at 0x7f98b0309f50>

<Figure size 432x288 with 3 Axes>


五.几何变换

1.缩放

In [ ]

# 1.第一种方法
lena=cv2.imread("例.jpg")
print(lena.shape) #变换前的大小
r,c=lena.shape[0],lena.shape[1]
lena=cv2.resize(lena,(int(c*0.9),int(r*0.6))) #宽度变为原来的0.9,高度变为原来的0.6
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
print(lena.shape) #变换后的大小
pylab.imshow(lena)
(599, 1440, 3)
(359, 1296, 3)
<matplotlib.image.AxesImage at 0x7f98b02855d0>

<Figure size 432x288 with 1 Axes>

In [ ]

# 2.第二种方法
lena=cv2.imread("例.jpg")
print(lena.shape) #变换前的大小
lena=cv2.resize(lena,None,fx=2,fy=0.5) #长度变为原来的2倍,高度变为原来的0.5
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
print(lena.shape) #变换后的大小
pylab.imshow(lena)
(599, 1440, 3)
(300, 2880, 3)
<matplotlib.image.AxesImage at 0x7f98b025cc50>

<Figure size 432x288 with 1 Axes>

2.翻转

In [ ]

lena=cv2.imread("例.jpg")
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
x=cv2.flip(lena,0) #0表示绕x轴变换
y=cv2.flip(lena,1) #1表示绕y轴变换
xy=cv2.flip(lena,-1) #-1表示绕xy轴进行变换
pylab.subplot(1,3,1) 
pylab.imshow(x)
pylab.subplot(1,3,2)
pylab.imshow(y)
pylab.subplot(1,3,3)
pylab.imshow(xy)
<matplotlib.image.AxesImage at 0x7f98b0197810>

<Figure size 432x288 with 3 Axes>

3.仿射

仿射变换是指图像可以通过一系列的几何变换来实现平移,旋转等多种操作。该变换能够保持图像的平直性和平行性。
平直性是指图像经过仿射变换后,直线仍然是直线;
平行性是指图像在完成仿射变换后,平行线仍然是平行线。


In [ ]

lena=cv2.imread("例.jpg")
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
height,width=img.shape[:2]
x=100 #x轴平行的距离
y=200 #y轴平行的距离
M=np.float32([[1,0,x],[0,1,y]]) #建立矩阵
move=cv2.warpAffine(img,M,(width,height)) #x,y分别向右,向下移动100,200个像素
pylab.subplot(1,2,1)
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.imshow(move)
<matplotlib.image.AxesImage at 0x7f98b06a9350>

<Figure size 432x288 with 2 Axes>

4.旋转

在使用函数cv2.warpAffine()对图像进行旋转时,可以通过函数cv2.getRotationMatrix2D()获得转换矩阵。该函数的语法格式为:
retval=cv2.getRotationMatrix2D(centrer,angle,scale)
center为旋转中心点
angle为旋转的角度,正数表示逆时针旋转,反之为逆时针旋转
scale为变换尺度(缩放大小)

In [ ]

#对lena进行逆时针45度的翻转,并进行0.6倍缩放
lena=cv2.imread("例.jpg")
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
height,width=lena.shape[:2]
M=cv2.getRotationMatrix2D((width/2,height/2),15,0.6)
rotate=cv2.warpAffine(lena,M,(width,height))
pylab.imshow(rotate)
<matplotlib.image.AxesImage at 0x7f98b82faf90>

<Figure size 432x288 with 1 Axes>

5.更复杂的仿射变换

面对更复杂的仿射变换,OpenCV提供了函数cv2.getAffineTransform()来生成放射函数cv2.warpAffine()所使用的转化矩阵M。该函数的语法格式为
retval=cv2.getAffineTransform(src,dst)
src代表输入图像的三个点的坐标
dst代表输出图像的三个点的坐标

In [ ]

lena=cv2.imread("例.jpg")
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
rows,cols,ch=img.shape
p1=np.float32([[0,0],[cols-1,0],[0,rows-1]])
p2=np.float32([[0,rows*0.33],[cols*0.85,rows*0.25],[cols*0.15,rows*0.7]])
M=cv2.getAffineTransform(p1,p2)
dst=cv2.warpAffine(lena,M,(cols,rows))
pylab.imshow(dst)
<matplotlib.image.AxesImage at 0x7f98b825cd10>

<Figure size 432x288 with 1 Axes>

6.重映射

把一幅图像的像素点放置到另一副图像内的指定位置,这个过程成为重映射。
OpenCV提供了多种重映射方式,但是我们有时希望使用自定义的方式来完成重映射。
OpenCV内的重映射函数cv2.remap()提供了更方便,更自由地映射方式,其语法格式如下:
dst=cv2.remap(src,map1,map2,interpolation[,borderMode[,borderValue]])
式中:
dst代表目标图像,它和src具有相同的大小和类型
src代表原始图像
map1参数有两种可能的值:
--表示(x,y)点的一个映射
--表示CV_16SC2,CV_32FC1,CV_32FC2类型(x,y)点的x值。
map2参数有两种可能的值:
--map1表示(x,y)时,该值为空
--map1表示(x,y)点的x值时,该值是CV_16UC1,CV_32FC1类型(x,y)点的y值。
Interpolation代表插值方式,这里不支持INTER_AREA方法。
borderMode代表边界方式。
borderValue代表边界值,默认为0

In [ ]

#例
img=np.random.randint(0,256,size=[4,5],dtype=np.uint8)#生成一个随机4*5的矩阵
rows,cols=img.shape
mapx=np.ones(img.shape,np.float32)*3
mapy=np.ones(img.shape,np.float32)*0
res=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) #res的每一个位置都被设置成了img[0][3]
print("img=\n",img)
print("mapx=\n",mapx)
print("mapy=\n",mapy)
print("rst='\n",res) 
img=
 [[141 139 166 135  48]
 [130   1  89 210 120]
 [251   4 255 252 250]
 [219 147  85 153 142]]
mapx=
 [[3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]]
mapy=
 [[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]
rst='
 [[135 135 135 135 135]
 [135 135 135 135 135]
 [135 135 135 135 135]
 [135 135 135 135 135]]

In [ ]

#用remap复制lena
lena=cv2.imread('例.jpg')
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2],np.float32)
mapy=np.zeros(lena.shape[:2],np.float32)
for i in range(rows):
    for j in range(cols):
        mapx.itemset((i,j),j)
        mapy.itemset((i,j),i)
res=cv2.remap(lena,mapx,mapy,cv2.INTER_LINEAR)
res=cv2.cvtColor(res,cv2.COLOR_BGR2RGB)
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
pylab.subplot(1,2,1)
pylab.title("original")
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.title("result")
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f98b838b8d0>

<Figure size 432x288 with 2 Axes>

In [ ]

#绕x轴旋转
lena=cv2.imread('例.jpg')
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2],np.float32)
mapy=np.zeros(lena.shape[:2],np.float32)
for i in range(rows):
    for j in range(cols):
        mapx.itemset((i,j),j)
        mapy.itemset((i,j),rows-1-i)
res=cv2.remap(lena,mapx,mapy,cv2.INTER_LINEAR)
pylab.subplot(1,2,1)
pylab.title("original")
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.title("result")
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f98b069da90>

<Figure size 432x288 with 2 Axes>

In [ ]

#绕y轴旋转
lena=cv2.imread('例.jpg')
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2],np.float32)
mapy=np.zeros(lena.shape[:2],np.float32)
for i in range(rows):
    for j in range(cols):
        mapx.itemset((i,j),cols-j-1)
        mapy.itemset((i,j),i)
res=cv2.remap(lena,mapx,mapy,cv2.INTER_LINEAR)
pylab.subplot(1,2,1)
pylab.title("original")
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.title("result")
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f98b0642d90>

<Figure size 432x288 with 2 Axes>

In [ ]

#绕xy轴旋转
lena=cv2.imread('例.jpg')
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2],np.float32)
mapy=np.zeros(lena.shape[:2],np.float32)
for i in range(rows):
    for j in range(cols):
        mapx.itemset((i,j),cols-j-1)
        mapy.itemset((i,j),rows-i-1)
res=cv2.remap(lena,mapx,mapy,cv2.INTER_LINEAR)
pylab.subplot(1,2,1)
pylab.title("original")
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.title("result")
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f98b00b9190>

<Figure size 432x288 with 2 Axes>

In [ ]

#x,y轴互换
lena=cv2.imread('例.jpg')
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2],np.float32)
mapy=np.zeros(lena.shape[:2],np.float32)
for i in range(rows):
    for j in range(cols):
        mapx.itemset((i,j),i)
        mapy.itemset((i,j),j)
res=cv2.remap(lena,mapx,mapy,cv2.INTER_LINEAR)
pylab.subplot(1,2,1)
pylab.title("original")
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.title("result")
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f98b00573d0>

<Figure size 432x288 with 2 Axes>

In [ ]

#图像缩放
lena=cv2.imread('例.jpg')
lena=cv2.cvtColor(lena,cv2.COLOR_BGR2RGB)
rows,cols=lena.shape[:2]
mapx=np.zeros(lena.shape[:2],np.float32)
mapy=np.zeros(lena.shape[:2],np.float32)
for i in range(rows):
    for j in range(cols):
        if 0.25*cols<j<0.75*cols and 0.25*rows<i<0.75*rows:
            mapx.itemset((i,j),2*(j-cols*0.25)+0.5)
            mapy.itemset((i,j),2*(i-rows*0.25)+0.5)
        else:
            mapx.itemset((i,j),0)
            mapy.itemset((i,j),0)
res=cv2.remap(lena,mapx,mapy,cv2.INTER_LINEAR)
pylab.subplot(1,2,1)
pylab.title("original")
pylab.imshow(lena)
pylab.subplot(1,2,2)
pylab.title("result")
pylab.imshow(res)
<matplotlib.image.AxesImage at 0x7f989c739510>

<Figure size 432x288 with 2 Axes>

六.阈值处理

阈值处理是值剔除图像内像素值高于一定值或低于一定值的像素点。例如,设定阈值为127,然后:

  • 将图像内所有像素值大于127的像素点的值设为255
  • 将图像内所有像素值小于或等于127的像素点的值设为0

通过上述方法能够得到一幅444二值图像。如图6-1所示,按照上述阈值处理方法将一幅灰度图像处理为一幅二值图像,有效地实现了前景和背景的分离
OpenCV提供了函数cv2.threshold()和函数cv2.adaptive.Threshold(),用于实现阈值处理。

1.threshold函数

retval,dst=cv2.threshold(src,shresh,maxval,type)
式中:

  • retval代表返回的阈值
  • dst代表阈值分割结果图像,与原始图像具有相同的大小和类型
  • src代表要进行阈值分割的图像,可以是多通道的,8位或32位浮点型数值
  • thresh代表要设定的阈值
  • maxval代表type参数位THRESH_BINARY或者THRESH_BINARY_INV类型时,需要设定的最大值
  • type代表阈值分割的类型,具体内容如下图所示

In [68]

# 二值化阈值处理(cv2.THRESH_BINARY)
lena=cv2.imread('例—灰度图.jpg',0)
pylab.subplot(1,2,1)
pylab.imshow(lena)
t,res=cv2.threshold(lena,127,255,cv2.THRESH_BINARY)
# pylab灰度图是三通道,如果用单通道 进行展示会造成图片失真,所以这里进行通道扩展
res = np.concatenate((np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2)),
                         axis = -1)
pylab.subplot(1,2,2)
pylab.imshow(res)
pylab.show()

<Figure size 432x288 with 2 Axes>

In [69]

# 反二值化阈值处理(cv2.THRESH_BIN_INV)
pylab.subplot(1,2,1)
pylab.imshow(lena)
t,res=cv2.threshold(lena,127,255,cv2.THRESH_BINARY_INV)
# pylab灰度图是三通道,如果用单通道 进行展示会造成图片失真,所以这里进行通道扩展
res = np.concatenate((np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2)),
                         axis = -1)
pylab.subplot(1,2,2)
pylab.imshow(res)
pylab.show()

<Figure size 432x288 with 2 Axes>

In [71]

# 截断阈值化处理(cv2.THRESH_TRUNC)
# 截断阈值化处理会将图像中大于阈值的像素点的值设定为阈值,小于或等于阈值的像素点保持不变
pylab.subplot(1,2,1)
pylab.imshow(lena)
t,res=cv2.threshold(lena,127,255,cv2.THRESH_TRUNC)
# pylab灰度图是三通道,如果用单通道 进行展示会造成图片失真,所以这里进行通道扩展
res = np.concatenate((np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2)),
                         axis = -1)
pylab.subplot(1,2,2)
pylab.imshow(res)
pylab.show()

<Figure size 432x288 with 2 Axes>

In [73]

# 超阈值零处理(cv2.THRESH_TOZERO_INV)
pylab.subplot(1,2,1)
pylab.imshow(lena)
t,res=cv2.threshold(lena,127,255,cv2.THRESH_TOZERO_INV)
# pylab灰度图是三通道,如果用单通道 进行展示会造成图片失真,所以这里进行通道扩展
res = np.concatenate((np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2), np.expand_dims(res, axis = 2)),
                         axis = -1)
pylab.subplot(1,2,2)
pylab.imshow(res)
pylab.show()

<Figure size 432x288 with 2 Axes>

In [75]

# 低阈值零处理(cv2.THRESH_TOZERO)
pylab.subplot(1,2,1)
pylab.imshow(lena)
t,res=cv2.threshold(lena,127,255,cv2.THRESH_TOZERO)
pylab.subplot(1,2,2)
pylab.imshow(res)
pylab.show()

<Figure size 432x288 with 2 Axes>

In [96]

# Otus处理
pylab.subplot(1,2,1)
pylab.imshow(lena)
t2,res=cv2.threshold(lena,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
pylab.subplot(1,2,2)
pylab.imshow(res)
pylab.show()
print("寻找的最佳阈值为{}".format(t2))

<Figure size 432x288 with 2 Axes>
寻找的最佳阈值为114.0

2.adaptiveThreshold()函数

dst=cv2.adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C)

  • dst代表自适应阈值代表结果
  • src代表要进行的原始图像。需要注意的是,该图像必须是位单通道的图像。
  • maxValue代表最大值
  • adaptiveMehod代表自适应方法
  • thresholdType代表阈值处理方法,该值必须是cv2.THRESH_BINARY或者cv2.THRESH_BINARY_INV中的一个
  • blockSize代表块大小。表示一个像素在计算其阈值时所使用的邻域尺寸,通常为3,5,7等
  • C是常量
    cv2.adaptiveThreshold()根据参数adaptiveMethod来确定自适应阈值的计算方法。
  • cv2.ADAPTIVE_THRESH_MEAN_C:邻域所有像素点的权重值是一致的。
  • cv2.ADAPTIVE_THRESH_GUASSIAN_C:与邻域各个像素点到中心点的距离有关,通过高斯方程得到各个点的权重值

In [92]

# 自适应阈值处理
pylab.subplot(1,3,1)
pylab.imshow(lena)
res_1=cv2.adaptiveThreshold(lena,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,71,3)
# pylab灰度图是三通道,如果用单通道 进行展示会造成图片失真,所以这里进行通道扩展
res_1 = np.concatenate((np.expand_dims(res_1, axis = 2), np.expand_dims(res_1, axis = 2), np.expand_dims(res_1, axis = 2)),
                         axis = -1)
pylab.subplot(1,3,2)
pylab.imshow(res_1)
res_2=cv2.adaptiveThreshold(lena,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,71,3)
# pylab灰度图是三通道,如果用单通道 进行展示会造成图片失真,所以这里进行通道扩展
res2 = np.concatenate((np.expand_dims(res_2, axis = 2), np.expand_dims(res_2, axis = 2), np.expand_dims(res_2, axis = 2)),
                         axis = -1)
pylab.subplot(1,3,3)
pylab.imshow(res_2)
pylab.show()

<Figure size 432x288 with 3 Axes>


七.图像平滑处理

1.均值滤波

dst=cv2.blur(src,ksize,anchor,borderType)

  • dst是返回值
  • src是需要处理的图像
  • kszie是滤波核(卷积核)的大小
  • anchor是锚点,默认值是(-1,-1)一般无需更改
  • borderType是边界样式,一般无需更改
    一般情况下,使用dst=cv2.blur(src,ksize)即可
    原理:它只取内核区域下所有像素的平均值并替换中心元素。3x3标准化的盒式过滤器如下所示:

In [101]

lena_noise=cv2.imread("噪声lena.jpg",0)
lena_deal=cv2.blur(lena_noise,(5,5))
lena_noise = np.concatenate((np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2)),
                         axis = -1)
lena_deal = np.concatenate((np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal, axis = 2)),
                         axis = -1)
pylab.subplot(1,2,1)
pylab.imshow(lena_noise)
pylab.subplot(1,2,2)
pylab.imshow(lena_deal)
pylab.show()

<Figure size 432x288 with 2 Axes>

2.方框滤波

二、cv2.boxFilter(img,-1,ksize,normalize=True) 方框滤波
说明:当normalize=True时,与均值滤波结果相同, normalize=False,表示对加和后的结果不进行平均操作,大于255的使用255表示。

In [108]

lena_noise=cv2.imread("噪声lena.jpg",0)
lena_deal_1=cv2.boxFilter(lena_noise,-1,(5,5))
lena_deal_2=cv2.boxFilter(lena_noise,-1,(5,5),normalize=False)
lena_noise = np.concatenate((np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2)),
                         axis = -1)
lena_deal_1 = np.concatenate((np.expand_dims(lena_deal_1, axis = 2), np.expand_dims(lena_deal_1, axis = 2), np.expand_dims(lena_deal_1,axis = 2)),
                         axis = -1)
lena_deal_2= np.concatenate((np.expand_dims(lena_deal_2, axis = 2), np.expand_dims(lena_deal_2, axis = 2), np.expand_dims(lena_deal_2, axis = 2)),
                         axis = -1)
pylab.subplot(1,3,1)
pylab.imshow(lena_noise)
pylab.subplot(1,3,2)
pylab.imshow(lena_deal_1)
pylab.subplot(1,3,3)
pylab.imshow(lena_deal_2)
pylab.show()

<Figure size 432x288 with 3 Axes>

3.高斯滤波

cv2.GaussianBlur(img, ksize,sigmaX,sigmaY)
说明:sigmaX,sigmaY分别表示X,Y方向的标准偏差。如果仅指定了sigmaX,则sigmaY与sigmaX相同.如果两者都为零,则根据内核大小计算它们。
原理:核中区域贡献率与距离区域中心成正比,权重与高斯分布相关。

In [111]

lena_noise=cv2.imread("噪声lena.jpg",0)
lena_deal=cv2.GaussianBlur(lena_noise,(5,5),0,0)
lena_noise = np.concatenate((np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2)),
                         axis = -1)
lena_deal = np.concatenate((np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal,axis = 2)),
                         axis = -1)
pylab.subplot(1,2,1)
pylab.imshow(lena_noise)
pylab.subplot(1,2,2)
pylab.imshow(lena_deal)
pylab.show()

<Figure size 432x288 with 2 Axes>

4.中值滤波

cv2.medianBlur(img, k)
说明:imgs为原图像,k为方框的尺寸,相当于将方框内的个值进行排序,取中值作为当前值。
原理:中心点的像素被核中中位数的像素值代替。
缺点:由于需要对周围的像素值进行排序所以需要的计算量比较大

In [116]

lena_noise=cv2.imread("噪声lena.jpg",0)
lena_deal=cv2.medianBlur(lena_noise,5)
lena_noise = np.concatenate((np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2)),
                         axis = -1)
lena_deal = np.concatenate((np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal,axis = 2)),
                         axis = -1)
pylab.subplot(1,2,1)
pylab.imshow(lena_noise)
pylab.subplot(1,2,2)
pylab.imshow(lena_deal)
pylab.show()

<Figure size 432x288 with 2 Axes>

5.双边滤波

cv2.bilateralFilter(img,d, sigmaColor, sigmaSpace)
说明:
d为邻域直径,sigmaColor为空间高斯函数标准差,参数越大,临近像素将会在越远的地方越小。

sigmaSpace灰度值相似性高斯函数标准差,参数越大,那些颜色足够相近的的颜色的影响越大。

双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的。
具有简单、非迭代、局部处理的特点。
之所以能够达到保边去噪的滤波效果是因为滤波器由两个函数构成:
1.一个函数是由几何空间距离决定滤波器系数
2.另一个是由像素差值决定滤波器系数。
缺点:处理耗时。
优点:在滤波的同时能保证一定的边缘信息。

In [118]

lena_noise=cv2.imread("噪声lena.jpg",0)
lena_deal=cv2.bilateralFilter(lena_noise,25,100,100)
lena_noise = np.concatenate((np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2)),
                         axis = -1)
lena_deal = np.concatenate((np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal,axis = 2)),
                         axis = -1)
pylab.subplot(1,2,1)
pylab.imshow(lena_noise)
pylab.subplot(1,2,2)
pylab.imshow(lena_deal)
pylab.show()

<Figure size 432x288 with 2 Axes>

6.2D卷积

dst=cv2.filter2D(src,ddepth,ksize,anchor,delta,borderType)

  • dst是返回值
  • src是需要处理的图像
  • ddepth处理结果图像的深度,如果是-1表示与原始图像使用相同的图片深度
  • kszie是滤波核(卷积核)的大小
  • anchor是锚点,默认值是(-1,-1)一般无需更改
  • delta修正值,作为可选项。如果存在,会在结果上加上该值作为最终滤波的处理结果
  • borderType是边界样式,一般无需更改
    一般情况下,使用dst=cv2.blur(src,ksize)即可
    原理:它只取内核区域下所有像素的平均值并替换中心元素。3x3标准化的盒式过滤器如下所示:

In [123]

lena_noise=cv2.imread("噪声lena.jpg",0)
kernel = np.ones((5,5),np.float32)/25
lena_deal = cv2.filter2D(lena_noise,-1,kernel)
lena_noise = np.concatenate((np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2), np.expand_dims(lena_noise, axis = 2)),
                         axis = -1)
lena_deal = np.concatenate((np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal, axis = 2), np.expand_dims(lena_deal,axis = 2)),
                         axis = -1)
pylab.subplot(1,2,1)
pylab.imshow(lena_noise)
pylab.subplot(1,2,2)
pylab.imshow(lena_deal)
pylab.show()

<Figure size 432x288 with 2 Axes>

如果对你有帮助多多支持哟!博主会持续分享编程干货,多多关注~

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码