cv(三)
1.roi和泛洪填充

1 '''方差大小可以清晰的反应出图像的内容 2 泛洪填充:从一个点开始迭代,直到边界上差距比较大的点为止,都变成一个颜色 3 roi 即兴趣区域,对图像提取想要的部分 4 ''' 5 import cv2 as cv 6 import numpy as np 7 from matplotlib import pyplot as plt 8 9 10 def roi_test(src): 11 face = src[100:510, 200:600] 12 gray = cv.cvtColor(face, cv.COLOR_BGR2GRAY) # face彩色图片变成灰度图片 13 cv.imshow("gray", gray) 14 back_face = cv.cvtColor(gray, cv.COLOR_GRAY2BGR) 15 cv.imshow("back_face", back_face) 16 src[100:510, 200:600] = back_face 17 cv.imshow("face", src) 18 19 def fill_color_demo(image): 20 # 泛洪填充 21 copyImg = image.copy() # 克隆 22 h, w = image.shape[:2] 23 mask = np.zeros([h+2, w+2], np.uint8) # opencv的mask类型必须是np.uint8 24 25 # 参数:原图,mask图,起始点,填充新值的颜色,起始点值减去该值作为最低值,起始点值加上该值作为最高值,彩色图模式 26 # cv.FLOODFILL_FIXED_RANGE模式填充于彩色图像 27 cv.floodFill(copyImg, mask, (30, 30), (0, 255, 255), (100,100,100), (50, 50, 50), cv.FLOODFILL_FIXED_RANGE) 28 cv.imshow("fill_color_demo", copyImg) 29 30 def fill_binary(): 31 # 二值图像填充 32 image = np.zeros([400, 400, 3], np.uint8) 33 image[100:300, 100:300, :] = 255 34 cv.imshow("fill_binary", image) 35 36 # 因为cv.FLOODFILL_MASK_ONLY,所以mask的位置一定要设置为一,填充区域设置为0 37 mask = np.ones([402, 402, 1], np.uint8) 38 mask[101:301, 101:301] = 0 39 40 cv.floodFill(image, mask, (200, 200), (100, 2, 255), cv.FLOODFILL_MASK_ONLY) 41 cv.imshow("filled binary", image) 42 43 def make_border(image): 44 """ 45 :param image:输入图像 46 top, bottom, left, right 对应边界的像素数目。 47 borderType 要添加那种类型的边界,类型如下: 48 – cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要 下一个参数(value)。 49 – cv2.BORDER_REFLECT边界元素的镜像。比如: fedcba|abcdefgh|hgfedcb 50 – cv2.BORDER_REFLECT_101orcv2.BORDER_DEFAULT 跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba 51 – cv2.BORDER_REPLICATE重复最后一个元素。例如: aaaaaa| abcdefgh|hhhhhhh 52 – cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh| abcdefgh|abcdefg 53 value 边界颜色,如果边界的类型是 cv2.BORDER_CONSTANT 54 """ 55 BLUE = [255, 0, 0] 56 57 replicate = cv.copyMakeBorder(image, 10, 10, 10, 10, cv.BORDER_REPLICATE) 58 reflect = cv.copyMakeBorder(image, 10, 10, 10, 10, cv.BORDER_REFLECT) 59 reflect101 = cv.copyMakeBorder(image, 10, 10, 10, 10, cv.BORDER_REFLECT_101) 60 wrap = cv.copyMakeBorder(image, 10, 10, 10, 10, cv.BORDER_WRAP) 61 constant = cv.copyMakeBorder(image, 10, 10, 10, 10, cv.BORDER_CONSTANT, value=BLUE) 62 63 plt.subplot(231), plt.imshow(image, 'gray'), plt.title('ORIGINAL') 64 plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE') 65 plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT') 66 plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101') 67 plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP') 68 plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT') 69 plt.show() 70 71 if __name__ == '__main__': 72 src = cv.imread("../images/CrystalLiu1.jpg") # 读入图片放进src中 73 cv.namedWindow("Crystal Liu") # 创建窗口 74 cv.imshow("Crystal Liu", src) # 将src图片放入该创建的窗口中 75 # roi_test(src) 76 # fill_color_demo(src) 77 fill_binary() 78 img = cv.imread("../images/opencv_logo.png") 79 make_border(img) 80 cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口 81 cv.destroyAllWindows() # 关闭所有窗口
2.几何变换

