边缘检测——Canny

Canny

参考视频:canny边缘检测算法视频讲解

步骤 

原图

1.RGB图片转灰度图片

代码

im = Image.open("nms.jpg")
im_gray = im.convert('L')   #rgb转灰度图

结果

 2.求梯度(sobel算子)

代码

grad = [[[0, 0] for i in range(im.size[0])] for j in range(im.size[1])]  #170 * 200 * 2 每个像素点的梯度大小和方向
for j in range(1, im.size[1] - 1):
    for i in range(1, im.size[0] - 1):
        #x方向梯度
        grad_x = im_list[j + 1][i + 1] + im_list[j - 1][i + 1] + 2 * im_list[j][i + 1] - \
                 im_list[j - 1][i - 1] - im_list[j + 1][i - 1] - 2 * im_list[j][i - 1]
        #y方向梯度
        grad_y = im_list[j + 1][i - 1] + im_list[j + 1][i + 1] + 2 * im_list[j + 1][i] - \
                 im_list[j - 1][i - 1] - im_list[j - 1][i + 1] - 2 * im_list[j - 1][i]
        grad_x = math.floor(grad_x / 4)
        grad_y = math.floor(grad_y / 4)
        #合梯度
        grad[j][i][0] = math.floor(math.sqrt(grad_x * grad_x + grad_y * grad_y))
        if(grad[j][i][0] > 255):
            grad[j][i][0] = 255
        # if(grad[j][i][0] < 50):
        #     grad[j][i][0] = 0
        #梯度方向
        if(grad_x == 0):
            grad[j][i][1] = 2  #y方向
        else:
            theta = math.atan2(grad_y, grad_x)
            if(math.fabs(theta) < math.pi / 8):
                grad[j][i][1] = 0 #x方向
            elif(theta > 0):
                if(math.fabs(theta) <math.pi * 3 / 8):
                    grad[j][i][1] = 1  #45度方向
                else:
                    grad[j][i][1] = 2#y方向
            else:
                if (math.fabs(theta) < math.pi * 3 / 8):
                    grad[j][i][1] = 3  # 135度方向
                else:
                    grad[j][i][1] = 2  # y方向

结果

3.非极大值抑制(使边缘更清晰)

代码

