访问OpenCV Mat元素时确定模板类型

mpe*_*kov 6 c++ opencv iterator image-processing

我正在使用以下代码为图像添加一些噪声(直接来自OpenCV参考,第449页 - 解释cv::Mat::begin):

void
simulate_noise(Mat const &in, double stddev, Mat &out)
{
    cv::Size s = in.size();
    vector<double> noise = generate_noise(s.width*s.height, stddev);

    typedef cv::Vec<unsigned char, 3> V4;
    cv::MatConstIterator_<V4> in_itr = in.begin<V4>();
    cv::MatConstIterator_<V4> in_end = in.end<V4>();
    cv::MatIterator_<V4> out_itr = out.begin<V4>();
    cv::MatIterator_<V4> out_end = out.end<V4>();

    for (; in_itr != in_end && out_itr != out_end; ++in_itr, ++out_itr)
    {
        int noise_index = my_rand(noise.size());
        for (int j = 0; j < 3; ++j)
            (*out_itr)[j] = (*in_itr)[j] + noise[noise_index];
    }
}
Run Code Online (Sandbox Code Playgroud)

没有什么过于复杂:

  • inout分配cv::Mat相同尺寸和类型的对象
  • 迭代输入图像 in
  • 在每个位置,从中选择一个随机数noise(my_rand(int n)返回一个随机数)[0..n-1]
  • 将像素in与随机噪声值相加
  • 将求和结果放入 out

我不喜欢这段代码,因为下面的陈述似乎是不可避免的:

typedef cv::Vec<unsigned char, 3> V4;
Run Code Online (Sandbox Code Playgroud)

它有两个硬编码:

  1. 图像有3个通道
  2. 通道深度为8bpp

如果我typedef弄错了(例如错误的频道深度或错误的频道数),那么我的程序会出现段错误.我最初用于typedef cv::Vec<unsigned char, 4> V4处理具有任意数量通道的图像(OpenCV支持的最大值为4),但这会导致段错误.

有什么办法可以避免硬编码上面的两件事吗?理想情况下,我想要一些通用的东西:

typedef cv::Vec<in.type(), in.size()> V4;
Run Code Online (Sandbox Code Playgroud)

ypn*_*nos 5

我知道这来晚了。但是,真正解决您问题的方法是使用 OpenCV 功能来做您想做的事情。

  1. 像您一样创建噪声向量(或使用 OpenCV 提供的提示功能
  2. shuffle 噪声向量,因此您不需要为每个像素设置单独的 noise_index;或预先创建随机噪声向量
  3. 围绕您的洗牌/随机向量构建一个矩阵标题: cv::Mat_<double>(noise);
  4. 使用矩阵运算进行计算:out = in + noise;cv::add(in, noise, out);
  5. 利润!

这种方法的另一个优点是 OpenCV 可能会使用多线程、SSE 或其他方法来加速这种大规模元素操作,而您却没有。您的代码更简单、更干净,而且 OpenCV 会为您完成所有讨厌的类型处理。


eta*_*ion 2

问题是您需要在运行时确定通道的类型和数量,但模板在编译时需要这些信息。cv::split您可以通过使用和cv::merge或将迭代更改为来避免对通道数进行硬编码

for(int row = 0; row < in.rows; ++row) {
    unsigned char* inp  = in.ptr<unsigned char>(row);
    unsigned char* outp = out.ptr<unsigned char>(row);
    for (int col = 0; col < in.cols; ++col) {
        for (int c = 0; c < in.channels(); ++c) {
            *outp++ = *inp++ + noise();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想摆脱类型的依赖性,我建议将上述内容放入模板化函数中,并根据矩阵的类型从您的函数中调用它。

  • 有一个继承自“cv::Mat”的模板 - 它是“cv::Mat_”并具有预制的 typedef,例如“cv::Mat3b”用于 3 通道图像,每个通道一个字节。 (4认同)