1 import cv2 as cv 2 import numpy as np 3 import matplotlib.pyplot as plt 4 5 # 学习对图像进行各种几个变换,例如移动,旋转,仿射变换等。 6 # 函数为:cv2.getPerspectiveTransform 7 # 代码参考:https://blog.csdn.net/songchunxiao1991/article/details/80226510 8 # 变换 OpenCV提供了两个变换函数,cv2.warpAffine和cv2.warpPerspective, 9 # 使用这两个函数你可以实现所有类型的变换。 10 # cv2.warpAffine 接收的参数是 2×3 的变换矩阵,而 cv2.warpPerspective 接收的参数是 3×3 的变换矩阵。 11 12 13 # 扩展缩放只是改变图像的尺寸大小。OpenCV 提供的函数 cv2.resize() 可以实现这个功能。 14 # 图像的尺寸可以自己手动设置,你也可以指定缩放因子。 15 # 我们可以选择使用不同的插值方法。在缩放时我们推荐使用cv2.INTER_AREA, 16 # 在扩展时我们推荐使用 v2.INTER_CUBIC(慢) 和 v2.INTER_LINEAR。 17 # 默认情况下所有改变图像尺寸大小的操作使用的插值方法都是cv2.INTER_LINEAR。 18 def resize_demo(image): 19 20 print("Origin size:", image.shape) 21 # 第一种方法:通过fx,fy缩放因子 22 res = cv.resize(image, None, fx=2, fy=2, interpolation=cv.INTER_CUBIC) 23 print("After resize 1 size:", res.shape) 24 # 第二种方法:直接设置输出图像的尺寸,所以不用设置缩放因子 25 height,width = image.shape[:1] 26 res=cv.resize(image,(2*width,2*height),interpolation=cv.INTER_CUBIC) 27 print("After resize 2 size:", res.shape) 28 29 while(1): 30 cv.imshow('res',res) 31 cv.imshow('img',image) 32 if cv.waitKey(1) & 0xFF == 27: 33 break 34 35 36 # 图像偏移:M = np.array([[1, 0, tx], [0, 1, ty]]) 37 def move_demo(image): 38 rows, cols = image.shape[:2] 39 M = np.float32([[1, 0, 100], [0, 1, 50]]) 40 dst = cv.warpAffine(image, M, (cols, rows)) 41 cv.imshow('image', dst) 42 43 44 def rotation_demo(img): 45 rows, cols = img.shape[:2] 46 # 将图像相对于中心旋转90度,而不进行任何缩放。旋转中心,角度,缩放比率 47 M = cv.getRotationMatrix2D((cols / 2, rows / 2), 90, 1) 48 dst = cv.warpAffine(img, M, (cols, rows)) 49 cv.imshow('original', img) 50 cv.imshow('result', dst) 51 cv.waitKey(0) 52 cv.destroyAllWindows() 53 54 55 # 仿射变换 56 # 在仿射变换中,原始图像中的所有平行线在输出图像中仍然是平行的。 57 # 为了找到变换矩阵,我们需要输入图像中的三个点以及它们在输出图像中的相应位置。 58 # 然后cv2.getAffineTransform将创建一个2x3矩阵,并将其传递给cv2.warpAffine。 59 def affine_demo(img): 60 61 rows, cols, ch = img.shape 62 63 pts1 = np.float32([[50, 50], [200, 50], [50, 200]]) 64 pts2 = np.float32([[10, 100], [200, 50], [100, 250]]) 65 66 M = cv.getAffineTransform(pts1, pts2) 67 68 dst = cv.warpAffine(img, M, (cols, rows)) 69 70 plt.subplot(121), plt.imshow(img), plt.title('Input') 71 plt.subplot(122), plt.imshow(dst), plt.title('Output') 72 plt.show() 73 74 75 # 透视转化 对于透视变换,您需要一个3x3变换矩阵。 即使在改造之后,直线仍将保持直线。 76 # 要找到这个变换矩阵,您需要输入图像上的4个点和输出图像上的对应点。 在这4点中,其中3个不应该在线。 77 # 然后可以通过函数cv2.getPerspectiveTransform找到变换矩阵。 78 # 然后将cv2.warpPerspective应用于这个3x3转换矩阵。 79 def perspective_demo(img): 80 81 rows, cols, ch = img.shape 82 83 pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]]) 84 pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]]) 85 86 M = cv.getPerspectiveTransform(pts1, pts2) 87 88 dst = cv.warpPerspective(img, M, (300, 300)) 89 90 plt.subplot(121), plt.imshow(img), plt.title('Input') 91 plt.subplot(122), plt.imshow(dst), plt.title('Output') 92 plt.show() 93 94 95 def main(): 96 src = cv.imread("../images/Crystal.jpg") 97 cv.imshow("demo",src) 98 # resize_demo(src) 99 # move_demo(src) 100 # rotation_demo(src) 101 # affine_demo(src) 102 perspective_demo(src) 103 cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口 104 cv.destroyAllWindows() # 关闭所有窗口 105 106 107 if __name__ == '__main__': 108 main()
3.模糊操作

