Ask Your Question
3

LUT must have 1 channel or the number of channels of the input image?!?

asked 2015-09-16 03:27:24 -0600

Micka gravatar image

updated 2015-09-16 05:28:33 -0600

Can someone explain me why there is the need of the LUT to have the same number of channels as the input image?

I don't even understand, which elements will be chosen...

For example if I have a BGR input image and a 1D LUT with 256 elements (each element is a cv::Vec3b).

Now for each pixel i of the input image: Output(i) = LUT(Input(i)).

But Input(i) is a cv::Vec3b element. So what will Output(i) be? LUT(Input(i)[0])??

In my opinion, LUT could have any number of channels, except if there are any algorithmic needs for optimization (I know that LUT is highly optimized).

Initially I wanted to create a Color image from Grayscale image with a single LUT call, but I had to use CV_GRAY2BGR in the beginning...

Here's some sample code:

cv::Mat input = cv::Mat(512,512,CV_8UC1, cv::Scalar(0));

for(int j=0; j<input.rows; ++j)
    for(int i=0; i<input.cols; ++i)
    {
        input.at<unsigned char>(j,i) = i/2;
    }


// unfortunately, we have to convert to grayscale, because OpenCV doesnt allow LUT from single channel to 3 channel directly. (LUT must have same number of channels as input)
cv::Mat input_3channels;
cv::cvtColor(input, input_3channels, CV_GRAY2BGR);

// create replacement look-up-table:
// 1. basic => gray values of given intensity
cv::Mat lookUpTable(1, 256, CV_8UC3);

for( int i = 0; i < 256; ++i)
    lookUpTable.at<cv::Vec3b>(0,i) = cv::Vec3b(i,i,i);

// 2. replace whatever you want:
lookUpTable.at<cv::Vec3b>(0,25) = cv::Vec3b(25,0,0);

lookUpTable.at<cv::Vec3b>(0,100) = cv::Vec3b(0,255,0);
lookUpTable.at<cv::Vec3b>(0,115) = cv::Vec3b(255,0,0);
lookUpTable.at<cv::Vec3b>(0,200) = cv::Vec3b(0,100,255);

// LUT will fail if used this way: cv::LUT(input, lookUpTable, output); - with assertion failed: (lutcn == cn || lutcn == 1) because LUT has 3 channels but input only has 1 channel.
cv::Mat output;
cv::LUT(input_3channels, lookUpTable, output);

cv::imshow("output", output);
cv::imshow("input", input);

cv::waitKey(0);
edit retag flag offensive close merge delete

1 answer

Sort by » oldest newest most voted
5

answered 2015-09-18 03:15:14 -0600

Hello @Micka!

Opencv LUT is a 1 Dimentional (1D) LookUpTable function , Meaning you can map the LUT for an 1 dimensional array consisting of a Single channel or Multi channel element!

Opencv Documentation

lut – look-up table of 256 elements; in case of multi-channel input array, 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 input array.

Here is the actual LUT function implementation:

LUT8u_( const uchar* src, const T* lut, T* dst, int len, int cn, int lutcn )
{
    if( lutcn == 1 )
    {
        for( int i = 0; i < len*cn; i++ )
            dst[i] = lut[src[i]];
    }
    else
    {
        for( int i = 0; i < len*cn; i += cn )
            for( int k = 0; k < cn; k++ )
                dst[i+k] = lut[src[i+k]*cn+k];
    }
}

From this you can Observe that when you pass an 3 Channel Mat to LUT function; the corresponding channel's LUT will be replaced just like the Single channel Mat.

So finally the answer is Yes! The LUT must have Single channel or number of Channels of the Input Mat! In case if you want to generate some color Maps you need to convert into a 3 Channel Mat.

I've just added Prefix to the Name of Mat variable with its type for better understanding! Though it looks bad just try to read the Prefix!

cv::Mat mInput_8UC1 = cv::Mat(512,512,CV_8UC1, cv::Scalar(0));

for(int j=0; j<mInput_8UC1.rows; ++j)
    for(int i=0; i<mInput_8UC1.cols; ++i)
    {
        mInput_8UC1.at<unsigned char>(j,i) = i/2;
    }


// unfortunately, we have to convert to grayscale, because OpenCV doesnt allow LUT from single channel to 3 channel directly. (LUT must have same number of channels as mInput_8UC1)
cv::Mat mInput_8UC3;
cv::cvtColor(mInput_8UC1, mInput_8UC3, CV_GRAY2BGR);

// create replacement look-up-table:
// 1. basic => gray values of given intensity
cv::Mat mlookUpTable_8UC1(1, 256, CV_8UC1);
cv::Mat mlookUpTable_8UC3(1, 256, CV_8UC3);

for( int i = 0; i < 256; ++i)
{
    mlookUpTable_8UC1.at<uchar>(0,i) = uchar(255-i);//Just an Inverse
    mlookUpTable_8UC3.at<cv::Vec3b>(0,i) = cv::Vec3b(255-i,255-i,0);
}

// LUT will fail if used this way: cv::LUT(mInput_8UC1, mlookUpTable_8UC3, m3CLUTOutput_8UC3); - with assertion failed: (lutcn == cn || lutcn == 1) because LUT has 3 channels but mInput_8UC1 only has 1 channel.

//The reason because the LUT is having a 3 channel element & the size of LUT Array will differ!

cv::Mat m1CLUTOutput_8UC3,m3CLUTOutput_8UC3,mOutput_8UC1;

cv::LUT(mInput_8UC1, mlookUpTable_8UC1, mOutput_8UC1);//Simple 1D LUT
cv::LUT(mInput_8UC3, mlookUpTable_8UC1, m1CLUTOutput_8UC3);//In this case same LUT is used for all the 3 Channels
cv::LUT(mInput_8UC3, mlookUpTable_8UC3, m3CLUTOutput_8UC3);//Individual Channel LUT is Substituited

cv::imshow("mInput_8UC1", mInput_8UC1);
cv::imshow("mInput_8UC3", mInput_8UC3);

cv::imshow("mOutput_8UC1", mOutput_8UC1);
cv::imshow("m3CLUTOutput_8UC3", m3CLUTOutput_8UC3);
cv::imshow("m1CLUTOutput_8UC3", m1CLUTOutput_8UC3);
edit flag offensive delete link more

Question Tools

2 followers

Stats

Asked: 2015-09-16 03:27:24 -0600

Seen: 10,042 times

Last updated: Sep 18 '15