最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++?OpenCV實(shí)現(xiàn)boxfilter方框?yàn)V波的方法詳解

 更新時(shí)間:2022年10月13日 11:34:34   作者:拜陽  
box?filter的作用很簡單,即對(duì)局部區(qū)域求平均,并把值賦給某個(gè)點(diǎn),一般我們賦給區(qū)域中心。本文將用C++實(shí)現(xiàn)boxfilter方框?yàn)V波,需要的可以了解一下

box filter簡單解釋

box filter的作用很簡單,即對(duì)局部區(qū)域求平均,并把值賦給某個(gè)點(diǎn),一般我們賦給區(qū)域中心。用公式表達(dá)如下:

其中patch是以(row,col)為中心的一塊區(qū)域。

為了跟后面的公式及程序?qū)?yīng),我們做如下定義:

  • r:patch的半徑。半徑在寬高方向可以不相等,但是本文目的不在于對(duì)半徑的處理,所以簡單起見設(shè)為相等。
  • n:patch的長度,等于(2∗r+1)。
  • (rows,cols):圖像的尺寸,行數(shù)和列數(shù)。
  • (row,col):對(duì)完整圖像的索引。
  • (i,j):對(duì)圖像patch的索引
  • k:對(duì)通道的索引。

1. 暴力實(shí)現(xiàn)——四循環(huán)

外層兩個(gè)循環(huán)是關(guān)于完整圖像(row,col)的循環(huán),內(nèi)層兩個(gè)循環(huán)是關(guān)于圖像patch(i,j)的循環(huán)。

注意:如果圖像是多通道的話實(shí)際上還有一個(gè)通常維度的循環(huán),但是通道數(shù)不是本文優(yōu)化的重心,所以本文不再贅述這個(gè)因素,后文也不再提,并且在計(jì)算量的估計(jì)中也會(huì)把這個(gè)因素省略掉。

這個(gè)實(shí)現(xiàn)比較簡單,需要做的計(jì)算有:

  • rows∗cols∗n∗n次加法,內(nèi)層循環(huán)的計(jì)算量o(n2),非常大。
  • rows∗cols次除法:除法為了求平均

2. 行列分離

patch的平均可以進(jìn)行行列分離,也就是先對(duì)行方向做平均,并緩存結(jié)果,再對(duì)緩存的結(jié)果做列方向的平均。以公式的形式表達(dá)如下:

舉個(gè)例子展開寫會(huì)容易理解,比如3*3的patch,共9個(gè)數(shù):

這種方式的計(jì)算量:

  • 2∗rows∗cols∗n次加法,相對(duì)于暴力版本,內(nèi)層循環(huán)降低了一個(gè)數(shù)量級(jí)的算力,變成o(n)了
  • 2∗rows∗cols次除法

3. 行列分離優(yōu)化版

第二種實(shí)現(xiàn)可以對(duì)求和做進(jìn)一步優(yōu)化。在單個(gè)維度做求和時(shí),可以對(duì)當(dāng)前一維patch的和做一個(gè)緩存,當(dāng)中心點(diǎn)移動(dòng)后,減去彈出像素的值,加上新增像素的值,這樣就避免了重復(fù)性求和操作。

這種方案需要對(duì)patch的和做一個(gè)初始化和緩存,該方案的計(jì)算量為:

  • 2∗rows∗cols次減法,2∗rows∗cols次加法,內(nèi)層循環(huán)的計(jì)算變?yōu)閛(1)了,進(jìn)一步降低了一個(gè)數(shù)量級(jí)算力。
  • 2∗rows∗cols次除法

代碼

上面做計(jì)算量估計(jì)的時(shí)候沒有考慮邊界條件,在具體代碼實(shí)現(xiàn)的時(shí)候需要仔細(xì)處理邊界,防止數(shù)組訪問越界。

代碼同時(shí)跟opencv做了個(gè)效果和性能的對(duì)比,第三種方式雖然仍然比opencv慢,但性能基本處于同一量級(jí)了,opencv可能還做了一些其他跟算法無關(guān)的優(yōu)化,比如指令集、并行化之類的。