img2 = img
for j in range(1, im.size[1] - 1):
    for i in range(1, im.size[0] - 1):
        dir = grad[j][i][1]
        grad_now = grad[j][i][0]
        if (dir == 0):  #梯度方向为x
            if(grad_now < grad[j][i + 1][0] or grad_now < grad[j][i - 1][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
        elif(dir == 1):#45度方向
            if(grad_now < grad[j + 1][i + 1][0] or grad_now < grad[j - 1][i - 1][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
        elif(dir == 2): #y方向
            if(grad_now < grad[j + 1][i][0] or grad_now < grad[j - 1][i][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
        else:  #145度
            if(grad_now < grad[j + 1][i - 1][0] or grad_now < grad[j - 1][i + 1][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0

 结果

4.双阈值(消去噪点,强化边缘) 

 代码

low = 30
high = 60

for i in range(im.size[1]):
    for j in range(im.size[0]):
        if(img2[i][j] < low):
            img2[i][j] = 0
        elif(img2[i][j] > high):
            img2[i][j] = 255

结果

5.抑制孤立弱边缘 

代码

listx = [-1, 0, 1]
listy = [-1, 0, 1]
img3 = img2
for j in range(1, im.size[1] - 1):
    for i in range(1, im.size[0] - 1):
        flag = 1
        for dx in range(len(listx)):
            for dy in range(len(listy)):
                j = j + listy[dy]
                i = i + listx[dx]
                if(img2[j][i] == 255):
                    flag = 0
                    break
            if(not flag):
                break
        if(flag):
            img3[j][i] = 0

 结果

完整代码

from PIL import Image
from matplotlib import pyplot as plt
import math
from PIL import ImageFilter

im = Image.open("pic.jpg")
im_gray = im.convert('L')   #rgb转灰度图
# im_gray.show()  #显示灰度图

# im_gray = im_gray.filter(ImageFilter.SMOOTH)

#Image转为list类型
im_array = im_gray.load()
im_list = [[0 for i in range(im.size[0])] for j in range(im.size[1])]
for i in range(im.size[1]):
    for j in range(im.size[0]):
        im_list[i][j] = im_array[j, i]
plt.figure(1)
plt.imshow(im_list, cmap='gray')
# plt.show()


#求梯度 (梯度模值和方向)
#方向:  0:0度(x)    1: 45度   2: 90度(y) 3: 135度
grad = [[[0, 0] for i in range(im.size[0])] for j in range(im.size[1])]  #170 * 200 * 2 每个像素点的梯度大小和方向
for j in range(1, im.size[1] - 1):
    for i in range(1, im.size[0] - 1):
        #x方向梯度
        grad_x = im_list[j + 1][i + 1] + im_list[j - 1][i + 1] + 2 * im_list[j][i + 1] - \
                 im_list[j - 1][i - 1] - im_list[j + 1][i - 1] - 2 * im_list[j][i - 1]
        #y方向梯度
        grad_y = im_list[j + 1][i - 1] + im_list[j + 1][i + 1] + 2 * im_list[j + 1][i] - \
                 im_list[j - 1][i - 1] - im_list[j - 1][i + 1] - 2 * im_list[j - 1][i]
        grad_x = math.floor(grad_x / 4)
        grad_y = math.floor(grad_y / 4)
        #合梯度
        grad[j][i][0] = math.floor(math.sqrt(grad_x * grad_x + grad_y * grad_y))
        if(grad[j][i][0] > 255):
            grad[j][i][0] = 255
        # if(grad[j][i][0] < 50):
        #     grad[j][i][0] = 0
        #梯度方向
        if(grad_x == 0):
            grad[j][i][1] = 2  #y方向
        else:
            theta = math.atan2(grad_y, grad_x)
            if(math.fabs(theta) < math.pi / 8):
                grad[j][i][1] = 0 #x方向
            elif(theta > 0):
                if(math.fabs(theta) <math.pi * 3 / 8):
                    grad[j][i][1] = 1  #45度方向
                else:
                    grad[j][i][1] = 2#y方向
            else:
                if (math.fabs(theta) < math.pi * 3 / 8):
                    grad[j][i][1] = 3  # 135度方向
                else:
                    grad[j][i][1] = 2  # y方向

#显示梯度图
img = [[0 for i in range(im.size[0])] for j in range(im.size[1])]
for i in range(im.size[1]):
    for j in range(im.size[0]):
        img[i][j] = grad[i][j][0]
plt.figure(2)
plt.imshow(img, cmap='gray')
# plt.show()


#非极大值抑制,使边缘更清晰和细
img2 = img
for j in range(1, im.size[1] - 1):
    for i in range(1, im.size[0] - 1):
        dir = grad[j][i][1]
        grad_now = grad[j][i][0]
        if (dir == 0):  #梯度方向为x
            if(grad_now < grad[j][i + 1][0] or grad_now < grad[j][i - 1][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
                print('0')
        elif(dir == 1):#45度方向
            if(grad_now < grad[j + 1][i + 1][0] or grad_now < grad[j - 1][i - 1][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
                print('1')
        elif(dir == 2): #y方向
            if(grad_now < grad[j + 1][i][0] or grad_now < grad[j - 1][i][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
                print('2')
        else:  #145度
            if(grad_now < grad[j + 1][i - 1][0] or grad_now < grad[j - 1][i + 1][0]):
                # grad[j][i][0] == 0
                img2[j][i] = 0
                print('3')

#显示非极大值抑制后的图像
plt.figure(3)
plt.imshow(img2, cmap='gray')
# plt.show()




#双阈值检测
low = 30
high = 60

for i in range(im.size[1]):
    for j in range(im.size[0]):
        if(img2[i][j] < low):
            img2[i][j] = 0
        elif(img2[i][j] > high):
            img2[i][j] = 255

#双阈值检测后的图像
plt.figure(4)
plt.imshow(img2, cmap='gray')
# plt.show()



#抑制孤立的弱边缘
listx = [-1, 0, 1]
listy = [-1, 0, 1]
img3 = img2
for j in range(1, im.size[1] - 1):
    for i in range(1, im.size[0] - 1):
        flag = 1
        for dx in range(len(listx)):
            for dy in range(len(listy)):
                j = j + listy[dy]
                i = i + listx[dx]
                if(img2[j][i] == 255):
                    flag = 0
                    break
            if(not flag):
                break
        if(flag):
            img3[j][i] = 0

#抑制孤立的弱边缘后的图像
# print('ssssssss')
plt.figure(5)
plt.imshow(img3, cmap='gray')
plt.show() 

 原图

猜你喜欢

转载自blog.csdn.net/qq_55126913/article/details/129732779