简体   繁体   中英

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?

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.

To delete row N:

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

To delete 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: 2nd code (delete column) reads extra row behind matrix. in most cases, this is acceptable, and algorithm keep simple. If needed, modify code for pass correct size into last memmove.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM