Efficient way to loop through the pixels of a 16-bit Mat in OpenCV

I am trying to do very simple (LUT-like) operations on a 16-bit OpenCV Mat-scale, which is efficient and does not slow down the debugger.

Despite the fact that the documentation has a detailed page devoted to this particular problem, it is not indicated that most of these methods are available on 8-bit images (including the ideal, optimized LUT function).

I tried the following methods:

uchar* p = mat_depth.data;
for (unsigned int i = 0; i < depth_width * depth_height * sizeof(unsigned short); ++i)
{
    *p = ...;
    *p++;
}

Really fast, unfortunately, only uchart support (exactly the same as LUT).


int i = 0;
    for (int row = 0; row < depth_height; row++)
    {
        for (int col = 0; col < depth_width; col++)
        {
            i = mat_depth.at<short>(row, col);
            i = ..
            mat_depth.at<short>(row, col) = i;
        }
    }

Adapted from this answer: qaru.site/questions/1574474 / ... . It didn’t work for me, and it was very slow.


cv::MatIterator_<ushort> it, end;
    for (it = mat_depth.begin<ushort>(), end = mat_depth.end<ushort>(); it != end; ++it)
    {
       *it = ...;   
    }

It works well, however it uses a lot of CPU and makes the debugger super slow.


qaru.site/questions/1574474/... LUT , , IPP OpenCL.

, , - , , ushorts.

? , - .data.

+4
3

, .

:

cv::Mat LUT_16(cv::Mat &mat, ushort table[])
{
    int limit = mat.rows * mat.cols;

    ushort* p = mat.ptr<ushort>(0);
    for (int i = 0; i < limit; ++i)
    {
        p[i] = table[p[i]];
    }
    return mat;
}

cv::Mat LUT_16_reinterpret_cast(cv::Mat &mat, ushort table[])
{
    int limit = mat.rows * mat.cols;

    ushort* ptr = reinterpret_cast<ushort*>(mat.data);
    for (int i = 0; i < limit; i++, ptr++)
    {
        *ptr = table[*ptr];
    }
    return mat;
}

cv::Mat LUT_16_if(cv::Mat &mat)
{
    int limit = mat.rows * mat.cols;

    ushort* ptr = reinterpret_cast<ushort*>(mat.data);
    for (int i = 0; i < limit; i++, ptr++)
    {
        if (*ptr == 0){
            *ptr = 65535;
        }
        else{
            *ptr *= 100;
        }
    }
    return mat;
}

ushort* tablegen_zero()
{
    static ushort table[65536];
    for (int i = 0; i < 65536; ++i)
    {
        if (i == 0)
        {
            table[i] = 65535;
        }
        else
        {
            table[i] = i;
        }
    }
    return table;
}

(/):

  • LUT_16: 0,202 / 0,773
  • LUT_16_reinterpret_cast: 0,184 /0.801
  • LUT_16_if: 0,249 /0,860

, , reinterpret_cast 9% , ptr - 4% .

, if LUT 0,065 .

: 640x480x16-bit , Visual Studio 2013, i7 4750HQ.

+3

OpenCV . OpenCV . :

  • 8- (uchar)
  • 8- (schar)
  • 16- (ushort)
  • 16- ()
  • 32- (int)
  • 32- (float)
  • 64- (double)
  • , ( ).

cv::Mat , , , cv::Mat. , , cv::Mat ( ROI, ), .

:

cv::Mat cvmat16sc1 = cv::Mat::eye(10, 10, CV_16SC1);

if (cvmat16sc1.data)
{
    if (!cvmat16sc1.isContinuous())
    {
        cvmat16sc1 = cvmat16sc1.clone();
    }

    short* ptr = reinterpret_cast<short*>(cvmat16sc1.data);
    for (int i = 0; i < cvmat16sc1.cols * cvmat16sc1.rows; i++, ptr++)
    {
        if (*ptr == 1)
            std::cout << i << ": " << *ptr << std::endl;
    }
}
+4

The best solution for your problem is already written in the tutorial mentioned in the chapter "Effective Way". All you need to do is replace each uchar instance with ushort. No other changes are required.

+3
source

All Articles