2

Actually, I'm encountering this problem:

OpenCV Error: Insufficient memory (Failed to allocate 225792004 bytes) in OutOfMemoryError, file /build/buildd/opencv-2.4.8+dfsg1/modules/core/src/alloc.cpp, line 52
terminate called after throwing an instance of 'cv::Exception'
  what():  /build/buildd/opencv-2.4.8+dfsg1/modules/core/src/alloc.cpp:52: error: (-4) Failed to allocate 225792004 bytes in function OutOfMemoryError

when I call the following method from the main.. I'm working with 36 images in listOfImages

void MainHelper::startProcessingDataSampleForROCCurve(bool downSampleData)
{
    /*Step 5: Load test data*/
    vector <Mat> imagesToTest;

    ///Looping over the segmented to validate the method we did
    Diagnostics diagnoLearningAndTesting;
    WindowsDataSet windowsDataSetInstance;
    map <int , vector < double > > areaCalculatedPerImageForEachK;
    for (int indexImage = 0; indexImage < listOfImages.size(); indexImage++)
    {
        Mat imageTestForIteration = listOfImages[indexImage];
        imagesToTest.push_back(imageTestForIteration);
        Mat imageTestBinaryForIteration = listOfBinaryImages[indexImage];

        //Prepare the learning image list by removing only the image for testing
        vector<Mat> listOfLearningImages(listOfImages.begin(),listOfImages.end());
        listOfLearningImages.erase(listOfLearningImages.begin() + indexImage);
        vector<Mat> listOfBinaryLearningImages(listOfBinaryImages.begin(),listOfBinaryImages.end());
        listOfBinaryLearningImages.erase(listOfBinaryLearningImages.begin() + indexImage);

        /*Step 7: Processing the images by having a vector of descriptor for every window in the image*/
        ImageProcessingManager imageManager;
        map <int , vector< vector<double> > > dictWindowPerFeaturesPerTile;
//        map <int , vector< vector<Mat> > > dictTilesPerLearningImage;
        map <int , vector< int > > dictAnnotationPerTile;


        diagnoLearningAndTesting.startMethod(StringUtils::stringFormat("Learning Part.. %d",(indexImage + 1)));
        for (int indexWindowLength = 0; indexWindowLength < Constants::windowsSize.size(); indexWindowLength ++)
        {
            int windowLength = Constants::windowsSize[indexWindowLength];
            vector < int > annotationPerTile;
            //TODO: It won't be filled for now for memory reasons
            vector < vector <Mat> > tilesPerLearningImage;
            vector < vector <double> > featuresPerTile = imageManager.processImagesInWindowsWithFeatures(listOfLearningImages, listOfBinaryLearningImages, tilesPerLearningImage, annotationPerTile, windowLength, Constants::percentageOfWhiteToConsiderIntrumentWindow);
            dictWindowPerFeaturesPerTile[windowLength] = featuresPerTile;
//            dictTilesPerLearningImage[windowLength] = tilesPerLearningImage;
            dictAnnotationPerTile[windowLength] = annotationPerTile;
        }
        diagnoLearningAndTesting.endMethod();
        MemoryUtils::displayMemoryUsage();


        diagnoLearningAndTesting.startMethod(StringUtils::stringFormat("Testing Part.. %d",(indexImage + 1)));
        //TODO: Change the value of the param here..
        for (int kNearestNeighbor = 2; kNearestNeighbor <= Constants::kNearestNeighbor; kNearestNeighbor ++)
        {
            Diagnostics::LogWithTime(StringUtils::stringFormat("*** Running annotations with K = %d", kNearestNeighbor));

            if (Constants::hierarchyWindowLevel == Multiple)
            {
                for (int indexOfImage = 0; indexOfImage < imagesToTest.size(); indexOfImage ++)
                {
                    Mat image = imagesToTest[indexOfImage];
                    vector <Mat> testImagesInVect = boost::assign::list_of(image);

                    Mat binaryResultOfImageTest(image.rows, image.cols, CV_8UC1, Scalar(0.));
                    vector <Mat> binaryTestImagesInVect = boost::assign::list_of(binaryResultOfImageTest);

                    for (int indexWindowLength = 0; indexWindowLength < Constants::windowsSize.size(); indexWindowLength ++)
                    {
                        int windowLength = Constants::windowsSize[indexWindowLength];
                        Diagnostics::LogWithTime(StringUtils::stringFormat("Running annotations with windowLength = %d", windowLength));

                        /*Step 7-1: Learning vectors already loaded */
                        vector < int > annotationPerTile = dictAnnotationPerTile[windowLength];
//                        vector < vector <Mat> > tilesPerLearningImage = dictTilesPerLearningImage[windowLength];
                        vector < vector <double> > featuresPerTile = dictWindowPerFeaturesPerTile[windowLength];

                        /*Step 8: Processing the samples on which we need to make our tests by having a vector of descriptor for every window in the image*/
                        //TODO: GET THE BINARY VERSION OF THE IMAGES******
                        vector< vector <int> > annotationPerImageForTiles;
                        vector < vector <Mat> > tilesPerTestImage;
                        vector < vector < vector <double> > > featuresPerTiles = imageManager.processSetOfImages(testImagesInVect, vector<Mat>(), tilesPerTestImage, windowLength, Constants::percentageOfWhiteToConsiderIntrumentWindow, annotationPerImageForTiles);
                        vector < vector <Mat> > binaryTiles = imageManager.divideBinaryImagesInTiles(binaryTestImagesInVect, windowLength);

                        /*Step 9: Knn Classifier train data */
                        Mat trainData = VectorUtility <double>::toMat(featuresPerTile);
                        Mat dataClasses = VectorUtility <int>::toMat(annotationPerTile);
                        ClassifierManager classifier(trainData, dataClasses, kNearestNeighbor);

                        /*Step 10: Annotation Step*/
                        vector < vector <int> > resultsForEachTilePerImage = classifier.annotateTheTilesInImages(featuresPerTiles);

                        /*Step 10-1: Annotation Step with window hierarchy: Extract tiles which have probability > 0*/
                        vector <Mat> instrumentTiles;
                        vector <Mat> instrumentBinaryTiles;
                        for (int resultIndex = 0; resultIndex < resultsForEachTilePerImage.size(); resultIndex ++)
                        {
                            vector <int> resultsForTilePerImage = resultsForEachTilePerImage[resultIndex];
                            vector <Mat> tilesPerImage = tilesPerTestImage[resultIndex];
                            vector <Mat> tilesPerBinaryImage = binaryTiles[resultIndex];
                            for (int resultIndex = 0; resultIndex < resultsForTilePerImage.size(); resultIndex ++)
                            {
                                int result = resultsForTilePerImage[resultIndex];
                                if (result > 0)
                                {
                                    Mat tile = tilesPerImage[resultIndex];
                                    instrumentTiles.push_back(tile);
                                    Mat binaryTile = tilesPerBinaryImage[resultIndex];
                                    instrumentBinaryTiles.push_back(binaryTile);

                                    if (indexWindowLength == Constants::windowsSize.size() - 1)
                                    {
                                        int valueOfPixel = (result * 255) / 100;
                                        //This region should be set to valueOfPixel..
                                        binaryTile.setTo(valueOfPixel);
                                    }
                                }
                            }
                        }
                        testImagesInVect = instrumentTiles;
                        binaryTestImagesInVect = instrumentBinaryTiles;

                        //Release objects for memory reasons..
                        resultsForEachTilePerImage.clear();
                        tilesPerTestImage.clear();binaryTiles.clear();
                        trainData.release();dataClasses.release();
                        featuresPerTiles.clear();
                    }

                    /*Step 11: Draw images with the regions of interest we want*/
                    string imagePrefix = StringUtils::stringFormat("%sM-ImageResult%d-k%d-WL", Constants::pathOfResultImages.c_str(), indexImage,kNearestNeighbor);
                    for (int indexWindowLength = 0; indexWindowLength < Constants::windowsSize.size(); indexWindowLength ++)
                    {
                        imagePrefix = StringUtils::concat(imagePrefix, numberToString(Constants::windowsSize[indexWindowLength]));
                    }
                    string imageName = StringUtils::stringFormat("%s.png", imagePrefix.c_str());
                    imwrite(imageName, binaryResultOfImageTest);

                    if (Constants::generateROCCurve)
                    {
                        /*Step 12: Validation steps by showing the percentage of accuracy of this method (ROC courbe)*/
                        double areaOfAZ = windowsDataSetInstance.ROCCurveFor(imageTestBinaryForIteration, binaryResultOfImageTest, image, Constants::pathOfResultImages, StringUtils::stringFormat("%d-k%d.txt",indexImage, kNearestNeighbor), kNearestNeighbor);
                        vector <double> listOfAreasCalculated = areaCalculatedPerImageForEachK[kNearestNeighbor];
                        listOfAreasCalculated.push_back(areaOfAZ);
                        areaCalculatedPerImageForEachK[kNearestNeighbor] = listOfAreasCalculated;
                    }

                }

            }
        }

        //Clear Objects for memory reasons
        dictAnnotationPerTile.clear();dictWindowPerFeaturesPerTile.clear();
        listOfLearningImages.clear();listOfBinaryLearningImages.clear();

        diagnoLearningAndTesting.endMethod();

        //Clear all elements of imagesToTest
        imagesToTest.clear();
        MemoryUtils::displayMemoryUsage();

    }


    //Step #12: Additional step to display the mean and standard variation of the list of Areas calculated for each value of K
    for (std::map<int, vector <double> >::iterator it = areaCalculatedPerImageForEachK.begin(); it != areaCalculatedPerImageForEachK.end(); ++it)
    {
        vector < double> areas = it->second;
        double mean = VectorUtility<double>::mean(areas);
        double std = VectorUtility<double>::standardDeviation(areas, mean);

        Diagnostics::LogWithTime(StringUtils::stringFormat("******* For K = %d : Mean(Az) = %f, Std(Az) = %f",it->first, mean, std));
    }
}

