在opencv中,将图像的每个通道除以权重图像

Divide every channel of image by weight image in opencv

本文关键字:图像 通道 权重 opencv      更新时间:2023-10-16

我有一个3通道的图像,基本上是加权补丁的组合。在将所有贡献添加到我的sum图像之后,我想将其除以权重。现在,我使用以下代码:

Mat weighted_sum, weights;
// for (Patch p: patches)
//   weighted_sum[loc_p] += w * p
//   weights[loc_p] += w;
vector<Mat> channels(3);
split(weighted_sum, channels);
for (Mat chan: channels) {
    divide(chan, weights, chan);
}
merge(channels, reconstructed);

是否有更有效的解决方案将图像的所有3个通道除以相同的1通道图像?

我测试了你的方法:

  1. split -divide - merge, @panmari
  2. 线性化矩阵,并应用元素划分@Miki
  3. 线性化矩阵,并应用元素明智的除法(带指针)@Miki和乘法而不是除法@Micka
  4. 使weights为3通道矩阵,并将divide应用于整个矩阵@Micka。

结果(单位:ms):

Size            Method1         Metdhod2        Method3         Method4
[2 x 2]         0.0359212       0.00183271      0.000733086     1.77333
[10 x 10]       0.0117294       0.00293234      0.00109963      0.0051316
[100 x 100]     0.422624        0.241918        0.0751413       0.319625
[1000 x 1000]   20.757          20.3673         7.28284         18.4389
[2000 x 2000]   83.6238         82.942          28.4353         74.2132
指出

  • 我的方法工作更快,但加速与矩阵的大小有关。
  • 方法3(带指针)是最快的
  • 方法2和方法3修改原矩阵。如果你不需要改变原始矩阵,你需要做一个深拷贝(clone(),见下面的代码注释行)。对于原始矩阵的深度拷贝,这两种方法都较慢,但方法3仍然是最快的。
  • 方法4不能与double矩阵一起工作,因为cvtColor不接受double)。
  • 方法4的预分配矩阵只是一个小小的改进。
  • 用编译器msvc12 (Visual Studio 2013)测试。在gcc 4.8中,Method 4似乎更快。
下面是我使用的代码。我正在测试浮点矩阵,但它很容易移植到其他类型。
    #include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;

int main()
{
    vector<Size> sizes{Size(2,2), Size(10,10), Size(100,100), Size(1000,1000), Size(2000,2000)};
    cout << "Size ttMethod1 tMetdhod2 tMethod3 tMethod4" << endl;
    for (int is = 0; is < sizes.size(); ++is)
    {
        Size sz = sizes[is];
        Mat3f weighted_sum(sz);
        randu(weighted_sum, 0, 200);
        Mat1f weights(sz);
        randu(weights, 0, 10);
        Mat3f ws1 = weighted_sum.clone();
        Mat3f ws2 = weighted_sum.clone();
        Mat3f ws3 = weighted_sum.clone();
        Mat3f ws4 = weighted_sum.clone();

        // Method 1 @parmari
        double tic1 = double(getTickCount());
        Mat3f rec1;
        vector<Mat> channels(3);
        split(ws1, channels);
        for (Mat chan : channels) {
            divide(chan, weights, chan);
        }
        merge(channels, rec1);
        double toc1 = (double(getTickCount() - tic1)) * 1000. / getTickFrequency();
        // Method 2 @Miki
        double tic2 = double(getTickCount());
        Mat3f rec2 = ws2.reshape(3, 1);
        //Mat3f rec2 = ws2.reshape(3, 1).clone(); // To not override original image
        Mat1f ww2 = weights.reshape(1, 1);
        for (int i = 0; i < rec2.cols; ++i)
        {
            double w = ww2(0, i);
            Vec3f& v = rec2(0, i);
            v[0] /= w;
            v[1] /= w;
            v[2] /= w;
        }
        rec2 = rec2.reshape(3, ws2.rows);
        double toc2 = (double(getTickCount() - tic2)) * 1000. / getTickFrequency();

        // Method 3 @Miki (+ @Micka)
        double tic3 = double(getTickCount());
        Mat3f rec3 = ws3.reshape(3, 1);
        //Mat3f rec3 = ws3.reshape(3, 1).clone(); // To not override original image
        Mat1f ww3 = weights.reshape(1, 1);
        Vec3f* prec3 = rec3.ptr<Vec3f>(0);
        float* pww = ww3.ptr<float>(0);
        for (int i = 0; i < rec3.cols; ++i)
        {
            float scale = 1. / (*pww);
            (*prec3)[0] *= scale;
            (*prec3)[1] *= scale;
            (*prec3)[2] *= scale;
            ++prec3; ++pww;
        }
        rec3 = rec3.reshape(3, ws3.rows);
        double toc3 = (double(getTickCount() - tic3)) * 1000. / getTickFrequency();

        // Method 4 @Micka
        double tic4 = double(getTickCount());
        Mat3f rec4;
        Mat3f w3ch4;
        cvtColor(weights, w3ch4, COLOR_GRAY2BGR);
        divide(ws4, w3ch4, rec4);
        double toc4 = (double(getTickCount() - tic4)) * 1000. / getTickFrequency();
        cout << sz << " t" << toc1 << " t" << toc2 << " t" << toc3 << " t" << toc4 <<  endl;
    }
    getchar();
    return 0;
}