0

Thanks in advance for any help you could provide to me, and sorry for my bad english.

I know there's a lot of questions about this topic, but I have looked a lot on all the Internet (and StackOverflow too) but I haven't found any answer for this...

I have four images; each one of them is in the TYPE_BYTE_GRAY color model. I have loaded these four images using this code:

int numElems = 4;
BufferedImage[] img = new BufferedImage[numElems];
for(int i=0;i<numElems;i++){
    FileInputStream in = new FileInputStream(args[i]);
    img[i] = ImageIO.read(in);
    in.close();
}

Just ImageIO read... I need to "merge" the four images into one RGB image... Each one of the images is one channel from a CMYK image. All these images have equal dimensions. I have converted the four images to one CMYK image using this code:

for(int j=0;j<img[0].getHeight();j++){
    //Read current point color...
    for(int k=0;k<numElems;k++){
        colPunto[k] = (img[k].getRGB(i, j) & 0xFF);
    }

    int colorPunto = convertComponentsRGB(colPunto);

    //Now, I set the point...
    out.setRGB(i, j, colorPunto);
    }
}

This function "convertComponentsRGB" is just natural math to convert CMYK color to RGB Color...

function convertComponentsRGB(int[] pointColor){
float cyan = (float)pointColor[0] / (float)255;
float magenta = (float)pointColor[1] / (float)255;
float yellow = (float)pointColor[2] / (float)255;
float black = (float)pointColor[3] / (float)255;

float c = min(1f,cyan * (1f - black) + black); //minimum value
float m = min(1f,magenta * (1f - black) + black); //minimum value
float y = min(1f, yellow * (1f - black) + black); //minimum value

result[0] = Math.round(255f*(1f - c));
result[1] = Math.round(255f*(1f - m));
result[2] = Math.round(255f*(1f - y));

    return (result[0]<<16) | (result[1]<<8) | result[2];
}

The problem here is... speed. It takes 12 seconds to process one image, because we've to read each pixel and write each pixel, and I think "getRGB" and "setRGB" functions aren't very quick (or, it's just a best way to achieve this).

¿How can I achieve this? I have reading a lot about ColorModel, filters, but I still don't understand how to achieve this in a better time.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • You could compute 1/255f once for all images and use it in a multiplication, instead of making a division. Try it and report back. :) – Marcus Johansson Jun 04 '12 at 14:47
  • Ok... it's better by 10%... But the thing is that I want to know if there's a way to achieve this using Raster Images, Filters, or something like this... Pure Java2D – epilefreyes Jun 04 '12 at 14:55
  • You do not even need the floats. I would guess this could be about 10 times faster if you only did it with integers. – Marcus Johansson Jun 04 '12 at 14:57
  • Sorry the question, but... how? Any ideas? – epilefreyes Jun 04 '12 at 14:58
  • Nope.... equal time to convert... I'm not sure if integer or float numbers have different times... – epilefreyes Jun 04 '12 at 15:14
  • Would it work to do everything using integers, as in `red=255-cyan; green=255-magenta; blue=255-yellow`, then scale for black by (a) multiplying each result by `(255-black)` and (b) dividing each result by 255? – Jim Garrison Jun 04 '12 at 18:41
  • From my experience, `getRGB` and `setRGB` are indeed slow. Reading and writing the data buffers directly is your best bet to improve performance. – lhballoti Jun 04 '12 at 19:26

1 Answers1

0

You can use getData and setData to speed up access to the pixels vs. getRGB and setRGB.

There's no need to convert the CMYK to floating point and back, you can work directly with the pixel values:

function convertComponentsRGB(int[] pointColor){
    int r = max(0, 255 - (pointColor[0] + pointColor[3]));
    int g = max(0, 255 - (pointColor[1] + pointColor[3]));
    int b = max(0, 255 - (pointColor[2] + pointColor[3]));

    return (r<<16) | (g<<8) | b;
}
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622