注意:下面為了方便比較,opencv boxFilter的邊界處理參數(shù)選擇BORDER_CONSTANT。即使是邊界處patch不滿覆蓋的情況下,opencv仍然除以n2 ,也就是說除以的數(shù)字有點(diǎn)大了,所以邊界會(huì)逐漸發(fā)黑,特別是kernel_size(對(duì)應(yīng)于radius)比較大時(shí)候視覺效果更明顯。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <string>
#include <ctime>


using namespace std;
using namespace cv;


Mat BoxFilter_1(const Mat& image, int radius);
Mat BoxFilter_2(const Mat& image, int radius);
Mat BoxFilter_3(const Mat& image, int radius);


int main()
{
    clock_t time_beg;
    clock_t time_end;

    Mat image = imread("lena_std.bmp", IMREAD_UNCHANGED);
    image.convertTo(image, CV_32FC3);
    image /= 255.0f;

    int radius = 9;
    int ksize = radius * 2 + 1;

    Mat image_box_filter_cv;
    time_beg = clock();
    boxFilter(image, image_box_filter_cv, -1, Size(ksize, ksize), Point(-1, -1), true, BORDER_CONSTANT);
    time_end = clock();
    cout << "box-filter-cv time cost: " << time_end - time_beg << endl;

    Mat image_box_filter_1 = BoxFilter_1(image, radius);
    Mat image_box_filter_2 = BoxFilter_2(image, radius);
    Mat image_box_filter_3 = BoxFilter_3(image, radius);

    

    namedWindow("original_image", 1);
    imshow("original_image", image);
    namedWindow("cv_box_filter", 1);
    imshow("cv_box_filter", image_box_filter_cv);
    namedWindow("box_filter-1", 1);
    imshow("box_filter-1", image_box_filter_1);
    namedWindow("box_filter-2", 1);
    imshow("box_filter-2", image_box_filter_2);
    namedWindow("box_filter-3", 1);
    imshow("box_filter-3", image_box_filter_3);

    Mat diff;
    cv::absdiff(image_box_filter_2, image_box_filter_3, diff);
    namedWindow("diff", 1);
    imshow("diff", 50 * diff);

    waitKey(0);
    destroyAllWindows();

    return 0;
}


Mat BoxFilter_1(const Mat& image, int radius)
{
    int cols = image.cols;
    int rows = image.rows;
    int channels = image.channels();
    int row_bound = rows - 1;
    int col_bound = cols - 1;
    Mat result(rows, cols, CV_32FC3);

    clock_t time_beg;
    clock_t time_end;
    time_beg = clock();

    for (int row = 0; row < rows; ++row) {
        int row_beg = max(row - radius, 0);
        int row_end = min(row + radius, row_bound);
        for (int col = 0; col < cols; ++col) {
            int col_beg = max(col - radius, 0);
            int col_end = min(col + radius, col_bound);

            vector<float> sums(channels, 0.0f);
            int count = 0;
            for (int i = row_beg; i <= row_end; ++i) {
                for (int j = col_beg; j <= col_end; ++j) {
                    count++;
                    for (int k = 0; k < channels; ++k) {
                        sums[k] += image.at<Vec3f>(i, j)[k];
                    }
                }
            }

            for (int k = 0; k < channels; ++k) {
                result.at<Vec3f>(row, col)[k] = sums[k] / static_cast<float>(count);

                // opencv BORDER_CONSTANT:
                /*float COUNT = (float)(2 * radius + 1) * (2 * radius + 1);
                result.at<Vec3f>(row, col)[k] = sums[k] / COUNT;*/
            }
        }
    }
    result = cv::max(cv::min(result, 1.0), 0.0);
    time_end = clock();
    cout << "box-filter-1 time cost: " << time_end - time_beg << endl;

    return result;
}