1 ''' 2 模糊操作基本原理: 3 1.基于离散卷积 4 2.定义好每个卷积核 5 3.不同卷积核得到不同的卷积效果 6 4.模糊是卷积的一种变现 7 一些图像知识: 8 1. 噪声:主要有三种: 9 椒盐噪声(Salt & Pepper):含有随机出现的黑白亮度值。 10 脉冲噪声:只含有随机的正脉冲和负脉冲噪声。 11 高斯噪声:含有亮度服从高斯或正态分布的噪声。高斯噪声是很多传感器噪声的模型,如摄像机的电子干扰噪声。 12 2. 滤波器:主要两类:线性和非线性 13 线性滤波器:使用连续窗函数内像素加权和来实现滤波,同一模式的权重因子可以作用在每一个窗口内,即线性滤波器是空间不变的。 14 如果图像的不同部分使用不同的滤波权重因子,线性滤波器是空间可变的。因此可以使用卷积模板来实现滤波。 15 线性滤波器对去除高斯噪声有很好的效果。常用的线性滤波器有均值滤波器和高斯平滑滤波器。 16 (1) 均值滤波器:最简单均值滤波器是局部均值运算,即每一个像素只用其局部邻域内所有值的平均值来置换. 17 (2) 高斯平滑滤波器是一类根据高斯函数的形状来选择权值的线性滤波器。 高斯平滑滤波器对去除服从正态分布的噪声是很有效的。 18 非线性滤波器: 19 (1) 中值滤波器:均值滤波和高斯滤波运算主要问题是有可能模糊图像中尖锐不连续的部分。 20 中值滤波器的基本思想使用像素点邻域灰度值的中值来代替该像素点的灰度值,它可以去除脉冲噪声、椒盐噪声同时保留图像边缘细节。 21 中值滤波不依赖于邻域内与典型值差别很大的值,处理过程不进行加权运算。 22 中值滤波在一定条件下可以克服线性滤波器所造成的图像细节模糊,而对滤除脉冲干扰很有效。 23 (2) 边缘保持滤波器:由于均值滤波:平滑图像外还可能导致图像边缘模糊和中值滤波:去除脉冲噪声的同时可能将图像中的线条细节滤除。 24 边缘保持滤波器是在综合考虑了均值滤波器和中值滤波器的优缺点后发展起来的,它的特点是: 25 滤波器在除噪声脉冲的同时,又不至于使图像边缘十分模糊。 26 过程:分别计算[i,j]的左上角子邻域、左下角子邻域、右上角子邻域、右下角子邻域的灰度分布均匀度V; 27 然后取最小均匀度对应区域的均值作为该像素点的新灰度值。分布越均匀,均匀度V值越小。v=<(f(x, y) - f_(x, y))^2 28 ''' 29 30 31 import cv2 as cv 32 import numpy as np 33 34 35 def blur_demo(image): 36 # dst = cv.blur(image, (5, 5)) # 卷积核为1x15,均值模糊,均值模糊对随机噪声去噪比较好 37 # dst = cv.medianBlur(image, 5) # 中值模糊,对椒盐噪声(黑白的点)去噪较好 38 39 # 自定义滤波器,卷积核总和等于0是针对处理边缘梯度像素,总和等于1是对数据做增强化等工作 40 # kernel = np.ones([5, 5], np.float32) / 25 # 内核大小, 41 kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) # 锐化算子 42 43 # filter2D(src:原图像, ddepth(图像深度,-1表示默认和src一样深度), kernel:卷积核, dst=None:输出结果, anchor=None(锚点,卷积核中心), delta=None, borderType=None:对边缘的填充模式) 44 dst = cv.filter2D(image, -1, kernel=kernel) # 二维滤波器 45 cv.imshow("blur_demo", dst) 46 47 48 def clamp(pv): 49 # 确保像素再0-255之间 50 if pv > 255: 51 return 255 52 elif pv < 0: 53 return 0 54 else: 55 return pv 56 57 58 def gaussian_noise(image): # 高斯模糊用来去除高斯噪声 59 h, w, c = image.shape 60 for row in range(h): 61 for col in range(w): 62 s = np.random.normal(0, 20, 3) # normal(loc=0.0, scale=1.0, size=None),均值,标准差,大小 63 64 b = image[row, col, 0] # B 65 g = image[row, col, 1] # G 66 r = image[row, col, 2] # R 67 68 # 自定义添加高斯噪声 69 image[row, col, 0] = clamp(b + s[0]) 70 image[row, col, 1] = clamp(g + s[1]) 71 image[row, col, 2] = clamp(r + s[2]) 72 73 cv.imshow("gaussian_noise", image) 74 75 76 if __name__ == '__main__': 77 78 src = cv.imread("../images/CrystalLiu1.jpg") # 读入图片放进src中 79 cv.namedWindow("Crystal Liu") # 创建窗口 80 cv.imshow("Crystal Liu", src) # 将src图片放入该创建的窗口中 81 # blur_demo(src) 82 t1 = cv.getTickCount() 83 gaussian_noise(src) 84 t2 = cv.getTickCount() 85 time = (t2 - t1)/cv.getTickFrequency() 86 print("time consume: %s"%(time * 1000)) 87 88 # GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None) 89 # ksize表示卷积核大小,sigmaX,Y表示x,y方向上的标准差,这两者只需一个即可,并且ksize为大于0的奇数 90 dst = cv.GaussianBlur(src, (5, 5), 0) # 高斯模糊比均值模糊好点,sigmaX与ksize要设置其中一个为0,因为ksize设置了sigmax就不会起作用了 91 cv.imshow("Gaussian blur", dst) 92 93 cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口 94 cv.destroyAllWindows() # 关闭所有窗口
4.边缘保留滤波

