1.11M Members

Image Processing - Curves (Objective-C)

 
0
 

This is actually an Objective-C question. I'm trying to implement a way to loop through pixels and map the colors to "curve" data.


I was wondering the easiest way to do this. Is there a prewritten algorithm for curves anywhere? I don't want a graphical curve grid, I just need data (maybe a matrix with the "points" in it?)

Thanks in advance :D

 
0
 

What do you mean by "curve data"? Do you mean you want to change the lookup table for the image so that you have false colour in the final image?

 
0
 

That is correct. Like say if you take the rgb curves in Photoshop and invert the color with them, I want to make my app invert the color when you import a photo (not really just an example)

 
0
 

I have done something similar before, where I had a grey-scale image, but I wanted to make it more colourful by going from black, through a yellowy-orange colour to white, instead of just going from black to white.

I went about this in a bit of a long-winded way:

  1. Found a colour scheme that I liked in an existing program (called Gwyddion in my case, but that's beside the point).
  2. Took a screen shot that included the scale bar.
  3. Opened the scale bar image in Gimp and looked at the RGB values at the different intensities on the scale bar. These were in hexidecimal, so I converted them to decimal values at this point.
  4. Fitted curves to the R, G & B values that I'd got from the image.
  5. Used these curves to scale the RGB values in my image.

Anyway, the curves that I generated are (for grey-scale to colour-mapped conversion):

/* Calculate the pixel values within the new contrast range */
for(unsigned i = 0; i < n; i++){
        /* Calculate the intensity value */
        double shade = 21*(outputImage[i] - outputMin)/(outputMax - outputMin);

        /* Clip values that exeed the range */
        if(shade < 0){          shade = 0;  }
        else if(shade > 21){    shade = 21;  }

        /* Weird-looking curves generate nice look-up table for false colour */
        double R = (32.0*shade - 1.5*shade*shade + 0.026*shade*shade*shade)/(32.0*21 - 1.5*21*21 + 0.026*21*21*21);
        double G = ( 2.6*shade + 0.8*shade*shade - 0.017*shade*shade*shade)/( 2.6*21 + 0.8*21*21 - 0.017*21*21*21);
        double B = (26.0*shade - 3.8*shade*shade + 0.150*shade*shade*shade)/(26.0*21 - 3.8*21*21 + 0.150*21*21*21);

        /* Colour the pixel */
        *pixel = Magick::ColorRGB(R,G,B);
        ++pixel;
}

I had also rescaled the contrast (with clipping of outliers) as well, so that's what the first few lines do. I normalise the contrast between 0 and 1 and then multiply these values by 21. This is a bit random, but it's because I ended up with curves that went from 0 to 255 on the y-axis for values 0 to 21 on the x-axis. This is very hacky but I was in a hurry! (FYI 21 is the number of points you get if you go from 0 to 100% in 5% intervals, so that's where that came from :) )

The new RGB values are calculated on lines 11 - 13 and are normalised to give values between 0 and 1 (by dividing by the maximum value for each curve, i.e. the value when shade = 21 ).

The new pixel value is written at the end (this bit's in C++ because I was using Magick++, but you can do it with whatever C library you're using for manipulating images).

Anyway, I don't know how much help that is, or how clear my explanation was, but that's what I did. I really wish I could find a resource that has a bunch of colour maps displayed along with the formulae for generating the lookup table data (or the lookup table data itself).

 
0
 

First off thanks a lot for your help :)

secondly, could you explain a little bit what your math for the curves is?

Thirdly, this is in C++? Do you have any idea if you can integrate C++ and Objective-C?

 
0
 

could you explain a little bit what your math for the curves is?

Since I was dealing with greyscale images, each pixel is a single number from 0 to (say) 255. For a colour image each pixel takes three or four numbers from 0 to 255 to describe (one for each of R, G and B and maybe a fourth for transparency). You can represent a greyscale image as a colour image where R, G & B all have the same value (so something like R = 79, G = 79, B= 79). The equations take a value from the original R (say) and translating it to a new value. However, the equation for the R values is not the same as that for the G values, and different again from the equation for B. So, you go from a situation where R = G = B to one where R, G & B have different values. This moves you away from the greyscale line into some other point in the colour-space.

Thirdly, this is in C++? Do you have any idea if you can integrate C++ and Objective-C?

Apart from line 16 (which is from Magick++) the rest of the code is valid C. Of course, C and Objective-C are different things. This is a C forum, so I thought that you were working in C. Although, I see now from your original post that you were asking about Objective-C. I don't know anything about Objective-C, I'm afraid. However, the general principle of what I was saying should still apply, I guess.

 
0
 

Thanks a ton :D one more thing. How did you go about loading the image and getting the pixel data? It's possible to use C with Objective-C, I just know hardly anything about C. This should be the last thing I need though :D

thanks!

 
0
 

Thanks a ton :D one more thing. How did you go about loading the image and getting the pixel data? It's possible to use C with Objective-C, I just know hardly anything about C. This should be the last thing I need though :D
thanks!

It depends what kind of format your image is in. My images are often TIFF, so I use libtiff for those. Getting the data in sensible format is a bit of a pain for this, the code that I use is something like:

/* Open a frame for reading */
TIFF *tif = TIFFOpen("imagename.tif", "r");
if (!tif){
    cerr << "Error can't open image for input. Exiting" << endl;
    return 1;
}

/* Get some details about the frame */
uint32 width, height;
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);

/* Get the size of each line from the frame */
uint32 lineSize = TIFFScanlineSize(tif);

/* Reserve space to read the frame into */
char *buf;
buf = new char[lineSize*height]

/* Read the frame into buffer line-by-line */
for (unsigned i = 0; i < height; i++)
    TIFFReadScanline(tif, &buf[i*lineSize], i, 0);

/* close image file, we're done with it */
TIFFClose(tif);

/* I had 16-bit grey-scale images, so there were 2 bytes/pixel (so use i+=2) */
double *frame = (double *)malloc(width*height*sizeof(double));
for(unsigned i = 0; i < height*lineSize; i+=2)
    frame[i/2] = (double)((buf[i + 1] << 8) | (unsigned char)buf[i]));    // There's some messing about to get the bits in the right places

Obviously, that won't help of you're not using TIFFs. For general image reading and such, Image Magic has a C API called Magik Wand. I've never used it, but you can find it here.

Hope that helps

You
This article has been dead for over six months: Start a new discussion instead
Post:
Start New Discussion
Tags Related to this Article