What's the best way to remove row or column from cv mat

Suppose I have a mat object like:

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 line from it, say the second line, to have the same math:

 [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 removing 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's the fastest way to do this? I can split the matrix into ROIs and then combine them with each other, but is there a better way?

+3


source to share


2 answers


I tested two ways:

  • Usage 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 ) );
    }
    
          

  • Usage 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;
        }
    }
    
          

The time 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 time results and the short implementation, the first method seems more appropriate. I checked out a minimal working github example to verify the results of this test.

+5


source


To remove line N:

memmove(mat + N * x_size, 
        mat + (N + 1) * x_size, 
        x_size * sizeof(int) * (y_size - N - 1));

      

To remove col N:



for(int y = 0; y < y_size; y++)
  memmove(mat + N + y * (x_size - 1), 
  mat + N + y * x_size + 1, 
  (x_size - 1) * sizeof(int));

      

ATTN: The second code (delete column) reads an extra row by matrix. in most cases this is acceptable and the algorithm remains simple. Modify the code as needed to get the correct size in the last memmove.

+1


source







All Articles