• openCV第二篇


    文章目录

    1. HSV

    2. 图像阈值

    3. 图像平滑

    4. 形态学-腐蚀操作

    5. 形态学-膨胀操作

    6. 开运算与闭运算

    7. 梯度运算

    8. 礼帽与黑帽

    9. 图像梯度-Sobel算子

    10. 图像梯度-Scharr算子和laplacian算子

    10. 知识点总结*

    1. HSV

    由我们上一章所学,导入图片将其转化为灰度图并定义显示图片函数cv_show()。 

    1. import cv2 #opencv读取的格式是BGR
    2. import numpy as np
    3. import matplotlib.pyplot as plt#Matplotlib是RGB
    4. %matplotlib inline
    5. def cv_show(name,img):
    6. cv2.imshow(name,img)
    7. cv2.waitKey(0)
    8. cv2.destroyAllWindows()
    9. img = cv2.imread('./data/gd01.jpg')
    10. img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    11. # img_gray.shape 为 (300,400)
    cv_show('win1',img_gray)

    HSV:

    • H - 色调(主波长)。
    • S - 饱和度(纯度/颜色的阴影)。
    • V值(强度)
    1. hsv = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # 转换成RGB
    2. cv_show('win',hsv)

    2. 图像阈值

    上章所学我们得知,矩阵中unit8值(0-255)越大表示越亮,我们可以设定一个阈值thresh,比它大的做什么什么操作,比它小的做什么什么操作。 

    • ret, dst = cv2.threshold(src, thresh, maxval, type)
      • src: 输入图,只能输入单通道图像,通常来说为灰度图
      • dst: 输出图

      • thresh: 阈值(0-255我们一般取127。)

      • maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值。

      • type:二值化操作的类型,包含以下5种类型:

        • cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0。

        • cv2.THRESH_BINARY_INV , THRESH_BINARY的反转。

        • cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变。

        • cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0。

        • cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转。

    1. ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
    2. ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
    3. ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
    4. ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
    5. ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
    6. # ps: ret为127 thresh1-5为图片矩阵
    7. titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
    8. images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
    9. for i in range(6):
    10. plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    11. plt.title(titles[i])
    12. plt.xticks([]), plt.yticks([])
    13. plt.show()

    可以看到,与原始图片对比,(阈值127)情况下BINARY在亮的地方更亮了(变为255),暗的地方更暗了(变为了0)。BINART_INV与其相反。后三种方法同理如上面所解释。

    3. 图像平滑

    对图像数据进行滤波操作。

    在这之前我们先来学习一下如何给图片加入噪声,变成以下这种。

     可以看到其实就是在这个矩阵随机位置的像素点变成了白色,255。

    1. img = cv2.imread('./data/gd07.jpg')
    2. #获取图片行、列、通道数
    3. rows,cols,channels = img.shape
    4. for i in range(0,5000):
    5.     #根据在0和行-1之间获取随机整数
    6.     x = np.random.randint(0,rows-1)
    7.     #根据在0和列-1之间获取随机整数
    8.     y = np.random.randint(0,cols-1)
    9.     #将通道颜色改为255, (255,255,255)
    10.     img[x,y][0] = 255
    11.     img[x,y][1] = 255
    12.     img[x,y][2] = 255
    13. cv_show('win',img)

    那么现在我们有了这种图像,该学习如何去掉噪音点了~

    • blur = cv2.blur(img, (3, 3))
      • 均值滤波
    • box = cv2.boxFilter(img,-1,(3,3), normalize=True)  
      • 方框滤波
    • box = cv2.boxFilter(img,-1,(3,3), normalize=False) 
      • 方框滤波
    • aussian = cv2.GaussianBlur(img, (5, 5), 1)  
      • 高斯滤波
    • median = cv2.medianBlur(img, 5)
      • 中值滤波

    均值滤波--简单的平均卷积操作(卷积核大小3*3内部值都是1,下方参数是3*3矩阵均值)

    1. blur = cv2.blur(img, (3, 3))
    2. cv_show('win',blur)

    方框滤波--基本和均值一样,可以选择归一化(-1表示颜色通道一致,3*3同上,normalize=True做归一化,此时与上方均值滤波是一样的。)

    1. box = cv2.boxFilter(img,-1,(3,3), normalize=True)
    2. cv_show('win',box)

    方框滤波--基本和均值一样,可以选择归一化,容易越界。(不再均值除以9,和大于255按255赋值。)

    1. box = cv2.boxFilter(img,-1,(3,3), normalize=False)  
    2. cv_show('win',box)

    高斯滤波--高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的。(此时卷积核不再全是1,而是离的近的相对较大,离得远的相对较小。)

    1. aussian = cv2.GaussianBlur(img, (5, 5), 1)
    2. cv_show('win',aussian)

    中值滤波--相当于用中值代替(5*5的矩阵25个数,中间值为处理结果。)

    1. median = cv2.medianBlur(img, 5) # 中值滤波
    2. cv_show('win',median)

    均值、高斯、中值滤波对比:

    1. res = np.hstack((blur,aussian,median))
    2. #print (res)
    3. cv_show('median vs average', res)

     

    4. 形态学-腐蚀操作

    所谓腐蚀操作,就是一点点侵蚀图片中的内容,如我刚刚挥笔写下的“帅”字,它长了很多“毛”,我们要把他侵蚀掉:

    1. img = cv2.imread('./data/s.jpg', cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((3,3),np.uint8)
    3. erosion = cv2.erode(img,kernel,iterations = 1)
    4. cv_show('win',erosion)
    • erosion = cv2.erode(img,kernel,iterations = 1) 
      • kernel 卷积核
      • iterations 迭代次数 

    这不比之前更帅了(被腐蚀得线条也变瘦了)

    关于卷积核选取和迭代次数:

    上面选用3*3,以帅字为例,当3*3区域出现不同值(如这里0和255),那么就把这个点腐蚀掉。

    卷积核如果选择太大,可能会直接被侵蚀没掉。  

    1. pie = cv2.imread('./data/pie.png')
    2. kernel = np.ones((30,30),np.uint8)
    3. erosion_1 = cv2.erode(pie,kernel,iterations = 1)
    4. erosion_2 = cv2.erode(pie,kernel,iterations = 3)
    5. erosion_3 = cv2.erode(pie,kernel,iterations = 5)
    6. res = np.hstack((erosion_1,erosion_2,erosion_3))
    7. cv_show('win',res)

    5. 形态学-膨胀操作

    我们上面不仅把“帅”边上长的“毛”去掉了,由于我们选择3*3卷积核,还顺便让它变瘦了,我们就以它变瘦之后的图片为例,再让它胖起来。

    1. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((3,3),np.uint8)
    3. shuai = cv2.erode(img,kernel,iterations = 1)
    4. kernel = np.ones((3,3),np.uint8)
    5. shuai_PLUS = cv2.dilate(shuai,kernel,iterations = 1)
    6. cv_show('win',shuai_PLUS )
    • shuai_PLUS = cv2.dilate(shuai,kernel,iterations = 1)

    同理

    1. pie = cv2.imread('./data/pie.png')
    2. kernel = np.ones((30,30),np.uint8)
    3. dilate_1 = cv2.dilate(pie,kernel,iterations = 1)
    4. dilate_2 = cv2.dilate(pie,kernel,iterations = 2)
    5. dilate_3 = cv2.dilate(pie,kernel,iterations = 3)
    6. res = np.hstack((dilate_1,dilate_2,dilate_3))
    7. cv_show('win',res)

    6. 开运算与闭运算

    开:先腐蚀,再膨胀

    1. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((5,5),np.uint8)
    3. opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    4. cv_show('win',opening)
    • opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

    闭:先膨胀,再腐蚀

    1. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((5,5),np.uint8)
    3. closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    4. cv_show('win',closing)
    • closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

    7. 梯度运算

    梯度=膨胀-腐蚀

    1. pie = cv2.imread('./data/pie.png',cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((7,7),np.uint8)
    3. dilate = cv2.dilate(pie,kernel,iterations = 5)
    4. erosion = cv2.erode(pie,kernel,iterations = 5)
    5. res = np.hstack((dilate,erosion))
    6. cv_show('win',res)

    以下是经过5次腐蚀和5次膨胀后的图像: 

    获得边界信息:梯度运算 

    1. gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
    2. cv_show('win',gradient)
    • gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)

    8. 礼帽与黑帽

    • 礼帽 = 原始输入-开运算结果
    • 黑帽 = 闭运算-原始输入
    1. # 礼帽
    2. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    3. tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
    4. cv_show('win',tophat)

    (只剩下“毛”了 ) 

    1. # 黑帽
    2. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    3. blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
    4. cv_show('win',blackhat)

    (只剩下小轮廓了) 

    9. 图像梯度-Sobel算子

    我们依旧引入图像pie

    1. img = cv2.imread('./data/pie.png',cv2.IMREAD_GRAYSCALE)
    2. cv_show('win',img)

     可见在边缘部分(黑白交界),梯度比较大。

    定义Gx,Gy处理水平和竖直方向上的梯度。

    1. sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    2. cv_show('sobelx',sobelx)
    • dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
      • ddepth:图像的深度(一般-1)
      • dx和dy分别表示水平和竖直方向
      • ksize是Sobel算子的大小
      • cv2.CV_64F处理差为负数情况。

    为什么只有一半呢?

    我们定义的矩阵计算时是右-左,白-黑>0正常显示,黑-白<0进行了截断为0, 

    白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值。

    我们需要对其进行一下转换:

    1. sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    2. sobelx = cv2.convertScaleAbs(sobelx)
    3. cv_show('sobelx',sobelx)
    • sobelx = cv2.convertScaleAbs(sobelx)

     上面是水平方向,下面是竖直方向:

    1. sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
    2. sobely = cv2.convertScaleAbs(sobely)
    3. cv_show('sobelx',sobely)

    分别计算x和y,再求和:

    1. sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    2. cv_show('sobelxy',sobelxy)

    但不建议都是设置成1,效果可能不好。

    1. sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
    2. sobelxy = cv2.convertScaleAbs(sobelxy) 
    3. cv_show('sobelxy',sobelxy)

    建议:分别算Gx,Gy自己进行求和操作:

    1. img = cv2.imread('./data/gd01.jpg',cv2.IMREAD_GRAYSCALE)
    2. sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    3. sobelx = cv2.convertScaleAbs(sobelx)
    4. sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
    5. sobely = cv2.convertScaleAbs(sobely)
    6. sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    7. sobelxy2=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
    8. sobelxy2 = cv2.convertScaleAbs(sobelxy2)
    9. res = np.hstack((sobelxy,sobelxy2))
    10. cv_show('res',res)

    10. 图像梯度-Scharr算子和laplacian算子

    Scharr算子

    laplacian算子 

    核中数值有差异,Scharr敏感些。

    laplacian算子涉及二阶导,更加敏感同时对噪声也更加敏感,一般和其他方法配合使用。

    原理同上,我们来对比一下这三种算子效果:

    1. img = cv2.imread('./data/gd01.jpg',cv2.IMREAD_GRAYSCALE)
    2. sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    3. sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
    4. sobelx = cv2.convertScaleAbs(sobelx)
    5. sobely = cv2.convertScaleAbs(sobely)
    6. sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    7. scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
    8. scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
    9. scharrx = cv2.convertScaleAbs(scharrx)
    10. scharry = cv2.convertScaleAbs(scharry)
    11. scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
    12. laplacian = cv2.Laplacian(img,cv2.CV_64F)
    13. laplacian = cv2.convertScaleAbs(laplacian)
    14. res = np.hstack((sobelxy,scharrxy,laplacian))
    15. cv_show('res',res)
    • scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
    • laplacian = cv2.Laplacian(img,cv2.CV_64F) 

    10. 知识点总结*

    • 图像阈值:
    1. ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
    2. ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
    3. ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
    4. ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
    5. ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
    6. # ps: ret为127 thresh1-5为图片矩阵
    7. titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
    8. images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
    9. for i in range(6):
    10. plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    11. plt.title(titles[i])
    12. plt.xticks([]), plt.yticks([])
    13. plt.show()
    • 图像平滑
    1. # 加入噪声
    2. img = cv2.imread('./data/gd07.jpg')
    3. #获取图片行、列、通道数
    4. rows,cols,channels = img.shape
    5. for i in range(0,5000):
    6. #根据在0和行-1之间获取随机整数
    7. x = np.random.randint(0,rows-1)
    8. #根据在0和列-1之间获取随机整数
    9. y = np.random.randint(0,cols-1)
    10. #将通道颜色改为255, (255,255,255)
    11. img[x,y][0] = 255
    12. img[x,y][1] = 255
    13. img[x,y][2] = 255
    14. cv_show('win',img)
    1. blur = cv2.blur(img, (3, 3))
    2. box = cv2.boxFilter(img,-1,(3,3), normalize=True)
    3. aussian = cv2.GaussianBlur(img, (5, 5), 1)
    4. median = cv2.medianBlur(img, 5)
    5. res = np.hstack((blur,aussian,median))
    6. cv_show('median vs average', res)
    • 形态学-腐蚀
    1. img = cv2.imread('./data/s.jpg', cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((3,3),np.uint8)
    3. erosion = cv2.erode(img,kernel,iterations = 1)
    4. cv_show('win',erosion)
    • 形态学-膨胀
    1. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((3,3),np.uint8)
    3. shuai = cv2.erode(img,kernel,iterations = 1)
    4. kernel = np.ones((3,3),np.uint8)
    5. shuai_PLUS = cv2.dilate(shuai,kernel,iterations = 1)
    6. cv_show('win',shuai_PLUS )
    • 开运算与闭运算
    1. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    2. kernel = np.ones((5,5),np.uint8)
    3. opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    4. cv_show('win',opening)
    • 梯度运算
    1. gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
    2. cv_show('win',gradient)
    • 礼帽与黑帽
    1. # 礼帽
    2. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    3. tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
    4. cv_show('win',tophat)
    5. # 黑帽
    6. img = cv2.imread('./data/s.jpg',cv2.IMREAD_GRAYSCALE)
    7. blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
    8. cv_show('win',blackhat)
    • Sobel、Scharr、Laplacian算子
    1. img = cv2.imread('./data/gd01.jpg',cv2.IMREAD_GRAYSCALE)
    2. sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
    3. sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
    4. sobelx = cv2.convertScaleAbs(sobelx)
    5. sobely = cv2.convertScaleAbs(sobely)
    6. sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
    7. scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
    8. scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
    9. scharrx = cv2.convertScaleAbs(scharrx)
    10. scharry = cv2.convertScaleAbs(scharry)
    11. scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
    12. laplacian = cv2.Laplacian(img,cv2.CV_64F)
    13. laplacian = cv2.convertScaleAbs(laplacian)
    14. res = np.hstack((sobelxy,scharrxy,laplacian))
    15. cv_show('res',res)
  • 相关阅读:
    哈佛积极心理学
    内容爆炸时代,如何打造品牌经营的“弹药库”?
    计算机视觉代码学习
    突破5000篇!H3K27me3如何影响癌症发展。
    Sprint产品待办列表的优先级要怎么排?
    翻译软件-免费翻译软件-自动批量翻译软件
    ETCD数据库源码分析——集群间网络层服务端RaftHandler
    Ant Design Vue UI框架的基础使用,及通用后台管理模板的小demo【简单】
    yarn的安装及使用
    DHP16P-10-05A/100T-BC、DHP16P-10-23A/35ET-BB电液比例式2级放大式方向控制阀放大器
  • 原文地址:https://blog.csdn.net/suic009/article/details/126093366