开发者

Determining template type when accessing OpenCV Mat elements

开发者 https://www.devze.com 2023-02-05 21:48 出处:网络
I\'m using the following code to add some noise to an image (straight out of the OpenCV reference, page 449 -- explanation of cv::Mat::begin):

I'm using the following code to add some noise to an image (straight out of the OpenCV reference, page 449 -- explanation of 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];
    }
}

Nothing overly complicated:

  • in and out are allocated cv::Mat objects of the same dimensions and type
  • iterate over the input image in
  • at each position, pick a random value from noise (my_rand(int n) returns a random number in [0..n-1]
  • sum the pixel from in with the random noise value
  • put the summation result into out

I don't like th开发者_如何学Gois code because the following statement seems unavoidable:

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

It has hard-coded two things:

  1. The images have 3 channels
  2. The channel depth is 8bpp

If I get this typedef wrong (e.g. wrong channel depth or wrong number of channels), then my program segfaults. I originally used typedef cv::Vec<unsigned char, 4> V4 to handle images with an arbitrary number of channels (the max OpenCV supports is 4), but this caused a segfault.

Is there any way I can avoid hard-coding the two things above? Ideally, I want something that's as generic as:

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


I know this comes late. However, the real solution to your problem is to use OpenCV functionality to do what you want to do.

  1. create noise vector as you do already (or use the functions that OpenCV provides hint!)
  2. shuffle noise vector so you don't need individual noise_index for each pixel; or create vector of randomised noise beforehand
  3. build a matrix header around your shuffled/random vector: cv::Mat_<double>(noise);
  4. use matrix operations for computation: out = in + noise; or cv::add(in, noise, out);
  5. PROFIT!

Another advantage of this method is that OpenCV might employ multithreading, SSE or whatever to speed-up this massive-element operation, which you do not. Your code is simpler, cleaner, and OpenCV does all the nasty type handling for you.


The problem is that you need determine to determine type and number of channels at runtime, but templates need the information at compile time. You can avoid hardcoding the number of channels by either using cv::split and cv::merge, or by changing the iteration to

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();
        }
    }
}

If you want to get rid of the dependance of the type, I'd suggest putting the above in a templated function and calling that from your function, depending on the type of the matrix.


They are hardcoded because performance is better that way.

In OpenCV1.x there is cvGet2D() , which can be used here since Mat can be casted as an IplImage. But it's slow since each time you access a pixel the function will find out the type, size, etc. Specially inefficient in loops.

0

精彩评论

暂无评论...
验证码 换一张
取 消