Премахване на странични пиксели от малко двоично изображение

В момента прилагам алгоритъм за идентифициране на оста на минимална инерция на цветна маса (осигурена от вторите моменти). За да го направя, трябва да придобия центъра на масата, както е дадено от първите моменти.

Функцията за претеглено осредняване работи добре, но поради пиксели, които се различават, получавам нежелани резултати.

Ето функцията за осредняване:

(напр. среднопретеглена стойност на 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: areshopencv.blogspot.com/ 2011/12/. След това можете да накарате OpenCV да изчисли моментите вместо вас: opencv.willowgarage.com/documentation/ cpp/ - person beaker; 16.07.2012
comment
Благодаря за вашата помощ! В крайна сметка използвах алгоритъм за етикетиране на свързани компоненти, тъй като обаче е по-подходящ за това, от което се нуждая. Благодаря за връзката към OpenCV API, чаша... въпреки че вече сам написах целия код за моментите предварително. Опа! - 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 за точката в изображението. Алгоритъмът за претегляне работи правилно. Опитах алгоритъм за етикетиране на свързани компоненти, след като зададох въпроса, но имах проблеми с намирането на добра имплементация за намиране на съюз в C++. Някакви препоръки? - person JT Cho; 14.07.2012
comment
Така че вие ​​сте. Предполагам, че съм се объркал от това, че максималния размер x е редове, а максималния размер y е колове. Съжалявам, случайно нямам добра реализация за намиране на обединение, към която да ви насоча. - person beaker; 14.07.2012
comment
Сигурни ли сте, че вашата colorAt(i,j) функция приема y (ред) като първи аргумент и x (колона) като втори? Може би грешката е там. Защото съобщавате правилни резултати, когато разменяте координатите. Бих предложил да използвате y и x вместо i и j за по-голяма яснота. EDIT: Мда, сега и аз се обърках. Предложението за преименуване на вашите променливи все още е в сила. - person TaZ; 14.07.2012
comment
Използвах функция colorAt за опростяване. Използвам OpenCV и данните от Matrix се съхраняват в масив от uchars. Така че достъпът до данни е правилен, тъй като съм го използвал за много други цветови изчисления преди. Съгласен съм с промените в имената, вероятно ще направя това просто, за да улесня живота си. Оказва се, че повечето ми проблеми сега се основават на това, че моите k-средства не са достатъчно точни... - person JT Cho; 14.07.2012