Thread: fast image crop

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    82

    fast image crop

    Hi!

    Just wanted to know if I'm the right track by using c for the following:
    I wanted to get an image and do multiple different cropping ops on it .. as fast as possible.

    I have done it with shell+imagemagick up till now, but obviously can't expect performance to be too hot there.

    So I thought of c ... just open the image with some library (prob libgd) and then fseek to the place I want cropping to begin ... then read in the first row of pixels/values, then fseek to the beginning of the next row, read it in, etc.

    The idea being not to read in the whole image, but using fseek bounce around it.

    All this in order to get performance. Probably there'd be some complexities I'll hit, but I thought I'd check in here to see if the concept made sense. Comments?

    Cheers.

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    It's not going to be quite that easy. You'll need to read the image, convert it to an array of RGB values, crop it, and then convert back to whatever format the image was originally in. Not especially difficult if you have a good image manipulation library, of course, but not trivial either.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Assuming the source and destination images are packed 24-bit RGB, and you have two open file handles to these images, and the headers are properly formed, try this:

    Code:
    void cropRGB( FILE *srcImg, unsigned int srcDataOffset, unsigned int sw, unsigned int sh,
                  FILE *dstImg, unsigned int dstDataOffset, unsigned int dw, unsigned int dh,
                  unsigned int cropX, unsigned int cropY )
    {
        unsigned int row;
        unsigned char *rowBuffer = malloc( 3 * dw );
        if( dstDataOffset > 0 )
            fseek( dstImg, dstDataOffset, SEEK_SET );
        for( row = cropY; row < cropY + dh; ++row )
        {
            fseek( srcImg, srcDataOffset + 3 * ( row * sw + cropX ), SEEK_SET );
            fread ( rowBuffer, 1, 3 * dw, srcImg );
            fwrite( rowBuffer, 1, 3 * dw, dstImg );
        }
        free( rowBuffer );
    }
    This crops the source image of dimension (sw x sh) starting at pixel (cropX, cropY) to the destination image of dimension (dw x dh).

    srcDataOffset and dstDataOffset point past the image headers to the first byte of where the image data starts for both the input and output images.

    if the destination is not seekable (for instance, it's a pipe or stdout) then you can pass 0 for the dstDataOffset and the data will be written where the file pointer is positioned.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Registered User
    Join Date
    Mar 2008
    Posts
    82
    @brewbuck, you're just too excellent.
    @sebastiani, libgd hasn't got a bad name for this ... cleaned up their documentation alot recently.
    Thank you!

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by stabu View Post
    @brewbuck, you're just too excellent.
    @sebastiani, libgd hasn't got a bad name for this ... cleaned up their documentation alot recently.
    Thank you!
    It might not necessarily be more efficient to seek. Seeking clears the stdio buffers. Another approach might be to simply read the excess data but discard it (which means you'd allocate a rowBuffer big enough for an entire SOURCE row instead of an entire DESTINATION row).

    Code:
    void cropRGB( FILE *srcImg, unsigned int srcDataOffset, unsigned int sw, unsigned int sh,
                  FILE *dstImg, unsigned int dstDataOffset, unsigned int dw, unsigned int dh,
                  unsigned int cropX, unsigned int cropY )
    {
        unsigned int row;
        unsigned char *rowBuffer = malloc( 3 * sw );
        fseek( srcImg, srcDataOffset + 3 * ( row * sw ), SEEK_SET );
        if( dstDataOffset > 0 )
            fseek( dstImg, dstDataOffset, SEEK_SET );
        for( row = cropY; row < cropY + dh; ++row )
        {
            fread ( rowBuffer, 1, 3 * sw, srcImg );
            fwrite( rowBuffer + 3 * cropX, 1, 3 * dw, dstImg );
        }
        free( rowBuffer );
    }

    You could try it either way to find out, but you'd probably need some fairly large images to be able to notice the difference.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    Registered User
    Join Date
    Mar 2008
    Posts
    82
    Quote Originally Posted by brewbuck View Post
    Seeking clears the stdio buffers.
    ah, OK.
    Quote Originally Posted by brewbuck View Post
    You could try it either way to find out, but you'd probably need some fairly large images to be able to notice the difference.
    yep, will do.
    cheers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem reading tiff image files?
    By compz in forum C++ Programming
    Replies: 9
    Last Post: 10-30-2009, 04:17 AM
  2. Replies: 1
    Last Post: 05-27-2009, 12:46 PM
  3. Simple Image Processing
    By ejohns85 in forum C++ Programming
    Replies: 4
    Last Post: 03-19-2009, 12:10 PM
  4. PPM file image crop bug
    By cdonlan in forum C++ Programming
    Replies: 2
    Last Post: 02-13-2005, 12:36 PM
  5. Replies: 4
    Last Post: 03-02-2003, 09:12 AM