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:
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 ) );
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With