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


    1.快速均值滤波

    1.1.实验过程中遇到的问题和解决方法

    • 问题一:

      • 问题:在使用积分图求快速均值滤波的时候,左上角的坐标应该是滤波核左上角位置x , y坐标都减去1。没减1导致图像有彩色边缘
      • 解决:如问题所述
    • 问题二:

      • 问题:滤波核的长度应该是奇数,因为计算一个位置的像素时,通常考虑其位于滤波核的中心

      • 解决:

        if(windowSize % 2 == 0) windowSize += 1;
        
        • 1

    2.结论分析与体会

    2.1.流程介绍

    代码写法有意避免if 的使用,这样运行速度快一点

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

      if(windowSize % 2 == 0) windowSize += 1;
      Mat padding_image;
      int padding = windowSize / 2;
      cv::copyMakeBorder(source_image , padding_image , padding , padding , padding , padding , cv::BORDER_DEFAULT);
      
      • 1
      • 2
      • 3
      • 4
    • 计算积分图。需要注意的是,需要在加了 padding 之后的图像上计算积分图。因为计算的时候使用了前缀和,因此保留了一个守卫节点,积分图索引从 1 开始存储。

    在这里插入图片描述

    在这里插入图片描述

    for(int i = 1 ; i <= padding_image.rows ; i++){ // 计算并保存积分图在 sum2d 中,因为使用前缀和,因此保留一个守卫节点,这里从1开始存储
            init();
            for(int j = 1 ; j <= padding_image.cols ; j++){
                for(int c = 0 ; c < 3 ; c++){
                    sum2d[i][j][c] = 0;
                    sum_row[c] += padding_image.at(i - 1 , j - 1)[c];//计算当前行的sum
                    sum2d[i][j][c] += sum2d[i - 1][j][c] + sum_row[c];//从1开始存,否则i-1越界
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 均值滤波。通过遍历原图,将原图像的每个像素点都作为滤波核的中心,计算滤波核内像素的平均值来代替当前像素的像素值。需要注意的是,积分图是在padding后的图像上计算的,所以原图像的 [x,y] 像素对应的是积分图中的 [x+padding,y+padding]像素。因此,需要将所有坐标都加上 padding

    在这里插入图片描述

    db calculate(int x , int y , int padding , int c){
        int Z = (2*padding + 1) * (2*padding + 1); // 窗口内像素个数
        ll temp = sum2d[x + 2 * padding + 1][y + 2 * padding + 1][c] + sum2d[x][y][c] // sum是在padding后图像上计算的,因此原图的索引在sum上需要加上一个padding
                - sum2d[x + 2 * padding + 1][y][c] - sum2d[x][y + 2 * padding + 1][c]; // 窗口内的和
        return (temp * 1.0) / (Z * 1.0); // 计算均值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2.结果展示

    本次实验算法计算积分图的过程中,又开了一个前缀和数组,用来计算当前行的当前位置及之前的数值和

        for(int i = 1 ; i <= padding_image.rows ; i++){
            init();
            for(int j = 1 ; j <= padding_image.cols ; j++){
                for(int c = 0 ; c < 3 ; c++){
                    sum2d[i][j][c] = 0;
                    sum_row[c] += padding_image.at(i - 1 , j - 1)[c];//计算当前行的sum
                    sum2d[i][j][c] += sum2d[i - 1][j][c] + sum_row[c];
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    左图为原始图像,中间的图为算法实现的变换图像,右边的图为Opencv API 实现的变换图像

    • Window Size = 1

    在这里插入图片描述

    在这里插入图片描述

    • Window Size = 9

    在这里插入图片描述

    在这里插入图片描述

    • Window Size = 20

    在这里插入图片描述

    在这里插入图片描述

    2.3.运行时间分析

    • boxFilter() 算法利用了加法的行列可分离行,复杂度为 windowSize * Width * Height

    在这里插入图片描述

    紫色的框为卷积核大小,往右平推,算每一列的和(每次只需要多算一列)。下面的红色点为算出的结果,然后在对红色点求和,得到总的和。

    算完之后直接找就行了,不用经过额外运算

    • 积分图的计算过程

    在这里插入图片描述

    S ( u , v ) = S ( u , v − 1 ) + sum ⁡ ( I [ 1 : u , v ] ) S(u, v)=S(u, v-1)+\operatorname{sum}(I[1: u, v]) S(u,v)=S(u,v1)+sum(I[1:u,v])

    这里可以看到,积分图的加法除了对数据本身求和之外,还要加上前一次的值,分析一下计算紫色框内的值要进行多少次加法

    在这里插入图片描述

    假如是一个 5 * 5 的框,需要计算 5 * 5 + 5 * 5 - 1 = 49 次。或者是 50次

    boxFilter需要计算 5 * 5 + 4 = 29次。基本上为积分图的一半。

    而且在计算完和之后,积分图还要利用以下公式来求解框内的数据和,boxFilter则是可以直接访问,因为boxFilter上一步的求和结果就是框内数据和。所以积分图这里又比boxFilter多进行运算。所以boxFilter更快

    在这里插入图片描述

    源码地址:Computer-Vision/3.2.cpp at main · SDU-NSY/Computer-Vision (github.com)

  • 相关阅读:
    GBase 8s静默安装
    带头双向循环链表的实现(C语言)
    【C++】内存分区模型
    java计算机毕业设计医院出入院管理系统源程序+mysql+系统+lw文档+远程调试
    【java爬虫】爬虫获取某交易所公司半年报全量数据
    Elastic:使用 Grafana 监视 Elasticsearch
    华为设备流量抑制及风暴控制配置命令
    php预约系统源码 网上预约小程序开发源码 整套系统搭建让在线预约更便捷
    leetcode59. 螺旋矩阵 II
    Django模版层
  • 原文地址:https://blog.csdn.net/qq_52852138/article/details/127454985