山东大学数字图像处理实验(六)

双边滤波

实验流程

高斯滤波:计算权重时只考虑空间位置之差

双边滤波:计算权重时同时考虑空间位置和像素颜色之差

在这里插入图片描述

流程介绍

  • 为图像加 padding。这里需要注意的是,滤波核的尺寸需要是奇数,因为一般将当前点作为滤波核的中心,如果是偶数的话就没有中心

    int padding = size / 2;
    cv::copyMakeBorder(source_image , padding_image , padding , padding , padding , padding , cv::BORDER_DEFAULT);
    
  • 将当前位置像素作为滤波核中心点,计算每个通道对应的滤波核

    • 计算滤波核一个位置的值

      db get_filterValue(int x , int y, int midRow, int midCol, int c){ // 计算当前滤波核某个位置的值
          db G_value = exp(-((x * x * 1.0) + (y * y * 1.0)) / (2.0 * sigmaD * sigmaD))
                  * exp(-pow(source_image.at<Vec3b>(midRow + x, midCol + y)[c] - source_image.at<Vec3b>(midRow,midCol)[c],2) / (2.0 * sigmaR * sigmaR));
          return G_value;
      }
      
    • 计算整个滤波核的值

      void getFilter(int midRow, int midCol, int c){ // 得到整个滤波核,(midRow,midCol)滤波核中心像素的真实行列
          db sum = 0;
          size = 6 * sigmaD - 1;
          int center = size / 2;
          for(int i = 0 ; i < size; i++)
              for(int j = 0; j < size; j++){
                  BilateralFilter[i][j] = get_filterValue(i - center, j - center, midRow, midCol, c);
                  sum += BilateralFilter[i][j];
              }
      
          for(int i = 0 ; i < size ; i++)
              for(int j = 0; j < size; j++)
                  BilateralFilter[i][j] /= sum; // 归一化
      }
      
  • 通过已经得到的滤波核,计算当前位置像素滤波后的像素值

    db get_transformedValue(int row, int col, int c){
        db sum = 0.0;
        for(int i = 0; i < size; i++)
            for(int j = 0; j < size; j++){
                sum += padding_image.at<Vec3b>(row - size / 2 + i, col - size / 2 + j)[c] * BilateralFilter[i][j];
            }
        return sum;
    }
    
  • 整个滤波流程,遍历所有像素进行上面的操作

    void transformProcess(){
        if(sigmaD == 0)
            sigmaD = 1;
        int padding = size / 2;
        cv::copyMakeBorder(source_image , padding_image , padding , padding , padding , padding , cv::BORDER_DEFAULT);
        transformed_image = Mat::zeros(source_image.size(), source_image.type());
    
        for(int i = 0 ; i < source_image.rows ; i++)//遍历所有行
            for(int j = 0 ; j < source_image.cols ; j++)//填充每一行的所有值
                for(int c = 0 ; c < 3 ; c++){
                    getFilter(i, j, c); // (i,j) 是原图像真实行列
                    transformed_image.at<Vec3b>(i,j)[c] = int(get_transformedValue(i, j, c));
                }
    }
    

结果展示

  • sigmaD=4,sigmaR=5

在这里插入图片描述

在这里插入图片描述

  • sigmaD=5,sigmaR=5

在这里插入图片描述

在这里插入图片描述

  • sigmaD=4,sigmaR=10

在这里插入图片描述

在这里插入图片描述

  • sigmaD=5,sigmaR=100

在这里插入图片描述

在这里插入图片描述

完整代码

#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include"opencv2/opencv.hpp"
#include <iostream>
#define db double
using namespace std;
using namespace cv;
int size; // 滤波核大小
db BilateralFilter[100][100];
int sigmaD, sigmaR; // 位置sigma和像素sigma
Mat source_image;
Mat padding_image;
Mat transformed_image;
Mat Gaussian_image;
Mat transformed_image3;

db get_filterValue(int x , int y, int midRow, int midCol, int c){ // 计算当前滤波核某个位置的值
    db G_value = exp(-((x * x * 1.0) + (y * y * 1.0)) / (2.0 * sigmaD * sigmaD))
            * exp(-pow(source_image.at<Vec3b>(midRow + x, midCol + y)[c] - source_image.at<Vec3b>(midRow,midCol)[c],2) / (2.0 * sigmaR * sigmaR));
    return G_value;
}

void getFilter(int midRow, int midCol, int c){ // 得到整个滤波核,(midRow,midCol)滤波核中心像素的真实行列
    db sum = 0;
    size = 6 * sigmaD - 1;
    int center = size / 2;
    for(int i = 0 ; i < size; i++)
        for(int j = 0; j < size; j++){
            BilateralFilter[i][j] = get_filterValue(i - center, j - center, midRow, midCol, c);
            sum += BilateralFilter[i][j];
        }

    for(int i = 0 ; i < size ; i++)
        for(int j = 0; j < size; j++)
            BilateralFilter[i][j] /= sum; // 归一化
}

db get_transformedValue(int row, int col, int c){
    db sum = 0.0;
    for(int i = 0; i < size; i++)
        for(int j = 0; j < size; j++){
            sum += padding_image.at<Vec3b>(row - size / 2 + i, col - size / 2 + j)[c] * BilateralFilter[i][j];
        }
    return sum;
}

void transformProcess(){
    if(sigmaD == 0)
        sigmaD = 1;
    int padding = size / 2;
    cv::copyMakeBorder(source_image , padding_image , padding , padding , padding , padding , cv::BORDER_DEFAULT);
    transformed_image = Mat::zeros(source_image.size(), source_image.type());

    for(int i = 0 ; i < source_image.rows ; i++)//遍历所有行
        for(int j = 0 ; j < source_image.cols ; j++)//填充每一行的所有值
            for(int c = 0 ; c < 3 ; c++){
                getFilter(i, j, c); // (i,j) 是原图像真实行列
                transformed_image.at<Vec3b>(i,j)[c] = int(get_transformedValue(i, j, c));
            }
}

int main()
{
    source_image = imread("D:\\cLion\\project\\queban.png");
    sigmaD = 5;
    sigmaR = 5;

    cv::GaussianBlur(source_image, Gaussian_image, Size(size,size) ,sigmaD , sigmaD , cv::BORDER_DEFAULT);
    int t1_s = getTickCount(); // 开始时间1
    cv::bilateralFilter(source_image , transformed_image3 , size ,sigmaR , sigmaD , cv::BORDER_DEFAULT);
    int t1_e = getTickCount(); // 开始时间1
    cout << "bilateralFilter time:" << (t1_e - t1_s) / getTickFrequency() << endl;

    int t2_s = getTickCount(); // 开始时间2
    transformProcess();
    int t2_e = getTickCount(); // 开始时间2
    cout << "selfBilateralFilter time:" << (t2_e - t2_s) / getTickFrequency() << endl;

    imshow("SelfBilateral Image", transformed_image);
    imshow("Gaussian Image", Gaussian_image);
    imshow("Bilateral Window", transformed_image3);
    imshow("Original Image" , source_image);
    waitKey(0);
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长命百岁️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值