前言
本文將是一篇爲圖像處理的初學者準備的濾波算法的入門文章。理論在前,代碼在後。
算法
高斯濾波算法
一維高斯函數
在圖像處理中,選定X方向上長度爲3的窗口,令δ=1,中心座標爲1,由上述公式,其卷積核(Xa,X,Xb)可以如下計算:
Xa = exp(-1*(0-1)(0-1)/(2*1*1))= 0.606530659712633
X = exp(-1*(1-1)(1-1)/(2*1*1))= 1
Xb = exp(-1*(2-1)(2-1)/(2*1*1))= 0.606530659712633
進行歸一化操作可得
Sum = Xa + X + Xb = 2.2130613194252668
Xa = Xa/Sum = 0.274068619061197
X = X/Sum = 0.451862761877606
Xb = Xb/Sum = 0.274068619061197
當然你不需要手動計算,opencv提供了這樣一個接口
import cv2 as cv
_kernel = cv.getGaussianKernel(3,1)
print(_kernel)
那麼二維卷積的計算?(3,1)*(1,3)矩陣即得(3,3)
import cv2 as cv
import numpy as np
_kernel_x = cv.getGaussianKernel(3,1)
_kernel_y = cv.getGaussianKernel(3,1)
_kernel = _kernel_x*np.transpose(_kernel_y)
print(_kernel)
輸出結果如下:
[[0.07511361 0.1238414 0.07511361]
[0.1238414 0.20417996 0.1238414 ]
[0.07511361 0.1238414 0.07511361]]
濾波前
濾波後
代碼
高斯濾波算法
python代碼(也是文本實例中使用的)
# -*- coding: utf-8 -*-
import cv2 as cv
if __name__ == "__main__":
img = cv.imread("Noise.bmp",1)
img = cv.GaussianBlur(img,(5,5),0.8)
#cv.imshow("godness",img)
cv.imwrite("liuyifei.bmp",img)
相關C++代碼
#include <cmath>
#include <limits>
#include <cstdlib>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <string>
using namespace cv;
using namespace std;
//生成高斯噪聲
double generateGaussianNoise(double mu, double sigma)
{
//定義小值
const double epsilon = numeric_limits<double>::min();
static double z0, z1;
static bool flag = false;
flag = !flag;
//flag爲假構造高斯隨機變量X
if (!flag)
return z1 * sigma + mu;
double u1, u2;
//構造隨機變量
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
//flag爲真構造高斯隨機變量
z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
return z0 * sigma + mu;
}
//爲圖像添加高斯噪聲
Mat addGaussianNoise(Mat &srcImag)
{
Mat dstImage = srcImag.clone();
int channels = dstImage.channels();
int rowsNumber = dstImage.rows;
int colsNumber = dstImage.cols*channels;
//判斷圖像的連續性
if (dstImage.isContinuous())
{
colsNumber *= rowsNumber;
rowsNumber = 1;
}
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
//添加高斯噪聲
int val = dstImage.ptr<uchar>(i)[j] +
generateGaussianNoise(2.0, 0.8) * 32;
if (val < 0)
val = 0;
if (val > 255)
val = 255;
dstImage.ptr<uchar>(i)[j] = (uchar)val;
}
}
return dstImage;
}
int main()
{
std::string Img_Name;
//載入圖像
Mat image = imread("src.bmp");
//創建窗口
namedWindow("噪聲圖像");
namedWindow("高斯濾波效果圖");
Mat dstImage = addGaussianNoise(image);
imshow("噪聲圖像", dstImage);
Img_Name = "Noise.bmp";
imwrite(Img_Name, dstImage);
//進行濾波
Mat out;
GaussianBlur(image, out, Size(7, 7), 0, 0);
imshow("高斯濾波效果圖", out);
Img_Name = "GaussianBlur.bmp";
imwrite(Img_Name, image);
Mat Gauss_diff = abs(out - dstImage);
Img_Name = "Gaussian_diff.bmp";
imwrite(Img_Name, Gauss_diff);
waitKey(0);
return 0;
}
NLmeans濾波算法(Python)
import numpy as np
import cv2
import matplotlib.pyplot as plt
from PIL import Image
filePath = r'Noise.bmp'
img = cv2.imread(filePath,0)
dst = cv2.fastNlMeansDenoisingColored(img, None,8, 20, 19 ,40)
cv2.imwrite('NlMeans.bmp', dst)
print(img.shape)
print(dst.shape)
diff =dst -img
cv2.imwrite('diff.bmp', diff)
各項異性濾波算法
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
float k = 15;
float lambda = 0.25;
int N = 20;
void anisotropy_demo(Mat &image, Mat &result);
int main(int argc, char** argv) {
Mat src = imread("Noise.jpg");
namedWindow("input image");
imshow("input image", src);
vector<Mat> mv;
vector<Mat> results;
split(src, mv);
for (int n = 0; n < mv.size(); n++) {
Mat m = Mat::zeros(src.size(), CV_32FC1);
mv[n].convertTo(m, CV_32FC1);
results.push_back(m);
}
int w = src.cols;
int h = src.rows;
Mat copy = Mat::zeros(src.size(), CV_32FC1);
for (int i = 0; i < N; i++) {
anisotropy_demo(results[0], copy);
copy.copyTo(results[0]);
anisotropy_demo(results[1], copy);
copy.copyTo(results[1]);
anisotropy_demo(results[2], copy);
copy.copyTo(results[2]);
}
Mat output;
normalize(results[0], results[0], 0, 255, NORM_MINMAX);
normalize(results[1], results[1], 0, 255, NORM_MINMAX);
normalize(results[2], results[2], 0, 255, NORM_MINMAX);
results[0].convertTo(mv[0], CV_8UC1);
results[1].convertTo(mv[1], CV_8UC1);
results[2].convertTo(mv[2], CV_8UC1);
Mat dst;
merge(mv, dst);
imshow("result", dst);
imwrite("result.jpg", dst);
std::string Img_Name = "merge.jpg";
imwrite(Img_Name, dst);
Mat merge_diff = src - dst;
Img_Name = "merge_diff .jpg";
imwrite(Img_Name, merge_diff);
waitKey(0);
return 0;
}
void anisotropy_demo(Mat &image, Mat &result) {
int width = image.cols;
int height = image.rows;
// 四鄰域梯度
float n = 0, s = 0, e = 0, w = 0;
// 四鄰域係數
float nc = 0, sc = 0, ec = 0, wc = 0;
float k2 = k * k;
for (int row = 1; row < height - 1; row++) {
for (int col = 1; col < width - 1; col++) {
// gradient
n = image.at<float>(row - 1, col) - image.at<float>(row, col);
s = image.at<float>(row + 1, col) - image.at<float>(row, col);
e = image.at<float>(row, col - 1) - image.at<float>(row, col);
w = image.at<float>(row, col + 1) - image.at<float>(row, col);
nc = exp(-n * n / k2);
sc = exp(-s * s / k2);
ec = exp(-e * e / k2);
wc = exp(-w * w / k2);
result.at<float>(row, col) = image.at<float>(row, col) + lambda * (n*nc + s * sc + e * ec + w * wc);
}
}
}
鄰域濾波算法
/*
*鄰域濾波
*/
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"
#include <math.h>
#include <iostream>
using namespace cv;
using namespace std;
void sharpen(const cv::Mat &image, cv::Mat &result)
{
result.create(image.size(), image.type());
for (int j = 1; j < image.rows - 1; j++) {
const uchar* previous = //上一行
image.ptr<const uchar>(j - 1);
const uchar* current = //當前行
image.ptr<const uchar>(j);
const uchar* next = //下一行
image.ptr<const uchar>(j + 1);
uchar* output = result.ptr<uchar>(j); //輸出行
for (int i = 1; i < image.cols - 1; i++) {
*output++ = cv::saturate_cast<uchar>(
5 * current[i] - current[i - 1] - current[i + 1] - previous[i] - next[i]);
}
}
//將沒有處理到的像素設置爲0
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
int main()
{
Mat src = imread("Noise.bmp");
vector<Mat>m;
split(src, m);
Mat image = m[0];
Mat image2;
sharpen(image, image2);
std::string Img_Name = "Sharpen.bmp";
imwrite(Img_Name, image2);
Mat Sharpen_diff = abs(image2 - image);
Img_Name = "Sharpen_diff.bmp";
imwrite(Img_Name, Sharpen_diff);
cv::namedWindow("Image");
cv::imshow("Image1", image);
cv::imshow("Image2", image2);
waitKey(0);
return 0;
}
總變分濾波算法
#@file util.py
import numpy as np
import imageio
import matplotlib.pyplot as plt
import cv2
def read_image():
real = cv2.imread('src.bmp',0)
# convert the image to numpy array
real = np.array(real)
real = real.astype(int)
# add noise to the image
noisy = imnoise(real)
return (noisy, real)
#return (real, noisy)
def imnoise(l):
noise = 3
return l + noise * l.std() * np.random.random(l.shape)
def gradient_x(u):
# get the height and width of a matrix
height, width = u.shape
# create a new empty matrix u2
# intialize this matrix with all zeros
u2 = np.zeros((height, width), dtype = int)
# loop over all elements
# for i in range(height):
# for j in range(width):
# u2[i, j] = u[i, j] - u[i - 1, j]
# faster one
u2[1:height, :] = u[1:height, :] - u[0:(height - 1), :]
u2[0, :] = u[0, :] - u[height - 1, :]
return u2
def gradient_y(u):
# get the height and width of a matrix
height, width = u.shape
# create a new empty matrix u2
# intialize this matrix with all zeros
u2 = np.zeros((height, width), dtype = int)
# loop over all elements
# for i in range(height):
# for j in range(width):
# u2[i, j] = u[i, j] - u[i, j - 1]
# faster one
u2[:, 1:width] = u[:, 1:width] - u[:, 0:(width - 1)]
u2[:, 0] = u[:, 0] - u[:, width - 1]
return u2
# move the matrix upward
def up(u):
# get the height and width of a matrix
height, width = u.shape
# get a copy a u to make change
u2 = np.copy(u)
u2[0:(height - 1), :] = u[1:height, :]
u2[height - 1, :] = u[0, :]
return u2
# downward
def down(u):
# get the height and width of a matrix
height, width = u.shape
# get a copy a u to make change
u2 = np.copy(u)
u2[1:height, :] = u[0:(height - 1), :]
u2[0, :] = u[height - 1, :]
return u2
# leftward
def left(u):
# get the height and width of a matrix
height, width = u.shape
# get a copy a u to make change
u2 = np.copy(u)
u2[:, 0:(width - 1)] = u[:, 1:width]
u2[:, width - 1] = u[:, 0]
return u2
# rightward
def right(u):
# get the height and width of a matrix
height, width = u.shape
# get a copy a u to make change
u2 = np.copy(u)
u2[:, 1:width] = u[:, 0:(width - 1)]
u2[:, 0] = u[:, width - 1]
return u2
def neighbors(u):
return up(u) + down(u) + left(u) + right(u)
def shrink(u, lambd):
z = np.zeros(u.shape)
u = np.sign(u) * np.maximum(np.abs(u) - (1. / lambd), z)
return u
def norm2(u):
sq = np.square(u)
s = np.sum(sq)
return s
def gaussian_method(u, f, dx, dy, bx, by, lambd, mu):
mul1 = lambd / (mu + 4 * lambd)
mul2 = mu / (mu + 4 * lambd)
# print('gradient x: \n{}'.format(gradient_x(u)))
# print('gradient y: \n{}'.format(gradient_y(u)))
G = mul1 * (neighbors(u) + gradient_x(dx) + gradient_y(dy) -
gradient_x(bx) - gradient_y(by)) + mul2 * f
return G
# this is more like a gaussian-seidel method
# but it takes longer to execute
# we can use it as an alternative of gaussian_method above
def gaussian_method2(u, f, dx, dy, bx, by, lambd, mu):
mul1 = lambd / (mu + 4 * lambd)
mul2 = mu / (mu + 4 * lambd)
height, width = u.shape
ddx = gradient_x(dx)
ddy = gradient_y(dy)
dbx = gradient_x(bx)
dby = gradient_y(by)
for i in range(height):
for j in range(width):
if i != (height - 1) and j != (width - 1):
u[i, j] = mul1 * (u[i - 1, j] + u[i + 1, j] +
u[i, j - 1] + u[i, j + 1] +
ddx[i, j] + ddy[i, j] -
dbx[i, j] - dby[i, j]) + \
mul2 * f[i,j]
elif i == (height - 1) and j != (width - 1):
u[i, j] = mul1 * (u[i - 1, j] + u[0, j] +
u[i, j - 1] + u[i, j + 1] +
ddx[i, j] + ddy[i, j] -
dbx[i, j] - dby[i, j]) + \
mul2 * f[i,j]
elif i != (height - 1) and j == (width - 1):
u[i, j] = mul1 * (u[i - 1, j] + u[i + 1, j] +
u[i, j - 1] + u[i, 0] +
ddx[i, j] + ddy[i, j] -
dbx[i, j] - dby[i, j]) + \
mul2 * f[i,j]
else: # i == (height - 1) and j == (width - 1)
u[i, j] = mul1 * (u[i - 1, j] + u[0, j] +
u[i, j - 1] + u[i, 0] +
ddx[i, j] + ddy[i, j] -
dbx[i, j] - dby[i, j]) + \
mul2 * f[i,j]
return u
def compute_s(u, bx, by):
return np.sqrt(np.square(gradient_x(u) + bx) + np.square(gradient_y(u) + by))
#@file:main.py
import numpy as np
import imageio
from util import *
from PIL import Image
import matplotlib
def itv(noisy, real):
u = noisy
u_prev = np.zeros(u.shape)
# initializing
dx = np.zeros(u.shape)
dy = np.zeros(u.shape)
bx = np.zeros(u.shape)
by = np.zeros(u.shape)
lambd = 0.1
mu = 0.05
tol = 0.001
epsilon = 0.0001
iter = 0
# terminate condition
while np.linalg.norm(u - u_prev) / np.linalg.norm(u) > tol \
and iter < 40:
iter = iter + 1
u_prev = u
u = gaussian_method(u, noisy, dx, dy, bx, by, lambd, mu)
s = compute_s(u, bx, by)
# print(s)
dx = shrink(s, lambd) * (gradient_x(u) + bx) / (s + epsilon)
dy = shrink(s, lambd) * (gradient_y(u) + by) / (s + epsilon)
bx = bx + (gradient_x(u) - dx)
by = by + (gradient_y(u) - dy)
print('converge step ratio: {:.04f}'.format(np.linalg.norm(u - u_prev) / np.linalg.norm(u)))
# print('distance to real: {}'.format(norm2(u - real)))
return u
if __name__ == "__main__":
# read image
noisy, real = read_image()
u = itv(noisy, real)
k =real +u
im = Image.fromarray(u)
plt.imshow(u, cmap='gray')
plt.xticks([])
plt.yticks([])
matplotlib.image.imsave('name.bmp', u)
#plt.subplot(121)
#plt.imshow(u, cmap='gray')
#plt.subplot(122)
#plt.imshow(noisy, cmap='gray')
plt.show()
Python學習
讀者可以通過此鏈接購買相關視頻,或者加入我們的學習QQ羣:916372346