OpenCV-跟我一塊兒學數字圖像處理之拉普拉斯算子

Laplace算子和Sobel算子同樣,屬於空間銳化濾波操做。起本質與前面的Spatial Filter操做大同小異,下面就經過Laplace算子來介紹一下空間銳化濾波,並對OpenCV中提供的Laplacian函數進行一些說明。算法

  • 數學原理

離散函數導數函數

離散函數的導數退化成了差分,一維一階差分公式和二階差分公式分別爲,spa

CodeCogsEqn

CodeCogsEqn(2)

Laplace算子的差分形式3d

分別對Laplace算子x,y兩個方向的二階導數進行差分就獲得了離散函數的Laplace算子。code

在一個二維函數f(x,y)中,x,y兩個方向的二階差分分別爲,orm

CodeCogsEqn(3)

CodeCogsEqn(4)

因此Laplace算子的差分形式爲,blog

CodeCogsEqn(5)

寫成filter mask的形式以下,ci

0 1 0
1 -4 1
0 1 0
注意該mask的特色,mask在上下左右四個90度的方向上結果相同,也就是說在90度方向上無方向性。爲了讓該mask在45度的方向上也具備該性質,對該filter mask進行擴展定義爲,
1 1 1
1 -8 1
1 1 1
 

注:get

有時咱們也會見到不一樣於上述結果的Laplace算子的filter mask,數學

0 -1 0
-1 4 -1
0 -1 0
 
-1 -1 -1
-1 8 -1
-1 -1 -1

其緣由是在定義二階導數的時候採用了相反的定義,這個可有可無,可是要注意,當用Laplace算子濾波後的圖像與原圖疊加時,混合操做是加仍是減因上述的定義而異。

圖像的Laplace操做

如同本文開始時說的那樣,將Laplace算子寫成filter mask後,其操做大同小異於其餘的空間濾波操做。將filter mask在原圖上逐行移動,而後mask中數值與其重合的像素相乘後求和,賦給與mask中心重合的像素,對圖像的第一,和最後的行和列沒法作上述操做的像素賦值零,就獲得了拉普拉斯操做結果。

拉普拉斯操做結果與原圖的混合

由於Laplace算子是二階導數操做,其在強調圖像素中灰度不連續的部分的同時也不在強調灰度值連續的部分。這樣會產生一個具備很明顯的灰度邊界,可是沒有足夠特徵的黑色背景。背景特徵能夠經過原圖像與Laplace算子操做後的圖像混合恢復。用公式,

CodeCogsEqn(6)

其中的參數c的取值和上面的兩種mask定義有關,當mask中心的數值取正時c=-1,相反c=1;

  • 基於OpenCV的Laplace算子的計算

OpenCV中Laplacian函數能夠實現對圖像的Laplace操做,具體用法以下,

Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );

參數意義爲,

  1. src_gray,輸入圖像
  2. dst,Laplace操做結果
  3. ddepth,輸出圖像深度,由於輸入圖像通常爲CV_8U,爲了不數據溢出,輸出圖像深度應該設置爲CV_16S
  4. kernel_size,filter mask的規模,咱們的mask時3x3的,因此這裏應該設置爲3
  5. scale,delta,BORDER_DEFAULT,默認設置就好

基於OpenCV的Laplace算子仿真代碼段以下,

//load the Original Image and get some informations
Mat src = imread("012.jpg",0);
namedWindow("OriginalImage");
imshow("OriginalImage",src);
CV_Assert(src.depth() == CV_8U);

//OpenCV solution - Laplacian
Mat dst,abs_dst_laplace;
Laplacian(src,dst,CV_16S,3);
convertScaleAbs(dst,abs_dst_laplace);

//show the result
namedWindow("result_laplacian");
imshow("result_laplacian",abs_dst_laplace);

其中convertScaleAbs函數功能是將CV_16S型的輸出圖像轉變成CV_8U型的圖像。

仿真結果:

原圖:

original

Laplace操做結果:

abs_dst_laplae

  • 基於mask operation原理仿真

Laplace算子濾波仿真

