计算机视觉----实验E4:图像滤波

实验内容

实验4.1 高斯滤波

实现图像的高斯滤波。

  • 通过参数sigma来控制平滑程度。
  • 滤波窗口大小取为[6*sigma-1],[.]表示取整。
  • 利用二维高斯函数的行列可分离性进行加速。

实验过程

1,计算卷积核大小。

 卷积核大小公式为[6*sigma-1],[.]表示取整。如果大小为偶数,则将大小加一。并计算进行卷积需要随原图扩充的边缘大小,大小为:卷积核大小整除 2。

int border_size = (int)(6 * sigma - 1) / 2;
2,计算一维的高斯滤波。

 公式为 G ( x ) = e − x 2 2 σ 2 G(x)=e^{-\frac{x^2}{2\sigma^2}} G(x)=e2σ2x2 b o r d e r _ s i z e border\_size border_size滤波窗口的中心。进行归一化。

double *kernel = new double[(long long)border_size * 2 + 1];
double sum = 1;
kernel[border_size] = 1;
for (int i = 1; i <= border_size; i++)
{
    double value = exp(-(i * i) / (2 * sigma * sigma));
    kernel[border_size - i] = value;
    kernel[border_size + i] = value;
    sum += 2 * value;
}
for (int i = 0; i < border_size * 2 + 1; i++)
{
    kernel[i] /= sum; // 归一化
}
3,对原图进行镜像填充。

b o r d e r e d _ i m g bordered\_img bordered_img的边长比原图多 2 个边缘宽,进行一次卷积后得到图像 t e m p temp temp,它的行数和填充后图相同,列数和原图相同。

Mat bordered_img;
copyMakeBorder(input, bordered_img, border_size, border_size, border_size, border_size,
               BORDER_REFLECT_101);
// 进行对列的卷积后图像
Mat temp = Mat(bordered_img.rows, input.cols, input.type());
4,进行对列的一维高斯滤波卷积。

 直接访问图像的像素,不使用 at 方法。每个索引的格式为[通道总数 ∗ 行号 ∗ 总列数 + 列号 + 通道号]。对行卷积也类似。

for (int i = 0; i < bordered_img.rows; i++)
{
    for (int j = border_size; j < bordered_img.cols - border_size; j++)
    {
        for (int c = 0; c < ch; c++)
        {
            temp.data[ch * (i * temp.cols + j - border_size) + c] = 0;
            for (int k = j - border_size; k <= j + border_size; k++)
            {
                temp.data[ch * (i * temp.cols + j - border_size) + c] +=
                    bordered_img.data[ch * (i * bordered_img.cols + k) + c] *
                    kernel[k - j + border_size];
            }
        }
    }
}
5,添加滑块.

 为了方便调整 sigma,添加滑块, 10 s i g m a 10sigma 10sigma s i g m a sigma sigma的十倍(因为滑块的参数是整数,使用 10 倍 sigma 使得 sigma 可以调整到一位小数)。

createTrackbar("10 * sigma", "image", &sigma10, 100, callBack, 0);
static void callBack(int, void *)
{
    gaussianBlur(input_img, output_img, (double)sigma10 / 10);
    imshow("image", output_img);
}
6,效果。

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

附源代码

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

void gaussianBlur(const Mat& input, Mat& output, double sigma) {

	int border_size = (int)(6 * sigma - 1)/2; //需要扩充的边缘宽度
	if (border_size < 1) {
		output = input;
		return;
	}

	//计算卷积核
	double* kernel = new double[(long long)border_size * 2 + 1];
	double sum = 1;
	kernel[border_size] = 1;
	for (int i = 1; i <= border_size; i++) {
		double value = exp(-(i * i) / (2 * sigma * sigma));
		kernel[border_size - i] = value;
		kernel[border_size + i] = value;
		sum += 2 * value;
	}
	for (int i = 0; i < border_size * 2 + 1; i++) {
		kernel[i] /= sum; //归一化
	}

	//填充后图像
	Mat bordered_img;
	copyMakeBorder(input, bordered_img, border_size, border_size, border_size, border_size, BORDER_REFLECT_101);
	//进行对列的卷积后图像
	Mat temp = Mat(bordered_img.rows, input.cols,input.type());

	int ch = input.channels();//图像通道数

	//对列卷积
	for (int i = 0; i < bordered_img.rows; i++) {
		for (int j = border_size; j < bordered_img.cols - border_size; j++) {
			for (int c = 0; c < ch; c++) {
				temp.data[ch * (i * temp.cols + j - border_size) + c] = 0;
				for (int k = j - border_size; k <= j + border_size; k++) {
					temp.data[ch * (i * temp.cols + j - border_size) + c] +=
						bordered_img.data[ch * (i * bordered_img.cols + k) + c] * kernel[k - j + border_size];
				}
			}
		}
	}

	//对行卷积
	for (int j = 0; j < temp.cols; j++) {
		for (int i = border_size; i < temp.rows - border_size; i++) 
			for (int c = 0; c < ch; c++) {
				output.data[ch * ((i - border_size) * output.cols + j) + c] = 0;
				for (int k = i - border_size; k <= i + border_size; k++) {
					output.data[ch * ((i - border_size) * output.cols + j) + c] +=
						temp.data[ch * (k * temp.cols + j) + c] * kernel[k - i + border_size];
				}
			}
		}
	}

void callBack(int, void*);
Mat input_img;
Mat output_img;
int sigma10=10; //十倍sigma
int main() {
	//图像加载
	input_img = imread("D:/Opencv/opencv-03/01.jpg");
	output_img = Mat(input_img.size(), input_img.type());
	namedWindow("image");
	//imshow("image", input_img);
	createTrackbar("10 * sigma", "image", &sigma10, 100, callBack, 0);
	waitKey();
	return 0;
}

static void callBack(int, void*)
{
	gaussianBlur(input_img, output_img, (double)sigma10 / 10);
	imshow("image", output_img);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值