Ask Your Question
0

How to iterate through a column in reverse?

asked 2013-09-28 21:15:36 -0600

wpd gravatar image

Or, equivalently, why does the following code crash (on my Ubuntu 12.04 LTS box running OpenCV 2.4.5)

#include <iostream>
#include <opencv2/core/core.hpp>

using namespace cv;
using namespace std;

int
main(int argc, char *argv[])
{
  Mat m = (Mat_<int>(3,3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
  cout << m << endl;

  MatConstIterator_<int> Mptr = m.col(0).end<int>() - 1;
  for (int i = 0; i < 3; i++) {
    cout << (int)*Mptr-- << endl;
  }
  return(0);
}

I feel like this should work, but it crashes on the second iteration through the loop. I'm not completely comfortable with C++ iterators, and don't understand the nuances of begin()/end() vs rbegin()/rend(), but, as there is no rbegin()/rend() defined for OpenCV matrices, I guess that doesn't matter. Can somebody tell me what I'm missing here?

What is the correct way to iterate through a column of data in reverse order?

Thanks.

--wpd

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
1

answered 2013-09-29 02:01:09 -0600

stereomatching gravatar image

I am not familiar with the iterator of openCV provided, but I could offer you a solution to iterate through the column(or row?) of cv::Mat.

template<typename T>
void reverse_row_data(cv::Mat const &input, int row)
{
    auto input_ptr = input.ptr<T>(row) + input.cols - 1;
    for(int col = 0; col != input.cols; ++col){
        std::cout<<*input_ptr<<std::endl;
        --input_ptr;
    }

}

template<typename T>
void reverse_col_data(cv::Mat const &input, int col)
{
    for(int row = input.rows - 1; row != -1; --row){
        auto input_ptr = input.ptr<T>(row) + col;
        std::cout<<*input_ptr<<std::endl;
    }

}

int main()
{    
    cv::Mat m = (cv::Mat_<int>(3,3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
    std::cout << m << std::endl;

    reverse_row_data<int>(m, 0);
    reverse_row_data<int>(m, 1);
    reverse_row_data<int>(m, 2);

    reverse_col_data<int>(m, 0);
    reverse_col_data<int>(m, 1);
    reverse_col_data<int>(m, 2);

    return 0;
}

If you want it become more versatile

template<typename T, typename UnaryFunc>
void reverse_row_data(cv::Mat const &input, int row, UnaryFunc func)
{
    auto input_ptr = input.ptr<T>(row) + input.cols - 1;    
    for(int col = 0; col != input.cols; ++col){
        func(*input_ptr);
        --input_ptr;
    }
}

template<typename T, typename UnaryFunc>
void reverse_col_data(cv::Mat const &input, int col, UnaryFunc func)
{
    for(int row = input.rows - 1; row != -1; --row){
        auto input_ptr = input.ptr<T>(row) + col;
        func(*input_ptr);
    }

}

There are rooms to improve the performance, you could give it a try if you like.

edit flag offensive delete link more

Comments

Thanks. That's a fabulous answer, and very well presented.

I wonder how it would compare to just using the at() function to stride through the data. It seems (at first glance) to be roughly the same complexity, in that each iteration through the loop, the address of the next element is computed by adding offsets and multiples of step sizes to the base address.

Ideally, I would like to figure out a way to do this using pointers (iterators) and to have the compiler keep track of the right number of bytes by which to decrement my pointer each time through my loop.

wpd gravatar imagewpd ( 2013-09-29 07:18:28 -0600 )edit

Question Tools

Stats

Asked: 2013-09-28 21:15:36 -0600

Seen: 1,286 times

Last updated: Sep 29 '13