1 import cv2 as cv 2 import numpy as np 3 '''E边缘P保留F滤波(EPF) 4 1.高斯双边:模糊来美颜 5 2.均值迁移 6 ''' 7 def bi_demo(image): # bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None) 8 """ 9 同时考虑空间与信息和灰度相似性,达到保边去噪的目的 10 双边滤波的核函数是空间域核与像素范围域核的综合结果: 11 在图像的平坦区域,像素值变化很小,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊; 12 在图像的边缘区域,像素值变化很大,像素范围域权重变大,从而保持了边缘的信息。 13 """ 14 dst = cv.bilateralFilter(image, 0, 100, 15) # 高斯双边 15 cv.imshow("bi_demo", dst) 16 17 18 # pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None) 19 # @param src The source 8-bit, 3-channel image. 20 # @param dst The destination image of the same format and the same size as the source. 21 # @param sp The spatial window radius. 22 # @param sr The color window radius. 23 # @param maxLevel Maximum level of the pyramid for the segmentation. 24 # @param termcrit Termination criteria: when to stop meanshift iterations. 25 def shift_demo(image): # 均值迁移 26 dst = cv.pyrMeanShiftFiltering(image, 10, 50) 27 cv.imshow("shift_demo", dst) 28 29 if __name__ == '__main__': 30 src = cv.imread("../images/CrystalLiu1.jpg") # 读入图片放进src中 31 cv.namedWindow("Crystal Liu") # 创建窗口 32 cv.imshow("Crystal Liu", src) # 将src图片放入该创建的窗口中 33 bi_demo(src) 34 shift_demo(src) 35 36 cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口 37 cv.destroyAllWindows() # 关闭所有窗口
5.直方图

