Boost logo

Boost Users :

Subject: [Boost-users] [GIL] Some questions about 2D iteration
From: Brett Gmoser (bgmoser_at_[hidden])
Date: 2010-03-31 17:33:39


Hello everybody,

I've been toying with GIL a bit for the last few days in my spare time,
and I've got a few questions that I can't seem to find answers to in the
documentation. The following function which I've written works, but I'd
like to get a better understanding of how to use iterators to accomplish
the same task (the documentation says that view(x, y) = z is
inefficient), as well as a few other things. The job of this function
is to crop an image, discarding any white background. In other words,
find the top-most, left-most, right-most, and bottom-most pixel that
isn't the background color (white), and crop the image around those
coordinates.

   template <typename ViewType, typename ImageType>
   void crop_image(ViewType& src, boost::scoped_ptr<ImageType>& dst) const
   {
     int top = 0;
     int right = 0;
     int bottom = 0;
     int left = 0;

     // Find the top, right, bottom, and left extents. First, find the top.
     for(int y=0; y < src.height(); ++y)
     {
       for(typename ViewType::x_iterator xpos = src.row_begin(y); xpos
!= src.row_end(y); ++xpos)
       {
         if(rgb8_pixel_t(255,255,255) != *xpos)
         {
           top = y;
           break;
         }
       }
       if(top)
         break;
     }

     // ... Do similar things for finding the right, bottom, and left
extents.

     // We should now have the rectangle of the image, and it should be
easy to copy everything over.
     dst.reset(new ImageType(1 + (right - left), 1 + (bottom - top)));
     for(int x = left; x <= right; ++x)
       for(int y = top; y <= bottom; ++y)
         view(*dst)((x - left), (y - top)) = src(x, y);
   }

So, my first question is - is there a better way to do that first chore
of finding each extent? Such as a way to use std::find or std::find_if,
keeping in mind that I have to do two of the four sides in reverse
(bottom-to-top to find bottom-most, right-to-left to find right-most)?

The next question is about the final loop which copies from the source
view to the newly created destination image. It seems that using
iterators, I could do something like this, assuming that I had the above
loops find iterator positions for all four extents (left, top, bottom,
and right are iterators):

     // Start the copying process by creating a column iterator for the
destination table beginning at column 0.
     // The top iterator starts at the top-most extent - and we cycle
through the source image in a top-to-bottom,
     // left-to-right fashion.
     for(typename ImageType::view_t::y_iterator dst_y =
view(*dst).col_begin(0);
         top <= bottom; ++dst_y,++top)
     {
       // The left iterator needs to be initialized with whatever row
we're on - this appears to be impossible. There doesn't
       // seem to be any suitable way to do this, so consider it pseudocode.
       typename ViewType::x_iterator src_x = left.y();

       // The destination X iterator also needs to know what Y position
to begin on. You'd think you would be able to initialize
       // it with an iterator position, but it doesn't seem that you
can. Again, this doesn't actually compile (it's the
       // view(*dst).row_begin(y) part).
       for(typename ImageType::view_t::x_iterator dst_x =
view(*dst).row_begin(y);
           // Here, I need to be able to tell if src_x has hit the right
extent. src_x <= right doesn't seem it will work, because
           // again right doesn't know it's Y position.
           src_x != right;

           // And increment both src and destination iterators.
           ++src_x,++dst_x
        )
        {
          // Finally do the should-be-simple task of assigning the
source pixel to the destination pixel.
          *dst_x = *src_x;
        }
     }

If you read the comments, most of this doesn't seem to be possible. I've
seen that there is a "transform_pixel_positions" algorithm that may do
something close to what I want, but unfortunately I cannot find any
documentation on it (other than mentioning that it exists, and a short
example that really doesn't help - one of the few examples actually
provided by the documentation). It seems to pass a unary argument to a
functor, but that doesn't seem useful if I don't have both the X and Y
coordinates, or an X iterator and Y iterator. Also, nowhere can I find
where it says what the argument passed to the functor actually /is/.

So after I figure these few things out, I'm hoping to be able to speed
up my program a little bit. Right now everything is pretty slow using
that view(x, y) method. I'd appreciate any help that anybody can give,
thanks!

Brett


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net