zoukankan      html  css  js  c++  java
  • opencv学习记录之图像梯度

    图像的梯度计算的是图像变化的速度,对于边缘部分呢灰度值变换大,梯度值也大,相反则灰度值变化小,梯度值小

    图像梯度值严格说应该需要求导数,但是图像梯度一般通过计算像素值的差,来得到梯度的近似值

    以下介绍三种算子的使用Sobel算子、Scharr算子和Laplacian算子

    Sobel算子是一种离散的微分算子,该算子结合了高斯平滑处理和微分求导运算。 该算子利用局部差寻找边缘

    Sobel算子如下所示

    -1 0 1
    -2 0 2
    -1 0 1

                                图一

    -1 -2 -1
    0 0 0
    1 2 1

                                图二    

     将Sobel算子图一和原始图像卷积可以得到水平方向的像素值变化,与图二卷积的到垂直方向的像素值变化

    P1 P2 P3
    P4 P5 P6
    P7 P8 P9

    如果要计算P5的水平方向的偏导数,则需要Sobel算子及P5邻域点

    公式为:P5x = (P3 - P1 ) + 2 * ( P6 - P4 ) + ( P9 - P7 )

    用P5右侧的像素点减左侧的像素点,因为P4和P6离P5较近,所以权值为2,其他为1

    垂直方向类似,垂直是下减上

    函数形式

    dst = cv2.Sobel( src , ddepth, dx , dy [, ksize [, scale [, delta [, borderType]]]])

    dst目标图像

    src原始图像

    ddepth 输出图像的深度,

    dx x方向上的求导阶数

    dy  y方向上的求导阶数

    ksize 代表Sobel核的大小,该值为-1时,会使用Scharr算子进行计算

    scale计算导数值时采用的缩放因子,默认为1,没有缩放

    delta加在目标图像dst上的值,默认为0

    borderType 边界样式 (上篇博客提到过不再重复)

    可以将ddepth设置为-1,在计算时可能得到的结果时错误的,

    如果处理的图像是8位图类型,且ddepth为-1 意味着指定运算结果也是8位图类型,所有负数都自动处理为0

    为了避免信息丢失在计算是要先使用更高的数据类型嗯 cv2.CV_64F,在通过取绝对值将其映射位8位图类型

    所以通常要将ddepth设置位cv2.CV_64F

    如下代码所示

    1 import cv2                                                                       
    2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
    3 Sobelx = cv2.Sobel(o , -1 , 1 , 0) 
    4 cv2.imshow("original" , o) 
    5 cv2.imshow("x" , Sobelx)
    6 cv2.waitKey()
    7 cv2.destroyAllWindows()

    原图

    效果图 

    如上图所示在8位灰度图中因为黑色的像素值位0,而白色为255,当使用Sobel算子后,对其水平方向计算近似偏导数

    右侧减左侧,右侧边缘得到的是正数所以可以正常显示,而左侧的边缘得到的是负数被处理为0后便显示黑色不能得到准确的结果

    将ddepth设置为cv2.CV_64F后 还要取绝对值才能获得所需的图像,则需要绝对值函数 cv2.convertScaleAbs()

    dx = 1 , dy = 0

    1 import cv2                                                                       
    2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
    3 Sobelx = cv2.Sobel(o , cv2.CV_64F , 1 ,0)
    4 Sobelx = cv2.convertScaleAbs(Sobelx)
    5 cv2.imshow("original" , o) 
    6 cv2.imshow("x" , Sobelx)
    7 cv2.waitKey()
    8 cv2.destroyAllWindows()

    如图   可以获得完整边缘信息

    垂直方向的边缘信息 dx = 0 . dy = 1

    1 import cv2                                                                       
    2 o = cv2.imread("example.bmp" , cv2.IMREAD_UNCHANGED)
    3 Sobely = cv2.Sobel(o , cv2.CV_64F , 0 , 1) 
    4 Sobely = cv2.convertScaleAbs(Sobely)
    5 cv2.imshow("original" , o) 
    6 cv2.imshow("y" , Sobely)
    7 cv2.waitKey()
    8 cv2.destroyAllWindows()

    如图

    当dx =1 , dy = 1 

    1 import cv2                                                                       
    2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
    3 Sobelxy = cv2.Sobel(o , cv2.CV_64F , 1 , 1) 
    4 sobelxy = cv2.convertScaleAbs(Sobelxy)
    5 cv2.imshow("original" , o) 
    6 cv2.imshow("xy" , Sobelxy)
    7 cv2.waitKey()
    8 cv2.destroyAllWindows()

     没有达到我们想要的结果,而是只留下几个点

    若想要x,y方向都显示边缘需要两个方向分别处理,然后向叠加

    import cv2                                                                       
    o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE )
    Sobelx = cv2.Sobel(o , cv2.CV_64F , 1 , 0)   
    Sobely = cv2.Sobel(o , cv2.CV_64F , 0 , 1)   
    Sobelx = cv2.convertScaleAbs(Sobelx)         
    Sobely = cv2.convertScaleAbs(Sobely)         
    Sobelxy = cv2.addWeighted(Sobelx , 0.5 , Sobely , 0.5 , 0) 
    cv2.imshow("original" , o) 
    cv2.imshow("xy" , Sobelxy)
    cv2.waitKey()  
    cv2.destroyAllWindows()

    Scharr算子

    在使用3x3的Sobel算子是精度可能不高,Scharr速度与Sobel算子一样 ,但精度更高

    Scharr算子通常为

    -3 0 3
    -10 0 10
    -3 0 3
    -3 -10 -3
    0 0 0
    3 10 3

    函数形式为

    dst = cv2.Scharr( src , ddepth , dx , dy [ , scale [ ,delta [, borderType]]])

    与Sobel相似少了Ksize参数, 即当Sobel中ksize = -1 时会使用Scharr算子计算

    函数cv2.Scharr()与cv2.Sobel()相似

    但有一些约束条件

    dx >= 0 && dy >=0 && dx + dy == 1

    x方向和y方向的边缘叠加

     1 import cv2                                                                       
     2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
     3 Scharrx = cv2.Scharr(o , cv2.CV_64F , 1 , 0) 
     4 Scharry = cv2.Scharr(o , cv2.CV_64F , 0 , 1) 
     5 Scharrx = cv2.convertScaleAbs(Scharrx)
     6 Scharry = cv2.convertScaleAbs(Scharry)
     7 Scharrxy = cv2.addWeighted(Scharrx , 0.5 , Scharry , 0.5 , 0) 
     8 cv2.imshow("original" , o) 
     9 cv2.imshow("xy" , Scharrxy)
    10 cv2.waitKey()
    11 cv2.destroyAllWindows()

    Sobel和Scharr的比较

    原图

     Sobel

     Scharr

     

    Laplacian算子

    该算子是一个二阶导数算子,具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求,

    通常情况下算子的系数和要为0

    Laplacian算子 

    0 1 0
    1 -4 1
    0 1 0
    p1 p2 p3
    p4 p5 p6
    p7 p8 p9

    P5点的近似导数值

    P5lap =( P2 + P4 + P6 + P8 ) - 4* P5

    该结果可能是正数也可能是负数,需要对计算结果取绝对值

    函数形式

    dst = cv2.Laplacian(src , ddepth , [,ksize [ ,scale [, delta [.borderType]]]])

    dst 目标图像

    src原始图像

    ddepth目标时图像的深度

    ksize二阶导数的核尺寸大小

    scale  计算Laplacian值的缩放比例因子

    delta 夹道目标图像上的可选值

    borderType 边界样式

    1 import cv2                                                                       
    2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
    3 Laplacian = cv2.Laplacian(o , cv2.CV_64F)
    4 Laplacian = cv2.convertScaleAbs(Laplacian)
    5 cv2.imshow("original" , o) 
    6 cv2.imshow("Laplacina" , Laplacian)
    7 cv2.waitKey()
    8 cv2.destroyAllWindows()

  • 相关阅读:
    [转载]iOS 开发中为什么更新UI都要放在主线程中?
    GCD小结
    多线程的实现
    图片缓存、PathForResource、NSBundle
    IOS全路径和文件名方法、NSBundle
    plist文件
    iphone区别翻新机
    iPhone4S国行、港版、美版、妖机识别与选购(转)
    应用沙盒
    IOS实现新特性功能
  • 原文地址:https://www.cnblogs.com/miaorn/p/12292908.html
Copyright © 2011-2022 走看看