Mat BoxFilter_2(const Mat& image, int radius)
{
    int cols = image.cols;
    int rows = image.rows;
    int channels = image.channels();
    int row_bound = rows - 1;
    int col_bound = cols - 1;
    Mat result(rows, cols, CV_32FC3);

    clock_t time_beg;
    clock_t time_end;
    time_beg = clock();

    // compute mean for row-wise
    Mat row_result(rows, cols, CV_32FC3);
    for (int row = 0; row < rows; ++row) {
        for (int col = 0; col < cols; ++col) {
            int col_beg = max(col - radius, 0);
            int col_end = min(col + radius, col_bound);

            vector<float> sums(channels, 0.0f);
            int count = 0;
            for (int j = col_beg; j <= col_end; ++j) {
                count++;
                for (int k = 0; k < channels; ++k) {
                    sums[k] += image.at<Vec3f>(row, j)[k];
                }
            }
            for (int k = 0; k < channels; ++k) {
                row_result.at<Vec3f>(row, col)[k] = sums[k] / static_cast<float>(count);
            }
        }
    }

    // compute mean for column-wise
    for (int col = 0; col < cols; ++col) {
        for (int row = 0; row < rows; ++row) {
            int row_beg = max(row - radius, 0);
            int row_end = min(row + radius, row_bound);

            vector<float> sums(channels, 0.0f);
            int count = 0;
            for (int i = row_beg; i <= row_end; ++i) {
                count++;
                for (int k = 0; k < channels; ++k) {
                    sums[k] += row_result.at<Vec3f>(i, col)[k];
                }
            }
            for (int k = 0; k < channels; ++k) {
                result.at<Vec3f>(row, col)[k] = sums[k] / static_cast<float>(count);
            }
        }
    }
    result = cv::max(cv::min(result, 1.0), 0.0);
    time_end = clock();
    cout << "box-filter-2 time cost: " << time_end - time_beg << endl;

    return result;
}


Mat BoxFilter_3(const Mat& image, int radius)
{
    int cols = image.cols;
    int rows = image.rows;
    int channels = image.channels();
    Mat result(rows, cols, CV_32FC3);

    clock_t time_beg;
    clock_t time_end;
    time_beg = clock();

    // compute mean for row-wise
    Mat row_result(rows, cols, CV_32FC3);
    for (int row = 0; row < rows; ++row) {
        // initialize sums for row
        vector<float> sums(channels, 0.0f);
        int count = 0;
        for (int col = 0; col < radius; ++col) {
            if (col < cols) {
                count++;
                for (int k = 0; k < channels; ++k) {
                    sums[k] += image.at<Vec3f>(row, col)[k];
                }
            }
        }
        // process row
        for (int col = 0; col < cols; ++col) {
            int left = col - radius - 1;
            int right = col + radius;
            if (left >= 0) {
                count--;
                for (int k = 0; k < channels; ++k) {
                    sums[k] -= image.at<Vec3f>(row, left)[k];
                }
            }
            if (right < cols) {
                count++;
                for (int k = 0; k < channels; ++k) {
                    sums[k] += image.at<Vec3f>(row, right)[k];
                }
            }
            for (int k = 0; k < channels; ++k) {
                row_result.at<Vec3f>(row, col)[k] = sums[k] / static_cast<float>(count);
            }
        }
    }

    // compute mean for column-wise
    for (int col = 0; col < cols; ++col) {
        // initialize sums for column
        vector<float> sums(channels, 0.0f);
        int count = 0;
        for (int row = 0; row < radius; ++row) {
            if (row < rows) {
                count++;
                for (int k = 0; k < channels; ++k) {
                    sums[k] += row_result.at<Vec3f>(row, col)[k];
                }
            }
        }
        // process column
        for (int row = 0; row < rows; ++row) {
            int up = row - radius - 1;
            int down = row + radius;
            if (up >= 0) {
                count--;
                for (int k = 0; k < channels; ++k) {
                    sums[k] -= row_result.at<Vec3f>(up, col)[k];
                }
            }
            if (down < rows) {
                count++;
                for (int k = 0; k < channels; ++k) {
                    sums[k] += row_result.at<Vec3f>(down, col)[k];
                }
            }
            for (int k = 0; k < channels; ++k) {
                result.at<Vec3f>(row, col)[k] = sums[k] / static_cast<float>(count);
            }
        }
    }
    result = cv::max(cv::min(result, 1.0), 0.0);
    time_end = clock();
    cout << "box-filter-3 time cost: " << time_end - time_beg << endl;

    return result;
}

