- •1. Программные системы и методы 3D-реконструкции биомедицинских данных
- •1.1. Обзор программных комплексов
- •1.2. Обзор основных подходов
- •1.2.1. Структуры визуализируемых объёмов
- •1.2.2. Сегментация и идентификация объектов
- •1.2.3. Построение поверхностей объектов
- •2. Модели, методы и алгоритмы, положенные в основу сегментации и поиска объектов
- •2.1. Формальная постановка задачи и основные этапы её решения
- •2.2. Сегментация данных компьютерной томографии и электронной микроскопии
- •2.3. Повышение производительности вычислений в методе k-средних
- •2.4. Метод иерархической декомпозиции сегментов
- •2.5. Морфологическая фильтрация сегментов
- •2.6. Построение признакового описания сегмента
- •2.7. Поиск объектов методом динамического программирования
- •3. Описание реализации программной системы
- •3.1. Основные классы, структуры и методы
- •3.2. Организация пользовательского интерфейса
- •Заключение
- •Список литературы
- •Приложение А. Примеры результатов сегментации и идентификации объектов
- •Приложение Б. Классы, реализующие семейство методов k-средних
- •Приложение В. Исходные коды базовых компонентов программной системы
- •В.1. Основные классы и структуры для хранения и обработки данных
- •В.2. Методы вычисления атрибутов сегментов
- •В.3. Поиск объектов по найденным сегментам
MeanDevXY[k][2] = sqrt(MeanDevXY[k][2]/N[k]-MeanDevXY[k][0]*MeanDevXY[k][0]); MeanDevXY[k][3] = sqrt(MeanDevXY[k][3]/N[k]-MeanDevXY[k][1]*MeanDevXY[k][1]);
}
delete [] N;
}
Листинг B.7: Объёмы связных областей в вокселах
size_t VolumeOfConnectedRegion_2D(TVoxelsData* Data, size_t LayerIndex, Vec2i ParentSegmentIndex, int SegmentIndex)
{
size_t result = 0;
for (size_t i = 0; i < Data->sizeX*Data->sizeY; ++i)
{
int index = Data->VoxelSegments[i+ LayerIndex*Data->sizeX*Data->sizeY].ComponentIndex_2D; if ((index == SegmentIndex) &&
(Data->VoxelSegments[i+LayerIndex*Data->sizeX*Data->sizeY].SegmentIndex_2D == ParentSegmentIndex[0]) && ((Data->VoxelSegments[i+
LayerIndex*Data->sizeX*Data->sizeY].SpatialSegmentIndex_2D == ParentSegmentIndex[1])||(ParentSegmentIndex[1] < 0)))
result++;
}
return result;
}
void CalcVolumesOfConnectedRegions_2D(TVoxelsData* Data, size_t LayerIndex, Vec2i ParentSegmentIndex, size_t RegionsCount, vector <size_t> &Volume)
{
Volume.clear();
for (size_t k = 0; k < RegionsCount; ++k) Volume.push_back(0);
for (size_t i = 0; i < Data->sizeX*Data->sizeY; ++i)
{
int index = Data->VoxelSegments[i+ LayerIndex*Data->sizeX*Data->sizeY].ComponentIndex_2D; if ((index >= 0) &&
(Data->VoxelSegments[i+LayerIndex*Data->sizeX*Data->sizeY].SegmentIndex_2D == ParentSegmentIndex[0]) && ((Data->VoxelSegments[i+ LayerIndex*Data->sizeX*Data->sizeY].SpatialSegmentIndex_2D == ParentSegmentIndex[1])||(ParentSegmentIndex[1] < 0)))
Volume[index]++;
}
}
В.3. Поиск объектов по найденным сегментам
Листинг В.8: Итерация динамического процесса для поиска соответствий
void DynamicProcess(int LayerIndex, int i, WHERE direction, TPath& path, vector <bool>* &IsSegmentUsed, TSegment& VirtualSegment)
{
int layer_index = LayerIndex, segment_index = i;
double CostFunction = 0.0;
int index_shift = direction == FORWARD ? 1 : -1;
76
int threshold = direction == FORWARD ? InputData->sizeZ-1 : 0;
while (index_shift*layer_index < index_shift*threshold)
{
int new_segment_index = -1; double MinCost = System::Double::MaxValue;
for (size_t j = 0; j < AllSegmentIndexes_2D[layer_index+index_shift].size(); ++j)
{
Vec3i tmpVec1 = AllSegmentIndexes_2D[layer_index].at(segment_index), tmpVec2 = AllSegmentIndexes_2D[layer_index+index_shift].at(j);
TSegment tmpSegment1 = Segments_2D[layer_index].at(tmpVec1[0]), tmpSegment2 = Segments_2D[layer_index+index_shift].at(tmpVec2[0]);
int level = 0;
while (tmpSegment1.NextLevelSegments)
tmpSegment1 = tmpSegment1.NextLevelSegments->at(tmpVec1[++level]); level = 0;
while (tmpSegment2.NextLevelSegments)
tmpSegment2 = tmpSegment2.NextLevelSegments->at(tmpVec2[++level]);
bool tmpValue = this->SegmentationForm->RadioButton_EveryEvery->Checked ?
VirtualSegment.IsAdjacentWith(tmpSegment2) : (this->SegmentationForm->RadioButton_Neighbours->Checked ? tmpSegment1.IsAdjacentWith(tmpSegment2) : true);
if (!IsSegmentUsed[layer_index+index_shift].at(j) && tmpValue && (tmpSegment2.Volume >= 10.0f) && (CostFunction +
tmpSegment1.DistanceTo(tmpSegment2, SegmentFlags) < MinCost))
{
MinCost = CostFunction + tmpSegment1.DistanceTo(tmpSegment2, SegmentFlags); new_segment_index = j;
}
}
if (new_segment_index == -1) break; else
{
CostFunction = MinCost; segment_index = new_segment_index;
Vec3i tmpVec=AllSegmentIndexes_2D[layer_index+index_shift].at(segment_index); TSegment tmpSegment=Segments_2D[layer_index+index_shift].at(tmpVec[0]);
int level = 0;
while (tmpSegment.NextLevelSegments)
tmpSegment = tmpSegment.NextLevelSegments->at(tmpVec[++level]);
VirtualSegment.MinDensity = max(VirtualSegment.MinDensity, tmpSegment.MinDensity);
VirtualSegment.MaxDensity = min(VirtualSegment.MaxDensity, tmpSegment.MaxDensity);
switch (direction)
{
case FORWARD: {path.forward.push_back(tmpVec); break;}
case BACKWARD: { path.backward.push_back(tmpVec); break; }
default:;
77
}
IsSegmentUsed[layer_index+index_shift].at(segment_index) = true;
}
}
}
Листинг B.9: Поиск соответствий между всеми 2D-сегментами
vector <TPath>* FindOptimalMatches()
{
vector <TPath>* result = new vector <TPath> [InputData->sizeZ]; vector <bool> *IsSegmentUsed = new vector <bool> [InputData->sizeZ];
for (size_t i = 0; i < InputData->sizeZ; ++i)
{
result[i].clear();
for (size_t j = 0; j < AllSegmentIndexes_2D[i].size(); ++j)
{
IsSegmentUsed[i].push_back(false);
}
}
for (size_t z = 0; z < InputData->sizeZ; ++z)
for (size_t i = 0; i < AllSegmentIndexes_2D[z].size(); ++i) if (!IsSegmentUsed[z].at(i))
{
TPath path; path.root = AllSegmentIndexes_2D[z].at(i);
parents[z].at(i).LayerRoot = z; parents[z].at(i).SegmentRoot = i;
Vec3i tmpVec = AllSegmentIndexes_2D[z].at(i);
TSegment VirtualSegment = Segments_2D[z].at(tmpVec[0]);
int level = 0;
while (VirtualSegment.NextLevelSegments)
VirtualSegment = VirtualSegment.NextLevelSegments->at(tmpVec[++level]);
if (VirtualSegment.Volume >= 10.0f)
{
DynamicProcess(z, i, FORWARD, path, IsSegmentUsed, VirtualSegment); DynamicProcess(z, i, BACKWARD, path, IsSegmentUsed, VirtualSegment); result[z].push_back(path);
}
}
return result;
}
78