使用LoG 滤波器,来对imori_noise.jpg
检测边缘吧!
LoG即高斯-拉普拉斯(Laplacian of Gaussian)的缩写,使用高斯滤波器使图像平滑化之后再使用拉普拉斯滤波器使图像的轮廓更加清晰。
为了防止拉普拉斯滤波器计算二次微分会使得图像噪声更加明显,所以我们首先使用高斯滤波器来抑制噪声。
LoG 滤波器使用以下式子定义:
\text{LoG}(x,y)=\frac{x^2 + y^2 – s^2}{2 \ \pi \ s^6} \ e^{-\frac{x^2+y^2}{2\ s^2}}
python实现:
import cv2
import numpy as np
# Gray scale
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# LoG filter
def LoG_filter(img, K_size=5, sigma=3):
H, W, C = img.shape
# zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float)
out[pad: pad + H, pad: pad + W] = gray.copy().astype(np.float)
tmp = out.copy()
# LoG Kernel
K = np.zeros((K_size, K_size), dtype=np.float)
for x in range(-pad, -pad + K_size):
for y in range(-pad, -pad + K_size):
K[y + pad, x + pad] = (x ** 2 + y ** 2 - sigma ** 2) * np.exp( -(x ** 2 + y ** 2) / (2 * (sigma ** 2)))
K /= (2 * np.pi * (sigma ** 6))
K /= K.sum()
# filtering
for y in range(H):
for x in range(W):
out[pad + y, pad + x] = np.sum(K * tmp[y: y + K_size, x: x + K_size])
out = np.clip(out, 0, 255)
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
return out
# Read image
img = cv2.imread("imori_noise.jpg")
# grayscale
gray = BGR2GRAY(img)
# LoG filtering
out = LoG_filter(gray, K_size=5, sigma=3)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
c++:
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
// BGR -> Gray
cv::Mat BGR2GRAY(cv::Mat img){
// get height and width
int width = img.cols;
int height = img.rows;
// prepare output
cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1);
// each y, x
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++){
// BGR -> Gray
out.at<uchar>(y, x) = 0.2126 * (float)img.at<cv::Vec3b>(y, x)[2] \
+ 0.7152 * (float)img.at<cv::Vec3b>(y, x)[1] \
+ 0.0722 * (float)img.at<cv::Vec3b>(y, x)[0];
}
}
return out;
}
// LoG filter
cv::Mat LoG_filter(cv::Mat img, int kernel_size, double sigma){
int height = img.rows;
int width = img.cols;
int channel = img.channels();
// prepare output
cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1);
// prepare kernel
int pad = floor(kernel_size / 2);
double kernel[kernel_size][kernel_size];
double kernel_sum = 0;
double _x, _y;
for (int y = 0; y < kernel_size; y++){
for (int x = 0; x < kernel_size; x++){
_y = y - pad;
_x = x - pad;
kernel[y][x] = (_x * _x + _y * _y - sigma * sigma) / (2 * M_PI * pow(sigma, 6)) * exp( - (_x * _x + _y * _y) / (2 * sigma * sigma));
kernel_sum += kernel[y][x];
}
}
for (int y = 0; y < kernel_size; y++){
for (int x = 0; x < kernel_size; x++){
kernel[y][x] /= kernel_sum;
}
}
double v = 0;
// filtering
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++){
v = 0;
for (int dy = -pad; dy < pad + 1; dy++){
for (int dx = -pad; dx < pad + 1; dx++){
if (((y + dy) >= 0) && (( x + dx) >= 0) && ((y + dy) < height) && ((x + dx) < width)){
v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dx + pad];
}
}
}
v = fmax(v, 0);
v = fmin(v, 255);
out.at<uchar>(y, x) = (uchar)v;
}
}
return out;
}
int main(int argc, const char* argv[]){
// read image
cv::Mat img = cv::imread("imori_noise.jpg", cv::IMREAD_COLOR);
// BGR -> Gray
cv::Mat gray = BGR2GRAY(img);
// LoG filter
cv::Mat out = LoG_filter(gray, 5, 3);
//cv::imwrite("out.jpg", out);
cv::imshow("answer", out);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
输入:
输出: