0
votes

I've written a method where an image descriptor (like OpenCV SIFT or VLFeat Dense SIFT) computes the descriptors for a set of images (save in std::vector<std::string> files). The descriptor is called through ComputeDescriptors(image, descriptorMatrix) where it fills descriptorMatrix with the descriptors computed from.

Then I randomly pick samples (usually 50) descriptors and push the sampledDescriptors matrix in the returned std::vector<cv::Mat1f> descriptors.

This is the code:

void SIFTDescriptor::ComputeDescriptorsRange(const std::vector<std::string> &files, std::vector<cv::Mat1f> &descriptors){
    cv::Mat1f imgDescriptors;
    cv::Mat img;
    for(int i=0 ; i<files.size() ; i++){
        std::cout<<"Describing "<<files[i]<<std::endl;
        img = cv::imread(files[i], cv::IMREAD_GRAYSCALE);
        if(!img.data)
            //throw error
        //resoze dim is a class member
        if(resizeDim>0)
            ImgUtility::resize(img,resizeDim);
        ComputeDescriptors(img,imgDescriptors);
        if(samples > 0 && samples < imgDescriptors.rows){
            std::cout<<"Sampling "<<imgDescriptors.rows<<" descriptors..."<<std::endl;
            cv::Mat1f sampledDescripotrs;
            std::vector<int> v(imgDescriptors.rows);
            std::iota (std::begin(v), std::end(v), 0); //fill v with 0 ... imgDescriptors.rows
            std::random_device rd;
            std::mt19937 g(rd());
            std::shuffle(v.begin(), v.end(), g);
            for(int j=0 ; j<samples; j++){
                sampledDescripotrs.push_back(imgDescriptors.row(v[j]));
            }
            descriptors.push_back(sampledDescripotrs);
            sampledDescripotrs.release();
        }
        else
            descriptors.push_back(imgDescriptors); //copy of a smart pointer, not expensive
        imgDescriptors.release();
        std::cout<<"descriptors["<<i<<"]="<<descriptors[i].rows<<std::endl;
        std::cout<<descriptors[i]<<std::endl;
    }

This is done to be memory efficient, especially for dense descriptors such as VLFeat Dense SIFT where thousands of descriptors are extracted. With thousands of images we would run out of memory in no time. Instead, using this solution, we keep only 50 descriptors per image (which is enough for my training).

However, for some weird reason, there is no big memory usage using OpenCV SIFT, but using VLFeat Dense SIFT the memory grows pretty fast, even if samples is equal in both cases!

My only explanation is that the memory used by imgDescriptors at each loop is not freed, even using imgDescriptors (which is should be not necessary anyway since cv::Mat1f should be kinda smart pointer and so deallocate itself at the end of the loop), but I don't understand how's this possible.

This is the ComputeDescriptor code for dense SIFT in VLFeat:

void DSIFTVLFeat::ComputeDescriptors(cv::Mat &img, cv::Mat1f &descriptors){
    descriptors.release();

    // transform image in cv::Mat to float vector
    cv::Mat imgFloat;
    img.convertTo(imgFloat, CV_32F, 1.0/255.0);
    if(!imgFloat.isContinuous())
        throw std::runtime_error("imgFloat is not continous");

    for(int i=binSize; i<=maxBinSize; i+=2){
        VlDsiftFilter *dsift = vl_dsift_new_basic (img.rows, img.cols, step, i);
        vl_dsift_process (dsift, imgFloat.ptr<float>());
        cv::Mat scaleDescs(vl_dsift_get_keypoint_num(dsift), 128, CV_32F, (void*) vl_dsift_get_descriptors(dsift));
        descriptors.push_back(scaleDescs);
        scaleDescs.release();
        free(dsift);
    }
}
1

1 Answers

0
votes

I found out by myself the problem: apparently free(dsift) doesn't de-allocate the created descriptors, so I was stacking them on the heap without releasing them.

Calling: vl_sift_delete(dsift) instead seems to have solved the problem.