Методы бинаризации, бинаризация среднего порога - PullRequest
0 голосов
/ 13 января 2012

Я пытаюсь преобразовать изображение в двоичную форму, сначала, конечно, подготовив его (оттенки серого). Мой метод - найти максимальное и минимальное значения оттенков серого, затем найти среднее значение (которое является моим порогом), а затем перебираявсе пиксели я сравниваю текущий с порогом, и если шкала серого больше порога, я помещаю 0 в матрицу, или для других я ставлю 1. Но теперь я столкнулся с проблемой.Обычно я бинаризирую изображения с белым фоном, поэтому мой алгоритм основан на этой функции.Но когда я встречаю изображение с черным фоном, все рушится, но я все еще могу ясно видеть число (теперь точки смещения 0 и 1). Как я могу решить эту проблему, сделать мою программу более распространенной?Возможно, мне лучше поискать другие способы бинаризации /

PS Я искал понятное объяснение порогового метода Оцу, но, похоже, я не готов к такому трудному пути или нахожу очень сложные объяснения.каждый раз, но я не могу написать это на языке C. Если бы кто-то мог hrlp здесь, это было бы замечательно.

Извините, что не отвечал на вопросы, просто не видел их Во-первых - код

for (int y=1;y<Source->Picture->Height;y++)
    for (int x=1;x<Source->Picture->Width;x++)
    {
        unsigned green = GetGValue(Source->Canvas->Pixels[x][y]);
        unsigned red = GetRValue(Source->Canvas->Pixels[x][y]);
        unsigned blue = GetBValue(Source->Canvas->Pixels[x][y]);
        threshold = (0.2125*red+0.7154*green+0.0721*blue);
        if (min>threshold)
            min=threshold;
        if (max<threshold)
            max = threshold;
    }
    middle = (max+min)/2;

Затем перебирая изображение

        if (threshold<middle)
        {
            picture[x][y]=1;
            fprintf( fo,"1");
        } else {
            picture[x][y]=0;
            fprintf( fo,"0");
        }
    }
    fprintf( fo,"\n");
}
fclose(fo);  

Итак, я получаю файл, что-то вроде этого

000000000
000001000
000001000
000011000
000101000
000001000
000001000
000001000
000000000

Здесь вы можете увидеть пример одного.enter image description here

Тогда я могу интерполировать это или делать что-то еще (распознавать), в зависимости от нуля и единицы.Но если я поменяю цвета, цифры не будут такими же.Таким образом, признание не будет работать.Интересно, есть ли алгоритм, который может мне помочь?

Ответы [ 4 ]

1 голос
/ 13 января 2012

Вместо использования среднего значения min и max вы должны использовать медиану всех точек в качестве порога. В общем, k-й процентиль (k = процент очков, которые вы хотите получить черным цветом) более уместен.

Другим решением является кластеризация данных в два кластера.

1 голос
/ 13 января 2012

Если ваш алгоритм работает правильно для белого фона, но не для черного фона, вам просто нужно определить, есть ли у вас черный фон, и инвертировать значения.Если вы предполагаете, что значение фона будет более распространенным, вы можете просто посчитать число 1 и 0 в результате;если 0 больше, инвертируйте результат.

1 голос
/ 13 января 2012

Я никогда не слышал о методе Оцу, но я понимаю некоторые страницы википедии, поэтому постараюсь упростить это.

1 Count how many pixels are at each level of darkness.
2 "Guess" a threshold.
3 Calculate the variance of the counts of darkness less than the threshold
4 Calculate the variance of the counts of darkness greater than the threshold
5 If the variance of the darker side is greater, guess a darker threshold, 
  else guess a higher threshold.
  Do this like a binary search so that it ends.
6 Turn all pixels darker than threshold black, the rest white.

Метод Оцу на самом деле «максимизирует межклассовую дисперсию», но я не понимаю эту часть математики.

Концепция дисперсии заключается в том, «насколько далеко друг от друга находятся значения». Низкая дисперсия означает, что все похоже. Высокая дисперсия означает, что значения находятся далеко друг от друга. Дисперсия радуги очень высокая, много цветов. Дисперсия фона stackoverflow равна 0, так как он полностью белый, без других цветов. Дисперсия рассчитывается примерно так

double variance(unsigned int* counts, int size, int threshold, bool above) {
    //this is a quick trick to turn the "upper" into lower, save myself code
    if (above) return variance(counts, size-threshold, size-threshold, false);
    //first we calculate the average value
    unsigned long long atotal=0;
    unsigned long long acount=0;
    for(int i=0; i<threshold; ++i) {
        atotal += counts[i]*i //number of px times value
        acount += counts[i];
    }
    //finish calculating average
    double average = double(atotal)/count;
    //next we calculate the variance
    double vtotal=0;
    for(int i=0; i<threshold; ++i) {
        //to do so we get each values's difference from the average
        double t = std::abs(i-average);
        //and square it (I hate mathmaticians)
        vtotal += counts[i]*t*t;
    }
    //and return the average of those squared values.
    return vtotal/count;
}
1 голос
/ 13 января 2012

Я бы решил эту проблему с помощью другого подхода:

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

Алгоритм будет выглядеть следующим образом:

  int bin [256];
  foreach pixel in image
       bin[pixelvalue]++;  
  endfor  // this computes the histogram of the image

  int thresholdCount = ImageWidth * ImageSize / 2;
  int count = 0;
  for int i = 0 to 255
    count = count + bin[i];
    if( count > thresholdCount)
         threshold = i;
         break; // we are done
    endif
  endfor

Этот алгоритм не вычисляет саму накопительную гистограмму, а использует гистограмму изображения для выполнениячто я сказал ранее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...