Обнаружение объектов глобальным и локальным метод Оцу

    

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

    Метод Оцу – это алгоритм вычисления порога бинаризации для полуторного изображения, который был разработан японским ученным Нобуюки Оцу (Отсу) в 1979 году, на данным момент он является самым быстрым и эффективном методом.

Вступление

    Итак, начнем разбираться со следующего вопроса, чем нам может помочь знания порога бинаризации?

    С помощью порога мы можем разделить изображения на светлые объекты и темный фон. Другими словами, если значение пикселя больше порога (pixel> t), то пикселю будет присвоено 255 (белый цвет), в противном случае, когда значение пикселя меньше либо равно порогу (pixel <= t), то присваиваем 0 (черный цвет).

    Как же выбрать данный порог бинаризации?

Алгоритм

Глобальный Оцу

    Пусть на вход подается 24 битное изображение img.
    Задача: применить глобальный метод Оцу к img.

    Суть метода Оцу заключается в том, чтобы выставить порог между классами таким образом, чтобы каждый их них был как можно более «плотным». Если выражаться математическим языком, то это сводится к минимизации внутриклассовой дисперсии, которая определяется как взвешенная сумма дисперсий двух классов:
    Здесь— вероятности двух классов, разделенных порогом t,
— средние арифметические значения для каждого из классов.

    Так как метод Оцу работает только с полуторными изображениями, то необходимо привести изображение к 8-битному(серому) изображение: image = 0.3 * r + 0.59 * g + 0.11 * b.

Теперь можем рассмотреть алгоритм метода Оцу:
  • Вычисляем гистограмму hist. Напомню, что гистограмма — это набор бинов, каждый из которых характеризует количество попаданий в него элементов выборки. В нашем случае выборка — это пиксели различной яркости, которая может принимать целые значения от 0 до 255.
  • Начиная с порога t = 1, проходим через всю гистограмму, на каждом шаге пересчитывая дисперсию σ(t). Далее рассмотрим алгоритм нахождения дисперсии:
  • Искомый порог doorstep найден.
    Теперь осталось пройти матрицу изображения и проверить, что если значение пикселя больше порога (pixel > doorstep ), то пикселю присваиваем 255, в противном случае, присвоить 0.

Локальный Оцу

    Пусть на вход подается 24 битное изображение img, n (количество разбиений изображения).
    Задача: применить локальный метод Оцу к img.


    Приводим img к 8-битному(серому) изображение. Делим изображение на n количество частей, по вашему усмотрению или по заданию (например: 2x2, 4x1, 1x4).
    Далее для каждой части находим собственный порог бинаризации по выше изложенному алгоритму и для каждой части по искомому порогу переприсваиваем пикселю 0 или 255.

Программная реализация на Python

    Программная реализация глобального метода Оцу:

def bin_global(img, w, h):
    r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]
    image = 0.3 * r + 0.59 * g + 0.11 * b
    k = 256
    hist = [0 for i in range(0, k)]
    n = 0
    wh = w * h
    histI = 0
    histI1 = 0
    maxDisp = 0
    for i in range(0, h):
        for j in range(0, w):
            hist[round(image[i][j])] += 1
    for i in range(0, k):
        histI += i * hist[i]
    histI = histI / wh
    for t in range(0, k):
        n += hist[t]
        omega1 = n / wh
        omega2 = 1 - omega1
        if (omega1 != 0) and (omega2 != 0):
            histI1 += t * hist[t]
            mu1 = histI1 / (wh * omega1)
            mu2 = (histI - mu1 * omega1) / omega2
            disp = omega1 * omega2 * (mu1 - mu2) ** 2
            if (disp > maxDisp):
                maxDisp = disp
                doorstep = t

    for i in range(0, h):
        for j in range(0, w):
            if (image[i][j] > doorstep):
                image[i][j] = 255
            else:
                image[i][j] = 0
    return image


    Программная реализация локального метода Оцу с разбиением изображения на 4 части в виде 2x2:

def bin_local(filename, m, n):
    original = Image.open(filename)
    width, height = original.size
    x = int(width // m)
    y = int(height // n)
    arr = [0, 0]
    arr[0] = [0 for i in range(0, m + 1)]
    arr[1] = [0 for i in range(0, n + 1)]
    for i in range(1, m + 1):
        arr[0][i] = i * x
    for i in range(1, n + 1):
        arr[1][i] = i * y
    k = 0
    part_image = [0 for i in range(0, m * n)]
    new_image = [0 for i in range(0, m)]
    result = [0 for i in range(0, n)]
    for i in range(0, m):
        for j in range(0, n):
            image = np.array(original.crop((arr[0][i], arr[1][j], arr[0][i + 1], arr[1][j + 1])))
            part_image[k] = np.array(bin_global(image, arr[0][i + 1] - arr[0][i], arr[1][j + 1] - arr[1][j]))
            k += 1

    new_image[0] = np.row_stack(([part_image[0], part_image[1]]))
    new_image[1] = np.row_stack(([part_image[2], part_image[3]]))
    result = np.column_stack([new_image[0], new_image[1]])
    return result

Результаты выполнения программы

Результат выполнения глобального метода Оцу:

Справа оригинал, слева результат выполнения функции bin_global

Результат выполнения локального метода Оцу:

Справа оригинал, слева результат выполнения функции bin_local

Вывод

    Итак, мы рассмотрели применение метода Оцу для обнаружения объектов на изображениях.

Достоинства глобального и локального метода Оцу:
  1. Простота реализации.
  2. Метод хорошо адаптируется к различного рода изображения, выбирая наиболее оптимальный порог, при этом не имеет никаких параметров.
  3. Быстрое время выполнения. Требуется O(N) операций, где N — количество пикселей в изображении. 
Недостатки глобального метода Оцу:
  1. Пороговая бинаризация чувствительна к неравномерной яркости изображения. 
    !! Существует решение данной проблемы, которое мы уже выше рассмотрели. Вместо глобального метода Оцу, использовать локальный метод Оцу с наиболее частым делением, которое также не гарантирует 100% обнаружения объектов на изображение.

Недостатки локального метода Оцу:
  1. При не правильном деление изображения мы можем терять объекты. Визуально это можно увидеть в пункте результат: правый верхний угол слишком темный практически не возможно распознать окно, а в левом нижнем углу не виден угловой узор на здании.