Удаление выделенных пикселей из небольшого бинарного изображения

В настоящее время я реализую алгоритм определения оси минимальной инерции цветной массы (обеспечиваемой вторыми моментами). Для этого мне нужно получить центр масс, заданный первыми моментами.

Функция взвешенного усреднения работает хорошо, но из-за выпадающих пикселей я получаю нежелательные результаты.

Вот функция усреднения:

(например, средневзвешенное значение x)

for (i = 0, i < rows, i++) {
    for (j = 0, j < cols, j++) {
        if (colorAt(i,j).isForeground()) {
            tempSumX++;
            totalForeground++;
        }
    }
    x_ += i*tempSumX;
    tempSumX = 0;
}
x_ /= totalForeground; //where x_ represents the x coordinate of the weighted center of mass.

Неправильный центр масс

Учитывая такое изображение, которое представлено исключительно двумя цветами (фон и передний план), как я могу удалить лишние пиксели? Примечание: Внешние пиксели относятся ко всему, что не является частью большой цветовой массы. Белая точка — это рассчитанный центр масс, который неверен.

Очень признателен.


person JT Cho    schedule 13.07.2012    source источник
comment
Вы смотрели на морфологические фильтры?   -  person mathematician1975    schedule 13.07.2012
comment
Я рассматривал их, но не уверен, насколько хорошо они будут работать в моем случае. Просто не слишком информирован. Я также рассматривал теорию графов для выявления связей.   -  person JT Cho    schedule 13.07.2012
comment
Это не похоже на среднее, или у вас есть какие-то выбросы, которые не видны на изображении? Что именно вы взвешиваете при расчете средневзвешенного значения?   -  person TaZ    schedule 13.07.2012
comment
из-за выбросов пикселей я получаю нежелательные результаты. На изображениях, где нет отдельных пикселей меньшего размера, как на том, что я показываю, взвешенный центр масс правильный. Или, возможно, нет. Позвольте мне еще раз взглянуть на мою программу.   -  person JT Cho    schedule 13.07.2012
comment
Текущий алгоритм, который я использую для взвешенного среднего, сейчас находится в сообщении выше.   -  person JT Cho    schedule 13.07.2012
comment
Можете ли вы опубликовать данные для вашего бинарного изображения? Кажется, это всего лишь 20x25 или около того.   -  person beaker    schedule 14.07.2012
comment
Это фактический размер бинарного изображения. Что я делаю, так это беру цветовой кластер из моего алгоритма k-средних и перебираю часть данного изображения, чтобы извлечь все цвета, которые считаются в этом кластере, создавая то, что вы видите здесь. Я могу предоставить несколько обновленных фотографий для лучшего результата.   -  person JT Cho    schedule 14.07.2012
comment
Причина, по которой я спрашиваю, заключается в том, что если я просто возьму все синие пиксели выше в качестве переднего плана, удалив белый «+», я получу центроид x = 15,81, y = 11,12, что кажется правильным, как это в основной блоб. (Диапазоны столбца/строки: 1..25 ​​и 1..20) Белый пиксель в нижней части «+» соответствует x=11, y=16.   -  person beaker    schedule 15.07.2012
comment
точка отображалась некорректно; Я случайно поменял местами значения x, y в точке. Как вы заметите, 16 и 11 просто поменялись местами, как вы поняли.   -  person JT Cho    schedule 16.07.2012
comment
Это то, на что я пытался указать. Я думал, что основная проблема заключалась в том, что центроид был не в том месте.   -  person beaker    schedule 16.07.2012


Ответы (3)


Существует множество алгоритмов заливки, которые идентифицируют все связанные пиксели с заданной начальной точкой.

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

person Martin Beckett    schedule 13.07.2012
comment
Я просматривал морфологические фильтры по рекомендации mathematician1975, но запутался в том, какой структурный элемент я буду использовать. Общий принцип имеет смысл, но я не совсем был уверен насчет SE. Если бы мне пришлось использовать заливку заливкой, я бы просто использовал ее несколько раз, чтобы определить, какая фигура самая большая? То есть, откуда мне знать, с чего начать поиск? - person JT Cho; 13.07.2012
comment
FloodFill кажется мне хорошим подходом. Даже если вы используете маркировку подключенных компонентов, вам придется решить, какой большой двоичный объект использовать. Здесь есть пример OpenCV: areshoopencv.blogspot.com/ 2011/12/. Затем вы можете получить OpenCV для расчета моментов для вас: cpp/ - person beaker; 16.07.2012
comment
Спасибо за вашу помощь! В итоге я использовал алгоритм маркировки подключенных компонентов, поскольку он лучше подходит для того, что мне нужно. Спасибо за ссылку на API OpenCV, стакан... хотя я уже сам заранее написал весь код для моментов. Упс. - person JT Cho; 17.07.2012