以上就是C++ OpenCV實(shí)現(xiàn)boxfilter方框?yàn)V波的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于C++ OpenCV boxfilter方框?yàn)V波的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++深入刨析優(yōu)先級(jí)隊(duì)列priority_queue的使用

    C++深入刨析優(yōu)先級(jí)隊(duì)列priority_queue的使用

    最近我學(xué)習(xí)了C++中的STL庫中的優(yōu)先級(jí)隊(duì)列(priority_queue)容器適配器,對(duì)于優(yōu)先級(jí)隊(duì)列,我們不僅要會(huì)使用常用的函數(shù)接口,我們還有明白這些接口在其底層是如何實(shí)現(xiàn)的
    2022-08-08
  • C語言實(shí)現(xiàn)單詞小幫手

    C語言實(shí)現(xiàn)單詞小幫手

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)單詞小幫手,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C++實(shí)現(xiàn)Armadillo庫與OpenCV庫之間的數(shù)據(jù)格式轉(zhuǎn)換

    C++實(shí)現(xiàn)Armadillo庫與OpenCV庫之間的數(shù)據(jù)格式轉(zhuǎn)換

    在C++領(lǐng)域,數(shù)據(jù)格式轉(zhuǎn)換是常見且關(guān)鍵的任務(wù),尤其是在使用多個(gè)不同的庫進(jìn)行復(fù)雜的數(shù)據(jù)處理時(shí),Armadillo和OpenCV是兩個(gè)在科學(xué)計(jì)算和計(jì)算機(jī)視覺領(lǐng)域非常受歡迎的庫,下面我們將詳細(xì)探討如何在C++中實(shí)現(xiàn)Armadillo庫與OpenCV庫之間的數(shù)據(jù)格式轉(zhuǎn)換,需要的朋友可以參考下
    2025-03-03
  • c++入門必學(xué)算法之快速冪思想及實(shí)現(xiàn)

    c++入門必學(xué)算法之快速冪思想及實(shí)現(xiàn)

    快速冪相較于普通的冪,具有占用空間少,效率更高等優(yōu)點(diǎn),全面碾壓普通的冪,下面這篇文章主要給大家介紹了關(guān)于c++入門必學(xué)算法之快速冪思想及實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • C++實(shí)現(xiàn)LeetCode(142.單鏈表中的環(huán)之二)

    C++實(shí)現(xiàn)LeetCode(142.單鏈表中的環(huán)之二)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(142.單鏈表中的環(huán)之二),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Qt學(xué)習(xí)之容器類的使用教程詳解

    Qt學(xué)習(xí)之容器類的使用教程詳解

    Qt提供了多個(gè)基于模板的容器類,這些類可以用于存儲(chǔ)指定類型的數(shù)據(jù)項(xiàng)。本文主要介紹了Qt常用容器類的使用,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-12-12
  • C++數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)

    C++數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)

    線性表的鏈?zhǔn)酱鎯?chǔ)又稱為單鏈表,它是指通過一組任意的存儲(chǔ)單元來存儲(chǔ)線性表中的數(shù)據(jù)元素。本文將用C++實(shí)現(xiàn)單鏈表,需要的可以參考一下
    2022-05-05
  • C++實(shí)現(xiàn)打印虛函數(shù)表的地址

    C++實(shí)現(xiàn)打印虛函數(shù)表的地址

    對(duì)于存在虛函數(shù)的類,如何打印虛函數(shù)表的地址,并利用這個(gè)虛函數(shù)表的地址來執(zhí)行該類中的虛函數(shù)呢,下面小編就來和大家一起簡單聊聊吧
    2023-07-07
  • C語言新手入門之格式化輸出和變量類型

    C語言新手入門之格式化輸出和變量類型

    這篇文章主要給大家介紹了關(guān)于C語言中格式化輸出和變量類型的相關(guān)資料,文中的教程非常適合新手零基礎(chǔ)的朋友們參考學(xué)習(xí),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • C語言實(shí)現(xiàn)個(gè)稅計(jì)算器

    C語言實(shí)現(xiàn)個(gè)稅計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)個(gè)稅計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評(píng)論

靖远县| 牟定县| 涟水县| 九寨沟县| 德安县| 肥城市| 南和县| 灌南县| 辽宁省| 米林县| 芜湖县| 南通市| 安陆市| 巴彦淖尔市| 浑源县| 镇沅| 宕昌县| 长垣县| 瑞金市| 都江堰市| 大安市| 武城县| 闻喜县| 沂水县| 望城县| 永仁县| 阿拉善盟| 兴义市| 循化| 北安市| 武山县| 南宫市| 平潭县| 武川县| 太谷县| 大丰市| 新绛县| 绥中县| 屏南县| 横峰县| 上蔡县|