Найти локальные экстремумы 3D массива
Название вопроса говорит само за себя.
Дан массив
float[][][] arr;с размерами width=w, height=h и depth=d найдите все локальные максимумы и минимумы. (индексация должна быть выполнена arr[глубина][высота][ширина])
Локальный экстремум обнаруживается, когда он больше/меньше, чем все его 26 соседей.
Конечная цель этого метода заключается в том, чтобы стать строительным блоком для реализации SIFT (вот ссылка на оригинальную статью, если вы хотите увидеть, откуда берется этот массив)
Что я уже пробовал:
Все примеры кода, представленные здесь,сделаны на Java, однако если вы более комфортно работаете с такими языками, как c, c++ и c#, вы можете отправить ответы, используя их вместо этого.
Я попробовал 2 разных решения, оба дающих совершенно разные ответы, и на поверхностном уровне ни одно из них, похоже, не дает мне правильного ответа...
Ответы,которые я здесь получаю,предполагают, что точка (x, y, z) задана в этом 3D-массиве. где
Image adj[3] = {arr[z-1],arr[z],arr[z+1]};
Функция getPixel просто возвращает значение пикселя, расположенное в точке (x,y) внутри 2D-среза 3D-массива.
private boolean isExtrema(int x, int y, BufferedImage low, BufferedImage curr, BufferedImage high) { BufferedImage[] adj = {low,curr,high}; float value = adj[1].getPixel(x, y); // Since all neighbors all need to be on the same 'side' for an // extremum we can just take an arbitrary neighbor to determine // if we might face a minimum or a maximum. float sign = Math.signum(value - adj[0].getPixel(x,y)); value *= sign; boolean isExtrema = true; isExtrema &= adj[0].getPixel(x - 1, y - 1) * sign < value; isExtrema &= adj[0].getPixel(x - 1, y) * sign < value; isExtrema &= adj[0].getPixel(x - 1, y + 1) * sign < value; isExtrema &= adj[0].getPixel(x, y - 1) * sign < value; isExtrema &= adj[0].getPixel(x, y) * sign < value; isExtrema &= adj[0].getPixel(x,y + 1) * sign < value; isExtrema &= adj[0].getPixel(x + 1, y - 1) * sign < value; isExtrema &= adj[0].getPixel(x + 1, y) * sign < value; isExtrema &= adj[0].getPixel(x + 1, y + 1) * sign < value; isExtrema &= adj[1].getPixel(x - 1, y - 1) * sign < value; isExtrema &= adj[1].getPixel(x - 1, y) * sign < value; isExtrema &= adj[1].getPixel(x - 1, y + 1) * sign < value; isExtrema &= adj[1].getPixel(x, y - 1) * sign < value; isExtrema &= adj[1].getPixel(x, y + 1) * sign < value; isExtrema &= adj[1].getPixel(x + 1, y - 1) * sign < value; isExtrema &= adj[1].getPixel(x + 1, y) * sign < value; isExtrema &= adj[1].getPixel(x + 1, y + 1) * sign < value; isExtrema &= adj[2].getPixel(x - 1, y - 1) * sign < value; isExtrema &= adj[2].getPixel(x - 1, y) * sign < value; isExtrema &= adj[2].getPixel(x - 1, y + 1) * sign < value; isExtrema &= adj[2].getPixel(x, y - 1) * sign < value; isExtrema &= adj[2].getPixel(x, y) * sign < value; isExtrema &= adj[2].getPixel(x, y + 1) * sign < value; isExtrema &= adj[2].getPixel(x + 1, y - 1) * sign < value; isExtrema &= adj[2].getPixel(x + 1, y) * sign < value; isExtrema &= adj[2].getPixel(x + 1, y + 1) * sign < value; return isExtrema; }
Второе решение, которое я пробовал
private boolean isExtrema(BufferedImage low, BufferedImage curr, BufferedImage high, int x, int y) { BufferedImage[] adj = {low,curr,high}; float cv = adj[1].getPixel(x, y); boolean isMax = true; MAX:for(int a = 0; a < 3; a++) { for (int j = -1; j < 1; j++) { for (int i = -1; i < 1; i++) { if (adj[a].getPixel(x + i, y + j) >= cv && !(i == 0 && j == 0 && a == 1)) { isMax = false; break MAX; } } } } if(isMax) return true; boolean isMin = true; MIN:for(int a = 0; a < 3; a++) { for (int j = -1; j < 1; j++) { for (int i = -1; i < 1; i++) { if (adj[a].getPixel(x + i, y + j) <= cv && !(i == 0 && j == 0 && a == 1)) { isMin = false; break MIN; } } } } return isMin; }
Учитывая выборку массива, первый метод дал 24000 экстремумов, тогда как второй дал более 200000 тысяч...
EDIT: контекст для приведенных примеров кода
public void findExtrema(BufferedImage[] pyramid) { for(int i = 1; i < pyramid.length - 1; i++) { final BufferedImage prev = dogpyr[i-1]; final BufferedImage img = dogpyr[i]; final BufferedImage next = dogpyr[i+1]; final int IMG_BORDER = 5; for(int row = IMG_BORDER; row < img.getHeight()-IMG_BORDER; row++) { for(int col = IMG_BORDER; col < img.getWidth()-IMG_BORDER; col++) { if(isExtrema(col,row,prev,img,next)) { // Further processing } } } } }
0x01AA
Вопрос не так прост. Давайте посмотрим на два измерения, и мы находимся на максимуме y= f(x). Теперь, если вы идете "налево", предположим, что y= 2. Если вы идете "правой" стороной y =1. Оба минимальны, но имеет ли меньший минимум большее значение? И если да, то почему? А для N измерений?
JONLIN
Определение экстремума здесь заключается в том, что данный пиксель больше или меньше, чем все его 26 соседей.
Таким образом, можно иметь 2 соседних экстремума, где один является максимумом, а другой-минимумом.
Нет никакого взвешивания, привязанного к экстремумам (пока, см. Главу 4.) так что все экстремумы считаются одинаковыми.