Новосибирский Государственный Университет
Опубликован: 20.08.2013 | Доступ: свободный | Студентов: 865 / 38 | Длительность: 14:11:00
Самостоятельная работа 2:

Базовые операции обработки изображений

2.4. Оператор Собеля

Оператор Собеля – дискретный дифференциальный оператор, вычисляющий приближенные значения производных разного порядка для функции яркости пикселей [1]. Наиболее распространенным примером практического использования является определение границ (ребер) объектов на изображении, т.е. точек резкого изменения яркости.

Данный оператор основан на свертке изображения с целочисленными фильтрами. В простейшем случае оператор построен на вычислении сверток исходного изображения с ядрами G_{x} и G_{y} , обеспечивающими вычисление первых производных по направлениям:

G_{x}=\begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1\end{bmatrix},G_{y}=\begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1\end{bmatrix}

Данный оператор используется для приближенного вычисления градиента функции интенсивности пикселей. Применение оператора G_{x} позволяет определить приближенное значение первой частной производной изменения интенсивности в горизонтальном направлении, G_{y} – в вертикальном. На основании данной информации можно вычислить магнитуду градиента для пикселя с координатами (i,j) согласно формуле \mid G^{ij} \mid = \sqrt{(G_{x}^{ij})^2 + (G_{y}^{ij})^2}. Также используя полученные данные, можно определить направление градиента как \theta^{ij} = arctan\left( \frac{G_{y}}{G_{x}}\right).

В библиотеке OpenCV поддерживается вычисление первых, вторых, третьих и смешанных производных функции интенсивности пикселей с использованием расширенного оператора Собеля [7]. Ниже приведен прототип соответствующей программной функции.

void Sobel(const Mat& src, Mat& dst, int ddepth, 
  int xorder, int yorder, int ksize=3, 
  double scale=1, double delta=0, 
  int borderType=BORDER_DEFAULT)       
    

Перечислим входные параметры функции Sobel:

  • src – исходное изображение.
  • dst – результирующее изображение.
  • ddepth – глубина результирующего изображения.
  • xorder – порядок производной по оси Ox.
  • yorder – порядок производной по оси Oy.
  • ksize – размер расширенного ядра оператора Собеля. Принимает одно из значений 1, 3, 5 или 7. Во всех случаях ядро имеет размер kSize x kSize, кроме ситуации, когда kSize=1. При kSize=1 ядра имеют размер 3x1 или 1x3, по существу применяется фильтр Гаусса. Указанное значение можно использовать только при вычислении первых и вторых частных производных по осям Ox и Oy. По умолчанию ядро имеет размер 3x3. Отметим, что дополнительно предусмотрено специальное значение параметра kSize = CV_SCHARR = -1, который соответствует ядру размера 3x3 фильтра Щарра (Scharr) и может давать более точные оценки производных по сравнению с оператором Собеля:
    G_{x}=\begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3\end{bmatrix}, G_{y}=\begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ 3 & 10 & 3\end{bmatrix}
  • scale – опциональный параметр, который задает коэффициент масштабирования для вычисляемых значений производных. По умолчанию масштабирование не применяется.
  • delta – опциональный параметр смещения интенсивности, добавляется перед сохранением результата в матрицу dst.
  • borderType – параметр, определяющий метод дополнения границы.

Далее приведен пример выделения ребер на изображении посредством применения горизонтального и вертикального операторов Собеля и усреднения полученных градиентов по направлениям. Заметим, что предварительно применяется фильтр Гаусса (GaussianBlur) для удаления шумов на исходном изображении и выполняется преобразование полученного изображения в оттенки серого (cvtColor). В результате применения оператора Собеля получаются изображения, глубина которых отличается от глубины исходного изображения, поэтому перед дальнейшими операциями выполняется преобразование указанных матриц в 8-битные целочисленные (convertScaleAbs).

#include <stdio.h> 
#include <opencv2/opencv.hpp> 
 
using namespace cv; 
 
const char helper[] = 
  "Sample_Sobel.exe <img_file>\n\ 
  \t<img_file> - image file name\n"; 
 
