6

I'm trying to access Pixel by Pixel of an IplImage. Im using Java and Processing, and sometimes I need to access pixel by pixel. I've done this so far, but I don't know what's wrong:

public IplImage PImageToIplImage(PImage imageSrc)
    {
        IplImage imageDst;
        if(imageSrc.format==RGB)
        {
            imageDst = IplImage.create(imageSrc.width, imageSrc.height, IPL_DEPTH_8U, 3);
            ByteBuffer imagePixels=imageDst.getByteBuffer();
            int locPImage, locIplImage, x, y;
            for(y=0; y<imageSrc.height; y++)
                for(x=0; x<imageSrc.width; x++)
                {
                    locPImage = x + y * width;
                    locIplImage=y*imageDst.widthStep()+3*x;
                    imagePixels.put(locIplImage+2, (byte)(red(imageSrc.pixels[locPImage])));
                    imagePixels.put(locIplImage+1, (byte)(green(imageSrc.pixels[locPImage])));
                    imagePixels.put(locIplImage, (byte)(blue(imageSrc.pixels[locPImage])));
                }
        }
}

After Karlphilip sugestion, I came to this, still doens't work. When I try to show, it gives me a nullPointer exception:

imageDst = IplImage.create(imageSrc.width, imageSrc.height, IPL_DEPTH_8U, 3);
CvMat imagePixels = CvMat.createHeader(imageDst.height(), imageDst.width(), CV_32FC1);  
cvGetMat(imageDst, imagePixels, null, 0); 
int locPImage, x, y;
for(y=0; y<imageSrc.height; y++)
   for(x=0; x<imageSrc.width; x++)
   {
       locPImage = x + y * width;
       CvScalar scalar = new CvScalar();
       scalar.setVal(0, red(imageSrc.pixels[locPImage]));
       scalar.setVal(1, green(imageSrc.pixels[locPImage]));
       scalar.setVal(2, blue(imageSrc.pixels[locPImage]));
       cvSet2D(imagePixels, y, x, scalar);
   }
   imageDst = new IplImage(imagePixels); 
lepe
  • 24,677
  • 9
  • 99
  • 108
Ricardo Alves
  • 1,071
  • 18
  • 36

2 Answers2

7

The fastest way to iterate over each pixel in JavaCV is:

ByteBuffer buffer = image.getByteBuffer();

for(int y = 0; y < image.height(); y++) {
    for(int x = 0; x < image.width(); x++) {
        int index = y * image.widthStep() + x * image.nChannels();

        // Used to read the pixel value - the 0xFF is needed to cast from
        // an unsigned byte to an int.
        int value = buffer.get(index) & 0xFF;

        // Sets the pixel to a value (greyscale).
        buffer.put(index, value);

        // Sets the pixel to a value (RGB, stored in BGR order).
        buffer.put(index, blue);
        buffer.put(index + 1, green);
        buffer.put(index + 2, red);
    }
}
lepe
  • 24,677
  • 9
  • 99
  • 108
ajshort
  • 3,684
  • 5
  • 29
  • 43
  • That's what I'm trying to do, but it's not working (reading a pixel is fine, but writing it's not). In your example, how do I put a RGB value? – Ricardo Alves Feb 15 '13 at 01:31
  • I've added an RGB example. – ajshort Feb 15 '13 at 01:44
  • Thanks. That's exactly what I did, but it doesn't work. Can you please look at the code above and see waht am I doing wrong? It's the first Code. Thanks. – Ricardo Alves Feb 15 '13 at 01:51
  • What do you mean doesn't work? You're missing a return statement in your example code. – ajshort Feb 15 '13 at 03:46
  • Well, this is weird. I was running that exact code again to show you the input and output (should be the same) and it turned out to work. Really really weird. Thanks. – Ricardo Alves Feb 15 '13 at 04:37
  • @ajshort I aim to add a yellowish flavour to my iplImage. The complexity though, is that its from a video. I want to iterate each frame and make them all yellowish. Can you please suggest some direct function, something that has similar implementation to cvInRangeS() or cvSmooth(), which does not loop through the entire length and breadth of the image to boost a color. – Parth Kapoor May 07 '14 at 06:58
1

