запись данных этикетки ITK в файл максимально быстрым способом

Я застрял в неприятной проблеме оптимизации в моем программном обеспечении для анализа КТ. Я использую ITK для выполнения тяжелой фильтрации данных и, наконец, с помощью itk binaryImageToshapeLabelMapFilter я изолирую некоторые отдельные регионы и сохраняю координаты каждой точки, принадлежащей им, в текстовый файл (который затем будет вводом другого отдельного программа уже сделана)

Проблема в том, что фаза записи в файл занимает, в случае очень больших регионов, гораздо больше времени, чем сама фильтрация (мне довелось отфильтровать некоторые наборы данных за 30 минут, а запись в файл заняла еще час).

В следующем коде я уже пытался избежать сбрасывания в конце каждой строки ("\n" вместо endl), но, похоже, ничего не изменилось. Есть ли у вас какие-либо идеи о том, как я могу значительно улучшить запись в файл этих данных?

С уважением, Эмилиано

ofstream outFile;
string labelsFile = subFolderPath+"/regionLabels_"+volumeCompleteName+".lri";
outFile.open(labelsFile.c_str());
outFile << "LabelIndexes - v1.0" << "\n";
outFile << "Dataset Origin : "<< originX << "," << originY << "," << originZ << "\n";

int cloud = 0;

for(unsigned int i = 0; i < binaryImageToShapeLabelMapFilter->GetOutput()->GetNumberOfLabelObjects(); i++){
    BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = binaryImageToShapeLabelMapFilter->GetOutput()->GetNthLabelObject(i);
    if(labelObject->GetNumberOfPixels()>4500){
        outFile << "Region " << cloud << "\n";
        outFile << "Centroid " << labelObject->GetCentroid() << "\n";
        outFile << labelObject->GetNumberOfPixels() << "\n";
        for(int j=0;j<labelObject->Size();j++){
            //Only save the labels for voxels at least 2 voxels distant from the edge of the dataset
            if(labelObject->GetIndex(j)[0]>2 && labelObject->GetIndex(j)[1]>2 && labelObject->GetIndex(j)[2]>2){
                if(labelObject->GetIndex(j)[0]<(maxX-2) && labelObject->GetIndex(j)[1]<(maxY-2) && labelObject->GetIndex(j)[2]<(maxZ-2)){
                    outFile << labelObject->GetIndex(j) << "\n";
                }
            }
        }
        cloud++;
    }
}
outFile << "EndOfFile" << "\n";
outFile.flush();
outFile.close();
cout << "All labels indices saved to file : " << labelsFile << endl;

Последний дополнительный вопрос. У меня не было времени попробовать набор данных, который я уже отфильтровал с помощью старого метода, но последние 2, которые я отфильтровал с помощью нового, похоже, теряют половину каждого региона. Я неправильно использую индексы, используя их следующим образом:

FILE* fout = fopen(labelsFile.c_str(), "w");
fprintf(fout,"LabelIndexes - v1.0\n");
fprintf(fout,"Dataset Origin : %d,%d,%d\n",originX,originY,originZ);

for(unsigned int i = 0; i < binaryImageToShapeLabelMapFilter->GetOutput()->GetNumberOfLabelObjects(); i++){
    BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = binaryImageToShapeLabelMapFilter->GetOutput()->GetNthLabelObject(i);
    if(labelObject->GetNumberOfPixels()>4500){
        fprintf(fout,"Region %d \n",cloud);
        double c1 = labelObject->GetCentroid()[0];
        double c2 = labelObject->GetCentroid()[0];
        double c3 = labelObject->GetCentroid()[0];
        fprintf(fout,"Centroid [%f, %f, %f]\n",c1,c2,c3);
        fprintf(fout,"%u\n",(long)labelObject->GetNumberOfPixels());
        for (int l = 0; l < labelObject->GetNumberOfLines(); ++l){
             LabelObjectLine<3> line = labelObject->GetLine(l);
             OutputImageType::IndexType startIndex = line.GetIndex();
             int i1 = startIndex[0];
             int i2 = startIndex[1];
             int i3 = startIndex[2];
             if(i1>2 && i2>2 && i3>2 && i1<(maxX-2) && i2<(maxY-2) && i3<(maxZ-2))fprintf(fout,"[%d, %d, %d]\n",i1,i2,i3);
         }
         cloud++;
    }
}

