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);
}
}