opencv-python学习笔记(三)---图像处理(一)

opencv中的图像处理(一)

改变颜色空间

改变颜色模型

. opencv中有上百中颜色空间的转换方法,其中最广泛的是BGR<->Gray和BGR<->HSV。
. 用于颜色转换的函数是cv2.cvtColor(input_image, flag),其中flag表示使用那种类型的转换,比如cv2.COLOR_BGR2GRAY或cv2.COLOR_BGR2HSV。可以通过简单的循环来查看所有的类型:

>>> import cv2
>>> flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
>>> print(flags)

对象追踪

. HSV颜色模型比BGR模型要更容易表现颜色,HSV模型中的H(色调)的值是0-180,S(饱和度)的取值范围是0-255,V(明亮度)的取值范围是0-255.因此在视频中提取颜色对象的步骤可以分为:
1.获取视频的每一帧;
2.将图片的色彩控件由BGR转换为HSV;
3.设置要提取的颜色对象的阈值;
4.提取颜色对象进行操作。

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while(1):
    #抓取每一帧
    _,frame = cap.read()
    #转换为HSV模型
    hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    #确定要抓取的颜色范围
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])
    #获取抓取的遮罩
    mask = cv2.inRange(hsv,lower_blue,upper_blue)
    #做图像的与处理
    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:
        break

cv2.destroyAllWindows()

图像阈值处理

简单阈值

. 简单的阈值处理就是将像素点的值与阈值作比较,大于就赋给这个像素点一个值,否则就赋给它另一个值。使用的函数是cv2.threshold,第一个参数是原始图像(应该是一个灰度化的图像),第二个参数是指定的阈值,第三个参数是将要位像素点重新指定的值,第四个参数是采用的处理方式,第四个参数的常用值有以下几种:
1.cv2.THRESH_BINARY:像素点超过阈值就取第三个参数的值,否则为0;
2.cv2.THRESH_BINARY_INV:第一种方式的反处理;
3.cv2.THRESH_TRUNC:像素点超过阈值就取第三个参数的值,否则保持不变;
4.cv2.THRESH_TOZERO:像素点超过阈值就保持不变,否则为0;
5.cv2.THRESH_TOZERO_INV:第四种方式的反处理。

import cv2

#以灰度化读取
img = cv2.imread('../kkxj.jpg',0)

ret,t1 = cv2.threshold(img,125,255,cv2.THRESH_BINARY)
ret,t2 = cv2.threshold(img,125,255,cv2.THRESH_BINARY_INV)
ret,t3 = cv2.threshold(img,125,255,cv2.THRESH_TRUNC)
ret,t4 = cv2.threshold(img,125,255,cv2.THRESH_TOZERO)
ret,t5 = cv2.threshold(img,125,255,cv2.THRESH_TOZERO_INV)
cv2.imshow('img',t1)
cv2.waitKey(0)
cv2.destroyAllWindows()

自适应阈值

. 通常图像的呈现会受到不同区域中光照或别的原因影响,因此使用简单的阈值处理得到的图像可能不太好,这种情况下使用自适应阈值,其可以在不同的区域使用不同的阈值来处理图像。
. 自适应阈值处理的函数是cv2.adaptiveThreshold,除了之前的几个参数,还包含了三个特殊的参数:
1.Adaptive Method:自适应处理的方式:
. cv2.ADAPTIVE_THRESH_MEAN_C:表示阈值为附近区域的平均值;
. cv2.ADAPTIVE_THRESH_GAUSSIAN_C :表示阈值为附近区域的加权总和,其中权重是高斯窗口(不知道是啥)。
2.Block Size:附近区域的大小;
3.C:作为一个常数,可以在计算出来的阈值后做减法。

import cv2

#以灰度化读取
img = cv2.imread('../kkxj.jpg',0)

ret,t1 = cv2.threshold(img,125,255,cv2.THRESH_BINARY)
t2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
                               cv2.THRESH_BINARY,11,2)
t3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)
cv2.imshow('img',t1)
cv2.waitKey(0)
cv2.destroyAllWindows()

