在opencv中,将图像的每个通道除以权重图像
Divide every channel of image by weight image in opencv
我有一个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通道图像?
我测试了你的方法:
- split -divide - merge, @panmari
- 线性化矩阵,并应用元素划分@Miki
- 线性化矩阵,并应用元素明智的除法(带指针)@Miki和乘法而不是除法@Micka
- 使
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;
}
相关文章:
- 在RAW图像中提取RGB通道值的库或方法
- 有没有办法使用 glDrawPixel 渲染单通道灰度图像?
- 与 alpha 通道的图像重叠在 QT 上不起作用
- 带有多通道内核的图像卷积
- 在未填充为 4 字节的 3 通道上进行图像重采样
- 我可以将从相机获取的单通道图像输出到 winAppi 窗口中吗?
- 想要从图像获取绿色 RGB 通道时出错
- 使用 cuda 将通道与 RGBA 图像分离(无法显示完整图像)
- OpenCV:将 3 通道图像转换为 4 通道图像
- 将 16 位单通道图像写入 Tiff
- 如何判断万智牌::图像是否具有阿尔法通道
- 在 CToolBar (MFC) 上具有 Alpha 通道的 32 位图像
- 图像深度和通道之间的差异
- 我可以在3个通道的图像中只平滑1个通道吗
- 将拜耳图像分离到彩色通道c++
- 叠加在4通道图像上
- 在Blackberry 10 Cascades中,有一种方法可以使用图像掩码或alpha通道更改Blackberry C
- OpenGL将原始图像转换为红色通道
- 如何在opencv中创建和初始化带有alpha通道的图像
- ImageMagick c++ API获取图像通道