Метод Оцу

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку
Граничний приклад зображення з використанням алгоритму Оцу.
Оригінальне зображення.

У комп'ютерному баченні та обробці зображень метод Оцу, названий на честь Нобуюкі Оцу[en] (大津展之 Ōtsu Nobuyuki), є методом, заснованим на кластеризації, для автоматичного обчислення порогового зображення,[1] або зведення сірого зображення до бінарного зображення. Алгоритм передбачає, що зображення містить два класи пікселів, наступної бі-модальної гістограми: пікселі переднього плану і пікселі тла, потім обчислюється оптимальний поріг, що розділяє два класи, так, що їх комбінований діапазон (дисперсія кластера) є мінімальною або рівноцінною (тому що сума попарних квадратичних відстаней постійна), так, що їх міжкластерна дисперсія є максимальною.[2] Отже, метод Оцу є приблизно одновимірним дискретним аналогом дискримінантного аналізу Фішера. Метод Оцу також безпосередньо пов'язаний з методом оптимізації Дженкса[en].

Розширення вихідного методу до багаторівневого порогового значення називається багатоточковим методом Оцу.[3]

Метод[ред. | ред. код]

У методі Оцу ми вичерпно шукаємо поріг, що мінімізує дисперсію всередині класу, яка визначається як зважена сума дисперсій двох класів:

Вага та ймовірності двох класів, розділені порогом і та  — відхилення цих двох класів.

Клас ймовірностей обчислюється з гістограм:

Oцу показує, що мінімізація дисперсії всередині класу збігається з максимізацією міжкласової дисперсії:[2]

що виражається в термінах ймовірностей класу та класу значень .

коли клас означає:

Наступні співвідношення можна легко перевірити:

Ймовірності класу і засоби класу можуть бути обчислені ітеративно. Ця ідея дає ефективний алгоритм.

Алгоритм[ред. | ред. код]

  1. Обчисліть гістограму та ймовірність кожного рівня інтенсивності
  2. Установіть початкові та
  3. Пройдіть усі можливі порогові значення максимальна інтенсивність
    1. Оновіть та
    2. Обчисліть
  4. Бажаний поріг відповідає максимуму

MATLAB реалізація[ред. | ред. код]

histogramCounts — це 256-елементна гістограма зображення в градаціях сірого, різних рівнях сірого (типові для 8-бітних зображень). Рівень — це поріг зображення.

function level = otsu(histogramCounts)
total = sum(histogramCounts); % '''total''' is the number of pixels in the given image. 
%% OTSU automatic thresholding method
sumB = 0;
wB = 0;
maximum = 0.0;
sum1 = dot( (0:255), histogramCounts); 
for ii=1:256
    wB = wB + histogramCounts(ii);
    wF = total - wB;
    if (wB == 0 || wF == 0)
        continue;
    end
    sumB = sumB +  (ii-1) * histogramCounts(ii);
    mF = (sum1 - sumB) / wF;
    between = wB * wF * ((sumB / wB) - mF) * ((sumB / wB) - mF);
    if ( between >= maximum )
        level = ii;
        maximum = between;
    end
end
end

Matlab має вбудовані функції graythresh() та multithresh() в Image Processing Toolbox, які реалізуються за допомогою методу Оцу та методу Мульти-Оцу, відповідно.

Інший підхід з векторизованним методом (може бути легко перетворений в версію матриці масиву python для обробки GPU)

function  [threshold_otsu] = Thresholding_Otsu( Image)
%Intuition:
%(1)pixels are divided into two groups
%(2)pixels within each group are very similar to each other 
%   Parameters:
%   t : threshold 
%   r : pixel value ranging from 1 to 255
%   q_L, q_H : the number of lower and higher group respectively
%   sigma : group variance
%   miu : group mean
%   Author: Lei Wang
%   Date  : 22/09/2013
%   References : Wikepedia, 
%   for multi children Otsu method, please visit : https://drive.google.com/file/d/0BxbR2jt9XyxteF9fZ0NDQ0dKQkU/view?usp=sharing
%   This is my original work




