user1139699
user1139699

Reputation: 188

how to optimized this image processing replace all pixels on image with closest available RGB?

Im' trying to replace all pixels of input image with closest available RGB. I have a array contain color and input image. Here is my code, it give me an output image as expected, BUT it take very LONG time( about a min) to process one image. Can anybody help me improve the code? Or if you have any other suggestions, please help.

 UIGraphicsBeginImageContextWithOptions(CGSizeMake(CGImageGetWidth(sourceImage),CGImageGetHeight(sourceImage)), NO, 0.0f);
 //Context size I keep as same as original input image size

 //Otherwise, the output will be only a partial image
 CGContextRef context; 
 context = UIGraphicsGetCurrentContext();

 //This is for flipping up sidedown
 CGContextTranslateCTM(context, 0, self.imageViewArea.image.size.height);
 CGContextScaleCTM(context, 1.0, -1.0);



        // init vars
        float d   = 0;                           // squared error
        int idx = 0;                             // index of palette color
        int min = 1000000;                       // min difference
        UIColor *oneRGB;                         // color at a pixel
        UIColor *paletteRGB;                     // palette color



        // visit each output color and determine closest color from palette
        for(int y=0; y<sizeY; y++) {
            for(int x=0; x<sizeX; x++) {
                // desired (avg) color is one pixel of scaled image
                oneRGB = [inputImgAvg colorAtPixel:CGPointMake(x,y)];


                // find closest color match in palette: init idx with index
                // of closest match; keep track of min to find idx
                min = 1000000;
                idx = 0;

                CGContextDrawImage(context,CGRectMake(xx, yy, 1, 1),img);
            }
        }

        UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        self.imageViewArea.image = output;

Upvotes: 1

Views: 1407

Answers (2)

Mark Ransom
Mark Ransom

Reputation: 308392

The usual answer is to use a k-d tree or some other Octree structure to reduce the number of computations and comparisons that have to be done at each pixel.

I've also had success with partitioning the color space into a regular grid and keeping a list of possible closest matches for each part of the grid. For example you can divide the (0-255) values of R,G,B by 16 and end up with a grid of (16,16,16) or 4096 elements altogether. Best case is that there's only one member of the list for a particular grid element and no need to traverse the list at all.

Upvotes: 1

Lou Franco
Lou Franco

Reputation: 89222

This is a similar question (with no definitive answer), but the answer there has the code for directly accessing pixels from an image.

Quantize Image, Save List of Remaining Colors

You should do that rather than use CG functions for each get and set pixel. Drawing 1 pixel of an image onto another image is a lot slower than changing 3 bytes in a array.

Also, what's in ColorDiff -- you don't need perfect diffing as long as the closest pixel has the smallest diff. There may be room for pre-processing this list so that for each palette entry you have the smallest diff to the nearest other palette entry. Then, while looping through pixels, I can quickly check to see if the next pixel is within half that distance to the color just found (because photos tend to have common colors near each other).

If that's not a match, then while looping through the palette, if I am within half this distance to any entry, there is no need to check further.

Basically, this puts a zone around each palette entry where you know for sure that this one is the closest.

Upvotes: 1

Related Questions