OpenCV學習指南(四)圖像濾波算法

前言

  本文將是一篇爲圖像處理的初學者準備的濾波算法的入門文章。理論在前,代碼在後。

算法

高斯濾波算法

  一維高斯函數
G(x)=12πex22σ2 G(x) = \frac{1}{\sqrt{2\pi }}e^{-\frac{x^{2}}{2\sigma ^{2}}}
  在圖像處理中,選定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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章