Otsu’s阈值处理

. Otsu算法是日本学者OTSU提出的一种对图像进行二值化的高效算法。当图像的直方图是双峰一样的形状的时候,可以近似的将双峰之间的中间值作为阈值。
. 使用OTSU阈值处理还是使用 cv2.threshold函数,只需要在二值化方式后面加上cv2.THRESH_OTSU,因此,第二个参数只需要传入0就可以了,函数会自动使用算法算出阈值:

ret2,t4 = cv2.threshold(img,0,255,\
			cv2.THRESH_BINARY+cv2.THRESH_OTSU)

图像的几何变换

. Opencv提供了两个几何变换的函数,cv2.warpAffinecv2.warpPerspective,前者采用2x3的矩阵,后者采用3x3的矩阵作为输入。

缩放

. Opencv中队图像进行调整大小的函数是resize(),可以手动制定图像的尺寸,并且可以指定处理图像时的插值,通常使用cv2.INTER_AREA来进行图像的缩小,使用cv2.INTER_CUBICcv2.INTER_LINEAR来进行图像的缩放:

img = cv2.imread('../kkxj.jpg')

res = cv2.resize(img,None,fx=0.5, fy=0.5, interpolation = cv2.INTER_AREA)
height, width = img.shape[:2]
res2 = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)

平移

. 做平移的时候的需要知道图像在x方向和y方向上的偏移量(tx,ty),然后就能创建一个转换矩阵:
.            M=[10tx01ty]M =\begin{bmatrix} 1&0&tx\\ 0&1&ty\end{bmatrix}
. 然后使用 cv2.warpAffine() 处理:

img = cv2.imread('../kkxj.jpg',0)
row,col = img.shape
M = np.float32([[1,0,100],[0,1,50]])
#第三个参数是输出图像的尺寸,宽对应列,高对应行
dst = cv2.warpAffine(img,M,(col,row))		

旋转

. 使用cv2.getRotationMatrix2D函数来完成平面图像的旋转,函数的第一个参数是旋转图像的旋转中心,第二个参数是旋转的角度,第三个参数是缩放因子,即可以将旋转后的图像放大或缩小:

M = cv2.getRotationMatrix2D((col/2,row/2),60,1)
dst = cv2.warpAffine(img,M,(col,row))

仿射变换

. 仿射变换就像是换个角度看图像,原图像的平行线在输出图像中依然是平行的。使用cv2.getAffineTransform函数来生成一个仿射变换的2x3矩阵,需要传入的参数是原图像的三个点和在它们在输出图像中的位置。

pts = np.float32([[50,50],[200,50],[50,200]])
ptd = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts,ptd)

dst = cv2.warpAffine(img,M,(col,row))

透视变换

. 感觉就是做一个四边形裁剪,使用cv2.getPerspectiveTransform函数来生成矩阵,需要传入原图像的四个点的位置的列表,和它们在输出图像中的位置列表。使用cv2.warpPerspective来应用这种变换:

pts1 = np.float32([[50,50],[200,50],[50,200],[200,200]])
pts2 = np.float32([[0,0],[200,0],[0,200],[200,200]])
M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(200,200))

平滑图像

2D卷积(图像过滤)

. 图像中使用卷积是为了对图像降噪,噪点是指图像中一种亮度或颜色信息的随机变化(被拍摄物体本身并没有),是图像本不应该存在的错误信息。卷积在图像处理中的应用主要主要是将像素点及其周围的像素点组成的矩阵与给定的平均矩阵做卷积公式处理,使得图像变得平滑,即让像素点的值根据周围像素点的值和某个给定的平均矩阵来进行改变。
. opencv中提供了cv2.filter2D函数来完成卷积。下面的例子定义一个5x5的矩阵,把它除以25作为要进行卷积的一个内核,与图像中的每个像素点及其周围5x5的像素点组成的矩阵做卷积运算:

