简体   繁体   中英

Most efficient way to clear an image in opencv2/3

I'm currently porting my old OpenCV C code to the C++ interface of OpenCV 2/3 and I'm not quite sure about some equivalents of old functions. Pretty early I ran into an issue with cvZero . The only possibility I found was to set the matrix content via Mat::setTo . Now, having to be able to manage multi-channel scalars and different data types, setTo iterates through all elements of the matrix and sets them one after another while cvZero basically did a memset . I am wondering what would be the recommended way for using the C++ interface, in case I just want to clear my image black.

Thanks!

yourMat = cv::Mat::zeros(yourMat.size(), yourMat.type()) does not seem to allocate new memory but only overwrites the existing Mat object (memory was previously allocated, otherwise .size is 0). Not sure whether memset is used internally, but this sample code gives 50% longer processing time for the version with .setTo compared to the version with cv::Mat::zeros - but I didn't evaluate the offset from the manipulation (which should be quite identical in both versions)!

int main(int argc, char* argv[])
{
    cv::Mat input = cv::imread("C:/StackOverflow/Input/Lenna.png");

    srand(time(NULL));

    cv::Mat a = input;
    cv::Mat b = input;
    cv::imshow("original", a);

    b = cv::Mat::zeros(a.size(), a.type());

    std::vector<int> randX;
    std::vector<int> randY;
    std::vector<cv::Vec3b> randC;

    int n = 500000;

    randX.resize(n);
    randY.resize(n);
    randC.resize(n);

    for (unsigned int i = 0; i < n; ++i)
    {
        randX[i] = rand() % input.cols;
        randY[i] = rand() % input.rows;
        randC[i] = cv::Vec3b(rand()%255, rand()%255, rand()%255);
    }

    clock_t start1 = clock();
    for (unsigned int i = 0; i < randX.size(); ++i)
    {
        b.at<cv::Vec3b>(randY[i], randX[i]) = randC[i];
        b = cv::Mat::zeros(b.size(), b.type());
    }
    clock_t end1 = clock();

    clock_t start2 = clock();
    for (unsigned int i = 0; i < randX.size(); ++i)
    {
        b.at<cv::Vec3b>(randY[i], randX[i]) = randC[i];
        b.setTo( cv::Scalar(0, 0, 0));
    }
    clock_t end2 = clock();

    std::cout << "time1 = " << ( (end1 - start1) / CLOCKS_PER_SEC )  << " seconds" << std::endl;
    std::cout << "time2 = " << ((end2 - start2) / CLOCKS_PER_SEC) << " seconds" << std::endl;


    cv::imshow("a", a);
    cv::imshow("b", b);

    cv::waitKey(0);
    return 0;
}

gives me output:

time1 = 14 seconds
time2 = 21 seconds

on my machine (Release mode) (no IPP). and a black image for both, a and b which indicates that no new memory was allocated, but the existing Mat memory was used.

int n = 250000; will produce output

time1 = 6 seconds
time2 = 10 seconds

This is no answer about whether or not memset is used internally or whether or not it is as fast as cvZero, but at least you know now how to set to zero faster than .setTo

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