Potya / Image-binarization

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Бинаризация документов

Задача №1 по курсу "Анализ изображений"

Потемкин Павел

Формулировка задачи

По заданному изображению необходимо разделить все пиксели 2 класса: "фон" и "объект". Исходное ихображение может быть как полноцветным, так и изохромным. После обработки изображения алгоритм должен возвращать бинарное изображение, равного размера исходному, в котором на месте фонов пикселя стоит 0, а на месте пикселей объекта - 1.

Основные подходы к решению

В основе любого подхода лежит деление пикселей на классы на основе их яркости. Предполагается, что объект будет яркостнее, чем фон. Таким образом можно пострить определенный порог T, по которому можно делить пиксели. Если яркость пиксеоля меньше T, то его стоит отнести к фону, а иначе к объекту.

Основываясь на идее выше можно определить 2 подхода: глобальный и локальный. Глобальный подход основывается на анализе сразу всех пикселей изображения. То есть по специальным формулам вычисляется некоторый порог Tglobal и этот порог используется для определения класса каждого пикселя на изображении. В локальном подходе для каждого пикселя берется некоторая окрестность и для неё находится порог Tlocal. Если яркость выбранного пикселя меньше Tlocal, то этот пиксель является фоном, иначе объектом. И такие вычисления применяются к каждому пикселю.

Предложенными для реализации глобальными алгоритмами является алгоритм Otsu и его модификация для несбалансированных классов. Для локальных - алгоритм Ниблека и его модфиикация В. Постниковым.

Алгоритм Otsu

Простой алгоритм Otsu предлагает определять порог T основываясь на дисперсии для каждого класа и на общей дисперсии для всего иображения. Посмотрим на общие обозначения во всей задаче: они понядобятся и в несбалансированной версии. Пусть k - порог деления по яркости

  • $$wk(k)=\sum_{i=1}^k{p_i}$$ - вероятность попасть в пиксели яркости до k
  • $$w0k = wk(k)$$ - вероятность попасть в класс 0, то есть в пиксель фона
  • $$w1k = 1 - wk(k)$$- вероятность попасть в класс 1, то есть в объект
  • $$muT$$ - средний уровень яркости по изображению
  • $$muk(k)=\sum_{i=1}^k{ip_i}$$ - первый момент для пикселей яркости до k
  • $$mu0k=\frac{muk(k)}{wk(k)}$$ - среднее значение яркости для фона
  • $$mu1k=\frac{muT-muk(k)}{1-wk(k)}$$ - среднее значение яркости для объекта
  • $$sigma_sqrd0^2=\sum_{i=1}^{k}{(i-mu0k)^2p_i/w0k}$$ - дисперсия среди класса фон
  • $$sigma_sqrd1^2=\sum_{i=k+1}^{L}{(i-mu1k)^2p_i/w1k}$$ - дисперсия среди класса объект

Основываясь на этих метриках, в статье по методу Otsu предлагается максимизировать метрику $$\frac{sigmaB^2}{sigmaT^2}$$, где sigmaB - межклассовая дисперсия ($$w0k*(mu0k-muT)^2+w1k*(mu1k-muT)^2$$), а sigmaT - дисперсия по всему изображению. Отметим, что sigmaT не зависит от порога k, поэтому про знаменатель можно забыть и просто максимизировать $$sigmaB^2$$.

Выполняя подстановки выше в выражение для $$sigmaB$$ получаем: $$sigmaB^2(k)=\frac{(muT*wk(k) - muk(k))^2}{wk(k)(1-wk(k))}$$

Ниже представлен код на Python, который высчитвает выражения выше

def calc_wk(dist, k):
    return np.sum(dist[:k])

def calc_muk(dist, k):
    return np.sum(dist[:k] * np.arange(1, k + 1))

def calc_muT(dist):
    return np.sum(dist[:] * np.arange(1, len(dist) + 1))

def calc_sigma02(dist, mu0k, w0k, k):
return np.sum((np.arange(1, k + 1) - mu0k) * dist[:k]) / w0k

def calc_sigma12(dist, mu1k, w1k, k):
    return np.sum((np.arange(k + 1, len(dist) + 1) - mu1k) * dist[k:]) / w1k

for k in range(1, np.max(img)):
    wk = calc_wk(probs[1:], k)
    muT = calc_muT(probs[1:])
    muk = calc_muk(probs[1:], k)
    sig = (muT * wk - muk) ** 2 / (wk * (1 - wk))

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

В версии алгоритма Otsu для несбалансированных классов предлагается использовать формулу: $$Q(k)=w0k\log{w0k} + w1k\log{w1k} - \log{\sigma_w(k)}$$, где $$\sigma_w^2=w0ksigma_sqrd0^2 + w1ksigma_sqrd1^2$$. Видно, что формула основывается только на количестве пикселей каждого класса.

w0k = wk
w1k = 1 - w0k
mu0k = muk / wk
mu1k = (muT - muk) / (1 - wk)
sigma_sqrd0 = (calc_sigma02(probs[1:], mu0k, w0k, k))
sigma_sqrd1 = (calc_sigma12(probs[1:], mu1k, w1k, k))
sigma_W = np.sqrt(w0k * sigma_sqrd0 + w1k * sigma_sqrd1)
Tq = w0k * np.log(w0k) + w1k * np.log(w1k) - np.log(sigma_W)

Результаты подсчета значения критерия для каждой яркости k Tq записываются также в результирующий массив. В итоговом массиве берется индекс наибольшего элемента. Это и считается порогом.

Алгоритм Ниблека и модификация В. Постникова.

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

Для области пикселя считается средняя яркость по области и среднеквадатическое отклонение. Далее порог определяется по формуле $$T = mean(area)+k*\sigma(area)$$. Причем если $$\sigma < sigma_0$$, где $$\sigma_0$$ - некоторый заданный параметр, то в случае модификации Постникова размер области необходимо увеличить вдвое. Если таким образом мы достигли размеров изображения, то необходимо закончить с отрицательным исходом.

mean, dev = calc_mean_dev(img[max(i - area, 0): min(i + area, w - 1), max(j - area, 0): min(j + area, h - 1)])
while (dev < dev0):
    area *= 2
    if (area > w or area > h):
        print("cant use hard nilback - broken on ", i, j, area)
        return
    mean, dev = calc_mean_dev(img[max(i - area, 0): min(i + area, w - 1), max(j - area, 0): min(j + area, h - 1)])
area = area0
k = 0.2
T = mean + k * dev
if (img[i][j] >= T):
    new[i][j] = 1

Как и в случае первых алгоритмов, если яркость пикселя больше порога, то он относится к объекту, иначе к фону.

About