Я работаю над диффузным МРТ-проектом и у меня проблема с ++, с которой мне нужна помощь.
Фон:
У меня есть изображение .nii в качестве эталона, в котором я хотел бы, чтобы управляющий узел (который является частью сплайна) выполнял случайную прогулку в пределах ограниченной области интереса изображения. Для пояснения: изображение .nii — это маска, показывающая белое вещество мозга (WM), я хочу, чтобы сплайн с 4 контрольными узлами произвольно перемещался в пределах этой маски, пока они не достигнут состояния, которое минимизирует функцию стоимости. В настоящее время я просто обновляю случайный управляющий узел для перемещения в случайном направлении в соответствии с распределением Гаусса, а затем проверяю, находится ли он внутри или вне WM, и перерисовываю, если он находится вне WM. Но это может привести ко многим ненужным розыгрышам, которых я хотел бы избежать.
На мой вопрос:
Есть ли лучший способ сделать это? У меня есть идея собрать все пиксельные координаты моего ROI в отдельный массив или матрицу, которые я могу вместо этого извлечь из индексов этой матрицы? Этот метод также будет полезен, если я хочу повторно инициализировать свои сплайны с четырьмя совершенно новыми контрольными точками. (Что мне тоже нужно реализовать в будущем)
Код используемого в настоящее время метода:
blitz::Array<Catmull,1> FIBERs; // Fiber with control nodes (knots) which I want to move
NIFTI<INT16>* niiWM = new NIFTI<INT16>; // .nii Image which contains WM mask
void SimulatedAnnealing_OneStep( void )
{
iF = floor( FIBERs.extent(0)*uniformGen.random()); // select randomly a FIBER
NewProposal(iF);
Pen = CheckWM(iF);
while(Pen >= 1){
NewProposal(iF);
Pen = CheckWM(iF);
}
}
void NewProposal( int ifff)
{
static int iK;
static POINT delta;
delta.Set( MOVE_sigma*normalGen.random(), MOVE_sigma*normalGen.random(), 0 );
iK = floor(uniformGen.random()*6);
if( iK==2 || iK==3 ) // Moving the middle control points within the WM
{ // FIBERs(ifff) is a randomly selected fiber (outside this method) which we are moving
FIBERs(ifff).KNOTs[iK].x += delta.x;
FIBERs(ifff).KNOTs[iK].y += delta.y;
FIBERs(ifff).KNOTs[iK].z += delta.z;
FIBERs(ifff).KNOTs[iK].x = fmin( fmax( FIBERs(ifff).KNOTs[iK].x,0), Nx );
FIBERs(ifff).KNOTs[iK].y = fmin( fmax( FIBERs(ifff).KNOTs[iK].y, 0), Ny );
FIBERs(ifff).KNOTs[iK].z = fmin( fmax( FIBERs(ifff).KNOTs[iK].z, 0), Nz );
}
}
int CheckWM( int iff )
{
int j,Pe;
int Vx, Vy, Vz;
Pe = 0;
for(j=0; j<FIBERs(iff).P.extent(0) ;j++){ // Loop through the segments on the curve
Vx = floor( FIBERs(iff).P(j).x ); // midpoint of the segment
Vy = floor( FIBERs(iff).P(j).y );
Vz = floor( FIBERs(iff).P(j).z );
if ((*niiWM->img)(Vx,Vy,Vz) == 0){ // Penalize when outside the WM
Pe += 1;}
}
return Pe;
}
Я надеюсь, что этого было достаточно информации. Спасибо за ваше время.
Какой тип функции стоимости у вас есть (если я читаю из вашего кода, это просто сумма пикселей, которые не выходят за пределы белого вещества?)? Если он плавный и непрерывный, вы можете попробовать градиентный спуск, чтобы найти минимум (так как ваш выглядит дискретно, есть ли способ приблизить градиентный спуск?). Это должно функционировать более эффективно, чем случайная прогулка.
Если поддержание случайности важно, то лучший способ сделать это, не испытывая много переизбраний, — это повторно нормализовать диапазон распределения, который вы можете выбрать. Если я правильно понимаю, у вас уже есть маска белого вещества, поэтому один из методов, который должен позволить вам сделать это:
1.) Присвойте вероятности всем пикселям белого вещества на основе гауссианы с центром в вашем текущем местоположении
2.) Повторно нормализуйте эти вероятности, чтобы они составили 1
3.) Вытащите случайное число из равномерного распределения и найдите, какому пикселю оно соответствует
4.) Переместите свою контрольную точку туда
Так, например, если у вас есть четыре возможных пикселя белого вещества, вы можете перейти с вероятностью 0.1, 0.17, 0.2, and 0.23
в соответствующих местах (x1,y1), (x2,y2), (x3, y3), (x4, y4)
если все остальные вероятные пиксели (основанные на вашем случайном шаге по Гауссу) представляют собой пиксели небелого вещества, которые заставят вас перерисовать, то вы изменили бы масштаб вероятности, разделив их на сумму (0.7
в этом случае). Затем вытащите случайное число из равномерного распределения (скажем, вы вытащили 0.3
). Это будет соответствовать второму пункту (x2, y2)
на основе перенормированных вероятностей, и вы бы переместили свою контрольную точку туда.
Как вы можете видеть, для выполнения этого процесса требуется достаточное количество вычислительных шагов, но при этом вы будете обновлять только одну случайную цель; поэтому любое улучшение производительности будет зависеть от относительной стоимости этих дополнительных вычислений от частоты повторной выборки. Я также написал это довольно быстро, так что вы можете найти более эффективный способ ограничить область вашего случайного выбора только хорошими пикселями.
Других решений пока нет …