python实现canny算法

博主是python入门小菜鸡,码代码是为了更深入理解并让自己更快熟悉python的规则,当然算法原理参考的是各种大佬的文章,下面链接其中一个大佬的博文:
Canny边缘检测算法原理及实现(Python + OpenCV)
建议想自己实现的小朋友们自行戳进链接学习下,我就不赘述啦~

算法实现步骤

1.对图片进行灰度化处理
2.对灰度图进行高斯滤波
3.利用sobel算子计算图像梯度
4.非极大值抑制(对象是四个斜角上的像素点,不是梯度方向哦~)
5.双边阈值检测连接边缘

(以上步骤都是自己手码的代码┗|`O′|┛ 嗷~~)
代码来咯!!

国际惯例先导入

import cv2
import numpy as np
import matplotlib.pyplot as plt

定义灰度化函数:

def img2gray(im):
    im[:,:,0] = im[:,:,0]*0.3
    im[:,:,1] = im[:,:,1]*0.59
    im[:,:,2] = im[:,:,2]*0.11
    im = np.sum(im, axis=2)
    im = np.array(im,dtype=np.uint8)
    return im

高斯滤波:

def gaussian_filter(img,k_size,sigma):
    if len( img.shape ) == 3:
        print("错误,请输入灰度图")
    else:
        print("输入成功")
        H,W = img.shape
    kplus = k_size//2
    K = np.zeros((k_size, k_size), dtype=np.float)
    y, x = np.ogrid[-kplus:-kplus+k_size, -kplus:-kplus+k_size]
    K[y + 1, x + 1] = np.exp(-(x ** 2 + y ** 2) / (2 * (sigma ** 2)))
    K /= (2 * np.pi * sigma * sigma)
    K /= K.sum()
    new = np.zeros((kplus*2+H,kplus*2+W),dtype=np.float)
    new[kplus:kplus+H,kplus:kplus+W] = img.copy().astype(np.float)
    tmp = new.copy()

    for h in range(H):
        for w in range(W):
                new[kplus + h, kplus + w] = np.sum(K*tmp[h:h+k_size,w:w+k_size])
    new = np.clip(new,0,255)
    new = new[kplus:kplus+H,kplus:kplus+W].astype(np.uint8)
    # cv.imshow("result", new)
    # cv.waitKey()
    return new

用sobel计算图像梯度:

def gradient(img):
#sobel算子
    S_x = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
    S_y = np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
    H,W = img.shape
#扩充图像边界
    img2=cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_REPLICATE)
    tmp = img2.copy().astype(np.float)
    I1 = np.zeros((H+2,W+2), dtype=np.float)
    I2 = np.zeros((H+2,W+2), dtype=np.float)
#卷积运算
    for h in range(H):
        for w in range(W):
                I1[h,w] = np.sum(S_x*tmp[h:h+3,w:w+3])
                I2[h,w] = np.sum(S_y*tmp[h:h+3, w:w+3])
    I1 = np.clip(I1,0,255)
    I2 = np.clip(I2,0,255)
# cv.imshow("i1",I1)
# cv.imshow("i2",I2)
    G = np.sqrt(I1*I1+I2*I2)
    theta = np.arctan2(I2,(I1+0.0000000000001))*180/np.pi
    return G,theta

非极大值抑制:

def nm_suppression(G):
    I_copy = np.zeros(G.shape)
    G_plus = cv2.copyMakeBorder(G, 1, 1, 1, 1, cv2.BORDER_CONSTANT, value=0)
    anchor = np.where(G_plus != 0)

    for i in range(len(anchor[0])):
        x = anchor[0][i]
        y = anchor[1][i]
        alter_point = G[x, y]
        g1 = G[x - 1, y - 1]
        g2 = G[x + 1, y - 1]
        g3 = G[x - 1, y + 1]
        g4 = G[x + 1, y + 1]
        if g1 < alter_point and g2 < alter_point and g3 < alter_point and g4 < alter_point:
            I_copy[x, y] = alter_point

    # img_uint8 = I_copy.astype(np.uint8)
    return I_copy

双边阈值检测连接边缘:

def b_threshold(I_copy):
    I_dt = np.zeros(I_copy.shape)
    TL = 0.4*np.max(I_copy)
    TH = 0.5*np.max(I_copy)
    for i in range(1,I_copy.shape[0]-1):
        for j in range(1,I_copy.shape[1]-1):
            if I_copy[i,j]<TL:
                I_dt[i,j] = 0
            elif I_copy[i,j]>TH:
                I_dt[i, j] = 255
            elif  (( I_copy[i+1,j] > TH) or (I_copy[i-1,j] > TH )or( I_copy[i,j+1] > TH )or
                    (I_copy[i,j-1] > TH) or (I_copy[i-1, j-1] > TH )or ( I_copy[i-1, j+1] >TH) or
                    ( I_copy[i+1, j+1] > TH ) or ( I_copy[i+1, j-1] > TH) ):
                I_dt[i, j] = 255
    return I_dt

主程序:

img = cv2.imread('hm2.jpg')
im = np.array(img)
im_gray = img2gray(im)
new = gaussian_filter(im_gray,k_size=3,sigma=1.3)
# cv2.imshow("mohu",new)
G,theta = gradient(new)
I_copy = nm_suppression(G)
img_uint8 = I_copy.astype(np.uint8)
I_dt = b_threshold(I_copy)
cv2.imshow("feijidazhi",img_uint8)
cv2.imshow("zuizhongjieguo",I_dt)
cv2.waitKey()

plt.subplot(221)
plt.imshow(img), plt.title('yuantu')
plt.subplot(222)
plt.imshow(im_gray, 'gray'), plt.title('huidutu')
plt.subplot(223)
plt.imshow(I_copy, 'gray'), plt.title('feijidazhiyizhi')
plt.subplot(224)
plt.imshow(I_dt, 'gray'), plt.title('zuizhongxiaoguo')
plt.show()

结果图(可爱滴赫敏):

变蛇院了是因为opencv读取图像是默认GBR读取,所以存取时按照RGB存放则会变绿,倒一下顺序就ok(也算是成全少爷和赫敏了~)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值