# ImageProcessor and ImageDesc

The image processing classes are designed to allow working on an identical sized section of multiple images.

For example, given two input images and a third image to output into:

The image processor can be used to divide the selected section into small regions that are processed independently. (The section can be an entire image of course) ParallelForEach can be used to schedule the processing in parallel.

# Example

## Setup Code

        #include "job_util/image_desc.h"
        #include "job_util/parallel_for_each.h"

        // Create an image descriptor
        // Section is 32 x 32 pixels
        // Regions are 16 x 4 pixels, making 32/16 * 32/4 = 2 * 8 = 16 regions
        //
        //             32 pixels wide
        //  +----------------+----------------+
        //  |                |                |
        //  | 16 x 4 pixels  |                |
        //  |    Region 0    |    Region 1    |
        //  |                |                |
        //  +----------------+----------------+
        //  |                |                |
        //  |                |                |
        //  |    Region 2    |    Region 3    |
        //  |                |                |
        //  +----------------+----------------+
        //  |                |                |
        //  |                |                |
        //  .                .                .
        //  .                .                .
        //  .                .                .
        //  |                |                |
        //  |                |                |
        //  +----------------+----------------+
        //  |                |                |
        //  |                |                |
        //  |    Region 14   |    Region 15   |
        //  |                |                |
        //  +----------------+----------------+

        ImageDesc id(32, 32, 16, 4);

        // Setup sections of images to process

        // img0 for x 0 to 31, y 0 to 31 as input
        id.SetImage(0, 0, 0, img0.mBytesPerPixel, img0.mBytesPerLine, img0.mSurface, 0);

        // img1 for x 16 to 47, y 16 to 47 as input
        id.SetImage(1, 16, 16, img1.mBytesPerPixel, img1.mBytesPerLine, img1.mSurface, 0);

        // img2 for x 32 to 63, y 32 to 63 as output
        id.SetImage(2, 32, 32, img2.mBytesPerPixel, img2.mBytesPerLine, 0, img2.mSurface);

        // img3 for x 0 to 31, y 0 to 31 as input and output.  The default
        // offset for x and y is 0 if they are not given.
        id.SetImage(3, img3.mBytesPerPixel, img3.mBytesPerLine, img3.mSurface, img3.mSurface);

        // img3 for x 32 to 63, y 0 to 31 as input and output
        id.SetImage(4, 32, 0, img3.mBytesPerPixel, img3.mBytesPerLine, img3.mSurface, img3.mSurface);

        // process image sections by region using 6 threads
        ParallelForEach pfe(mJobScheduler, mForEachJobEntryPoint, id, 6);

        pfe.SetAllowSleepOn(true);
        pfe.Run();
        pfe.SleepOn();

## Job Code

        static void TestImageProcessor(uint32_t imageDescEa, uint32_t jobIndex, uint32_t, uint32_t)
        {
            size_t const bufferSize = 32 * 1024;
            #if defined EA_PLATFORM_PS3_SPU
                EA_PREFIX_ALIGN(16) char buffer[bufferSize] EA_POSTFIX_ALIGN(16);
            #else
                char * buffer = 0;
            #endif

            ImageProcessor imageProcessor
            (
                 imageDescEa,
                 jobIndex,
                 buffer,
                 bufferSize
            );

            for( imageProcessor.First(); ! imageProcessor.Done(); imageProcessor.Next() )
            {
                for (size_t line = 0; line < imageProcessor.GetRegionHeight(); ++line)
                {
                    // Pixel is user defined.

                    Pixel const * img0Line = imageProcessor.GetRegionLine<Pixel>(0, line);
                    Pixel const * img1Line = imageProcessor.GetRegionLine<Pixel>(1, line);
                    Pixel       * img2Line = imageProcessor.GetRegionLine<Pixel>(2, line);
                    Pixel       * img3Line = imageProcessor.GetRegionLine<Pixel>(3, line);
                    Pixel       * img4Line = imageProcessor.GetRegionLine<Pixel>(4, line);

                    for (size_t x = 0; x < imageProcessor.GetRegionWidth(); ++x)
                    {
                        // process each line of the region.
                    }
                }
            }
        }

# Working with multi-line regions.

If you specify regions with multiple lines in them you should not assume that the number of bytes per line matches the source image for the region. On the Spu the number of bytes per line will be different, since the lines are packed together when they get Dma'd onto the Spu.

You should call `GetRegionLine<T>` for each line:

        size_t const numLines = 4;
        Pixel * line[numLines];

        for (size_t i = 0; i < numLines; ++i)
            line[i] = imageProcessor.GetRegionLine<Pixel>(0, i);

Alternately you can compute the byte per line like so:

        pixel * region = imageProcessor.GetRegionLine<Pixel>(0, 0);
        size_t bytesPerLine = imageProcessor.GetRegionLine<Pixel>(0, 1) - region;

This works regardless of whether the you are using a buffer (Spu) of not, since we load all the lines of a image's region one after another into the local buffer when one is provided.