Gradient and edge detection operators of image processing

The gradient is the speed at which a quantity changes. In mathematics, derivation and partial derivation are usually used to obtain the gradient or the gradient in a certain direction.
In a digital image, the gradient can be regarded as the change speed of the pixel value in the x and y directions respectively. Because of the discrete type of the digital image and the characteristic that the pixel is the smallest processing unit, when calculating the gradient of the digital image, there is no need to calculate the derivative, only Addition and subtraction are required. (In fact, it is the differential approximation form of derivation). As shown in the figure below:
insert image description here

1. Sobel operator

The Sobel operator includes two sets of 3 ∗ 3 matrices, which are the horizontal and vertical templates, which are convolved with the image to obtain the horizontal and vertical brightness difference approximations respectively. Below is G x G_xGxG y G_yGyDefault
G x = [ + 1 0 − 1 + 2 0 − 2 + 1 0 − 1 ] ∗ A G_x= \left[ \begin{array} {cccc} +1&0&-1\\ +2 &0&-2\ \ +1 &0&-1 \end{array}\right]*AGx= +1+2+1000121 A

G y = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] ∗ A G_y= \left[ \begin{array} {cccc} +1&+2&+1\\ 0&0&0\\ -1&-2&-1 \end{array} \right]*A Gy= +101+202+101 A
is as above formula,G x G_xGxG y G_yGyDenote the results obtained by performing horizontal and vertical gradient detection on image A, respectively.
Take the sum of the squares of the two to get the gradient value of each point on the image, that is, calculate xx at this point at the same timex direction andyyThe gradient in the y direction.
G = G x 2 + G y 2 G=\sqrt{G_x^2+G_y^2}G=Gx2+Gy2
The direction of the gradient at that point can be determined by taking the arctan arctan arctan of the ratio of these two valuesΘ = arctan ( G and G x ) \Theta=arctan\left(\frac{G_y}{G_x} \ right )
Th=I 'm sorry _(GxGy)
implementation code is as follows:

def SobelX(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            result[i,j] =v
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def SobelY(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] =h
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

def Sobel(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

The test results are as follows:
insert image description here

Two, Scharr operator

Scharr operator is a special form of Sobel operator. The form of its kernel is as follows:
[ + 3 0 − 3 + 10 0 − 10 + 3 0 − 3 ] \left[ \begin{array} {cccc} +3&0&-3\\ +10 &0&-10\\ +3&0&- 3 \end{array} \right] +3+10+30003103
[ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] \left[ \begin{array} {cccc} -3&-10&-3\\ 0 &0&0\\ +3&+10&+3 \end{array} \right] 30+3100+1030+3
As mentioned earlier, the larger the kernel in the Sobel operator, the better the approximate derivative and the higher the accuracy. Therefore, when the kernel is relatively small, such as 3×3, the accuracy of the Sobel kernel is poor, and using the Scharr operator instead of the 3×3 Sobel kernel can improve the accuracy. Because the weight in the x direction or y direction is increased, the gradient angle (gradient direction) will not be too far away from the x or y direction, so the error will not be too large. For example, when only the gradient in the x direction is calculated, the two weights in the x direction of the center point of the kernel are much larger than the other weights, which makes the obtained gradient closer to the x direction and reduces the error to a certain extent.

def Scharr(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])
    G_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

Test results:
insert image description here

3. Roberts operator

[ − 1 0 0 1 ] \left[ \begin{array} {cccc} -1&0\\ 0&1\\ \end{array} \right] [1001]
[ 0 − 1 1 0 ] \left[ \begin{array} {cccc} 0&-1\\ 1 &0\\ \end{array} \right] [0110]

The kernel of the Roberts operator is shown in the figure above. It is a simple cross-difference algorithm, which is most effective when calculating the gradient of ±45°.
Compared with the general horizontal and vertical difference operators, the Roberts operator can effectively preserve the corner points of the edge, and the calculation speed is faster. The disadvantage is that it is sensitive to details and is also very sensitive to noise.
Implementation code:

def Roberts(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0], [0,1]])
    G_y = np.array([[0, -1], [1,0]])
    result = np.zeros(img.shape)
    for i in range(0, width - 1):
        for j in range(0, height - 1):
            v = np.sum(G_x * img[i:i + 2, j:j + 2])
            h = np.sum(G_y * img[i:i + 2, j:j + 2])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

The test results are as follows:
insert image description here

4. Laplacian operator

