OpenCV 图像梯度计算(学习笔记) 电脑版发表于:2024/1/9 14:25  >#OpenCV 图像梯度计算(学习笔记) [TOC] ## Sobel算子简介 tn2>Sobel算子是一个图像边缘检测的算法。 其基本原理是通过计算像素点梯度值来确定图像中的边缘信息。 ### 什么情况下会产生梯度? tn2>举例:在一个白心圆黑心背景图中,纯白或纯黑部分都不会产生,只有的边缘部分将会产生梯度的情况。  ### 定义Sobel算子模板 tn2>Sobel算子模板是一个`3*3`的矩阵卷积核。 将`3*3`的模板矩阵与图像中的某个像素点对应位置进行对齐。 如下图所示:  tn2>当我们要求出模板矩阵与该像素点周围8个像素点的加权平均值,水平`x`方向为:  tn>含义:当目标(P5点)左右两列差别特别大的时候,目标点的值会很大,说明该点为边界。 tn2>求`y`方向的权值公式如下:  ### Sobel算子的梯度问题 tn2>1.目标像素点求得的值小于0或者大于255怎么办? 通常Opencv默认的是是截断操作,即小于0就按0算,大于255按255算。 2.截断操作合适吗? 不合适,因为呈现的程度不一样。举例:-200或-1它都是按照0来算 3.应该如何操作? 对于小于0的值取出绝对值,大于255的可按255算(因为255是最大的值了) ### 总梯度计算  ### 示例代码 ```python import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline ``` tn2>展示原图。 ```python img = cv2.imread('pie.png',cv2.IMREAD_GRAYSCALE) cv2.imshow("img",img) cv2.waitKey() cv2.destroyAllWindows() ```  tn2>可通过`cv2.Sobel`来进行计算,举例:`dst = cv2.Sobel(src, ddepth, dx, dy, ksize)`参数如下: `ddepth`:图像的深度 `dx`和`dy`分别表示水平和竖直方向 `ksize`是Sobel算子的大小 ```python def cv_show(img,name): cv2.imshow(name,img) cv2.waitKey() cv2.destroyAllWindows() ``` ```python sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) cv_show(sobelx,'sobelx') ```  tn2>白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值。 ```python sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) # 进行取绝对值操作 sobelx = cv2.convertScaleAbs(sobelx) cv_show(sobelx,'sobelx') ```  tn2>再求`y`的Sobel算子。  tn2>分别计算x和y,再求和. ```python sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) cv_show(sobelxy,'sobelxy') ```  tn2>不建议直接计算. ```python sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3) sobelxy = cv2.convertScaleAbs(sobelxy) cv_show(sobelxy,'sobelxy') ```  tn2>再举个例子。 ```python img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE) cv_show(img,'img') ```  ```python img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE) sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) sobelx = cv2.convertScaleAbs(sobelx) sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3) sobely = cv2.convertScaleAbs(sobely) sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) cv_show(sobelxy,'sobelxy') ```  tn2>但是如果直接计算就会效果不佳。 ```python img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE) sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3) sobelxy = cv2.convertScaleAbs(sobelxy) cv_show(sobelxy,'sobelxy') ```  ## Scharr算子 tn2>与Sobel算子一样的原理,只是数值比它大一些,对于细节刻画得更明显一些。  ## laplacian算子 tn2>这个很不一样,不会进行梯度。 Laplacian是利用二阶导数来检测边缘,因为图像是二维的,我们需要在两个方向上求导,如下式所示:   tn2>计算P5的梯度公式如下: $$\large P5{_n}ew=(P2+P4+P6+P8)-4*P5 $$ ## 代码实验对比 tn2>通过进行Sobel、Scharr和laplacian的代码如下所示: ```python #不同算子的差异 img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE) sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3) sobelx = cv2.convertScaleAbs(sobelx) sobely = cv2.convertScaleAbs(sobely) sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) scharrx = cv2.Scharr(img,cv2.CV_64F,1,0) scharry = cv2.Scharr(img,cv2.CV_64F,0,1) scharrx = cv2.convertScaleAbs(scharrx) scharry = cv2.convertScaleAbs(scharry) scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0) laplacian = cv2.Laplacian(img,cv2.CV_64F) laplacian = cv2.convertScaleAbs(laplacian) res = np.hstack((sobelxy,scharrxy,laplacian)) cv_show(res,'res') ``` 