How to use Matlab's 512 element lookup table a

2020-06-27 08:58发布

问题:

I am designing morphological operations in OpenCV. I am trying to mimic the functions remove and bridge in Matlab's bwmorph. To do this I referred to the function definition of bwmorph.m, there I obtained the Look up table arrays for remove and bridge.

After that step the procedure is same for both Matlab and OpenCV.

      lut(img,lutarray,img)

Problem is that Matlab uses a 512 element (9bit) look up table scheme while OpenCV uses a 256 element (8bit) look up scheme, how do I use the Matlab lutarray in OpenCV?

After doing some research I came across this post.

What does the person mean when they're saying that they "split" the image from 0-512 and then into two parts?

Is the above method even correct? Are there any alternates to doing this?

回答1:

bwlookup(bw,lut)

http://se.mathworks.com/help/images/ref/bwlookup.html

or internally, applylut both perform a 2-by-2 or 3-by-3 neighborhood operation on a binary (black & white) image, whereas OpenCV's cv::LUT performs a per pixel gray level transform (closely related to intlut in MATLAB). An example of latter is performing a gamma correction on gray level image.

//! transforms array of numbers using a lookup table: dst(i)=lut(src(i))
CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst,
                  int interpolation=0);

To my knowledge, there is no neighborhood bwlookup implementation in OpenCV. However, following the description of MATLAB's bwlookup, you can write it yourself.

// performs 3-by-3 lookup on binary image
void bwlookup( 
    const cv::Mat & in, 
    cv::Mat & out, 
    const cv::Mat & lut,
    int bordertype=cv::BORDER_CONSTANT, 
    cv::Scalar px = cv::Scalar(0) ) 
{
    if ( in.type() != CV_8UC1 )
        CV_Error(CV_StsError, "er");
    if ( lut.type() != CV_8UC1 || lut.rows*lut.cols!=512 || !lut.isContinuous() )
        CV_Error(CV_StsError, "lut size != 512" );
    if ( out.type() != in.type() || out.size() != in.size() )
        out = cv::Mat( in.size(), in.type() );

    const unsigned char * _lut = lut.data;
    cv::Mat t;
    cv::copyMakeBorder( in,t,1,1,1,1,bordertype,px);
    const int rows=in.rows+1;
    const int cols=in.cols+1;
    for ( int y=1;y<rows;++y)
    {
        for ( int x=1;x<cols;++x)
        {
            int L = 0;
            const int jmax=y+1;
#if 0 // row-major order
            for ( int j=y-1, k=1; j<=jmax; ++j, k<<=3 )
            {
                const unsigned char * p = t.ptr<unsigned char>(j) + x-1;
                for ( unsigned int u=0;u<3;++u )
                {
                    if ( p[u] )
                        L += (k<<u);
#else // column-major order (MATLAB)
            for ( int j=y-1, k=1; j<=jmax; ++j, k<<=1 )
            {
                const unsigned char * p = t.ptr<unsigned char>(j) + x-1;
                for ( unsigned int u=0;u<3;++u )
                {
                    if ( p[u] )
                        L += (k<<3*u);
#endif
                }
            }
            out.at<unsigned char>(y-1,x-1)=_lut[ L ];
        }
    }
}

I tested it against remove and bridge so should work. Hope that helps.

Edit: After checking against a random lookup table,

lut = uint8( rand(512,1)>0.5 ); % @MATLAB
B = bwlookup( A, lut );

I flipped the order the indices appear in the lookup table (doesn't matter if the operation is symmetric).