Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

For test cases I need a unique way to set any structure to zero. For openCV I wrote this:

  // Fill every basic structure of openCV with zero.
  template < typename Tp >
  void zero( cv::Point_<Tp>& p ) {
    p.x = p.y = 0;
  }
  template < typename Tp >
  void zero( cv::Point3_<Tp>& p ) {
    p.x = p.y = p.z = 0;
  }
  template < typename Tp >
  void zero( cv::Size_<Tp>& s ) {
    s.width = s.height = 0;
  }
  template < typename Tp >
  void zero( cv::Rect_<Tp>& r ) {
    r.x = r.y = r.width = r.height = 0;
  }
  inline void zero( cv::RotatedRect& r ) {
    zero( r.center );
    zero( r.size );
    r.angle = 0;
  }
  inline void zero( cv::TermCriteria& t ) {
    t.type = t.maxCount = 0;
    t.epsilon = 0.0;
  }
  template < typename Tp, int M, int N>
  void zero( cv::Matx<Tp, M, N>& m ) {
    m = 0;
  }
  // Vec<> and Scalar<> are derived from Matx<>
  inline void zero( cv::Range& r ) {
    r.start = r.end = 0;
  }
  inline void zero( cv::Mat& m ) {
    m = 0;
  }
  inline void zero( cv::SparseMat& sm ) {
    sm.clear();
  }
  template < typename Tp >
  void zero( cv::SparseMat_<Tp>& sm ) {
    sm.clear();
  }

Setting cv::Mat to zero by assigning a new zero filled Mat is reallocating. But looping over would be slow (now done by *= 0). Using memset( m.data, ... ) is only possible if m.isContinuous(). Any idea of being safe and fast? Is it possible to join some derived cases?

The template parameters _Tp has been replaced by Tp because starting with _, followed by uppercase letter is reserved. That is something the openCV authors do violate too (I copied it from the openCV core code).

Mat, Matx and derived Vec and Scalar can be set to zero by multiplying with zero. Internal this is a for() over all elements but without the realloc of the zeros() assignment.

share|improve this question
    
A hint: names starting with _, followed by uppercase letter, are reserved for use by the compiler and Standard library. Better just name your template parameters T. – glampert Jan 11 at 16:33
    
Thanks. That is one of the laxness I just cut&pasted from the openCV core code. The openCV library already feels like standard :-) – Kellerspeicher Jan 11 at 16:57
    
@jamal: Is that the usual behavior here? – Kellerspeicher Jan 11 at 22:58
    
up vote 2 down vote accepted

If you want to zero a Matx, you can take advantage of its val public data member, which is a good old C array. Then you can rely on the standard library algorithm std::fill to set every element of the matrix to 0; the algorithm generally does static dispatch at compile time to call std::memset whenever possible. Using it should allow you to always be safe but also to be safe when possible:

template < typename Tp, int M, int N>
void zero( cv::Matx<Tp, M, N>& m ) {
  std::fill(std::begin(m.val), std::end(m.val), 0);
}

Since Matx::val is a fixed-size C array, std::begin and std::end should work. If you don't use a C++11 standard library, you can implement it as follows instead:

template < typename Tp, int M, int N>
void zero( cv::Matx<Tp, M, N>& m ) {
  std::fill(m.val, m.val + M*N, 0);
}

For cv::Mat, the documentation says that:

To set all the matrix elements to the particular value after the construction, use the assignment operator Mat::operator=(const Scalar& value).

It means that you can zero the matrix like this (I couldn't find equivalent overloads for Matx or SparseMat):

inline void zero( cv::Mat& m ) {
  m = 0;
}

Also, as a side note, most modern compilers just don't care about inline, at least they don't take it as a hint for inlining since they already do a great job when it comes to inlining stuff. Nowadays, inline is just a way to solve ODR problems, which don't happen with templates. All of your functions are function templates, so you can safely remove inline.

share|improve this answer
    
Thanks. Interesting way especially for larger cv::Matx<> if it really leads to memset() usage. In another forum I found the hint, that most cv::Mat<> instances are continues too. So if ( m.isContinuous()) std::fill( m.data, m.data + m.rows * m.step, 0 ); else m *= 0; might be a reasonable compromise for cv::Mat (m.data is uchar*). – Kellerspeicher Jan 11 at 19:48
    
@Kellerspeicher You can probably use std::fill(m.begin(), m.end(), 0); and it should do the job if iterators are good enough to go from the beginning to the end of a matrix even if it's not conitnuous. – Morwenn Jan 11 at 19:53
    
Would be interesting if linear iterating along a non continuous iterator is faster than m *= 0. Assign instead of multiplying should be faster, but I don't think openCV is internally doing something different. – Kellerspeicher Jan 11 at 19:55
    
@Kellerspeicher I updated the answer, you can simply write m = 0 to set every element of Mat to zero. – Morwenn Jan 11 at 19:57
    
Quite simple. Thanks. Having trouble with the assignment operator for cv::Vec and others I didn't thought about this for cv::Mat. – Kellerspeicher Jan 11 at 20:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.