Last active
October 9, 2020 11:42
-
-
Save enpe/369a7a17fd9b3856b544 to your computer and use it in GitHub Desktop.
Deleting rows (or columns) from cv::Mat.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For more details see: http://stackoverflow.com/questions/29696805/what-is-the-best-way-to-remove-a-row-or-col-from-a-cv-mat | |
#include "Timer.h" // http://www.songho.ca/misc/timer/timer.html | |
#include <opencv2/core/core.hpp> | |
#include <algorithm> | |
#include <numeric> | |
#include <iostream> | |
#include <cstring> | |
// Toggle the line below to test both versions. | |
#define US_CV_RECT | |
#ifdef US_CV_RECT | |
#define METHOD "cv::Rect + cv::Mat::copyTo()" | |
#else | |
#define METHOD "std::memcpy and/or for-loop" | |
#endif // US_CV_RECT | |
namespace { | |
template <typename T> | |
double removeRow( cv::Mat_<T> & matIn, int row ) | |
{ | |
cv::Size size = matIn.size(); | |
cv::Mat_<T> matOut( size.height - 1, size.width ); | |
Timer timer; | |
timer.start(); | |
#ifdef USE_CV_RECT | |
if ( row > 0 ) | |
{ | |
cv::Rect rect( 0, 0, size.width, row ); | |
matIn( rect ).copyTo( matOut( rect ) ); | |
} | |
if ( row < size.height - 1 ) | |
{ | |
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 ) ); | |
} | |
#else | |
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 ); | |
} | |
#endif | |
matIn = matOut; | |
return timer.getElapsedTimeInMicroSec();; | |
} | |
template <typename T> | |
double removeCol( cv::Mat_<T> & matIn, int col ) | |
{ | |
cv::Size size = matIn.size(); | |
cv::Mat_<T> matOut( size.height, size.width - 1 ); | |
Timer timer; | |
timer.start(); | |
#ifdef USE_CV_RECT | |
if ( col > 0 ) | |
{ | |
cv::Rect rect( 0, 0, col, size.height ); | |
matIn( rect ).copyTo( matOut( rect ) ); | |
} | |
if ( col < size.width - 1 ) | |
{ | |
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 ) ); | |
} | |
#else | |
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; | |
} | |
} | |
#endif | |
matIn = matOut; | |
return timer.getElapsedTimeInMicroSec();; | |
} | |
template < typename T > | |
void test( | |
double (*remove)( cv::Mat_<T> &, int ), | |
std::string removeDesc, | |
cv::Size size = cv::Size( 5, 5 ), | |
int rowcol = 3 ) | |
{ | |
cv::RNG rng( 0 /*cv::getCPUTickCount()*/ ); | |
cv::Mat_< T > mat( size ); | |
rng.fill( mat, cv::RNG::UNIFORM, 0, 10 ); | |
std::cout << "mat = " << std::endl << mat << std::endl << std::endl; | |
std::cout << "Removing " << removeDesc << ": " << rowcol << std::endl; | |
double elapsedTime = remove( mat, rowcol ); | |
std::cout << "mat = " << std::endl << mat << std::endl << std::endl; | |
} | |
template < typename T > | |
void measureTime( | |
double (*remove)( cv::Mat_<T> &, int ), | |
std::string removeDesc, | |
cv::Size size = cv::Size( 500, 500 ), | |
int count = 10000 ) | |
{ | |
cv::RNG rng( 0 ); | |
std::vector< double > times( count, 0. ); | |
for ( int i = 0; i < count; ++i ) | |
{ | |
cv::Mat_< T > mat = cv::Mat_< T >::eye( size ); | |
int row = rng.uniform( 0, std::min( size.width, size.height ) - 1 ); | |
times[ i ] = remove( mat, row ); | |
} | |
if ( times.size() > 0 ) | |
{ | |
double numTimes = static_cast< double >( times.size() ); | |
double min = *( std::min_element( times.begin(), times.end() ) ); | |
double max = *( std::max_element( times.begin(), times.end() ) ); | |
double avg = std::accumulate( times.begin(), times.end(), 0. ) / numTimes; | |
std::sort( times.begin(), times.end() ); | |
double med = times[ times.size() / 2 ]; | |
std::cout << "Removed: " << removeDesc << std::endl; | |
std::cout << "Method: " << METHOD << std::endl; | |
std::cout << "Iterations: " << count << std::endl; | |
std::cout << "Size: " << size << std::endl; | |
std::cout << "Best time: " << min << "ms" << std::endl; | |
std::cout << "Worst time: " << max << "ms" << std::endl; | |
std::cout << "Average time: " << avg << "ms" << std::endl; | |
std::cout << "Median time: " << med << "ms" << std::endl; | |
} | |
} | |
} // namespace | |
int main( int argc, char ** argv ) | |
{ | |
std::cout << "--- Removing rows -----------------------------------------------" << std::endl; | |
test< int >( removeRow, "row" ); | |
measureTime< int >( removeRow, "row" ); | |
std::cout << std::endl; | |
std::cout << "--- Removing columns --------------------------------------------" << std::endl; | |
test< int >( removeCol, "column" ); | |
measureTime< int >( removeCol, "column" ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment