6

I've been playing around with opencv2 implemented in C++ for a couple of days and noticed that the lookup tables are the fastest way to apply changes to an image. However, I've been having some troubles with using them for my purposes.

The code below shows an example of inverting pixels' values:

bool apply(Image& img) {
   int dim(256);
   Mat lut(1, &dim, CV_8U);
   for (int i=0; i<256; i++)
      lut.at<uchar>(i)= 255-i;
   LUT(img.final,lut,img.final);
   return true;
}

class Image {
public:
   const Mat& original;
   Mat final;
...
};

As it's very efficient, much more efficient than changing each pixel by one (verified by my own tests), I'd like to use this method for other operations. However to do this, I have to access each layer (each color, the picture is in BGR) separately. So for example, I'd like to change blue to 255-i, green to 255-i/2 and red to 255-i/3.

I've been searching the net for a while, but couldn't come up with a correct solution. As far as I know, it's possible (documentation) but I can't find a way to implement it.

Michal B
  • 280
  • 5
  • 10

1 Answers1

6

The key is this paragraph in the docs:

the table should either have a single channel (in this case the same table is used for all channels) or the same number of channels as in the source array

So, you must create a multichannel LUT:

bool apply(Image& img) {
   int dim(256);

   Mat lut(1, &dim, CV_8UC(img.final.channels()));

   if( img.final.channels() == 1)
   {
      for (int i=0; i<256; i++)
         lut.at<uchar>(i)= 255-i;
   }
   else // stupid idea that all the images are either mono either multichannel
   {
      for (int i=0; i<256; i++)
      {
         lut.at<Vec3b>(i)[0]= 255-i;   // first channel  (B)
         lut.at<Vec3b>(i)[1]= 255-i/2; // second channel (G)
         lut.at<Vec3b>(i)[2]= 255-i/3; // ...            (R)
      }
   }

   LUT(img.final,lut,img.final); // are you sure you are doing final->final? 
   // if yes, correct the LUT allocation part

   return true;
}
Sam
  • 19,708
  • 4
  • 59
  • 82
  • Thanks for the reply! I knew, it was possible because of that paragraph, but I couldn't find an example how to do it. Yes, I want to overwrite img.final. What do you mean by correcting the LUT allocation part? Having it like this: "Mat lut(1, &dim, CV_8U(img.final.channels()));" I get a compilation error: "‘0’ cannot be used as a function". – Michal B Jul 16 '12 at 12:10
  • It's probably CV_8UC(channels); you can check the docs for the correct formula – Sam Jul 16 '12 at 12:29
  • I finally got it, the line should be as follows: "Mat lut(1, &dim, CV_8UC3);". Can you change it in the above code, so that other people can take use of the solution? Thanks for pointing me the right direction! – Michal B Jul 16 '12 at 12:37
  • I know that way, but I want the piece of code to work regardless the number of channels - so if you have a grayscale it will build a 1-channel LUT, and if you have more channels, it will build a LUT with the same number of channels as the input. – Sam Jul 16 '12 at 12:45
  • Oh, I see. I think this does the job: Mat lut(1, &dim, CV_MAKETYPE(CV_8UC3, img.final.channels())); – Michal B Jul 16 '12 at 12:49
  • 1
    hmmmm, my latest edit should work (I did not try it) and yours too, with the mention that it should be CV_MAKETYPE(CV_8U, img.final.channels()). You already specify the number of channels if you say CV_8UC3. it means 8bit unsigned, C-channels 3-channels number. – Sam Jul 16 '12 at 12:51
  • @sammy What if i have curves and the code behind curves contain `LUT` like here http://stackoverflow.com/questions/23641208/how-to-draw-curve-on-control-points-using-opencv , i want to move the curve and when i find it exact i leave the curve there because i got the image which i want, but the next time i don't want to move the curve i want to get that image directly like by inserting value or by saving value , how i can save the value with `LUT` – AHF Jul 02 '14 at 11:01