2011-01-20 50 views
6

我用下面的代码一些噪音添加到图像时确定的模板类型(直出的OpenCV参考,449页 - 的cv::Mat::begin说明):访问OpenCV的垫块元件

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]; 
    } 
} 

没有过于复杂:

  • inout被分配相同尺寸的cv::Mat对象和在输入图像0123键入
  • 迭代
  • 在每个位置,从in挑从noise的随机值(my_rand(int n)返回一个随机数在[0..n-1]
  • 总和像素与随机噪声值
  • 就把求和结果转换成out

我不喜欢这样的代码,因为下面的说法似乎不可避免:

typedef cv::Vec<unsigned char, 3> V4; 

它具有硬编码的两件事情:

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

如果我得到这个错误typedef(例如通道深度错误或通道数量错误),那么我的程序段错误。我最初使用typedef cv::Vec<unsigned char, 4> V4来处理任意数量的通道(最大OpenCV支持4)的图像,但这导致了段错误。

有没有什么办法可以避免硬编码上述两件事?理想情况下,我想要的东西是一样的:

typedef cv::Vec<in.type(), in.size()> V4; 

回答

2

问题是,您需要确定在运行时确定通道的类型和数量,但模板在编译时需要这些信息。您可避免或者使用cv::splitcv::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(); 
     } 
    } 
} 

如果你想摆脱型的Dependance的,我建议把上面的模板化函数,并根据矩阵的类型从函数中调用该函数。

+0

感谢您的回复。我可能最终会使用像你提到的行指针,但我有点说,看到迭代器去,因为这是使用它们的理想场所。此外,即使我模板函数,我仍然必须在编译时指定它的类型名称,这实际上只是将问题移到代码中的另一个点。也许我有点愤世嫉俗,但对我来说,在编译时指定这些信息似乎首先会失去模板和多态性的观点。 – misha 2011-01-20 10:12:05

+0

它不会“只是”移动问题 - 如果你没有模板功能,你必须复制整个代码的类型。另外,你的根本问题是你试图在不知道它包含什么的情况下对图像进行操作,并且注定会失败(例如,对于整数值图像需要不同的噪声而不是实值图像。 ,如果generate_noise返回平均值为0的高斯噪声,那么噪声会产生一个偏差,使图像变暗(因为整数舍入_down_) – etarion 2011-01-20 10:27:17

1

它们是硬编码的,因为性能是更好的方式。

在OpenCV1.x中有cvGet2D(),可以在这里使用它,因为Mat可以作为IplImage被转换。 但是,由于每次访问像素时都会很慢,因此函数将查找类型,大小等。循环中特别低效。

+1

感谢您的建议,但我宁愿留在C++界面,因为它更清洁(除了这个问题,我对它很满意)。另外,我不明白为什么`cv :: Mat`不是一个模板类 - 这将避免必须对迭代器/访问器函数进行模板化。这是出于效率的原因吗? – misha 2011-01-20 10:00:30

3

我知道这来得晚。但是,真正解决您的问题的方法是使用OpenCV功能来执行您想要的操作。

  1. 产生噪声向量作为你已经(或使用OpenCV提供提示功能!)
  2. 洗牌噪声矢量,所以你不需要为每个像素单独noise_index;或事先创建
  3. 随机噪声向量构建矩阵头在你的洗牌/随机向量:cv::Mat_<double>(noise);
  4. 使用矩阵运算的计算:out = in + noise;cv::add(in, noise, out);
  5. 利润!

这种方法的另一个优点是OpenCV可能会使用多线程,SSE或其他来加速这种大规模元素操作,而你不这样做。你的代码更简单,更清晰,OpenCV为你处理所有令人讨厌的类型。