int main(int argc, char* argv[]) 
{ 
  const char *initialWinName = "Initial Image", 
    *xGradWinName = "Gradient in the direction Ox",
    *yGradWinName = "Gradient in the direction Oy",
    *gradWinName = "Gradient"; 
  int ddepth = CV_16S; 
  double alpha = 0.5, beta = 0.5; 
  Mat img, grayImg, xGrad, yGrad, 
    xGradAbs, yGradAbs, grad; 
  if (argc < 2) 
  { 
    printf("%s", helper); 
    return 1; 
  } 
  // загрузка изображения 
  img = imread(argv[1], 1);
  // сглаживание помощью фильтра Гаусса 
  GaussianBlur(img, img, Size(3,3), 
      0, 0, BORDER_DEFAULT); 
  // преобразование в оттенки серого 
  cvtColor(img, grayImg, CV_RGB2GRAY); 
  // вычисление производных по двум направлениям 
  Sobel(grayImg, xGrad, ddepth, 1, 0); // по Ox 
  Sobel(grayImg, yGrad, ddepth, 0, 1); // по Oy 
  // преобразование градиентов в 8-битные 
  convertScaleAbs(xGrad, xGradAbs); 
  convertScaleAbs(yGrad, yGradAbs); 
  // поэлементное вычисление взвешенной 
  // суммы двух массивов 
  addWeighted(xGradAbs, alpha, yGradAbs, beta, 0, grad); 
 
  // отображение результата 
  namedWindow(initialWinName, CV_WINDOW_AUTOSIZE); 
  namedWindow(xGradWinName, CV_WINDOW_AUTOSIZE); 
  namedWindow(yGradWinName, CV_WINDOW_AUTOSIZE); 
  namedWindow(gradWinName, CV_WINDOW_AUTOSIZE);   
  mshow(initialWinName, img); 
  imshow(xGradWinName, xGradAbs); 
  imshow(yGradWinName, yGradAbs); 
  imshow(gradWinName, grad); 
  waitKey(); 
   // закрытие окон 
  destroyAllWindows(); 
  // осовобождение памяти 
  img.release(); 
  grayImg.release(); 
  xGrad.release(); 
  yGrad.release(); 
  xGradAbs.release(); 
  yGradAbs.release(); 
  return 0; 
} 
      

Ниже на рисунке (рис. 7.7) показан результат выполнения приведенной программы на тестовом изображении (рис. 7.2, слева).

Результат применения оператора Собеля в горизонтальном и вертикальном направлениях, усредненное значение проекций

Рис. 7.7. Результат применения оператора Собеля в горизонтальном и вертикальном направлениях, усредненное значение проекций

Очевидно, что применение горизонтального оператора Собеля позволяет отчетливо выделить вертикальные ребра, а вертикального – горизонтальные ребра. Смесь указанных градиентов с весовыми коэффициентами, равными 0.5 обеспечивает вычисление приближенного значения градиента. Для этого используется вызов функции addWeighted.

Отметим, что библиотека OpenCV содержит функцию getDerivKernels, которая позволяет получить ядро для вычисления конкретной частной производной с определенной апертурой. Подробное описание параметров данной функции можно найти в документации [7].

Александра Максимова
Александра Максимова

При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка?
 

Алена Борисова
Алена Борисова

В лекции по обработке полутоновых изображений (http://www.intuit.ru/studies/courses/10621/1105/lecture/17979?page=2) увидела следующий фильтр:


    \begin{array}{|c|c|c|}
    \hline \\
    0 & 0 & 0 \\
    \hline \\
    0 & 2 & 0 \\
    \hline \\
    0 & 0 & 0 \\
    \hline 
    \end{array} - \frac{1}{9} \begin{array}{|c|c|c|}
    \hline \\
    0 & 0 & 0 \\
    \hline \\
    0 & 1 & 0 \\
    \hline \\
    0 & 0 & 0 \\
    \hline 
    \end{array}

В описании говорится, что он "делает изображение более чётким, потому что, как видно из конструкции фильтра, в однородных частях изображение не изменяется, а в местах изменения яркости это изменение усиливается".

Что вижу я в конструкции фильтра (скорее всего ошибочно): F(x, y) = 2 * I(x, y) - 1/9 I(x, y) = 17/9 * I(x, y), где F(x, y) - яркость отфильтрованного пикселя, а I(x, y) - яркость исходного пикселя с координатами (x, y). Что означает обычное повышение яркости изображения, при этом без учета соседних пикселей (так как их множители равны 0).

Объясните, пожалуйста, как данный фильтр может повышать четкость изображения?