The Laplacian can be defined by the second derivative:
Δ 2 ( x , y ) = ∂ 2 f ( x , y ) ∂ x 2 + ∂ 2 f ( x , y ) ∂ y 2 \Delta^2(x, y)=\frac{\partial^2f(x,y)}{\partial x^2}+\frac{\partial^2f(x,y)}{\partial y^2}D2(x,y)=x22f(x,y)+y22f(x,y)
However, in the discretization of digital images, the second-order difference is expressed as:
∂ 2 f ( x , y ) ∂ x 2 ≈ Δ xf ( i + 1 , j ) − Δ xf ( i , j ) = [ f ( i + 1 , j ) − f ( i , j ) ] − [ f ( i , j ) − f ( i − 1 , j ) ] = f ( i + 1 , j ) + f ( i − 1 , j ) − 2 f ( i , j ) \begin{align*} \begin{split} \frac{\partial^2f(x,y)}{\partial x^2} &\approx \Delta_xf(i+1,j)- \Delta_xf(i,j) \\ &= \left[ f(i+1,j)-f(i,j) \right]- \left[f(i,j)-f(i-1,j ) \right] \\ &=f(i+1,j)+f(i-1,j)-2f(i,j) \end{split} \end{align*}x22f(x,y)Dxf(i+1,j)Dxf(i,j)=[f(i+1,j)f(i,j)][f(i,j)f(i1,j)]=f(i+1,j)+f(i1,j)2f(i,j)
同理可得:
∂ 2 f ( x , y ) ∂ y 2 ≈ f ( i , j + 1 ) + f ( i , j − 1 ) − 2 f ( i , j ) \frac{\partial^2f(x,y)}{\partial y^2} \approx f(i,j+1)+f(i,j-1)-2f(i,j) y22f(x,y)f(i,j+1)+f(i,j1)2f(i,j )
So the Laplacian operator can be expressed as:
Δ 2 ( x , y ) = f ( i + 1 , j ) + f ( i − 1 , j ) + f ( i , j + 1 ) + f ( i , j − 1 ) − 4 f ( i , j ) \Delta^2(x,y)=f(i+1,j)+f(i-1,j)+f(i,j+1) +f(i,j-1)-4f(i,j)D2(x,y)=f(i+1,j)+f(i1,j)+f(i,j+1)+f(i,j1)4 f ( i ,j )
The convolution kernel is as follows:
[ 0 1 0 1 − 4 1 0 1 0 ] \left[ \begin{array} {cccc} 0&1&0\\ 1&-4&1\\ 0&1&0 \end{array} \right] 010141010
The Laplacian method is actually an image edge enhancement operator, which is often used for image sharpening. While enhancing the edge, it also enhances the noise, so it needs to be smoothed or filtered before use. As shown in the figure below, it can be seen that when the function value changes suddenly, the second derivative can enhance the contrast between the sudden change point and its two sides. In a digital image, the edge of the image is enhanced, thus realizing the sharpening of the image.
insert image description here

The code is implemented as follows:

def Laplacian(img):
    temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    height, width = img.shape[::-1]
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            result[i][j] = np.abs(np.sum(temLaplacian * img[i:i + 3, j:j + 3]))
    return result

The test results are as follows:
insert image description here
The overall code is as follows:

import numpy as np
import cv2
import imgShow as iS

def SobelX(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            result[i,j] =v
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

def SobelY(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] =h
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

def Sobel(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Sobel(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Scharr(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])
    G_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Roberts(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0], [0,1]])
    G_y = np.array([[0, -1], [1,0]])
    result = np.zeros(img.shape)
    for i in range(0, width - 1):
        for j in range(0, height - 1):
            v = np.sum(G_x * img[i:i + 2, j:j + 2])
            h = np.sum(G_y * img[i:i + 2, j:j + 2])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Laplacian(img):
    temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    height, width = img.shape[::-1]
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            result[i][j] = np.abs(np.sum(temLaplacian * img[i:i + 3, j:j + 3]))
    return result

img=cv2.imread("./originImg/HorizontalAndVertical.jpg")
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
sobelImg=Sobel(img,56)
iS.showImagegray(sobelImg, img, 25, 15, 'sobelDetection', 'origin', './ProcessedImg/sobelDetection.jpg')
imageList=[]
origin_img=[img,'origin_img']
imageList.append(origin_img)
sobelx=SobelX(img,0)
sobel2=[sobelx,'Sobel_X']
imageList.append(sobel2)
sobely=SobelY(img,0)
sobel1=[sobely,'Sobel_Y']
imageList.append(sobel1)
sobelImg=Sobel(img,56)
sobel3=[sobelImg,'Sobel']
imageList.append(sobel3)
iS.showMultipleimages(imageList,25,25,'./ProcessedImg/sobelEdge.jpg')
img1=cv2.imread('./originImg/Goldhill.tif')
img1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
LapImg=Laplacian(img1)
iS.showImagegray(LapImg, img1, 25, 15, 'LapImg', 'origin', './ProcessedImg/lapImg.jpg')
scharrImg=Scharr(img,56)
iS.showImagegray(scharrImg, img, 25, 15, 'scharrDetection', 'origin', './ProcessedImg/scharrDetection.jpg')
robertsImg=Roberts(img,56)
iS.showImagegray(robertsImg, img, 25, 15, 'robertsDetection', 'origin', './ProcessedImg/robertsDetection.jpg')
# cv2.imshow('sobely',sobely)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

Drawing code:

import matplotlib.pyplot as plt
import numpy as np
import math
#图像实际大小为 W*100 * H*100 像素  ,
def showImagegray(newImg,oldImg,W,H,newImgtitle,oldImgtitle,saveImgpath):

    plt.figure(figsize=(W,H))
    plt.subplot(121)
    plt.title(oldImgtitle,fontsize=30)
    plt.axis('off')
    plt.imshow(oldImg, cmap='gray')

    plt.subplot(122)
    plt.title(newImgtitle,fontsize=30)
    plt.axis('off')
    plt.imshow(newImg, cmap='gray')
    # plt.tight_layout()  # 调整整体空白
    plt.savefig(saveImgpath)
    plt.show()

def showMultipleimages(imageList,W,H,saveImgpath):

    imageLength=len(imageList)

    plt.rcParams['figure.figsize'] = (W,H)
    col=row=math.ceil(np.sqrt(imageLength))
    fig, a = plt.subplots(col, row)
    m = 0
    for i in range(col):
        for j in range(row):
            a[i][j].set_title(imageList[m][1])
            a[i][j].imshow(imageList[m][0], cmap=plt.cm.gray)
            m += 1
        #去掉边框和刻度
        for ax in a.flat:
            ax.set_axis_off()

    fig.tight_layout()  # 调整整体空白
    plt.subplots_adjust(wspace=0.2, hspace=0.2)  # 调整子图间距
    plt.savefig(saveImgpath)
    plt.show()



Guess you like

Origin blog.csdn.net/weixin_42491648/article/details/131756263