Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the best way to remove a row or col from a cv mat

Assume that I have a mat object such as follow:

mat = 
   [75, 97, 66, 95, 15, 22;
    24, 21, 71, 72, 34, 66;
    21, 69, 88, 72, 64, 1;
    26, 47, 26, 40, 95, 24;
    70, 37, 9, 83, 16, 83];

and I want to remove a row from it say second row to have a mat like this:

 [75, 97, 66, 95, 15, 22;
 21, 69, 88, 72, 64, 1;
 26, 47, 26, 40, 95, 24;
 70, 37, 9, 83, 16, 83]

or deleting a col say col 3:

[75, 97,  95, 15, 22;
 24, 21,  72, 34, 66;
 21, 69,  72, 64, 1;
 26, 47,  40, 95, 24;
 70, 37,  83, 16, 83]

what is the fastest way to do this? I can break the matrix into to ROI and then merge them to each other, but is there any better way?

like image 714
mans Avatar asked Sep 11 '25 20:09

mans


1 Answers

I tested two ways:

  1. Using cv::Rect and cv::Mat::copyTo:

    // Removing a row
    cv::Mat matIn;    // Matrix of which a row will be deleted.
    int row;          // Row to delete.
    int col;          // Column to delete.
    cv::Mat matOut;   // Result: matIn less that one row.
    
    if ( row > 0 ) // Copy everything above that one row.
    {
        cv::Rect rect( 0, 0, size.width, row );
        matIn( rect ).copyTo( matOut( rect ) );
    }
    
    if ( row < size.height - 1 ) // Copy everything below that one row.
    {
        cv::Rect rect1( 0, row + 1, size.width, size.height - row - 1 );
        cv::Rect rect2( 0, row, size.width, size.height - row - 1 );
        matIn( rect1 ).copyTo( matOut( rect2 ) );
    }
    
    // Removing a column
    if ( col > 0 ) // Copy everything left of that one column.
    {
        cv::Rect rect( 0, 0, col, size.height );
        matIn( rect ).copyTo( matOut( rect ) );
    }
    
    if ( col < size.width - 1 ) // Copy everything right of that one column.
    {
        cv::Rect rect1( col + 1, 0, size.width - col - 1, size.height );
        cv::Rect rect2( col,     0, size.width - col - 1, size.height );
        matIn( rect1 ).copyTo( matOut( rect2 ) );
    }
    
  2. Using std::memcpy and cv::Mat::data:

    // Removing a row
    int rowSizeInBytes = size.width * sizeof( T );
    
    if ( row > 0 )
    {
        int numRows  = row;
        int numBytes = rowSizeInBytes * numRows;
        std::memcpy( matOut.data, matIn.data, numBytes );
    }
    
    if ( row < size.height - 1 )
    {
        int matOutOffset = rowSizeInBytes * row;
        int matInOffset  = matOutOffset + rowSizeInBytes;
    
        int numRows  = size.height - ( row + 1 );
        int numBytes = rowSizeInBytes * numRows;
        std::memcpy( matOut.data + matOutOffset , matIn.data + matInOffset, numBytes );
    }
    
    // Removing a column
    int rowInInBytes  = size.width * sizeof( T );
    int rowOutInBytes = ( size.width - 1 ) * sizeof( T );
    
    if ( col > 0 )
    {
        int matInOffset = 0;
        int matOutOffset = 0;
        int numCols = col;
        int numBytes = numCols * sizeof( T );
    
        for ( int y = 0; y < size.height; ++y )
        {
            std::memcpy( matOut.data + matOutOffset, matIn.data + matInOffset, numBytes );
    
            matInOffset  += rowInInBytes;
            matOutOffset += rowOutInBytes;
        }
    }
    
    if ( col < size.width - 1 )
    {
        int matInOffset = ( col + 1 ) * sizeof( T );
        int matOutOffset = col * sizeof( T );
        int numCols = size.width - ( col + 1 );
        int numBytes = numCols * sizeof( T );
    
        for ( int y = 0; y < size.height; ++y )
        {
            std::memcpy( matOut.data + matOutOffset, matIn.data + matInOffset, numBytes );
    
            matInOffset  += rowInInBytes;
            matOutOffset += rowOutInBytes;
        }
    }
    

A timing test for the first method showed:

Removed:      row
Method:       cv::Rect + cv::Mat::copyTo()
Iterations:   10000
Size:         [500 x 500]
Best time:    67ms
Worst time:   526ms
Average time: 70.9061ms
Median time:  70ms

Removed:      column
Method:       cv::Rect + cv::Mat::copyTo()
Iterations:   10000
Size:         [500 x 500]
Best time:    64ms
Worst time:   284ms
Average time: 80.3893ms
Median time:  79ms

And for the second method:

Removed:      row
Method:       std::memcpy and/or for-loop
Iterations:   10000
Size:         [500 x 500]
Best time:    31ms
Worst time:   444ms
Average time: 68.9445ms
Median time:  68ms

Removed:      column
Method:       std::memcpy and/or for-loop
Iterations:   10000
Size:         [500 x 500]
Best time:    49ms
Worst time:   122ms
Average time: 79.3948ms
Median time:  78ms

So, given the close timing results and the short implementation, the first method seems more suitable. I posted a minimal working example on github in order to verify the results of this test.

like image 123
nils Avatar answered Sep 14 '25 10:09

nils