img = cv2.imread('../kkxj.jpg')
kernel = np.ones((5,5),np.float32)/25
#第二个参数是指定输出图像的深度(指存储每个像素所用的位数,
#也用于量度图像的色彩分辨率),如果是-1表示和原图像深度相同
dst = cv2.filter2D(img,-1,kernel)

图像模糊

. 通过将图像与低通滤波器内核进行卷积来实现图像模糊,主要是为了消除噪点。实际上,他会从图像中删除高频内容(噪点、边缘等)。opencv主要提供四种模糊技术:

1.平均化

. 通过获取内核区域的平均值来替换中心元素的值,使用**cv2.blur()cv2.boxFilter()**来完成。一个3x3的过滤器可能如下所示:
.       M=19[111111111]M =\frac{1}{9}\begin{bmatrix} 1&1&1\\ 1&1&1\\ 1&1&1\end{bmatrix}

blur = cv2.blur(img,(3,3))

2.高斯滤波

. 高斯滤波对去除高斯噪声(概率密度函数服从高斯分布,即正态分布的一类噪声)很有效,其使用高斯内核来进行卷积运算,opencv中使用的函数是cv2.GaussianBlur,需要传递的参数是内核的宽度和高度,这两个值都应该为正数和奇数,还要指定X方向和Y方向上的标准偏差(sigmaX和sigmaY),如果仅指定sigmaX,则默认sigmaY和它相等,如果都为0,它会根据内核大小进行计算。

blur = cv2.GaussianBlur(img,(5,5),0)

3.中值过滤

. 中值滤波对消除椒盐噪声很有效,它通过计算内核(内核大小应为正整数)窗口下所有元素的中值(统计总体当中的各个变量值按大小顺序排列起来,处于变量数列中间位置的变量值),再和中心元素的值进行替换。opencv中使用**cv2.medianBlur()**来完成,第二个参数是线性度,应当置为大于1的奇数。

median = cv2.medianBlur(img,5)

4.双边滤波

. 双边滤波能完成高斯滤波类似的模糊操作,于此同时能保留边缘的值,其在完成运滤波时多考虑两个权重域:空间域(spatial domain S)和像素范围域(range domain R),在图像的平坦区域,像素值变化很小,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;在图像的边缘区域,像素值变化很大,像素范围域权重变大,从而保持了边缘的信息。
. opencv中使用cv2.bilateralFilter完成滤波,第二个参数表示滤波期间使用的每个像素邻域的直径,第三个参数表示色彩空间中的过滤值,第四个参数表示再座标空间中的过滤值,

blur = cv2.bilateralFilter(img,9,75,75)

形态学操作

. 形态学操作通常使用再二值化的图像处理上,两个基础的操作时腐蚀和膨胀,通过这两种可以扩展其它的一些操作。

腐蚀

. 腐蚀的原理时内核再图像上滑动的时候,仅当内核下的所有元素都为1的时候,才将原始图像元素的值视为1,否则将被腐蚀(视为0)。这对于分割两个连接的部分很有用:

img = cv2.imread('../j.png')
kenel = np.ones((5,5),np.uint8)
#iterations表示施加腐蚀的次数
dst = cv2.erode(img,kenel,iterations=1)

膨胀

. 膨胀与腐蚀的操作相反,当内核下有一个元素为1的时候,九江原始图像元素的值视为1,否则视为0。在做连接对象的损坏部分的操作的时候很有用:

dst2 = cv2.dilate(img,kenel,iterations=1)

开放

. 开放的操作时先腐蚀再膨胀,通过传递给 cv2.morphologyEx函数标志位来实现:

opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

关闭

. 关闭与开放相反,先膨胀再腐蚀:

closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

形态梯度

. 与之前的处理结果不同,形态梯度处理的结果像是取得图像的轮廓:

gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

不一样的内核

. 之前可以使用numpy模块手动创建矩形的内核,但有时可能需要圆形或其它形状的内核,通过使用**cv2.getStructuringElement()**来自动创建内核,只需要传递内核形状和内核尺寸:

>>> import cv2
>>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
>>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章