nbins = 256;
counts = imhist(Image,nbins);
p = counts / sum(counts);




for t = 1 : nbins
   q_L = sum(p(1 : t));
   q_H = sum(p(t + 1 : end));
   miu_L = sum(p(1 : t) .* (1 : t)') / q_L;
   miu_H = sum(p(t + 1 : end) .* (t + 1 : nbins)') / q_H;
   sigma_b(t) = q_L * q_H * (miu_L - miu_H)^2;
end




[~,threshold_otsu] = max(sigma_b(:));
end

Реалізація має невелику надмірність обчислень. Але оскільки метод Oцу виконується швидко, реалізація прийнята і зрозуміла. Хоча в деяких середовищах, оскільки ми використовуємо форму векторизації, обчислення циклів може бути швидше. Цей метод може бути легко перетворений в многопороговий метод з мінімальними мітками для heap—children labels.

Python реалізація[ред. | ред. код]

 1 import numpy as np
 2 from collections import Counter
 3 
 4 def Thresholding_Otsu(img):
 5     nbins = 256
 6     pixel_counts  = Counter(img.ravel())
 7     counts = np.array([0 for x in range(256)])
 8     for c in sorted(pixel_counts):
 9         counts[c] = pixel_counts[c]
10     p = counts/sum(counts)
11     sigma_b = np.zeros((256,1))
12     for t in range(nbins):
13         q_L = sum(p[:t]) 
14         q_H = sum(p[t:]) 
15         if q_L ==0 or q_H == 0:
16             continue
17             
18         miu_L = sum(np.dot(p[:t],np.transpose(np.matrix([i for i in range(t)]) )))/q_L
19         miu_H = sum(np.dot(p[t:],np.transpose(np.matrix([i for i in range(t,256)]))))/q_H
20         sigma_b[t] = q_L*q_H*(miu_L-miu_H)**2
21         
22     return np.argmax(sigma_b)

JavaScript реалізація[ред. | ред. код]

Варіант 1[ред. | ред. код]

Вхідний аргумент total — це кількість пікселів в даному зображенні. Вхідний аргумент histogram являє собою 256-елементну гістограму зображення в градаціях сірого, різних рівнів сірого (типові для 8-бітних зображень). Ця функція виводить поріг для зображення.

function otsu(histogram, total) {
    var sum = 0;
    for (var i = 1; i < histogram.length + 1; ++i) //normally it will be 255 but sometimes we want to change step
        sum += i * histogram[i];
    var sumB = 0;
    var wB = 0;
    var wF = 0;
    var mB;
    var mF;
    var max = 0.0;
    var between = 0.0;
    var threshold1 = 0.0;
    var threshold2 = 0.0;
    for (var i = 0; i < histogram.length; ++i) {
        wB += histogram[i];
        if (wB == 0)
            continue;
        wF = total - wB;
        if (wF == 0)
            break;
        sumB += i * histogram[i];
        mB = sumB / wB;
        mF = (sum - sumB) / wF;
        between = wB * wF * (mB - mF) * (mB - mF);
        if ( between >= max ) {
            threshold1 = i;
            if ( between > max ) {
                threshold2 = i;
            }
            max = between;            
        }
    }
    return ( threshold1 + threshold2 ) / 2.0;
}

Варіант 2[ред. | ред. код]

function otsu(histogram, pixelsNumber) {
	var sum = 0
	  , sumB = 0
	  , wB = 0
	  , wF = 0
      , mB
	  , mF
	  , max = 0
	  , between
	  , threshold = 0;
	for (var i = 0; i < 256; ++i) {
      wB += histogram[i];
      if (wB == 0)
        continue;
      wF = pixelsNumber - wB;
      if (wF == 0)
        break;
      sumB += i * histogram[i];
      mB = sumB / wB;
      mF = (sum - sumB) / wF;
      between = wB * wF * Math.pow(mB - mF, 2);
      if (between > max) {
        max = between;
        threshold = i;
      }
    }
    return threshold;
}




// To test: open any image in browser and run code in console
var im = document.getElementsByTagName('img')[0]
  , cnv = document.createElement('canvas')
  , ctx = cnv.getContext('2d');
cnv.width = im.width;
cnv.height = im.height;
ctx.drawImage(im, 0, 0);
var imData = ctx.getImageData(0, 0, cnv.width, cnv.height)
  , histogram = Array(256)
  , i
  , red
  , green
  , blue
  , gray;
for (i = 0; i < 256; ++i)
	histogram[i] = 0;
for (i = 0; i < imData.data.length; i += 4) {
  red = imData.data[i];
  blue = imData.data[i + 1];
  green = imData.data[i + 2];
  // alpha = imData.data[i + 3];
  // https://en.wikipedia.org/wiki/Grayscale
  gray = red * .2126 + green * .07152 + blue * .0722;
  histogram[Math.round(gray)] += 1;
}
var threshold = otsu(histogram, imData.data.length / 4);
console.log("threshold = %s", threshold);
for (i = 0; i < imData.data.length; i += 4) {
  imData.data[i] = imData.data[i + 1] = imData.data[i + 2] =
    imData.data[i] >= threshold ? 255 : 0;
  // opacity 255 = 100%
  imData.data[i + 3] = 255;
}
ctx.putImageData(imData, 0, 0);
document.body.appendChild(cnv);
console.log("finished");

Result.

Обмеження[ред. | ред. код]

Метод Оцу демонструє відносно хорошу продуктивність, якщо припустити, що гістограма має бімодальний розподіл і передбачає наявність глибокої і гострої долини між двома піками. Але якщо площа об'єкта мала в порівнянні з фоновою областю, гістограма більше не має бімодального розподілу.[4] І якщо дисперсія об'єкта та інтенсивність фону великі в порівнянні з середньою різницею, або зображення сильно пошкоджено адитивним шумом, гостра долина гістограми рівня сірого погіршується. Тоді можливий неправильний поріг, визначений методом Оцу, призводить до помилки сегментації. (Тут ми визначаємо розмір об'єкта як відношення площі об'єкта до всієї області зображення, а середня різниця — різниця середніх інтенсивностей об'єкта і фону)

Показано, що з результатів експериментів ефективність глобальних методів порога, включаючи метод Оцу, обмежена розміром невеликого об'єкта, малої середньої різниці, великими дисперсіями об'єкта та інтенсивністю фону, великою кількістю доданого шуму і т. д.[5]

Поліпшення[ред. | ред. код]

Існує безліч поліпшень, спрямованих на різні обмеження методу Оцу.[6] Один відомий і ефективний спосіб відомий як двовимірний метод Оцу. У цьому підході вивчається значення рівня сірого для кожного пікселя, а також середнє значення його безпосередній околиці, так що результати бінаризації значно поліпшуються, особливо для зображень, спотворених шумом.[7]

На кожному пікселі обчислюється середнє значення сірого рівня околиці. Нехай сірий рівень даного зображення буде розділений на значення та середній рівень сірого також буде розділений на ті ж самі значення . Потім формується пара: рівень сірого пікселя і середнє значення околиці. Кожна пара належить двовимірному скриньки. Загальна кількість ящиків, очевидно, . Загальна кількість входжень (частота), , пари поділеній на загальну кількість пікселів на зображенні , визначає спільну функцію ймовірності ймовірності в двовимірної гістограмі:

Двомірний метод Оцу буде розроблений на основі двовимірної гістограми наступним чином.

Ймовірності двох класів можна позначити як:

Інтенсивність означає вектори значень двох класів і загальної середньої вектора, які можуть бути виражені таким чином:

У більшості випадків ймовірність недіагональної оцінки буде незначною, тому легко перевірити:

Міжкласова дискретна матриця визначається як

Слід дискретної матриці може бути виражений як

де

Подібно одновимірному методу Оцу, оптимальний поріг виходить шляхом максимізації .

Алгоритм[ред. | ред. код]

і отримуються ітеративно, що дуже схоже на одновимірний Метод Оцу. Значення і змінюються доки ми не досягнемо максимуму , що є

max,s,t = 0;
for ss: 0 to L-1 do
    for tt: 0 to L-1 do
        evaluate tr(S_b);
        if tr(S_b) > max
            max = tr(S,b);
            s = ss;
            t = tt;
        end if
    end for
end for
return s,t;

Matlab implementation[ред. | ред. код]

функції входу та виходу:

function threshold = 2D_otsu(hists, total)
maximum = 0.0;
threshold = 0;
helperVec = 0:255;
mu_t0 = sum(sum(repmat(helperVec',1,256).*hists));
mu_t1 = sum(sum(repmat(helperVec,256,1).*hists));
p_0 = zeros(256);
mu_i = p_0;
mu_j = p_0;
for ii = 1:256
    for jj = 1:256
        if jj == 1
            if ii == 1
                p_0(1,1) = hists(1,1);
            else
                p_0(ii,1) = p_0(ii-1,1) + hists(ii,1);
                mu_i(ii,1) = mu_i(ii-1,1)+(ii-1)*hists(ii,1);
                mu_j(ii,1) = mu_j(ii-1,1);
            end
        else
            p_0(ii,jj) = p_0(ii,jj-1)+p_0(ii-1,jj)-p_0(ii-1,jj-1)+hists(ii,jj);
            mu_i(ii,jj) = mu_i(ii,jj-1)+mu_i(ii-1,jj)-mu_i(ii-1,jj-1)+(ii-1)*hists(ii,jj);
            mu_j(ii,jj) = mu_j(ii,jj-1)+mu_j(ii-1,jj)-mu_j(ii-1,jj-1)+(jj-1)*hists(ii,jj);
        end

        if (p_0(ii,jj) == 0)
            continue;
        end
        if (p_0(ii,jj) == total)
            break;
        end
        tr = ((mu_i(ii,jj)-p_0(ii,jj)*mu_t0)^2 + (mu_j(ii,jj)-p_0(ii,jj)*mu_t0)^2)/(p_0(ii,jj)*(1-p_0(ii,jj)));

        if ( tr >= maximum )
            threshold = ii;
            maximum = tr;
        end
    end
end
end

Див. також[ред. | ред. код]

Примітки[ред. | ред. код]

  1. M. Sezgin & B. Sankur (2004). Survey over image thresholding techniques and quantitative performance evaluation. Journal of Electronic Imaging 13 (1): 146–165. doi:10.1117/1.1631315. 
  2. а б Nobuyuki Otsu (1979). A threshold selection method from gray-level histograms. IEEE Trans. Sys., Man., Cyber. 9 (1): 62–66. doi:10.1109/TSMC.1979.4310076. 
  3. Ping-Sung Liao and Tse-Sheng Chen and Pau-Choo Chung (2001). A Fast Algorithm for Multilevel Thresholding. J. Inf. Sci. Eng. 17 (5): 713–727. 
  4. Kittler, Josef & Illingworth, John (1985). On threshold selection using clustering criteria. Systems, Man and Cybernetics, IEEE Transactions on. SMC-15 (5): 652–655. doi:10.1109/tsmc.1985.6313443. 
  5. Lee, Sang Uk and Chung, Seok Yoon and Park, Rae Hong (1990). A comparative performance study of several global thresholding techniques for segmentation. Computer Vision, Graphics, and Image Processing 52 (2): 171–190. doi:10.1016/0734-189x(90)90053-x. 
  6. Vala, HJ & Baxi, Astha (2013). A review on Otsu image segmentation algorithm. International Journal of Advanced Research in Computer Engineering \& Technology (IJARCET) 2 (2): 387. 
  7. Jianzhuang, Liu and Wenqing, Li and Yupeng, Tian (1991). Automatic thresholding of gray-level pictures using two-dimension Otsu method. Circuits and Systems, 1991. Conference Proceedings, China., 1991 International Conference on: 325–327.