person drHogan    schedule 15.10.2014    source источник


Ответы (2)


Вы пробовали профилировать свой код? Это, вероятно, скажет вам, куда идет время вычислений.

Однако я думаю, что дело в многочисленных вызовах labelObject::GetIndex. Если вы посмотрите на реализацию LabelObject::GetIndex, вы увидите, что она соответствует количеству строк в объекте метки. Вы вызываете его 7 раз на индекс. Просто сохраните результаты вызова этой функции в переменную, и вы получите 7-кратное ускорение.

Однако давайте посмотрим на вычислительную стоимость цикла! Цикл выполняется по количеству индексов в объекте метки, а затем по коэффициенту умножения вызова GetIndex. Это приводит к тому, что порядок вычислений значительно превышает количество индексов в объекте метки.

Лучшим подходом было бы использование метода LabelObject::GetLine и линейного алгоритма:

 for (l = 0; l < labelObject.GetNumberOfLines(); ++l)
   line = labelObject.GetLine(l)
   startIndex = line.GetIndex();
   endIndex = startIndex;
   endIndex[0] = endIndex[0] + line.GetLength() - 1
   // determine which indexes to print.

Это уменьшит вычислительную сложность до количества строк. Меня бы не удивило, если бы с этим подходом это заняло меньше минуты.

person blowekamp    schedule 15.10.2014
comment
Я попробую немедленно, вчера я пытался переписать все это на C (fprintf и т. д.), а также буферизовать индексы, но результаты были не намного более обнадеживающими. Я дам вам знать как можно скорее! Спасибо! - person drHogan; 16.10.2014
comment
Вы абсолютно сделали мой день с этим решением. И мой последний день перед недельным отпуском, вы сделали меня намного счастливее и спокойнее! мы действительно снизились до менее чем 1 минуты. Ваше здоровье! - person drHogan; 16.10.2014
comment
Я не вижу ничего явно плохого в том, что может дать ваши недостающие регионы. Однако переменная c1, c2, c3 установлена ​​неправильно. - person blowekamp; 17.10.2014
comment
я вижу центроид, где я забыл изменить индекс, спасибо. у меня такое ощущение, что для каждой строки я печатаю только первый индекс. теперь возвращаюсь к работе, даже если это суббота, я постараюсь это исправить, спасибо. Довольно сложно найти подробную документацию и примеры некоторых нишевых функций ITK. - person drHogan; 25.10.2014

В конце концов, я неправильно использовал индексы, в противном случае решение блэкампа было оптимальным. Вот рабочая версия цикла (для решения проблемы потребовалась неприятная отладка):

for(unsigned int i = 0; i < binaryImageToShapeLabelMapFilter->GetOutput()->GetNumberOfLabelObjects(); i++){
        BinaryImageToShapeLabelMapFilterType::OutputImageType::LabelObjectType* labelObject = binaryImageToShapeLabelMapFilter->GetOutput()->GetNthLabelObject(i);
        if(labelObject->GetNumberOfPixels()>4500){
            fprintf(fout,"Region %d \n",cloud);
            double c1 = labelObject->GetCentroid()[0];
            double c2 = labelObject->GetCentroid()[1];
            double c3 = labelObject->GetCentroid()[2];
            fprintf(fout,"Centroid [%f, %f, %f]\n",c1,c2,c3);
            fprintf(fout,"%u\n",(long)labelObject->GetNumberOfPixels());
            for (int l = 0; l < labelObject->GetNumberOfLines(); ++l){
                 LabelObjectLine<3> line = labelObject->GetLine(l);
                 OutputImageType::IndexType startIndex = line.GetIndex();
                 long lastIndex = startIndex[0]+line.GetLength();
                 for(OutputImageType::IndexType idx = startIndex;idx[0]<lastIndex;idx[0]++){
                     int i1 = idx[0];
                     int i2 = idx[1];
                     int i3 = idx[2];
                     if(i1>2 && i2>2 && i3>2 && i1<(maxX-2) && i2<(maxY-2) && i3<(maxZ-2))fprintf(fout,"[%d, %d, %d]\n",i1,i2,i3);
                 }
            }
            cloud++;
        }
    }
fprintf(fout,"EndOfFile");
fclose(fout);
person drHogan    schedule 25.10.2014