The following code loads an image from the disk and performs a grayscale conversion by iterating over the pixels of the image:

    IplImage image = cvLoadImage("pipeline.png", CV_LOAD_IMAGE_COLOR);
    if (image == null) 
    {
        System.out.println("Erro ao carregar imagem!");
        return;
    }

    double r, g, b;
    r = g = b = 0.0;       

    CvMat mtx = CvMat.createHeader(image.height(), image.width(), CV_32FC1);  
    cvGetMat(image, mtx, null, 0); 

    System.out.println(mtx.rows() + "x" + mtx.cols());

    for (int i = 0; i < mtx.rows(); i++)
    {
        for (int j = 0; j < mtx.cols(); j++)
        {
            CvScalar rgb = cvGet2D(mtx, i, j);
            r = rgb.val(0);
            g = rgb.val(2);
            b = rgb.val(1);

            double gray = (r + g + b) / 3;

            CvScalar scalar = new CvScalar();
            scalar.setVal(0, gray);
            scalar.setVal(1, gray);
            scalar.setVal(2, gray);
            cvSet2D(mtx, i, j, scalar);
        }
    }        

    IplImage result = new IplImage(mtx); 
    cvSaveImage("manual_gray.png", result);

    cvReleaseImage(image); 

Not sure if creating a new CvMat is the best approach, but it's the only way I know to work in javacv.

EDIT:

Unfortunately you use data types that are not from OpenCV, like PImage, but I did my best to simulate what you are doing.

    // Create a black image
    IplImage imageDst = IplImage.create(imageSrc.width(), imageSrc.height(), IPL_DEPTH_8U, 3); 

    // Create a temporary mat to iterate over it's pixels
    CvMat imagePixels = CvMat.createHeader(imageDst.height(), imageDst.width(), CV_32FC1); 

    // Copy black image to temporary mat
    cvGetMat(imageDst, imagePixels, null, 0);

    int x, y;
    for(y=0; y<imageSrc.height(); y++)
       for(x=0; x<imageSrc.width(); x++)
       {
            // At this point you tried to do: locPImage = x + y * width;
            // but I think you might have mistaken for: locPImage = y + x * width;

            //...
       }
       imageDst = new IplImage(imagePixels); 
lepe
  • 24,677
  • 9
  • 99
  • 108
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • Thanks a lot. I'm going to try that. I managed to read the value using a similiar approach as I showed. I'll try that later, but thanks in advance ;) – Ricardo Alves Feb 14 '13 at 19:00
  • There's no need for thanks, you can simply up vote the answer :) – karlphillip Feb 14 '13 at 19:29
  • I tried it, but it's not working with me. The image is null, I don't know how :/ – Ricardo Alves Feb 15 '13 at 01:32
  • Do you mean cvLoadImage() failed to load the image? If you are using Netbeans you need to place the image in the root directory of the project. Or, simply use the FULL path the file when calling cvLoadImage(). The code works, guaranteed. Whatever problem you are having has nothing to do with the code. – karlphillip Feb 15 '13 at 01:34
  • I adapter your code. The result is showed in my queston (I edited it). It gives me a nullpointerexception when tryng to show the result. – Ricardo Alves Feb 15 '13 at 01:48
  • Well, OK, here's how stackoverflow works: you ask a question and then you get an answer for it. If you have new questions (and you do), then you are free to ask them in new threads. But do not hijack you own thread. You wanted to know how to perform per pixel operation and you got the answer for it. Right now you are asking a totally different question: "why is my program not working". Go ahead, ask a new question and I'll do my best to help you. But I feel like this thread is over. – karlphillip Feb 15 '13 at 01:52
  • If no answer suits me, then I don't think the question is over. I got two sugestions, one of them I did before Ii even posted this and doesn't work. I also managed to do your sugestion and it still doesn't work. I posted my code so people could help me on what am I doing wrong. I've searched the whole web, and found no answer that works. It would be helpfull for other users, that the problem is found in a single page and not on multiple pages. In fact, in my question, I already gave an answer to my question,but it seems no to work, just like your code. – Ricardo Alves Feb 15 '13 at 02:05
  • Are you saying that you copied and paste my code into a new project, adjusted the filename so cvLoadImage() loads something that exists in your machine, and it still didn't work? What I'm trying to point out is that there's a difference between *the code on my answer* doens't work, and *your adaption of it* that doesn't. – karlphillip Feb 15 '13 at 02:13
  • What I do is simple. I need to create a new IplImage (empty) and write to it. That's what I've done with your code. Uusing CvSset2d i write to a "pixel" in a CvMat, and when I've done everything I needed, I create a IplImage using a CvMat. – Ricardo Alves Feb 15 '13 at 02:15
  • My Java is a bit rusty, but I think the error says that you tried to access a memory area that doesn't belong to you. Please review my answer carefully. – karlphillip Feb 15 '13 at 02:43
  • Thanks for your effort, really ;). What I want to do is converting a PImage to IplImage (the opposite I already can). Bbut forget about that. Imagine That I woul want to draw a blank IplImage. I just need to write to every pixels some colors (even random). As I showed in my edit, shouldn't be enough that? – Ricardo Alves Feb 15 '13 at 03:02