I don't think we should go through the details of each method called here because what I'm looking for is a way to free up the memory at the end of each iteration of the first for which means free up the vectors/maps allocated and their objects. I could not find any solution to do so, so my question: Do you have any idea on how to do it? Also, am I on the right track or I should go through to the details to find where exactly the problem is?

Maystro
  • 2,907
  • 8
  • 36
  • 71

1 Answers1

4

You are doing some copies, try instead to keep const ref on your objects that won't be modified. You can also use the std::move in order to avoid copies.

For example, in your code :

Mat image = imagesToTest[indexOfImage];

You are actually copying a Mat that in your case is an image and therefore take a big part of memory.

That's the same with a big part of your code.

See here to move your data instead of doing actual copies : When to use Move Constructors/Assignments


You can also limit the lifetime of your variables to the minimum possible by "pushing" them to the minimal stack you can. You can even create artificial stack to limit the reach of your variables.

For example :

Mat a;
{
    Mat b;
    // ... do some stuff
} // Mat b won't exists any more after here
// Mat a still exists

When you say :

I don't think we should go through the details of each method called here

I think you are doing a mistake and you should actually check the signature of each of your methods to see if you don't actually do any superfluous copy. See : Is it better in C++ to pass by value or pass by constant reference?

Community
  • 1
  • 1
dkg
  • 1,775
  • 14
  • 34