1. 程式人生 > >各項異性擴散(Anisotropic diffusion)

各項異性擴散(Anisotropic diffusion)

1.原理簡介

各向異性擴散濾波主要是用來平滑影象的,克服了高斯模糊的缺陷,各向異性擴散在平滑影象時是保留影象邊緣的,和雙邊濾波很像。各向異性擴散,也叫做P–M擴散,在影象處理和計算機視覺中廣泛用於保持影象細節特徵的同時減少噪聲。

通常我們有將影象看作矩陣的,看作圖的,看作隨機過程的,記得過去還有看作力場的。這次新鮮,將影象看作熱量場了。每個畫素看作熱流,根據當前畫素和周圍畫素的關係,來確定是否要向周圍擴散。比如某個鄰域畫素和當前畫素差別較大,則代表這個鄰域畫素很可能是個邊界,那麼當前畫素就不向這個方向擴散了,這個邊界也就得到保留了。

具體的推導公式都是熱學上的,自己也不太熟悉,感興趣的可以去看原論文,引用量超7000吶。我這裡只介紹一下最終結論用到的公式。
主要迭代方程如下:

I就是影象了,因為是個迭代公式,所以有迭代次數t。
四個散度公式是在四個方向上對當前畫素求偏導,news就是東南西北嘛,公式如下:

而cN/cS/cE/cW則代表四個方向上的導熱係數,邊界的導熱係數都是小的。公式如下:

最後整個公式需要先前設定的引數主要有三個,迭代次數t,根據情況設定;導熱係數相關的k,取值越大越平滑,越不易保留邊緣;lambda同樣也是取值越大越平滑。

2.程式碼實現(python)

import cv2
import numpy as np
import math
class anisodiff2D(object):
 
    def __init__(self, num_iter=5, delta_t=1/7, kappa=30, option=2):
 
        super(anisodiff2D, self).__init__()
 
        self.num_iter = num_iter
        self.delta_t = delta_t
        self.kappa = kappa
        self.option = option
 
        self.hN = np.array([[0, 1, 0], [0, -1, 0], [0, 0, 0]])
        self.hS = np.array([[0, 0, 0], [0, -1, 0], [0, 1, 0]])
        self.hE = np.array([[0, 0, 0], [0, -1, 1], [0, 0, 0]])
        self.hW = np.array([[0, 0, 0], [1, -1, 0], [0, 0, 0]])
        self.hNE = np.array([[0, 0, 1], [0, -1, 0], [0, 0, 0]])
        self.hSE = np.array([[0, 0, 0], [0, -1, 0], [0, 0, 1]])
        self.hSW = np.array([[0, 0, 0], [0, -1, 0], [1, 0, 0]])
        self.hNW = np.array([[1, 0, 0], [0, -1, 0], [0, 0, 0]])
 
    def fit(self, img):
 
        diff_im = img.copy()
 
        dx = 1; dy = 1; dd = math.sqrt(2)
 
        for i in range(self.num_iter):
            nablaN = cv2.filter2D(diff_im, -1, self.hN)
            nablaS = cv2.filter2D(diff_im, -1, self.hS)
            nablaW = cv2.filter2D(diff_im, -1, self.hW)
            nablaE = cv2.filter2D(diff_im, -1, self.hE)
            nablaNE = cv2.filter2D(diff_im, -1, self.hNE)
            nablaSE = cv2.filter2D(diff_im, -1, self.hSE)
            nablaSW = cv2.filter2D(diff_im, -1, self.hSW)
            nablaNW = cv2.filter2D(diff_im, -1, self.hNW)
 
            cN = 0; cS = 0; cW = 0; cE = 0; cNE = 0; cSE = 0; cSW = 0; cNW = 0
 
            if self.option == 1:
                cN = np.exp(-(nablaN/self.kappa)**2)
                cS = np.exp(-(nablaS/self.kappa)**2)
                cW = np.exp(-(nablaW/self.kappa)**2)
                cE = np.exp(-(nablaE/self.kappa)**2)
                cNE = np.exp(-(nablaNE/self.kappa)**2)
                cSE = np.exp(-(nablaSE/self.kappa)**2)
                cSW = np.exp(-(nablaSW/self.kappa)**2)
                cNW = np.exp(-(nablaNW/self.kappa)**2)
            elif self.option == 2:
                cN = 1/(1+(nablaN/self.kappa)**2)
                cS = 1/(1+(nablaS/self.kappa)**2)
                cW = 1/(1+(nablaW/self.kappa)**2)
                cE = 1/(1+(nablaE/self.kappa)**2)
                cNE = 1/(1+(nablaNE/self.kappa)**2)
                cSE = 1/(1+(nablaSE/self.kappa)**2)
                cSW = 1/(1+(nablaSW/self.kappa)**2)
                cNW = 1/(1+(nablaNW/self.kappa)**2)
 
            diff_im = diff_im + self.delta_t * (
 
                (1/dy**2)*cN*nablaN +
                (1/dy**2)*cS*nablaS +
                (1/dx**2)*cW*nablaW +
                (1/dx**2)*cE*nablaE +
 
                (1/dd**2)*cNE*nablaNE +
                (1/dd**2)*cSE*nablaSE +
                (1/dd**2)*cSW*nablaSW +
                (1/dd**2)*cNW*nablaNW
            )
 
        return diff_im
這個是八向擴散的封裝類
--------------------- 
作者:GlassySky0816 
來源:CSDN 
原文:https://blog.csdn.net/qq_38784098/article/details/81605963 
版權宣告:本文為博主原創文章,轉載請附上博文連結!