【摘要】
Laplace算子作為邊緣檢測之一,和Sobel算子一樣也是工程數學中常用的一種積分變換,屬於空間銳化濾波操作。拉普拉斯算子(Laplace Operator)是n維歐幾里德空間中的一個二階微分算子,定義為梯度(▽f)的散度(▽·f)。拉普拉斯算子也可以推廣為定義在黎曼流形上的橢圓型算子,稱為拉普拉斯-貝爾特拉米算子。(百度百科)
【原理】
拉普拉斯算子是二階微分線性算子,在圖像邊緣處理中,二階微分的邊緣定位能力更強,銳化效果更好,因此在進行圖像邊緣處理時,直接采用二階微分算子而不使用一階微分。
圖1 一階微分和二階微分計算圖
離散函數的導數退化成了差分,一維一階差分公式和二階差分公式分別為:如圖2所示
圖2 一階微分和二階微分計算
分別對Laplace算子x,y兩個方向的二階導數進行差分就得到了離散函數的Laplace算子。在一個二維函數f(x,y)中,x,y兩個方向的二階差分分別為:如圖3所示
圖3 x,y兩個方向的二階差分
所以Laplace算子的差分形式為:
寫成filter mask的形式如下:
該mask的特點,mask在上下左右四個90度的方向上結果相同,也就是說在90度方向上無方向性。為了讓該mask在45度的方向上也具有該性質,對該filter mask進行擴展定義為
將Laplace算子寫成filter mask后,其操作大同小異於其他的空間濾波操作。將filter mask在原圖上逐行移動,然后mask中數值與其重合的像素相乘后求和,賦給與mask中心重合的像素,對圖像的第一,和最后的行和列無法做上述操作的像素賦值零,就得到了拉普拉斯操作結果。因為Laplace算子是二階導數操作,其在強調圖像素中灰度不連續的部分的同時也不在強調灰度值連續的部分。這樣會產生一個具有很明顯的灰度邊界,但是沒有足夠特征的黑色背景。背景特征可以通過原圖像與Laplace算子操作后的圖像混合恢復。用公式。
【C++代碼】

// MyLaplace.cpp : 定義控制台應用程序的入口點。 // #include "stdafx.h" #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> using namespace std; using namespace cv; //**********************// //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]; } } //*****************************// //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)); } } int main() { Mat src = imread("D:/10.jpg"); //get some informations of original image int nr = src.rows; int nc = src.cols*3; 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 imshow("結果", LaResult_own); waitKey(0); }
【參考文獻】
http://www.cnblogs.com/german-iris/p/4840647.html
https://baike.baidu.com/item/%E6%8B%89%E6%99%AE%E6%8B%89%E6%96%AF%E7%AE%97%E5%AD%90/7261323?fr=aladdin