Как насчет псевдокода:

for( y = 0; y < rows; y++ )
{    
   for ( x = 0; x < cols; x++ )
   {
       if ( pixel( x, y ).isColor() )
       {
          int sum = 0;
          // forgetting about edge cases for clarity...
          if ( !pixel( x-1, y-1 ).isColor() ) sum++;
          if ( !pixel( x,   y-1 ).isColor() ) sum++;
          if ( !pixel( x+1, y-1 ).isColor() ) sum++;
          if ( !pixel( x-1, y   ).isColor() ) sum++;
          if ( !pixel( x+1, y   ).isColor() ) sum++;
          if ( !pixel( x-1, y+1 ).isColor() ) sum++;
          if ( !pixel( x,   y+1 ).isColor() ) sum++;
          if ( !pixel( x+1, y+1 ).isColor() ) sum++;
          if ( sum >= 7 )
          {
             pixel( x, y ).setBackground();
             x -= 1;
             y -= 1;
          }
       }
   }
}

То есть удалить любой пиксель, окруженный 7 фоновыми пикселями. Если вы измените цвет пикселя обратно на самый ранний пиксель, который теперь может быть затронут.

Ваша мера «выброса» может измениться, например. вы можете считать диагональные пиксели равными 1/2. Например. пиксели непосредственно выше, ниже, слева и справа считаются за 2. Затем используйте другое число для суммы.

Вы можете повысить точность, увеличив размер фильтра — например, до 5x5 вместо 3x3. В этом случае пиксели на расстоянии 2 должны иметь еще меньшее значение.

person Rafael Baptista    schedule 13.07.2012

Я считаю, что ваш алгоритм неверен. m10 (извините, я не мог понять, как делать индексы) в двоичном изображении — это сумма x-координат пикселей переднего плана, поэтому ваш код должен быть примерно таким:

for (i = 0, i < rows, i++) {
    for (j = 0, j < cols, j++) {
        if (colorAt(i,j).isForeground()) {
            tempSumX += i;
            totalForeground++;
        }
    }
}
x_ = tempSumX/totalForeground; //where x_ represents the x coordinate of the weighted center of mass.

Предполагая, что это связано с вашим предыдущим сообщением Алгоритм поиска самого длинного участка значения под любым углом в 2D-матрице, вы должны вычислить другие моменты первого и второго порядка в том же цикле:

m01 += j;
m20 += i*i;
m02 += j*j;
m11 += i*j;

(tempSumX в вашем алгоритме — это просто m10, а totalForeground — m00)

Попробуйте, и если у вас все еще возникают проблемы с выбросами, вы можете использовать маркировку подключенных компонентов http://en.wikipedia.org/wiki/Connected_component_labeling, чтобы найти наибольшую массу. (Доступно в Matlab с использованием bwlabel или bwconncomp.)

person beaker    schedule 13.07.2012
comment
Это фактически то, что я делаю, за исключением того, что вы упростили это, удалив аспект умножения. tempSumX++ в цикле с tempSumX*i снаружи — это то же самое, что и tempSumX + i в цикле. Проблема с изображением в том, что я поменял местами координаты x и y для точки на изображении. Алгоритм взвешивания работает корректно. Я попробовал алгоритм маркировки подключенных компонентов после того, как задал вопрос, но у меня возникли проблемы с поиском хорошей реализации объединения-поиска на С++. Есть рекомендации? - person JT Cho; 14.07.2012
comment
Так ты. Я думаю, что меня смутило максимальное измерение по оси x, равное rows, и максимальное измерение по оси y, равное cols. Извините, у меня нет хорошей реализации union-find, на которую я мог бы вам указать. - person beaker; 14.07.2012
comment
Вы уверены, что ваша функция colorAt(i,j) принимает y (строку) в качестве первого аргумента и x (столбец) в качестве второго? Возможно, ошибка кроется в этом. Потому что вы сообщаете правильные результаты, когда меняете координаты. Я бы предложил использовать y и x вместо i и j для ясности. РЕДАКТИРОВАТЬ: Мех, теперь я тоже запутался. Предложение переименовать ваши переменные остается в силе. - person TaZ; 14.07.2012
comment
Я использовал функцию colorAt для упрощения. Я использую OpenCV, а данные Matrix хранятся в массиве символов. Таким образом, доступ к данным правильный, так как я использовал его для множества других расчетов цвета раньше. Я согласен с изменением имени, я, вероятно, сделаю это просто, чтобы облегчить себе жизнь. Оказывается, большинство моих проблем теперь основаны на том, что мои k-средние недостаточно точны... - person JT Cho; 14.07.2012