Ask Your Question

Revision history [back]

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);