根據數學原理中介紹的算法,編寫相應代碼,進行相關仿真。其中對Laplace操做結果進行了圖像拉伸顯示,由於Laplace操做結果的像素值範圍可能落在了[0,255]以外,而計算機在顯示的時候將賦值所有置爲0,大於255的像素所有顯示成255。

代碼段以下,

//get some informations of original image
int nr = src.rows;
int nc = src.cols;
int n = nr*nc;
int arr[9] = {0};

//scan the whole pixels of original image 
//and do Laplacian Operation
int* table_lap = new int[n];
int* table_orig = new int[n];
int l;
for (int i=0;i<n;i++)
{
    table_lap[i] = 0;
    table_orig[i] = 0;
}
for (int i=1;i<nr-1;i++)
{
    const uchar* previous = src.ptr<uchar>(i-1);
    const uchar* current = src.ptr<uchar>(i);
    const uchar* next = src.ptr<uchar>(i+1);
    for (int j=1;j<nc-1;j++)
    {
        for (int k=0;k<3;k++)
        {
            arr[k] = previous[j+k-1];
            arr[k+3] = current[j+k-1];
            arr[k+6] = next[j+k-1];
        }
        l = nc*i+j;        //calculate the location in the table of current pixel
        Lmaskoperation(table_lap,arr,l);
        table_orig[l] = arr[4];
    }
}

//pixels scale
uchar* La_scaled = new uchar[n];
table_scale(table_lap,La_scaled,n);

//padding values
Mat LaResult_own;
LaResult_own.create(src.size(),src.type());
uchar* p = NULL;
for (int i=0;i<nr;i++)
{
    p = LaResult_own.ptr<uchar>(i);
    for (int j=0;j<nc;j++)
    {
        l = nc*i+j;
        p[j] = La_scaled[l];
    }
}

//show results
namedWindow("LaResult_own");
imshow("LaResult_own",LaResult_own);

其中Lmaskoperation是我寫的mask爲Laplace mask的mask operation操做函數,函數段以下,

//**********************//
//Laplacian mask operation
//**********************//
void Lmaskoperation(int* table,int* arr,int l)
{
    int tmp[9] = {-1,-1,-1,-1,8,-1,-1,-1,-1};
    for (int i=0;i<9;i++)
    {
        table[l] = table[l] + tmp[i]*arr[i];
    }
}

tabel_scale函數就是我寫的圖像拉伸函數,將Laplace操做結果拉伸到[0,255],具體函數段以下,

//*****************************//
//scale the pixels to [0 255]
//*****************************//
void table_scale(int* table,uchar* result,int n)
{
    int min = table[0];
    int max = table[0];
    for (int i=0;i<n;i++)
    {
        if(min>table[i])
        {
            min = table[i];
        }
        if(max<table[i])
        {
            max = table[i];
        }
    }
    for (int i=0;i<n;i++)
    {
        result[i] = (uchar)(255*(table[i]-min)/(max-min));
    }
}

仿真結果,拉伸後Laplace算子的操做結果

LaResult_own

以灰色爲主色調的顯示結果就是Laplace算子操做拉伸後顯示的一大特色。

Laplace濾波圖像與原圖像的混合

我使用的mask中心值爲正,因此混合操做須要原圖減去Laplace濾波圖像,代碼段以下,

//blending with the original image using Eq g(x,y)=f(x,y)+c*Lap(x,y)
int* table_blend = new int[n];
for(int i=0;i<n;i++)
{
    table_blend[i] = table_orig[i] - table_lap[i];
    if(table_blend[i]<0)
    {
        table_blend[i] = 0;
    }
    else if (table_blend[i]>255)
    {
        table_blend[i] = 255;
    }
}

//padding values to blending result
Mat Blresult;
Blresult.create(src.size(),src.type());
for (int i=0;i<nr;i++)
{
    p = Blresult.ptr<uchar>(i);
    for(int j=0;j<nc;j++)
    {
        l = nc*i+j;
        p[j] = table_blend[l];
    }
}

//show blending result
namedWindow("blending result_laplacian");
imshow("blending result_laplacian",Blresult);

仿真結果:

blending result_laplacian

最後給出岡薩雷斯在介紹Laplacian時所給素材的仿真結果

blending result_laplacian

相關文章
相關標籤/搜索