2015-07-08 2 views
0

Я пытаюсь создать программу «Сумка визуальных слов», но у меня возникает проблема. Каждый раз, когда я запускаю программу, я либо получаю ошибку segmentation fault: 11, либо если я изменяю переменную dictSize, я получаю error: (-215) N >= K in function kmeans. Я попытался изменить размер изображений, используя разные, но ничего не помогает. Вот то, что я до сих пор:Любая ошибка сегментации 11 или (-215) N> = K

#include <opencv2/core/core.hpp> 
#include "opencv2/highgui/highgui.hpp" 
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/features2d/features2d.hpp> 
#include <opencv2/xfeatures2d.hpp> 

#include <iostream> 
#include <stdio.h> 
#include <dirent.h> 
#include <string.h> 

using namespace std; 
using namespace cv; 

int main(int argc, const char** argv) { 

    //=================================== LEARN =================================== 

    struct dirent *de = NULL; 
    DIR *d = NULL; 
    d = opendir(argv[1]); 
    if(d == NULL) 
    { 
     perror("Couldn't open directory"); 
     return(2); 
    } 

    Mat input; 
    vector<KeyPoint> keypoints; 
    Mat descriptor; 
    Mat featuresUnclustered; 
    Ptr<DescriptorExtractor> detector = xfeatures2d::SIFT::create(); 


    while((de = readdir(d))){ 
      if ((strcmp(de->d_name,".") != 0) && (strcmp(de->d_name,"..") != 0) && (strcmp(de->d_name,".DS_Store") != 0)) { 

      char fullPath[] = "./"; 
      strcat(fullPath, argv[1]); 
      strcat(fullPath, de->d_name); 
      printf("Current File: %s\n",fullPath); 

      input = imread(fullPath,CV_LOAD_IMAGE_GRAYSCALE); 
      cout << "Img size => x: " << input.size().width << ", y: " << input.size().height << endl; 
      // If the incoming frame is too big, resize it 
      if (input.size().width > 3000) { 
       double ratio = (3000.0)/(double)input.size().width; 
       resize(input, input, cvSize(0, 0), ratio, ratio); 
       cout << "New size => x: " << input.size().width << ", y: " << input.size().height << endl; 
      } 

      detector->detect(input, keypoints); 
      detector->compute(input, keypoints, descriptor); 
      featuresUnclustered.push_back(descriptor); 
     } 
    } 

    closedir(d); 

    int dictSize = 200; 
    TermCriteria tc(CV_TERMCRIT_ITER,100,0.001); 
    int retries = 1; 
    int flags = KMEANS_PP_CENTERS; 
    BOWKMeansTrainer bowTrainer(dictSize,tc,retries,flags); 
    Mat dictionary = bowTrainer.cluster(featuresUnclustered); 
    FileStorage fs("dict.yml",FileStorage::WRITE); 
    fs << "vocabulary" << dictionary; 
    fs.release(); 

    return 0; 
} 

ответ

1
char fullPath[] = "./"; 
    strcat(fullPath, argv[1]); 
    strcat(fullPath, de->d_name); 

Та часть кода представляет собой серьезную ошибку (неопределенное поведение, но сегментный вина скорее всего). strcat does не выделить дополнительное пространство для конкатенации. Он только перезаписывает все, что следует за завершающим нулем в первой строке. Ваш fullPath выделяется достаточно места для начальных двух символов плюс завершающий нуль. Независимо от того, что завершающий нуль может быть памятью, принадлежащей какой-либо другой части вашей программы.

Если вы знаете максимальную длину пути к файлу для своей ОС, вы можете использовать грубую коррекцию для помещения этого max plus 2 в число (или названную константу) между [] в объявлении fullPath.

Более грубая поправка заключается в вычислении требуемой длины строки, которую вы хотите построить, и malloc, что много места (обязательно подсчитайте завершающий нуль) и объедините три строки там.

+0

Вышеуказанный ответ сфокусирован только на ошибку seg, которая, по-видимому, является фокусом исходного вопроса. Есть еще что-то, что я считал бы «неправильным» с исходным кодом, например, идея добавления «./» к указанному каталогу. Мои предложения по исправлению ** того, как вы это делаете, не должны рассматриваться как одобрение идеи о том, что вы должны это делать. Я не пытаюсь переписать всю вашу программу лучше. – JSF

+0

Кроме того, ваша манипуляция строками C в коде C++ неразумна. Хотя мой ответ был направлен на устранение ошибки seg из-за неправильного использования строк C, ваш лучший выбор заключался бы в сокращении использования строк C. Преобразуйте строки C в std :: string перед тем, как манипулировать ими, а затем войдите в std :: string как строку C после манипуляции, когда вам понадобится снова строка C. – JSF

+0

Эй, JSF, как вы могли заметить, я полный новичок на C++. Я исправил то, что вы указали, но это не решило мою проблему. Я посмотрю, смогу ли я это исправить. – ruben1691