1 '''直方图 2 直方图的几个基本概念: 3 1.range:0-255 4 2.bins:bar的数量 bin的大小=像素个数/bind的数目 5 ''' 6 import cv2 as cv 7 import matplotlib.pyplot as plt 8 import numpy as np 9 10 11 def plot_demo(image): 12 plt.hist(image.ravel(), 256, [0, 256]) # image.ravel()将图像展开,256为bins数量,[0, 256]为范围 13 plt.show() 14 15 16 def image_hist(image): # 图像直方图 17 color = ('blue', 'green', 'red') 18 for i, color in enumerate(color): 19 20 # 计算出直方图,calcHist(images, channels, mask, histSize(有多少个bin), ranges[, hist[, accumulate]]) -> hist 21 # hist 是一个 256x1 的数组,每一个值代表了与该灰度值对应的像素点数目。 22 23 hist = cv.calcHist(image, [i], None, [256], [0, 256]) 24 print(hist.shape) 25 plt.plot(hist, color=color) 26 plt.xlim([0, 256]) 27 plt.show() 28 29 30 def equalHist_demo(image): 31 gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) 32 33 # 全局直方图均衡化,用于增强图像对比度,即黑的更黑,白的更白 34 dst = cv.equalizeHist(gray) 35 cv.imshow("equalHist_demo", dst) 36 37 # 局部直方图均衡化 38 clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) 39 clahe_dst = clahe.apply(gray) 40 cv.imshow("clahe", clahe_dst) 41 42 43 # 创建直方图 44 def create_rgb_demo(image): 45 h, w, c = image.shape 46 rgbHist = np.zeros([16*16*16, 1], np.float32) 47 bsize = 256 / 16 48 for row in range(h): 49 for col in range(w): 50 b = image[row, col, 0] 51 g = image[row, col, 1] 52 r = image[row, col, 2] 53 index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize) 54 rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1 55 56 return rgbHist 57 58 59 # 利用直方图比较相似性,用巴氏和相关性比较好 60 def hist_compare(image1, image2): 61 hist1 = create_rgb_demo(image1) 62 hist2 = create_rgb_demo(image2) 63 match1 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_BHATTACHARYYA) 64 match2 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_CORREL) 65 match3 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_CHISQR) 66 print("巴式距离:%s, 相关性:%s, 卡方:%s"%(match1, match2, match3)) 67 68 if __name__ == '__main__': 69 src = cv.imread("../images/rice.png") # 读入图片放进src中 70 cv.namedWindow("demo") # 创建窗口 71 cv.imshow("demo", src) # 将src图片放入该创建的窗口中 72 # plot_demo(src) 73 image_hist(src) 74 75 # equalHist_demo(src) 76 image1 = cv.imread("../images/rice.png") 77 image2 = cv.imread("../images/noise_rice.png") 78 79 # create_rgb_demo(image1) 80 # cv.imshow("image1", image1) 81 # cv.imshow("image2", image2) 82 # hist_compare(image1=image1, image2=image2) 83 84 cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口 85 cv.destroyAllWindows() # 关闭所有窗口