python进阶—OpenCV之图像处理(一)
文章目录
颜色空间转换
RGB色彩空间
HSV色彩空间
YUV色彩空间
简单的物体跟踪示例
HSV空间目标阈值选取
图像几何变换
图像的缩放
图像的位移
图像的旋转
图像的仿射
图像的投射
图像阈值(二值化)
图像的简单阈值二值化
图像的自适应阈值二值化
Otsu’s二值化
图像模糊操作
均值模糊
中值模糊
自定义模糊
高斯模糊
双边沿模糊
本篇接着记录python-OpenCV的基础部分:图像处理
https://docs.opencv.org/3.4.0/d6/d00/tutorial_py_root.html
颜色空间转换
这里主要说明BRG与HSV两种应用最为广泛的色彩空间
RGB色彩空间
在RGB颜色空间中,任意色光F都可以用R、G、B三色不同分量的相加混合而成:F=r[R]+r[G]+r[B]。RGB色彩空间还可以用一个三维的立方体来描述。当三基色分量都为0(最弱)时混合为黑色光;当三基色都为k(最大,值由存储空间决定)时混合为白色光
RGB色彩空间根据每个分量在计算机中占用的存储字节数分为如下几种类型:
RGB555:RGB555是一种16位的RGB格式,各分量都用5位表示,剩下的一位不用。
高字节 -> 低字节
XRRRRRGGGGGBBBBB
RGB565:RGB565也是一种16位的RGB格式,但是R占用5位,G占用6位,B占用5位。
RGB24R:GB24是一种24位的RGB格式,各分量占用8位,取值范围为0-255。
RGB32:RGB32是一种32位的RGB格式,各分量占用8位,剩下的8位作Alpha通道或者不用。
RGB色彩空间采用物理三基色表示,因而物理意义很清楚,适合彩色显象管工作。然而这一体制并不适应人的视觉特点。因而,产生了其它不同的色彩空间表示法。
HSV色彩空间
HSV是一种将RGB色彩空间中的点在倒圆锥体中的表示方法。HSV即色相(Hue)、饱和度(Saturation)、明度(Value),又称HSB(B即Brightness)。色相是色彩的基本属性,就是平常说的颜色的名称,如红色、黄色等。饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。明度(V),取0-max(计算机中HSV取值范围和存储的长度有关)。HSV颜色空间可以用一个圆锥空间模型来描述。圆锥的顶点处,V=0,H和S无定义,代表黑色。圆锥的顶面中心处V=max,S=0,H无定义,代表白色。
注意:在opencv的HSV色彩空间中:H取值范围是[0-179], S的取值范围是[0-255], V的取值范围是[0-255]
YUV色彩空间
1、YUV(亦称YCrCb)是被欧洲电视系统所采用的一种颜色编码方法。在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄影机进行取像,然后把取得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和两个色差总共三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V信号分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。
2、YUV主要用于优化彩色视频信号的传输,使其向后相容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面─色调与饱和度,分别用Cr和Cb来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之同的差异。
3、YUV和RGB互相转换的公式如下(RGB取值范围均为0-255)︰
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
简单的物体跟踪示例
import cv2import numpy as npcap = cv2.VideoCapture(0)while(1): # Take each frame _, frame = cap.read() # Convert BGR to HSV hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # define range of blue color in HSV lower_blue = np.array([110,50,50]) upper_blue = np.array([130,255,255]) # Threshold the HSV image to get only blue colors mask = cv2.inRange(hsv, lower_blue, upper_blue) # Bitwise-AND mask and original image res = cv2.bitwise_and(frame,frame, mask= mask) cv2.imshow('frame',frame) cv2.imshow('mask',mask) cv2.imshow('res',res) k = cv2.waitKey(5) & 0xFF if k == 27: breakcv2.destroyAllWindows()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HSV空间目标阈值选取
如何在HSV空间,跟踪目标时选择一个合适的阈值呢?办法如下:
使用cv2.cvtColor函数,传入一个BRG颜色值,flag参数为cv2.COLOR_BGR2HSV,函数的返回值就是此颜色在HSV空间的取值。示例如下:green = np.uint8([[[0,255,0 ]]])hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)print hsv_green# [[[ 60 255 255]]]12341234
那么在HSV空间跟踪此颜色的目标时,选取目标的颜色阈值可为: [H-10, 100,100] 到 [H+10, 255, 255]
图像几何变换
图像的缩放操作主要包括缩小与放大、旋转、仿射、投射等
图像的缩放
图像的缩放操作主要是函数:cv2.resize,函数原型如下:
cv2.resize(src,dsize,dst=None,fx=None,fy=None,interpolation=None)
关于此函数的详细说明记录在:python进阶—OpenCV之常用图像操作函数说明
函数使用示例如下:
import cv2import numpy as npimg = cv2.imread('messi5.jpg')res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)height, width = img.shape[:2]res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
图像的位移
图像的旋转要靠函数cv2.warpAffine完成,可以完成x或者y方向的上的移动
图像的移动操作需要一个2*3 的矩阵来指明x、y分别移动的像素大小
矩阵格式为:M = [[1, 0, tx], [0, 1, ty]]
函数示例如下:import cv2import numpy as npimg = cv2.imread('messi5.jpg',0)rows,cols = img.shapeM = np.float32([[1,0,100],[0,1,50]])dst = cv2.warpAffine(img,M,(cols,rows))cv2.imshow('img',dst)cv2.waitKey(0)cv2.destroyAllWindows()123456789101112123456789101112
注意:cv2.warpAffine此函数的地撒个参数是一个元组分别表示图像的宽、高:(width, height)
函数的详细说明记录在:python进阶—OpenCV之常用图像操作函数说明
图像的旋转
图像的旋转要靠函数cv2.warpAffine完成,此函数可以将图像以指定的中心坐标进行旋转,此处既是图像的中心。
把图像以中心店旋转一个角度,需要依靠一个2*3的旋转矩阵,可以通过函数cv2.getRotationMatrix2D来获得旋转矩阵
img = cv2.imread('messi5.jpg',0)rows,cols = img.shapeM = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)dst = cv2.warpAffine(img,M,(cols,rows))
1
2
3
4
5
1
2
3
4
5
图像的仿射
图像的仿射也是靠函数cv2.warpAffine完成,此函数可以将图像以指定的坐标进行旋转,
仿射操作也需要依靠一个2*3的旋转矩阵,可以通过函数cv2.getAffineTransform来获得旋转矩阵import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('drawing.png')rows,cols,ch = img.shapepts1 = np.float32([[50,50],[200,50],[50,200]])pts2 = np.float32([[10,100],[200,50],[100,250]])M = cv2.getAffineTransform(pts1,pts2)dst = cv2.warpAffine(img,M,(cols,rows))plt.subplot(121),plt.imshow(img),plt.title('Input')plt.subplot(122),plt.imshow(dst),plt.title('Output')plt.show()12345678910111213141516171234567891011121314151617
函数的详细说明记录在:python进阶—OpenCV之常用图像操作函数说明
图像的投射
图像的仿射也是靠函数cv2.warpPerspective完成,此函数可以将图像以指定的坐标进行旋转,
投射操作也需要依靠一个3*3的旋转矩阵,可以通过函数cv2.getPerspectiveTransform来获得旋转矩阵
img = cv2.imread('sudokusmall.png')rows,cols,ch = img.shapepts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])M = cv2.getPerspectiveTransform(pts1,pts2)dst = cv2.warpPerspective(img,M,(300,300))plt.subplot(121),plt.imshow(img),plt.title('Input')plt.subplot(122),plt.imshow(dst),plt.title('Output')plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
函数的详细说明记录在:python进阶—OpenCV之常用图像操作函数说明
图像阈值(二值化)
图像的简单阈值二值化
cv.threshold实现图像的二值化操作,典型二值化操作如下
cv.THRESH_BINARY
cv.THRESH_BINARY_INV
cv.THRESH_TRUNC
cv.THRESH_TOZERO
cv.THRESH_TOZERO_INV
示例代码如下:import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('gradient.png',0)ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]for i in xrange(6): plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([])plt.show()1234567891011121314151612345678910111213141516
函数的详细说明记录在:python进阶—OpenCV之常用图像操作函数说明
图像的自适应阈值二值化
cv.adaptiveThreshold函数实现自适应阈值二值化
自适应阈值计算方式有如下两种
cv.ADAPTIVE_THRESH_MEAN_C : 邻近阈值计算
cv.ADAPTIVE_THRESH_GAUSSIAN_C : 高斯邻近阈值计算
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('sudoku.png',0)img = cv.medianBlur(img,5)ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\ cv.THRESH_BINARY,11,2)th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\ cv.THRESH_BINARY,11,2)titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']images = [img, th1, th2, th3]for i in xrange(4): plt.subplot(2,2,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
函数的详细说明记录在:python进阶—OpenCV之常用图像操作函数说明
Otsu’s二值化
当在函数cv.threshold函数的第4箱参数flag中使用cv.THRESH_OTSU标识时,表示使用Otsu’s二值化方式,即对那些在灰度图像的直方图中具有明显2个波峰的图像比较合适。import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('noisy2.png',0)# global thresholdingret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)# Otsu's thresholdingret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# Otsu's thresholding after Gaussian filteringblur = cv.GaussianBlur(img,(5,5),0)ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# plot all the images and their histogramsimages = [img, 0, th1, img, 0, th2, blur, 0, th3]titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)', 'Original Noisy Image','Histogram','Otsu's Thresholding', 'Gaussian filtered Image','Histogram','Otsu's Thresholding']for i in xrange(3): plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray') plt.title(titles[i*3]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256) plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray') plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])plt.show()12345678910111213141516171819202122232425261234567891011121314151617181920212223242526
图像模糊操作
模糊操作使用卷积计算实现的
均值模糊
均值模糊就是计算卷积核对应所有像素的平均值,然后用平均值替换卷积核中心对应的像素值
典型均值卷积核如下图:
函数原型:dst = cv.blur( src, ksize[, dst[, anchor[, borderType]]] )
src:输入图像,通道数任意,每个通道会独立处理,但是图像的深度depth只能是 CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
dst:输出图像,大小与输入图像一致
ksize:卷积核大小
anchor:卷积核中心点默认值是 Point(-1,-1) 表示卷积核的正中心与进行处理的像素重合的点
borderType:边沿模式
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')blur = cv.blur(img,(5,5))plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(blur),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
以上代码中blur函数的ksize参数对应的卷积核如下图:
中值模糊
中值模糊就是取卷积核对应所有像素的中值,然后用此中值替换卷积核中心对应的像素值
中值模糊只能定义卷积核的大小,内容不能自定义,卷积核的方式与均值模糊的卷积核相同
中值模糊适合去除椒盐类图像噪点
函数原型:dst = cv.medianBlur( src, ksize[, dst] )
src:输入图像,图像为1、3、4通道的图像,当模板尺寸为3或5时,图像深度只能为CV_8U、CV_16U、CV_32F中的一个,如而对于较大尺寸的图片,图像深度只能是CV_8U
dst:出图像,尺寸和类型与输入图像一致
ksize:卷积核大小,也叫滤波模板的尺寸大小,必须是大于1的奇数,如3、5、7……import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')median = cv.medianBlur(img,5)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(median),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()1234567891012345678910
自定义模糊
所谓自定义模糊就是,自定义卷积核,即可实现自定义模糊
函数原型:dst = cv.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]] )
src:输入图像
dst:输出图像,和输入图像具有相同的尺寸和通道数量
ddepth:目标图像深度,如果没写将生成与原图像深度相同的图像。当ddepth输入值为-1时,目标图像和原图像深度保持一致。
kernel:卷积核(或者是相关核),一个单通道浮点型矩阵。如果想在图像不同的通道使用不同的kernel,可以先使用split()函数将图像通道事先分开。
anchor:卷积核的基准点(anchor),其默认值为(-1,-1)表示位于kernel中心位置。基准点即选取的kernel中心位置与进行处理像素重合的点。
delta:在储存目标图像前可选的添加到像素的值,默认值为0
borderType:图像边界逼近模式,默认值是BORDER_DEFAULT,即对全部边界进行计算
import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('opencv_logo.png')kernel = np.ones((5,5),np.float32)/25dst = cv.filter2D(img,-1,kernel)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(dst),plt.title('Averaging')plt.xticks([]), plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
kernel = np.ones((5,5),np.float32)/25定义的卷积核与上例均值模糊卷积核相同,所以输出图像的效果类似
自定义模糊可以实现图像的锐化
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
高斯模糊
高斯模糊对图像的噪声去除更为有效
可以通过函数cv.getGaussianKernel获取高斯卷积核
函数原型:dst = cv.GaussianBlur( src, ksize, sigmaX[, dst[, sigmaY[, borderType]]] )
src:输入图像,可以是任意通道数的图片,每个通道独立处理;但需要注意,图片深度应该为CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一
dst:目标图像,与原图大小类型一致
ksize:高斯内核的大小,其中ksize.width和ksize.height可以不同,但他们都必须为正数和奇数;参数值为0时,将由sigmaX与sigmaY参数计算得到
sigmaX:表示高斯核函数在X方向的的标准偏差
sigmaY:表示高斯核函数在Y方向的的标准偏差;若sigmaY为零,就将它设为sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来
borderType:图像边界逼近模式,默认值是BORDER_DEFAULT,即对全部边界进行计算import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')blur = cv.GaussianBlur(img,(5,5),0)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(median),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()1234567891012345678910
双边沿模糊
双边沿模糊主要用于保持图像的边沿梯度更加明显
函数原型:dst = cv.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]] )
src:输入图像,图像必须是8位或浮点型单通道、三通道的图像
dst:输出图像,和原图像有相同的尺寸和类型。
d:表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从第五个参数sigmaSpace计算该值。该值越大计算速度越慢。
sigmaColor:颜色空间过滤器的sigma值,这个参数的值越大,表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
sigmaSpace:坐标空间中滤波器的sigma值,如果该值较大,则意味着颜色相近的较远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace五官,否则d正比于sigmaSpace
borderType:图像边界逼近模式,默认值是BORDER_DEFAULT,即对全部边界进行计算
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')blur = cv.bilateralFilter(img,9,75,75)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(median),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
写到这,发现图像处理的内容太多了,一篇容不下了,只好再写另一篇了。