Tag Archives: OpenCV

OpenCV로 배우는 영상 처리 및 응용/ 영역 처리

회선 (Convolution)

공간 영역의 개념과 회선

  • 영상 처리에서 ‘영역’에 대한 하나의 의미는 두 개의 다른 범위(domain)의 구분이다.
    • 하나는 공간 영역(spatial domain)이고, 다른 하나는 주파수 영역(frequency domain)이다.
      • 공간 영역은 영상들이 다루어지는 화소 공간을 의미하는데, x, y 차원의 2차원 공간을 말한다.
    • 다른 하나는 영역 기반 처리(area based processing)라는 표현에서 사용하는 영역이다.
      • 이는 화소 기반 처리와 상반되는 의미로서, 화소점 하나 하나의 개념이라기 보다는 화소가 모인 특정 범위(영역)의 화소 배열을 의미한다.
  • 화소 기반 처리가 화소값 각각에 대해 여러 가지 연산을 수행하는 것이라면, 공간 영역 기반 처리는 마스크(mask)라 불리는 규정된 영역을 기반으로 연산이 수행된다. 이러한 이유에서 공간 영역 기반 처리를 마스크 기반 처리라고도 한다.
  • 마스크 기반 처리는 마스크 내의 원소값과 공간 영역에 있는 입력 영상의 화소값들을 대응되게 곱하여 출력화소값을 계산하는 것을 말한다. 이러한 처리를 하는 과정을 모든 출력화소값에 대해 이동하면서 수행하는 것을 회선(convolution)이라고 한다.
    • 이때 입력 영상에 곱해지는 마스크는 커널(kernel), 윈도우(window), 필터(filter) 등의 용어로 불려진다.
  • 위 그림은 3×3 크기의 마스크로 회선을 수행하는 과정을 표현한 것으로, 출력 화소 O22는 대응되는 위치에 있는 입력화소 I22와 마스크 크기만큼의 주위 화소들을 이용해서 계산된다.
    • 즉 마스크의 각 원소가 같은 위치의 입력화소와 곱해지며, 이 곱한 값들을 모두 더해서 출력 화소가 계산된다.
    • 계속적으로 출력화소 O23은 입력 영상에서 마스크를 한 화소 오른쪽으로 이시킨 후에 대응되는 입력화소들과 곱하여 계산된다.
    • 같은 방법으로 입력 영상의 모든 화소에 대해 마스크를 이동시켜 곱하고, 그 값들을 모두 더해서 해당 위치의 출력화소가 계산된다.
  • 결과적으로 회선으로 생성되는 영상은 마스크의 원소 값에 따라 결정된다. 즉, 입력 영상의 각 화소의 위치에서 마스크의 크기의 주변 화소들을 마스크 원소의 비율만큼 반영하는 것이다.
    • 이 마스크의 원소를 어떻게 결정하느냐에 따라 결과 영상이 드라마틱하게 달라진다.

블러링(Blurring)

  • 블러링은 영상에서 화소값이 급격하게 변하는 부분들을 감소시켜 점진적으로 변하게 함으로써 영상이 전체적으로 부드러운 느낌이 나게 하는 기술이다.
    • 경우에 따라 스무딩(smoothing)이라고 하는 경우도 있다.
  • 화소값이 급격하게 변하는 것을 점진적으로 하는 방법은 회선을 이용한 필터링을 이용하는 것이다.
    • 마스크를 아래 그림과 같이 모든 원소의 값을 같게 구성하여 회선을 수행하면 블러링이 적용된다.
    • 이때 마스크의 전체 원소의 합은 1이 되어야 입력 영상의 밝기가 유지된다.
  • 아래 그림은 회선을 통한 블러링을 설명하기 위한 내용이다.
    • 아래 그림에서 O22와 O23의 계산에서 입력 영상 중 6개 화소가 동일하며, 나머지 3개 화소만 다르다.
    • 이웃하는 두 출력화소는 마스크 크기 내에서 입력화소의 2/3가 공통 부분이고 블러링 마스크의 원소 값이 모두 같기 때문에 입력화소가 같은 비율로 출력화소에 반영된다.
    • 따라서 입력화소의 공통부분이 같은 비율로 반영되기 떄문에 출력 영상에서 이웃하는 화소들이 비슷한 값을 갖게 된다.

샤프닝(sharpening)

  • 블러링이 이웃 화소의 차이를 감소시켜서 부드럽게 만드는 것이라면, 샤프닝은 이웃 화소끼리 차이를 크게 해서 날카로운 느낌이 나게 만드는 것이다.
    • 이렇게 함으로써 영상의 세세한 부분을 강조할 수 있으며 경계 부분에서 명암대비가 증가되는 효과를 낼 수 있다.
  • 입력 영상의 화소와 출력 영상의 화소가 마스크의 중심 위치에서 대응된다. 이 마스크의 중심 위치의 계수를 중심계수라고 한다.
    • 마스크 중심계수의 비중이 크면 출력 영상은 입력 영상의 형태를 유지하게 된다. 추가적으로 주변 계수들을 중심계수와 값의 차이를 크게 만들면 샤프닝이 수행된다.
    • 여기서 마스크 원소의 전체 합이 1이 되어야 입력 영상의 밝기가 손신 없이 출력 영상의 밝기로 유지된다. 마스크 원소의 합이 1보다 작으면 출력 영상의 밝기가 입력 영상보다 어두워지며, 1보다 크면 입력 영상보다 더 밝아진다.
    • 따라서 중심계수는 1보다 훨씬 크게 구성하며, 주변 화소는 비중을 감소시킬 수 있도록 음수 값을 갖게 한다. 그리고 전체 원소의 합은 1이 되도록 구성하면 샤프닝 필터가 완성된다. 아래 그림은 이와 같은 조건에 부합하는 샤프닝 마스크의 예이다.

에지(Edge) 검출

  • 영상처리에서 에지는 윤곽선 혹은 경계선의 의미를 갖는다. 이 윤곽선은 객체에서 크기, 위치, 모양을 인지할 수 있으며, 그 방향성을 탐지할 수 있다.
    • 따라서 에지 검출은 영상 처리에서 아주 중요하며 기본적인 처리 분야로 다루어진다.
  • 위 그림은 영상의 특정 지점(40, 250)에서 가로로 50개의 화소를 가져와서 그 화소값을 그래프로 나타낸 모습이다.
    • 그래프에서 원으로 표시한 부분들을 보면 화소값에서 급격하게 변하여 그래프가 꺾이는 것을 볼 수 있는데, 28번째 픽셀에서 화소값이 급격하게 낮아지며, 32번째 픽셀 주위에서는 다시 급격하게 높아진다.
    • 이렇게 화소값 그래프에서 급격하게 꺽이는 부분을 영상에서 보면 모서리나 윤곽선 혹은 경계 부분인 것을 알 수 있다.
  • 에지 검출(edge detection)이란 에지에 해당하는 화소를 찾는 과정으로 그 방법으로는 가장 간단하게 이웃하는 화소의 차분을 이용하여 그 차분이 특정 임계값 이상인 곳을 에지로 지정하는 것이다.
    • 또한 에지는 마스크를 이용하여 계산할 수도 있는데, 1차 미분 마스크나 2차 미분 마스크를 사용하여 회선을 수행하는 것이다.

차분 연산을 통한 에지 검출

  • 단순하고 빠른 에지 검출 방법으로 유사 연산자와 차 연산자를 이용한 방법이 있다.
    • 유사 연산자는 중심화소에서 각 방향의 주변 화소와 차분을 계산하고, 그 중에서 가장 큰 값을 출력화소로 결정하는 방법이다. 아래 그림에서 보듯 8방향의 차분을 계산해야 한다.
    • 반면 차 연산자는 중심화소를 배제하고 주변 화소의 상하 차분, 좌우 차분, 그리고 대각선 차분을 계산하고 그 중에서 가장 큰 값을 출력 화소로 결장하는 방법이다.
  • 회선의 방법과 유사하게 입력 영상의 해당 화소에 마스크를 위치시키지만 화소값과 마스크 원소를 곱하는 것이 아니라 마스크 범위의 입력 화소들 간에 차분을 계산한다.
    • 차 연산자의 경우 중심화소를 배제시켰기 때문에 4번의 차분만 계산하여 속도 면에서 유리하다.
  • 위 그림은 차 연산자를 이용한 에지 검출 예제이다. 여기서 반복을 통해서 원소의 대각선 방향 차분(start-end)을 구하기 위해 mask 벡터를 도입해서 그림과 같이 계산한다.

1차 미분 마스크

  • 영상의 특정 좌표에서 가로 방향(혹은 세로방향)으로 화소값들을 구성했을 때, 결과 그래프에서 밝기의 변화를 파악할 수 있다.
    • 에지가 화소의 밝기가 급격히 변하는 부분이기 때문에 함수의 변화율을 취하는 미분 연산을 이용해서 에지를 검출할 수 있다.
    • 영상에서 밝기의 변화율을 검출하는 방법은 밝기에 대한 기울기(gradient)를 계산하는 것이다. 현재 화소에서 밝기의 기울기를 계산하고, 이 기울기의 크기를 구하면 에지가 된다. 
    • 그러나 디지털 영상은 연속이 아닌 이산된 데이터이기 때문에 엄밀한 의미에서 미분 연산을 할 수 없다. 그래서 다음과 같은 수식으로 근사하여 계산한다.

G[f(x, y)] = \left[ \begin{array}{rr} G_{x} \\ G_{y}  \end{array} \right] = \left[ \begin{array}{rr} {\partial f(x, y) \over \delta x} \\ {\partial f(x, y) \over \delta y}  \end{array} \right]

G_{x} = {f(x + dx, y) - f(x, y) \over dx} \fallingdotseq f(x+1, y) - f(x, y), (dx = 1)

G_{y} = {f(x, y + dy) - f(x, y) \over dy} \fallingdotseq f(x, y+1) - f(x, y), (dy = 1)

G[f(x, y)] \fallingdotseq \sqrt{G_{x}^{2} + G_{y}^{2}} \approx |G_{x}| + |G_{y}|

\theta = tan^{-1}({G_{y} \over G_{x}})

  • 먼저 2차원 공간 상의 한 화소에서 수평 방향과 수직 방향으로 각각 미분한다. 이를 편미분이라 한다.
    • 그리고 각 방향의 편미분을 한 화소단위 (dx = 1, dy = 1)의 차분으로 근사한다.
    • 다음으로 각 방향의 차분을 이용해서 기울기의 크기를 계산한다. 이 크기가 에지의 강도가 된다.
    • 여기서 계산 복잡도를 줄이기 위해 제곱과 제곱근 대신, 절댓값을 사용하기도 한다. 또한 역탄젠트(arctan) 함수에 가로 방향과 세로 방향 차분을 적용하면 에지의 방향을 계산할 수도 있다.
  • 이러한 1차 미분 공식을 영상에 구현하는 쉬운 방법이 1차 미분 마스크로 회선을 적용하는 것이다.
    • 마스크의 중심 위치의 입력 화소가 f(x, y)일 때 주변 화소의 위치를 보면 위 그림과 같다.
    • 마스크 원소를 (a)와 같이 f(x, y), f(x, y+1) 위치에 -1과 1을 구성하여 회선을 수행하면, 회선의 내부 계산 수식이 f(x, y+1) – f(x, y) 이 되어서 y 방향 미분인 Gy와 같은 결과가 된다.
    • 또한 (b)와 같이 f(x, y), f(x+1, y) 위치에 -1과 1을 구성하여 회선을 수행하면, 회선 수식이 f(x+1, y) – f(x, y)이 되어서 x 방향 미분인 Gx가 적용된다.
    • 이렇게 회선의 수식을 이용해서 차분을 계산할 수 있도록 마스크의 원소를 구성하면 1차 미분 마스크가 된다. 이 마스크를 적용해서 입력 영상에 회선을 수행하면 에지 검출이 가능하다. 이때 마스크 계수의 합은 0이 되어야 한다.
  • 이 외에도 다양한 1차 미분 마스크가 있으며 대표적으로는 소벨(Sobel), 프리윗(Prewitt), 로버츠(Roberts) 등이 있다.

로버츠(Roberts) 마스크

  • 로버츠 마스크는 아래 그림과 같이 대각선 방향으로 1과 -1을 배치하여 구성된다. 나머지 원소의 값이 모두 0이어서 다른 1차 미분 마스크에 비해 수행 속도가 빠르다.
    • 그리고 한 번만 차분을 계산하기 때문에 차분의 크기가 작고, 이로 인해 경계가 확실한 에지만을 추출하며, 잡음에 매우 민감하다.

프리윗(Prewitt) 마스크

  • 프리윗 마스크는 로버츠 마스크의 단점을 보완하기 위해 고안되었다.
    • 먼저 수직 마스크를 보자. 원소의 배치가 수직 방향으로 구성되어서 수직 마스크라고 하며, 결과 영상에서 에지의 방향도 수직으로 나타난다.
    • 중심화소의 앞과 뒤 화소로 x 방향의 차분을 3번 계산하고, 다음 수평 마스크는 중심화소에서 위와 아래의 화소로 y 방향으로 차분을 3번 계산한다.
    • 최종적으로 수직 마스크의 회선 결과와 수평 마스크의 회선 결과에 대해서 크기(magnitude)로 결과 영상(에지 강도)을 생성한다.
    • 세 번의 차분을 합하기 때문에 로버츠 연산자에 비해 에지의 강도가 강하며, 수직과 수평 에지를 동등하게 찾는데 효과적이다.

소벨(Sobel) 마스크

  • 소벨 마스크는 에지 추출을 위한 가장 대표적인 1차 미분 연산자이다. 마스크의 구성은 프리윗 마스크와 유사하지만, 중심화소의 차분에 대한 비중을 2배로 키운 것이 특징이다.

2차 미분 마스크

  • 1차 미분 연산자는 밝기가 급격하게 변화하는 영역 뿐만 아니라 점진적으로 변화하는 부분까지 민감하게 에지를 검출하여 너무 많은 에지가 나타날 수 있다.
    • 이를 보완하기 위한 방법으로 1차 미분에서 한 번 더 미분을 하는 방법이 2차 미분 연산이 있다.
    • 2차 미분 연산자는 변화하는 영역의 중심에 위치한 에지만을 검출하며, 밝기가 점진적으로 변화되는 영역에 대해서는 반응을 보이지 않는다.
    • 대표적인 방법으로는 라플라시안(Laplacian), LoG(Laplacian of Gaussian), DoG(Difference of Gaussian) 등이 있다.

라플라시안(Laplacian) 에지 검출

  • 가장 대표적인 2차 미분 연산자로 라플라시안이 있다. 프랑스 수학자 라플라시안의 이름을 따서 지은 라플라시안은 함수 f에 대한 그래디언트의 발산으로 정의되며 수식으로 표현하면 다음과 같다.

\Delta f = \nabla^{2} f = \nabla \nabla f

  • 영상은 2차원 좌표계이기 때문에 2차원 직교좌표계에서 라플라시안의 수식은 다음과 같다.

\nabla^{2} f = {\partial^{2} f \over \partial x^{2}} + {\partial^{2} f \over \partial y^{2}}

  • 각 항을 디지털 영상의 화소로 근사하여 1차 미분한 결과에 한 번 더 미분을 수행하면 다음과 같이 정리할 수 있다.

{\partial^{2} f \over \partial x^{2}} = {\partial f(x+1, y) \over \partial x} - {\partial f(x, y) \over \partial x}

= [f(x+1, y) - f(x,y)] - [f(x,y) - f(x-1, y)]

= f(x+1, y) - 2 \cdot f(x, y) - f(x-1, y)

{\partial^{2} f \over \partial y^{2}} = {\partial f(x, y+1) \over \partial y} - {\partial f(x, y) \over \partial y}

= [f(x, y+1) - f(x,y)] - [f(x,y) - f(x, y-1)]

= f(x, y+1) - 2 \cdot f(x, y) - f(x, y-1)

  • 두 항을 더하면 라플라시안 마스크의 공식이 완성된다.

\nabla^{2} f(x, y) = f(x-1, y) + f(x+1, y) + f(x, y-1) + f(x, y+1) - 4 \cdot f(x, y)

  • 3 x 3 크기의 마스크를 예로 라플라시안 마스크 공식에 적용하면 중심화소를 4배로 하고 상하좌우 화소를 중심화소와 반대 부호를 갖게 구성한다. 또한 마스크 원소의 전체 합은 0이 되어야 한다.
  • 이런 방법으로 아래 그림 (a)와 같이 두 개의 마스크를 구성할 수 있으며, 4방향을 가지는 마스크가 된다.
    • 경우에 따라서는 (b)와 같이 8방향으로 늘려 보면 모든 방향의 에지를 검출하고자 할 때도 있다. 중심계수의 값을 더 크게 하고 8방향의 모든 값을 반대 부호가 되게 하면 된다.

LoG와 DoG

  • 라플라시안은 잡음에 민감한 단점이 있다. 그래서 잡음을 먼저 제거하고 라플라시안을 수행한다면 잡음에 강한 에지 검출이 가능할 것이다. 잡음 제거의 수단이 다양하게 있기에 미디언 필터링 혹은 최대/최솟값 필터링 등을 수행할 수 있다.
    • 그러나 이런 방법들은 비선형 공간 필터링이기 때문에 먼저 잡음 제거 필터링을 수행하고, 다시 라플라시안을 수행해야 한다. 바로 속도에서 문제가 있는 것이다.
  • 잡음을 제거하는 달느 방법으로 선형 공간 필터를 선택하여 회선을 하고, 그 후에 라플리사인 마스크로 회선하는 방법을 생각해 볼 수 있다. 이 경우 두 가지 모두 선형 필터링이기 때문에 다음 수식과 같이 단일의 마스크로 계산할 수 있다.
    • 여기서 Gσ는 가우시안 스무딩 마스크이며, *는 회선을 의미한다.

\Delta [G_{\sigma}(x, y) * f(x, y)] = [\Delta G_{\sigma}(x, y)] * f(x, y) = Log * f(x, y)

  • 이렇게 구성한 마스크를 LoG(Laplacian of Gaussian)라고 한다. LoG 마스크를 수식에 따라 풀면 다음과 같다.

LoG(x, y) = - {1 \over \pi \sigma^{4}} [1 - {x^{2} + y^{2} \over 2 \sigma^{2}}] \cdot e^{{-(x^{2} + y^{2}) \over 2 \sigma^{2}}}

  • 이 수식으로 마스크의 계수를 구성하고, 회선을 수행하면 잡음에 강한 에지를 검출할 수 있다.
    • 다만 수식에 따라 마스크 계수를 생성할 때 값의 범위가 너무 작은 관계로 전체 계수의 합이 0에 가까워지도록 스케일 조정이 필요하다.
  • LoG는 복잡한 공식에 의해 마스크를 생성해야 하며, 그에 따라 수행 시간도 많이 걸리게 된다. 이런 단점을 보완하여 LoG와 유사한 기능을 하면서 단순한 방법으로 구현하는 알고리즘이 바로 DoG(Difference of Gaussian)이다.
  • DoG는 가우시안 스무딩 필터링의 차이를 이용해서 에지를 검출하는 방식으로 공식은 아래와 같다.

DoG(x, y) = ({1 \over 2 \pi \sigma_{1}^{2}} \cdot e^{{-(x^{2} + y^{2}) \over 2 \sigma_{1}^{2}}}) - ({1 \over 2 \pi \sigma_{2}^{2}} \cdot e^{{-(x^{2} + y^{2}) \over 2 \sigma_{2}^{2}}}) (\sigma_{1} < \sigma_{2})

  • 두 개의 표준 편차를 이용해서 가우시안 마스크를 만들고 그 차이가 DoG 마스크가 된다.
    • 이 마스크로 회선을 수행하면 에지 검출이 가능하다. 여기서 각 표준 편차의 값을 조절함으로써 검출할 에지의 넓이를 조절할 수 있다.
    • 또한 좀 더 쉽게 DoG를 구현하는 방법은 두 개의 표준 편차로 가우시안 마스크를 생성하여 회선을 수행하고, 그 결과 행렬들의 차분을 계산하는 것이다.

캐니 에지 검출

  • 영상 내에서 잡음은 다른 부분과 경계를 이루는 경우가 많다. 그러다 보니 대부분의 에지 검출 방법이 이 잡음들을 에지로 검출하게 된다. 이런 문제를 보완하는 방법 중의 하나가 John F. Canny에 의해 개발된 캐니 에지(Canny Edge) 검출 방법이다.
  • 캐니 에지 알고리즘은 일반적으로 다음 네 단계의 알고리즘으로 구성되어 있다.
    1. 블러링을 통한 노이즈 제거(가우시안 블러링)
    2. 화소 기울기(gradiant)의 강도와 방향 검출 (소벨 마스크)
    3. 비최대치 억제(non-maximum suppression)
    4. 이력 임계값(hysteresis threshold)으로 에지 결정
  • 첫 단계에서 블러링은 5 x 5 크기의 가우시안 필터를 적용해서 수행한다. 여기서 블러링은 불필요한 잡음을 제거하기 위해서 수행하는 것이기 때문에 마스크의 크기를 다르게 하든지 혹은 다른 필터링을 적용해도 무관하다.
  • 다음으로 화소 기울기(gradient) 검출에는 가로 방향과 세로 방향의 소벨 마스크로 회선을 적용하고 회선이 완료된 행렬(Gx, Gy)를 이용해서 화소 기울기의 크기(magnitude)와 방향(direction)을 계산한다. 그리고 기울기의 방향은 4개 방향 (0, 45, 90, 135)로 근사하여 단순화 한다.
    • 여기서 아래 그림과 같이 기울기의 방향과 에지의 방향은 수직을 이루는 것에 유의하자.
  • 비최대치 억제(non-maximum suppression)라는 것은 현재 화소가 이웃하는 화소들보다 크면 에지로 보존하고 그렇지 않으면 에지가 아닌 것으로 간주해서 제거하는 것이다.
    • 먼저 에지의 방향에 있는 이웃 화소는 비교할 필요가 없기 때문에 아래 그림과 같이 기울기의 방향에 있는 두 개의 화소를 비교 대상으로 선택한다.
    • 그리고 현재 화소와 선택된 두 화소의 에지 강도를 비교하여 최대치가 아니면 억제되고, 최대치인 것만 에지로 결정한다.
  • 비최대치를 억제하여도 에지가 아닌 것이 에지로 결정된 경우가 많이 존재한다. 잘못된 에지를 제거하는 쉬운 방법 중 하나가 임계값을 설정하고, 에지의 강도가 이 임계값보다 작으면 에지에서 제외하는 것이다.
    • 그러나 이 방법은 임계값이 높으면 실제 에지도 제거될 수 있으며, 임계값이 낮으면 잘못된 에지를 제거하지 못하는 문제가 생길 수 있다.
  • 캐니 알고리즘은 잘못된 에지를 제거하고 정확한 에지만을 검출하여 에지가 끊어지는 것을 방지하는 방법으로 이력 임계값 방법(hysteresis thresholding)을 사용한다.
    • 이것은 두 개의 임계값 (Thigh, Tlow)을 사용해서 에지의 이력을 추적하여 에지를 결정하는 방법이다.
    • 이 방법은 각 화소에서 높은 임계값 (Thigh) 보다 크면 에지 추적을 시작한다.
    • 그리고 추적을 싲가하면 추적하지 않은 이웃 화소들을 대상으로 낮은 임계값 (Tlow) 보다 큰 화소를 에지로 결정하는 방식이다.
  • 아래 그림의 예시를 보면 A 부분은 높은 임계값보다 높아서 에지로 결정된다. C 부분은 높은 임계값보다 낮지만 에지 추적에 의해서 에지로 결정된다.
    • 반면 B 부분은 C 부분보다 에지의 강도는 높지만, 높은 임게값 보다 큰 이웃하는 부분이 없기 때문에 에지로 결정되지 않는다. 
    • 즉 낮은 임계값 이상인 에지들이 높은 임계값에서부터 연결되어 있다면 에지로 간주하는 것이다.

기타 필터링

최댓값/최솟값 필터링

  • 최댓값/최솟값 필터링은 입력 영상의 해당 화소(중심화소)에서 마스크로 씌워진 영역의 입력화소들을 가져와서 그 중에 최댓값 혹은 최솟값을 출력화소로 결정하는 방법이다.
  • 따라서 최댓값 필터링은 가장 큰 값인 밝은 색들로 출력화소가 구성되기 때문에 돌출되는 어두운 값이 제거되며, 전체적으로 밝은 영상이 된다.
    • 최솟값 필터링은 가장 작은 값들인 어두운 색들로 출력화소가 구성되기 때문에 돌출되는 밝은 값들이 제거되며, 전체적으로 어두운 영상이 된다.
    • 최댓값 필터링은 밝은 임펄스 잡음이 강조되며, 최솟값 필터링은 어두운 임펄스 잡음이 강조될 수 있다. 경우에 따라 높은 대조를 가진 영상에서 특징을 확대시키기 위한 기법으로 이용될 수 있다.

평균값 필터링

  • 평균값 필터링은 마스크로 씌워진 영역의 입력화소들을 가져와서 그 화소들의 평균을 구하여 출력화소로 지정하는 방법이다.
    • 마스크 영역의 화소값들을 평균하기 때문에 블러링의 효과가 나타난다.
  • 입력 영상의 상하좌우 끝부분에 있는 화소들은 마스크를 씌웠ㅇㄹ 때 입력화소가 존재하지 않는 화소들이 있다.
    • 3 x 3 마스크일 경우에는 상하좌우로 한 화소씩이 해당하며, 5 x 5 마스크일 경우에는 상하좌우 두 화소씩이 해당된다.
    • 이 경우 배열 참조가 잘못되어 오류가 발생하기 때문에 추가적인 방법을 적용해서 출력화소를 결정해야 한다.
    • OpenCV에서도 cv::filter2D(), cv::blur(), cv::boxFilter(), cv::sepFilter2D()와 같은 필터링을 수행하는 함수들에서 상하좌우 경계부분의 화소값을 결정하는 방법으로 borderType 이라는 옵션 상수를 다음과 같이 정의해 두었다.
옵션 상수 설명
BORDER_CONSTANT 0 특정 상수값으로 대체
BORDER_REPLICATE 1 계산 가능한 경계의 출력화소 하나만으로 대체
BORDER_REFLECT 2 계산 가능한 경계의 출력화소로부터 대칭되게 한 화소씩 지정
BORDER_WRAP 3 영상의 왼쪽 끝과 오른쪽 끝이 연결되어 있다고 가정하여 한 화소씩 가져와서 지정

미디언 필터링

  • 미디언 필터링은 중간값을 이용하기에 중간값 필터링이라고도 한다.
  • 중간값 필터링 과정은 아래 그림과 같다.
    • 먼저 입력 영상에서 해당 입력화소를 중심으로 마스크를 씌워 마스크 크기 내에 있는 입력화소들을 가져온다. 회선과는 다르게 마스크 계수는 필요하지 않고, 마스크의 크기만 필요하다.
    • 그리고 마스크 내에 있는 화소들을 크기 순으로 정렬한다.
    • 정렬된 화소값 중에서 중간 값을 취하여 출력 화소로 지정한다.
    • 이와 같은 과정을 마스크를 이동하며 모든 입력솨호에 대해 수행해서 출력영상을 생성한다.
  • 일정 영역에서 다른 화소들과 밝기가 심하게 차이가 나는 화소들은 임펄스(impulse noise) 잡음이나 소금-후추(salt & pepper) 잡음일 가능성이 높다.
    • 미디언 필터링 과정에서 마스크 영역 내의 심하게 차이가 나는 화소들은 정렬로 인해서 최하위 값이나 최상위 값이 된다. 따라서 중간 값만이 출력화소로 지정되고, 나머지 값들은 출력화소로 지정되지 않고 제거된다.
    • 이러한 이유로 미디언 필터링은 임펄스 잡음이나 소금-후추 잡음을 잘 제거해 준다. 또한 평균 필터를 이용한 필터링에 비하면 블러링 현상이 적다.
    • 다만 마스크의 크기가 커지면 잡음의 제거 성능은 향상되지만, 정렬 알고리즘을 수행해야 하는 부담 때문에 수행 시간이 기하급수적으로 증가한다.
  • 미디언 필터링은 보통 명암도 영상에서 효과적으로 수행된다.
    • RGB 컬러 공간에서는 3개 채널간의 상호 의존도가 매우 크다. 예컨대 한 채널에서는 특정 화소가 주위와 심한 차이를 보여서 제거되어도, 다른 채널에서는 같은 화소가 주위와 차이가 작아서 제거되지 않는 경우들이 생긴다. 이런 경우 RGB 조합이 맞지 않아서 오히려 잡음이 더 많아질 수도 있다.

가우시안 스무딩 필터링

  • 스무딩(smoothing)은 영상의 세세한 부분을 회선을 통해서 부드럽게 하는 기법으로 블러링과 같은 의미이다.
  • 스무딩 처리에 사용되는 대표적인 방법으로 가우시안 필터링이 있다. 가우시안 필터링은 가우시안 분포를 마스크의 계수로 사용해서 회선을 수행하는 것을 말한다.
    • 가우시안 분표는 정규 분포(normal distribution)으로 특정 값의 출현 비율을 그래프로 그렸을 때, 평균에서 가장 큰 수치를 가지며, 평균을 기준으로 좌우 대칭의 형태가 나타나고, 좌우 양끝으로 갈수록 급격하게 수치가 낮아지는 종 모양의 형태를 보인다.
    • 정규 분포를 평균(\mu )과 표준편차(\sigma )를 이용해서 함수식으로 표현하면 아래 수식과 같고, 이 수식에 따라 그래프를 그리면 아래 그림과 같다.
    • 그래프에서 표준 편차가 커지면 그래프의 폭이 넓어지고 표준편차가 작아지면 폭이 좁하진다.

N(\mu, \sigma)(x) = {1 \over \sigma \sqrt{2\pi}} exp(- {(x - \mu)^{2} \over 2 \sigma^{2}})

 

  • 가우시안 분포를 회선 마스크로 적용하려면 2차원으로 구성해야 한다. x, y 좌표를 축으로 2차원 가우시안 분포 함수를 구성하면 다음의 수식과 같고 이것을 그래프로 표현하면 아래 그림과 같다.

N(\mu, \sigma_{x}, \sigma_{y})(x, y) = {1 \over \sigma_{x} \sigma_{y} \sqrt{2\pi}} exp[- ({(x - \mu)^{2} \over 2 \sigma_{x}^{2}} + {(y - \mu)^{2} \over 2 \sigma_{y}^{2}})]

  • 이 가우시안 분포 값으로 마스크를 구성하여 회선을 수행하면 가우시안 스무딩을 수행할 수 있다.
    • 단, 마스크 계수의 전체 합이 1이 되어야 입력 영상의 밝기를 유지할 수 있다.
    • 여기서 표준편차를 변경하면 그래프에서 기둥의 폭을 조절할 수 있다. 즉, 마스크 계수의 구성을 표준편차로 조정하는 것이다.
    • 표준편차가 클수록 평균의 높이는 낮아지고, 폭이 넓어진다. 따라서 생성되는 마스크는 블러링 마스크와 유사하게 만들어진다. 결과 영상에 중심화소와 비슷한 비중으로 주변 화소가 반영되기 때문에 흐림의 정도가 심해진다.
    • 표준편차가 작아지면 구성된 마스크에서 중심계수의 값이 커지고, 주변 계수의 값은 작아진다. 이럴 경우 결과 영상에 중심화소의 비중이 커지기 때문에 흐림의 정도가 약화된다.

모폴로지(morphology)

  • 모폴로지는 형태학이라는 뜻으로서 영상 처리에서는 객체들의 형태(shape)를 분석하고 처리하는 기법을 말한다. 이 형태학적 처리를 활용하여 영상의 경계, 골격, 블록 등의 형태를 표현하는데 필요한 요소를 추출한다.
  • 영상 내에서 아주 작은 크기의 객체들은 잡음일 가능성이 높다. 이런 작은 크기의 객체는 그 크기를 더 깎아내서 제거하거나, 객체들을 분리하거나, 객체를 팽창하거나 할 때 필요한 것이 모폴로지이다.
  • 모폴로지는 객체의 형태를 변형시켜야 하기 때문에 주로 이진 영상에서 수행된다. 대표적인 연산 방법으로는 침식 연산과 팽창 연산이 있으며, 이 두 개를 결합한 닫힘 연산과 열림 연산이 있다.

침식 연산(erosion operation)

  • 침식 연산은 말 그대로 객체를 침식시키는 연산이다. 따라서 객체의 크기는 축소되고 배경은 확장된다. 객체의 크기가 축소되기 때문에 영상 내에 존재하는 잡음 같은 작은 크기의 객체들은 사라질 수도 있다.
  • 이러한 현상을 이용해서 소금-후추(salt & papper) 잡음과 같은 임펄스(impulse) 잡음들을 제거한다. 영상 내에서 객체의 돌출부를 감소시키기 때문에 서로 닿는 물체를 분리할 때도 유용하게 사용할 수 있다.
  • 위 그림은 이진 영상에서 침식 연산의 과정에 대한 내용이다. 
    • 입력 영상의 중심화소 주변에서 마스크 크기의 화소들을 가져와서 침식 마스크와 원소 간(element-wise)에 일치하는지를 비교한다. 여기서 침식 마스크의 원소가 1인 값에 대해서만 비교를 수행한다.
    • 그림의 상단과 같이 입력 영상의 화소와 마스크 원소가 한 개의 화소라도 일치하지 않으면 출력화소는 검은색인 0이 된다.
    • 반면 그 아래쪽의 그림과 같이 입력 영상의 화소와 마스크 원소와 비교해서 모두가 일치하면 출력화소는 흰색인 1이 지정된다.
    • 마스크의 크기와 원소의 구성은 입력 영상의 형태에 따라 사용자가 조정하여 더 나은 결과를 생성할 수 있다.
  • 아래 그림은 입력 영상에 값을 표시하고 침식 연산을 수행하여 결과 영상에 값을 표시한 예이다.
    • 입력된 이진 영상에서 객체로 인식되는 흰색의 블록들은 그 경계부분이 깎여져서 출력 영상이 만들어진다.

팽창 연산(dilation operation)

  • 팽창 연산은 객체를 팽창시키는 연산이다. 객체의 최외곽 화소를 확장시키는 기능을 하기 때문에 객체의 크기는 확대되고 배경은 축소된다. 또한 객체의 팽창으로 인해 객체 내부에 있는 빈 공간도 메워지게 된다.
  • 위 그림은 이진 영상에서 팽창 연산을 수행하는 과정을 나타낸 것이다.
    • 마스크 범위의 입력화소와 팽창 마스크의 원소 간(element-wise)에 일치하는 지를 비교한다. 팽창 마스크가 1인 원소와 해당 입력화소가 모두 불일치하면 출력화소로 0을 지정한다. 그리고 1개 화소라도 일치하게 되면 1이 출력화소로 결정된다.
  • 아래 그림은 팽창 연산의 결과를 예시한 것이다.
    • 팽창 연산 수행 결과로 객체의 외각이 확장되며 객체 내부의 빈 공간이 경계부분의 확장으로 인해 메워진다. 
    • 반면에 잡음으로 예상되는 작은 크기의 객체도 확장되는 것을 볼 수 있다.

열림 연산과 닫힘 연산

  • 열림 연산과 닫힘 연산은 모폴로지의 기본 연산인 침식 연산과 팽창 연산의 순서를 조합하여 수행한다.
  • 열림 연산(opening operator)은 침식 연산을 먼저 수행하고, 바로 팽창 연산을 수행한다.
    • 침식 연산으로 인해 객체는 축소되고, 배경 부분의 미세한 잡음들은 제거된다.
    • 다음으로 축소되었던 객체들이 팽창 연산으로 인해 다시 원래 크기로 돌아간다.
  • 아래 그림은 열림 연산의 과정을 예시한 것이다. 배경 부분의 잡음을 제거하면서 침식 연산으로 인한 객체 크기의 축소를 방지할 수 있다. 
    • 다만 돌출된 부분은 제거된 후 다시 원래 크기로 돌아가지 않는다.
  • 닫힘 연산(closing operator)은 팽창 연산을 먼저 수행하고, 다음으로 침식 연산을 수행한다.
    • 팽창 연산으로 객체가 확장되어서 객체 내부의 빈 공간이 메워진다.
    • 다음으로 침식 연산으로 확장되었던 객체의 크기가 원래대로 축소된다.
    • 최종 결과 영상을 보면 객체 내부의 비어있던 공간이 채워지며, 인접한 객체를 이어지게 하는 효과도 있다.
    • 모폴로지 연산은 한 번의 수행으로 결과 영상이 미흡할 경우에는 여러 번 반복적으로 수행할 수 있다.

OpenCV로 배우는 영상 처리 및 응용/ 화소 처리

영상 화소의 접근

at

  • 행렬의 지정된 원소(화소)에 접근하는 템플릿 함수
반환형 이름 파라미터
_Tp& at int i,
_Tp& at int i, int j,
_Tp& at int i, int j, int k
_Tp& at Point pt
_Tp& at const int* idx
_Tp& at const vec<int, n>& idx

ptr

  • 행렬에서 지정된 행에 대한 포인터를 반환한다.

MatIterator/ MatConstIterator

  • Mat의 반복자 클래스
  • MatIterator는 읽기와 쓰기가 가능한 반복자를 반환
  • MatConstIterator는 읽기만 가능한 반복자를 반환
반환형 이름 파라미터
MatIterator_<_Tp> begin  
MatIterator_<_Tp> end  
MatConstIterator_<_Tp> begin  
MatConstIterator_<_Tp> end  

화소 밝기 변환

밝기 조절

  • Mat에 at을 각 원소별로 접근하고 그 값을 제어
  • Mat에 Rect를 이용해서 범위을 가져오고 그 값을 제어
  • Mat에 상수를 더해서 영상을 밝게 만들 수 있고, 상수를 빼서 영상을 어둡게 만들 수 있다.
  • 255에서 Mat을 빼면 영상을 반전시킬 수 있다.

영상 합성

  • 두 Mat을 더하면 영상 합성이 되고, 두 Mat을 빼면 차영상(difference image)가 된다.

명암 대비

  • 낮은 명암 대비 영상은 밝은 부분과 어두운 부분의 차이가 크지 않아 전체적으로 어둡거나 밝은 영상이고, 높은 명암 대비 영상은 밝은 부분과 어두운 부분의 차이가 큰 영상이다.
  • 영상 내에서 명암 대비를 제어하려면 어두운 부분은 더 어둡게, 밝은 부분은 더 밝게 만들어야 하는데, 이는 곱셈 연산을 통해 가능하다.
  • 명암 대비를 늘리기 위해서는 1.0 이상의 값을 곱하고, 명암 대비를 줄이려면 1.0 이하의 값을 곱해주면 된다.

히스토그램

  • 히스토그램이란 어떤 데이터가 얼마나 많은지를 나타내는 도수 분포표를 그래프로 나타낸 것.
    • 보통 히스토그램에서는 가로축이 계급, 세로축이 빈도수를 뜻한다.
    • 영상 처리에서 히스토그램은 화소의 분포를 나타내는 지표이기 때문에 이 분포를 이해하면 영상의 특성을 판단할 수 있는 유용한 도구가 될 수 있다.
반환형 이름 파라미터 내용
void calcHist const Mat* images,
int nimages,
const int* channels,
InputArray mask,
OutputArray hist,
int dims,
const int* histSize,
const float** ranges,
bool uniform = true,
bool accumulate = false
다차널의 행렬에서 다차원의 히스토그램을 그리는 함수

히스토그램 스트레칭(stretching)

  • 히스토그램 스트레칭이란 명암 분포가 좁은 히스토그램을 좌우로 잡아 당겨서 고른 명암 분포를 가진 히스토그램이 되게 하는 것. 이를 통해 영상의 화질이 변경되고 개선될 수 있다.
  • 히스토그램의 스트레칭 대상이 되는 두 곳이 빈도갑이 가장 낮은 화소값과 가장 높은 화소값이 된다.
    • 가장 낮은 화소값을 0으로 당기고, 가장 높은 화소값을 255로 당기면 그 중간의 화소값들은 각각의 비율에 따라 스트레칭 된다. (가장 낮은 화소값은 히스토그램 그래프 상 가장 왼쪽, 가장 높은 화소값은 가장 오른쪽이 된다)
  • 히스토그램 스트레칭 공식
    • 새 화소값 = (화소값 – low) x 255 / (high – low)
      • high는 최고 화소값, low는 최저 화소값

히스토그램 평활화(equalization)

  • 히스토그램 평활화 알고리즘은 ‘분포의 균등’이라는 방법을 이용해 명암 대비를 증가시킨다. 이를 통해 영상의 인지도를 높이며, 영상의 화질을 개선할 수 있다.
  • 히스토그램의 분포가 좁지는 않지만 특정 부분에서 한쪽으로 치우친 명암 분포를 가진 영상들은 명암 분포가 좁지 않기 때문에 히스토그램 스트레칭으로는 문제가 해결되지 않는다. 이런 영상에서는 히스토그램 평활화를 이용해야 한다.
  • 히스토그램 평활화 과정
    • 영상의 히스토그램을 계산한다.
    • 히스토그램 빈도값에서 누정 빈도수(누적합)를 계산한다.
    • 누적 빈도수를 정규화(정규화 누적합)한다.
    • 결과 화소값 = 정규화 누적합 * 최대 화소값
  • 평활화 화소값 계산식
    • 평활화 결과 화소값 = 입력 화소의 정규화 누적합 x 최대 화소값

평활화 예제

  • 아래와 같은 분포를 가진 이미지가 있다고 하자
0 2 2 1
1 2 3 2
1 2 3 2
1 3 1 7
  • 각 화소값에 대한 빈도수, 누적 빈도수, 정규화 누적합, 평활화 결과는 아래와 같다.
    • 평활화 결과는 반올림해서 사용한다.
화소값 0 1 2 3 4 5 6 7
빈도수 1 5 6 3 0 0 0 1
누적 빈도수 1 6 12 15 15 15 15 16
정규화 누적합 1/16 = 0.0625 6/16 = 0.375 12/16 = 0.75 15/16 = 0.9375 15/16=0.9375 15/16=0.9375 15/16=0.9375 16/16 = 1
평활화 결과 0.0625 x 7=0.4375 0.375 x 7=2.625 0.75 x 7 = 5.25 0.9375 x 7 = 6.5625 0.9375 x 7 = 6.5625 0.9375 x 7 = 6.5625 0.9375 x 7 = 6.5625 1 x 7 = 7

컬러 공간 변환

RGB 컬러 공간

  • 빛의 3원색을 이용해 만든 컬러 공간. 빨강(red), 파랑(blue), 초록(green)으로 이루어진다.
  • 원색의 조합은 섞을 수록 밝아지기 때문에 가산혼합이라 한다.

CMY(K) 컬러 공간

  • 색의 삼원색을 이용한 컬러 공간. 빛의 삼원색과 보색 관계에 있는 청록(cyan), 자홍(magenta), 노랑(yellow)로 이루어진다.
  • 색은 섞을수록 어두워지기 때문에 감산 혼합이라 한다.

HSI 컬러 공간

  • HSI는 색상(Hue), 채도(Saturation), 명도(Intensity Value)라는 3가지 변수로 구분된다.
    • 색상은 빛이 물체에서 반사되어 나온 색으로 파장을 시각적으로 표현한 값.
    • 채도는 색의 순수한 정도로 순색(pure color)에 흰색의 혼합 비율에 따라 0~100의 값을 갖는다.
    • 명도는 빛의 세기로 색의 밝고 어두운 정도를 나타낸다. 0~100의 값이며 0이면 검은색, 100이면 흰색이 된다.
  • RGB 컬러 공간에서 HIS 컬러 공간으로 변경하는 공식
    • H
      • If B ≤ G
        • H = cos^{-1} [ {((R - G) + (R + B)) \times 0.5 \over \sqrt{(R - G^{2}) + (R - B) \times (G - B)} } ]
      • Else
        • H = 360 - H
    • S
      • S = 1 - {3 \times min (R, G, B) \over (R + G + B)}
    • I
      • I = {(R + G + B) \over 3}
  • HSV 컬러 공간에 대한 변환 공식
    • H
      • If V = R
        • H = {(G - B) \times 60 \over S}
      • Else if V = G
        • H = {(G - B) \times 60 \over S} +120
      • Else if V = B
        • H = {(G - B) \times 60 \over S} + 240
    • S
      • If V = 0
        • S = 0
      • Else
        • S = {min (R, G, B) \over V}
    • V
      • V = max(R, G, B)

YCrCb 컬러 공간

  • YCrCb 컬러 공간은 영상 시스템에서 사용되는 색공간의 일종으로 영상 데이터를 압축하는 방식이다.
  • 인간의 시각은 밝기에 민감하지만 색상에는 덜 민감하다는 점을 이용해서 YCrCb 컬러 공간에서는 색차 신호인 Cr, Cb 성분을 Y 성분보다 상대적으로 낮은 해상도고 구성해서 인간의 시각에서 화질의 큰 저하 없이 영상 데이터의 용량을 감소 시킬 수 있다.
  • RGB와 YCbCr 변환 공식
    • Y = 0.299R + 0.857G + 0.114B
    • Cb = (R - Y) \times 0.564 + 128
    • Cr = (B - Y) \times 0.713 + 128
    • R = Y + 1.403 \times (Cr - 128)
    • G = Y - 0.714 \times (Cb - 128) - 0.344(Cb - 128)
    • B = Y + 1.773 \times (Cb - 128)
    • R = Y + 1.403 x (Cr – 128)
    • G = Y – 0.714 x (Cb – 128) – 0.344 x (Cb – 128)
    • B = Y + 1.773 x (Cb – 128)

YUV 컬러 공간

  • YUV 컬러 공간은 TV 방송 규격에서 사용하는 컬러 표현 방식이다. PAL 방식의 아날로그 비디오를 위해 개발되었지만 디지털 비디오에서도 유럽의 비디오 표준으로 사용하고 있다.
  • RGB와 YUV 변환 공식
    • Y = 0.2160R + 0.7142G + 0.0722B
    • U = -0.0999R - 0.3360G + 0.4360B
    • V = 0.6150R - 0.5586G - 0.05639B
    • R = Y + 1.28033V
    • G = Y - 0.21482U - 0.38059V
    • B = Y + 2.12798U

OpenCV로 배우는 영상 처리 및 응용/ 기본 행렬 연산(Operations on Arrays) 함수

기본 배열 처리 함수

반환형 이름 파라미터 내용
void flip InputArray src, OutputArray dst, Int flipCode 입력된 2차원 배열을 수직, 수평, 양축으로 뒤집는다.
void repeat InputArray src, int ny, int nx, OutputArray dst 입력된 배열의 반복된 복사본으로 출력 배열을 채운다.
Mat repeat const Mat& src, int ny, int nx 입력된 배열의 반복된 복사본으로 출력 배열을 채운다.
void transpose InputArray src, OutputArray dst 입력 행렬의 전치 행렬을 출력 인수로 반환한다.

채널 처리 함수

반환형 이름 파라미터 내용
void merge const Mat* mv, size_t count, OutputArray dst 여러 개의 단일 채널 배열로 다중 채널의 배열을 합성한다.
void merge InputArrayOfArrays mv, OutputArray dst 여러 개의 단일 채널 배열로 다중 채널의 배열을 합성한다.
void split InputArray m, OutputArrayOfArrays mv 다중 채널 배열을 여러 개의 단일 채널 배열로 분리한다.
void mixChannels const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs 명시된 채널의 순서쌍에 의해 입력 배열들(src)로부터 출력 배열들(dst)을 복사한다.
void mixChannels const vector<Mat>& src, Vector<Mat>& dst, const int* fromTo, size_t npairs 명시된 채널의 순서쌍에 의해 입력 배열들(src)로부터 출력 배열들(dst)을 복사한다.

산술 연산 함수

반환형 이름 파라미터 내용
void add InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), int dtype = -1 두 개의 배열이나 배열과 스칼라의 각 원소 간(per-element) 합을 계산한다. 입력 인수 src1, src2 중 하나는 스칼라일 수 있다.
void substat InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), int dtype = -1 두 개의 배열이나 배열과 스칼라의 각 원소간 차분을 계산한다.
void multiply InputArray src1, InputArray src2, OutputArray dst, InputArray scale = 1 int dtype = -1 두 배열의 각 원소 간 곱을 계산한다.
void divide InputArray src1, InputArray src2, OutputArray dst, InputArray scale = 1 int dtype = -1 두 배열의 각 원소 간 나눗셈을 수행한다.
void divide double scale, InputArray src2, OutputArray dst, int dtype = -1 두 배열의 각 원소 간 나눗셈을 수행한다.
void scaleAdd InputArray src1, double alpha, InputArray src2, OutputArray dst 스케일된 배열과 다른 배열의 합을 계산한다.
void addWeighted InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1 두 배열의 가중된(weighted) 합을 계산한다.
void exp InputArray src, OutputArray dst 모든 배열 원소의 지수(exponent)를 구한다.
void log InputArray src, OutputArray dst 모든 배열 원소의 절댓값에 대한 자연로그를 계산한다.
void sqrt InputArray src, OutputArray dst 모든 배열 원소에 대해 제곱근을 계산한다.
void pow InputArray src, double power, OutputArray dst 모든 배열 원소에 대해 power 승수를 계산한다.
void magnitude InputArray x, InputArray y, OutputArray magnitude 2차원 벡터들의 크기(magnitude)를 계산한다.
void phase InputArray x, InputArray y, OutputArray angle, bool angleInDegree = false 2차원 벡터의 회전 각도를 계산한다.
void cartToPolar InputArray x, InputArray y, OutputArray magnitude, OutputArray angle, bool angleInDegree = false 2차원 벡터들의 크기(magnitude)와 각도를 계산한다.
void polarToCart InputArray magnitude, InputArray angle, OutputArray x, OutputArray y, bool angleInDegree = false 각도와 크기로부터 2차원 벡터들의 좌표를 계산한다.
void bitwise_and InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray() 두 배열의 원소 간 혹은 배열 원소와 스칼라 간의 비트 간 논리곱 연산을 수행한다. 입력 인수 src1, src2 중 하나는 스칼라 값일 수 있다.
void bitwise_or InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray() 두 배열의 원소 간 혹은 배열 원소와 스칼라 간의 비트 간 논리합 연산을 수행한다.
void bitwise_xor InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray() 두 배열의 원소 간 혹은 배열 원소와 스칼라 간의 비트 간 배타적 논리합 연산을 수행한다.
void bitwise_not InputArray src, OutputArray dst, InputArray mask = noArray() 입력 배열의 모든 원소에 대해 각 비트의 역을 계산한다.

절댓값, 최댓값, 최솟값 관련 함수

반환형 이름 파라미터 내용
MatExpr abs const Mat& m 행렬의 각 원소에 대한 절대값을 계산하여 수식을 위한 행렬인 MatExpr 객체로 반환한다.
MatExpr abs const MatExpr& e 행렬의 각 원소에 대한 절대값을 계산하여 수식을 위한 행렬인 MatExpr 객체로 반환한다.
void absdiff InputArray src1, InputArray src2, OutputArray dst 두 배열간 각 원소 간 차분의 절댓값을 계산한다. src1, src2 중 하나는 스칼라값이 될 수 있다.
void convertScaleAbs InputArray src, OutputArray dst, double alpha = 1, double beta = 0 입력 배열의 각 원소에 alpha만큼 배율을 곱하고 beta 만큼 더한 후에 절댓값을 계산한 결과를 8비트 자료형으로 반환한다.
void min InputArray src1, InputArray src2, OutputArray dst 두 입력 행렬을 원소 간 비교하여 작은 값을 출력 행렬로 반환한다.
void min const Mat& src1, const Mat& src2, Mat& dst 두 입력 행렬을 원소 간 비교하여 작은 값을 출력 행렬로 반환한다.
MatExpr min const Mat& a, double s 행렬의 원소와 스칼라를 비교하여 작은 값을 출력 행렬로 반환한다.
MatExpr min double s, const Mat& a 행렬의 원소와 스칼라를 비교하여 작은 값을 출력 행렬로 반환한다.
void max InputArray src1, InputArray src2, OutputArray dst 두 입력 행렬을 원소 간 비교하여 큰 값을 출력 행렬로 반환한다.
void max const Mat& src1, const Mat& src2, Mat& dst 두 입력 행렬을 원소 간 비교하여 큰 값을 출력 행렬로 반환한다.
MatExpr max const Mat& a, double s 행렬의 원소와 스칼라를 비교하여 큰 값을 출력 행렬로 반환한다.
MatExpr max double s, const Mat& a 행렬의 원소와 스칼라를 비교하여 큰 값을 출력 행렬로 반환한다.
void minMaxIdx InputArray src, double* minVal, double* maxVal, int* minIdx = 0, int* maxIdx = 0, InputArray mask = noArray() 전체 배열에서 최솟값과 최댓값인 원소의 위치와 그 값을 반환한다.
void minMaxLoc InputArray src, double* minVal, double* maxVal, Point* minLoc = 0, Point* maxLoc = 0, InputArray mask = noArray() 전체 배열에서 최댓값과 최솟값을 갖는 원소의 위치와 그 값을 반환한다. 위치를 Point 형으로 반환한다.

통계 관련 함수

반환형 이름 파라미터 내용
Scalar sum InputArray src 배열의 각 채널 별로 원소들의 합을 계산하여 스칼라 값으로 반환한다.
Scalar mean InputArray src, InputArray mask = noArray() 배열의 각 채널 별로 원소들의 평균을 계산하여 스칼라 값으로 반환한다.
void meanStdDev InputArray src, OuputArray mean, OutputArray stddev, InputArray mask = noArray() 배열 원소들의 평균과 표준편차를 계산한다.
int countNonZero InputArray src 0이 아닌 배열 원소를 개수 N을 반환한다.
void reduce InputArray src, OutputArray dst, int dim, int rtype, int dtype = -1 행렬을 열방향 혹은 행방향으로 옵션상수(rtype)의 연산을 수행하여 벡터로 감축한다.   <옵션 상수> REDUCE_SUM/ 0/ 행렬의 모든 행(열)들을 합한다. REDUCE_AVG/ 1/ 행렬의 모든 행(열)들을 평균한다. REDUCE_MAX/ 3/ 행렬의 모든 행(열)들의 최댓값을 구한다. REDUCE_MIN/ 4/ 행렬의 모든 행(열)들의 최솟값을 한다.
void sort InputArray src, OutputArray dst, int flags 행렬의 각 행 혹은 각 열의 방향으로 정렬한다.   <옵션 상수> SORT_EVERY_ROW/ 0/  각 행을 독립적으로 정렬 SORT_EVERY_COLUMN/ 1/  각 열을 독립적으로 정렬 SORT_ASCENDING/ 0/  오름차순으로 정렬 SORT_DESENDING/ 16/  내림차순으로 정렬
void sortIdx InputArray src, OutputArray dst, int flags 행렬의 각 행 혹은 각 열로 정렬한다. 출력 배열(dst)에 정렬된 원소의 인덱스들을 저장한다. 인수는 sort와 동일하다.

행렬 연산 함수

반환형 이름 파라미터 내용
void gemm InputArray src1, InputArray src2, double alpha, InputArray src3, double beta, OutputArray dst, Int flags = 0 일반화된 행렬 곱셈을 수행한다.   <옵션> GEMM_1_T/ 1/ src1을 전치 GEMM_2_T/ 2/ src2을 전치 GEMM_3_T/ 4/ src3을 전치
void perspectiveTransform InputArray src, OutputArray dst, InputArray m 입력 배열의 모든 원소에 행렬 변환을 수행한다.
void transform InputArray src, OutputArray dst, InputArray m 입력 벡터들에 대해 투영(perspective) 변환 m을 수행한다.
double invert InputArray src, OutputArray dst, Int flags = DECOMP_LU 행렬의 역행렬을 계산한다.
bool solve InputArray src1, InputArray src2, OutputArray dst, Int flags = DECOMP_LU 연립 방정식이나 최소자승 문제를 해결한다.

OpenCV로 배우는 영상 처리 및 응용/ OpenCV 인터페이스 기초/ 사용자 인터페이스 및 I/O 처리

윈도우 창 제어

반환형 이름 파라미터 내용
void namedWindow const string& winname, int floats = WINDOW_AUTOSIZE 윈도우의 이름을 설정하고 해당 이름으로 윈도우를 생성한다.
<윈도우의 크기 조정 옵션>
WINDOW_NORMAL – 0 – 윈도우의 크기 재조정 가능
WINDOW_AUTOSIZE – 1 – 표지될 행렬의 크기에 맞춰 자동 설정
WINDOW_OPENGL – 8 – OpenGL을 지원하는 윈도우 생성
void imshow() const string& winname, InputArray mat Winname 이름의 윈도우에 mat 행렬을 영상으로 표시한다.
해당 이름의 윈도우가 없으면 winname 이름으로 창을 생성하고, 영상을 표시한다.
void destroyWindow() const string& winname 인수로 지정된 타이틀의 윈도우를 파괴한다.
void destroyAllWindows()   HighGUI로 생성된 모든 윈도우를 파괴한다.
void moveWindow() const string& winname, int x, int y Winname 이름의 윈도우를 지정된 위치(x, y)로 이동시킨다. 이동되는 윈도우의 기준 위치는 좌상단이다.
void resizeWindow() const string& winname, int width, int height 윈도우의 크기를 재설정한다.

이벤트 처리 함수

반환형 이름 파라미터 내용
int waitKey int delay = 0 delay(ms) 시간만큼 키 입력 대기하고, 키 이벤트가 발생하면 해당 키 값을 반환한다.
void setMouseCallback() const string& winname, MouseCallback onMouse, void* userdata = 0 사용자가 정의한 마우스 콜백함수를 시스템에 등록하는 함수
void (*MouseCallback)()   발생한 마우스 이벤트에 대해서 처리 및 제어를 구현하는 콜백 함수이다.
setMouseCallback() 함수의 두 번째 인수(함수포인터)의 구현 부이기 때문에 함수명이 인수명과 같아야 한다
typedef 통해서 함수포인터로 정의되어 있어 인수의 구조를 유지해야 함
int createTrackbar() const string& trackbarname, const string& winname, int value, int count, TrackarCallback onChange = 0, Void* userdata = 0 트랙바를 생성하고, 그것을 지정된 윈도우 창에 추가하는 함수
int getTrackbarPos()   지정된 트랙바의 슬라이더 위치를 반환 받는다
void setTrackbarPos()   지정된 트랙바의 슬라이더 위치를 설정한다.

그리기 함수

반환형 이름 파라미터 내용
void line Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = 8, int shift = 0 선 그리기
void rectangle Mat& img, Point pt1, Point pt2, const Scalar color, int thickness = 1, int lineType = 8, int shift = 0 사각형 그리기
void rectangle Mat& img, Rect rec, const Scalar color, int thickness = 1, int lineType = 8, int shift = 0 사각형 그리기
void putText Mat& img, const string& text, Point org, Int fontFace, double fontSacle, Sclar color, int thickness = 1, int lineType = 8, bool bottomLeftOrigin = false 글자 쓰기
void circle Mat& img, Point center, int radius, const Scalar& color, int thickness = 1, int lineType = 8, int shift = 0 원 그리기
void ellipse Mat& img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness = 1, int lineType = 8, int shift = 0 타원 그리기
void ellipse Mat& img, const RotatedRect& box, const Scalar& color, int thickness = 1, int lineType = 8, int shift = 0 타원 그리기

이미지 파일 처리

반환형 이름 파라미터 내용
Mat imread() const string& filename, int flags = 1 지정된 파일로부터 영상을 로드하여 Mat 클래스로 반환한다
bool imwrite() const string* filename, InputArray img, const vector<int>& params = vector<int>() 지정된 파일에 img 행렬을 영상으로 저장한다.

비디오 처리

VideoCapture

반환형 이름 파라미터 내용
VideoCapture()   생성자
bool open()   동영상 캡쳐를 위한 동영상 파일 혹은 캡쳐 장치를 개방한다.
bool isOpened()   캡쳐 장치의 연결 여부를 반환한다.
bool release()   동영상 파일이나 캡쳐 장치를 해제한다.
double get()   비디오 캡쳐의 속성 식별자로 지정된 속성의 값을 반환한다. 캡쳐 장치가 제공하지 않는 속성은 0을 반환한다.
bool set()   지정된 속성식별자로 비디오캡쳐의 속성을 설정한다.
bool grab()   캡쳐 장치나 동영상 파일로부터 다음 프레임을 잡는다.
bool retrieve()   grab()으로 잡은 프레임을 디코드해서 image 행렬로 전달한다.
bool read(), >>   다음 동영상 프레임을 잡아서 디코드하고 image 행렬로 전달한다. 즉, grab()과 retrieve()를 동시에 수행한다.

VideoWriter

반환형 이름 파라미터 내용
VideoWriter   생성자
bool open()   영상을 동영상 파일의 프레임으로 저장하기 위해 동영상 파일을 개방한다.
bool isOpened()   동영상 파일 저장을 위해 VideoWriter 객체의 개방 여부를 확인한다.
void write(), <<   image 행렬(프레임)을 동영상 파일로 저장한다.

데이터의 파일 저장 및 읽기

FileStorage

반환형 이름 파라미터 내용
FileStorage()   생성자
bool open()   파일 열기
bool isOpened()   클래스에 지정된 파일이 열려 있는지 확인.
bool release()   파일을 닫고 모든 메모리 버퍼를 해제한다.
void writeRaw()   다중의 숫자들을 저장한다. 데이터를 raw 파일로 저장한다.

FileNode

반환형 이름 파라미터 내용
FileNode()   생성자
string name()   노드 이름을 반환한다.
size_t size()   노드에서 원소의 개수를 반환한다.
bool empty()   노드가 비어있는지 확인한다.
bool isNamed()   노드가 이름이 있는지 확인한다.
bool isNone()   노드가 “none” 객체인지 확인한다.
bool isInt() isReal()   노드타입이 정수형, 실수형인지 확인한다.
bool isString()   노드타입이 문자열형인지 확인한다.
bool isMap(), isSeq()   노드의 종류가 매핑인지 시퀀스인지 확인한다.

OpenCV로 배우는 영상 처리 및 응용/ OpenCV의 기본 자료 구조

기본 템플릿 클래스

Point

멤버

타입 이름 내용
T x X 값
T y Y 값

함수

타입 이름 내용
T dot() 내적
double corss() 외적
bool inside() Point가 Rect 안에 있는지 여부

Point3

멤버

타입 이름 내용
T x X 값
T y Y 값
T z Z 값

함수

타입 이름 내용
T dot() 내적
double corss() 외적

Size

멤버

타입 이름 내용
T width Width 값
T height Height 값

함수

타입 이름 내용
T area() 내부 영역의 넓이 (Width x Height)

Rect

멤버

타입 이름 내용
T x X 값
T y Y 값
T width Width 값
T height Height 값

함수

타입 이름 내용
Point tl() 좌상된 좌표 반환
Point br() 우하단 좌표 반환
Size size() 사각형의 크기를 Size 형으로 반환
T area() 내부 영역의 넓이 (Width x Height)
bool contains() 사각형 내부에 좌표가 있는지 확인

Vec

  • Template 클래스
  • [ ]를 이용하여 원소들에 접근할 수 있다.
  • mul

함수

타입 이름 내용
T mul() 벡터의 element-wise 곱을 계산한다.

Scalar

  • Vec<Tp, 4>에서 파생된 템플릿 클래스로서 4개의 원소를 갖는다.
  • OpenCV에서 특별히 화소의 값을 지정하기 위한 자료형으로 정의되었으며 RGBA 4개의 값을 저장한다.

RotatedRect

  • 회전된 사각형을 나타내기 위한 클래스

멤버

타입 이름 내용
Point2f center 중심점
Size2f size 크기
float angle 회전된 각도

함수

타입 이름 내용
Rect boundingRect() 회전사각형 4개 모서리를 모두 포함하는 최소 크기의 사각형 영역을 반환
void points() 인수로 입력되는 pts 배열에 회전사각형의 4개 꼭짓점을 전달

Mat 클래스

행렬 자료형의 종류

데이터형 설명 Depth
CV_8U uchar 0
CV_8S signed char 1
CV_16U unsigned short int 2
CV_16S signed short int 3
CV_32S int 4
CV_32F float 5
CV_64F double 6

행렬 초기화 함수

타입 이름 내용
MatExpr ones() 행렬의 모든 원소 1인 행렬을 반환
MatExpr eye() 지정된 크기와 타입의 단위 행렬을 반환
MatExpr zeros() 행렬의 모든 원소를 0으로 초기화

멤버

타입 이름 내용
int dims 차원 수
int rows 행 갯수
int cols 열 개수        
uchar* data 행렬 원소 데이터에 대한 포인터
MatStep step 행렬의 한 행이 차지하는 바이트 수
MatSize size 행렬의 크기를 Size 형으로 반환

함수

타입 이름 내용
int channels() 행렬의 채널 수 반환
int depth() 행렬의 깊이 값 반환
Size elemSize() 행렬의 한 원소에 대한 바이트 크기 반환
Size elemSize1() 행렬의 한 원소의 한 채널에 대한 바이트 크기 반환
bool empty() 행렬 원소가 비어있는지 여부 반환
bool isSubmatrix() 참조 행렬인지 여부 반환
size step1() Step을 elemSize1()로 나누어서 정규화된 step 반환
size total() 행렬 원소의 전체 개수 반환
int type() 행렬의 데이터 타입(자료형 + 채널 수) 반환 자료형으로 상위 3비트 + 채널 수로 하위 3비트
void resize() 행의 개수를 기준으로 기존 행렬의 크기를 변경한다. 기존 행렬의 행의 개수보다 sz가 작으면 하단 행을 제거하고, 크면 기존 행렬 하단에 행을 추가한다.
Mat reshape() 행렬의 전체 원소 개수는 바뀌지 않으면서 행렬의 모양을 변경하여 새 행렬을 반환한다. 기존 행렬과 변경된 행렬의 전체 원소 개수(채널 수 x 행수 x 열수)가 일치하지 않으면 에러가 발생한다.
void create() 기존에 존재하는 행렬의 차원, 행, 열, 자료형을 변경하여 다시 생성한다. 기존 행렬과 크기와 자료형이 다르면 기존 메모리를 해제하고 새로운 데이터를 생성한다.
Mat clone() 행렬 데이터와 같은 값을 복사해서 새로운 행렬을 반환한다.
void copyTo() 행렬 데이터를 인자로 입력된 mat 행렬에 복사한다.
void convertTo() 행렬 원소의 데이터 타입을 변경하여 인수로 입력된 mat 행렬에 반환한다.
void push_back() 행렬의 마지막(bottom)에 원소들을 추가한다.
void pop_back() 행렬의 마지막(bottom)에서 원소들을 제거한다.
Mat cross() 두 개의 3-원소 벡터들의 외적(cross-product)을 계산한다.
Double dot() 두 벡터의 내적(dot-product)을 계산한다. 1행(1열) 벡터가 아니면 1차원 벡터로 간주하고 내적을 계산한다. 1차원 벡터의 구성은 위에서 아래로, 왼쪽에서 오른쪽의 순서로 스캔한다. 행렬이 1채널 이상이면, 각 채널들의 내적을 구하여 합산한다.
MatExpr inv() 역행렬을 계산한다.
MatExpr mul() 두 행렬의 각 원소 간(element-wise) 곱셈을 수행하여 반환한다.
MatExpr t() 해당 행렬의 전치를 수행한다. 여기서 t()는 실제로 전치를 수행하는 것이 아니라 임시로 전치된 행렬의 헤더를 반환한다. 반환된 헤더는 복잡한 행렬 연산에 사용하거나 새 행렬에 할당할 수 있다.

연산자

오른쪽 항의 데이터 타입 예문 내용
스칼라값 m1 = 100 행렬의 모든 원소를 지정된 스칼라값으로 변경하고자 할 때 사용한다. 마스크 행렬이 없는 MatsetTo()와 같은 역할을 한다.
행렬 수식 m1 = m2 + m3
m1 = m3 -7
수식의 결과가 m1 행렬에 복사된다.
행렬 m1 = m2 m2 행렬이 m1 행렬에 복사되는 것이 아니라 m2 행렬을 m1 행렬이 공유한다. 따라서 m2 행렬의 원소가 변경되면, m1 행렬의 원소도 변경된다.

Range 클래스

  • Range 클래스는 하나의 시퀀스에서 연속되는 서브 시퀀스를 지정하는 클래스이다. 주로 Mat 클래스에서 행 또는 열의 범위를 지정할 때 사용된다.
  • 멤버 변수로 start, end가 존재하는데, start는 주어진 범위 안에 포함되며, end는 포함되지 않는다.

함수

타입 이름 내용
int size() 서브 시퀀스의 크기를 반환한다.
bool empty() 서브 시퀀스가 비어있는지를 확인한다.
Range all() 서브 시퀀스가 가득차 있는지 반환한다.

행렬 헤더 관련 함수

타입 이름 내용
Mat row() 기존 행렬에서 지정된 행을 위한 행렬 헤더를 생성하여 반환한다.
Mat col() 기존 행렬에서 지정된 열을 위한 행렬 헤더를 생성하여 반환한다.
Mat rowRange() 기존 행렬에서 지정된 연속된 행을 위한 행렬 헤더를 생성하여 반환한다. 연속되는 행을 공유하고자 할 때 사용된다.
Mat colRange() 기존 행렬에서 지정된 연속된 열을 위한 행렬 헤더를 생성하여 반환한다. 연속되는 열을 공유하고자 할 때 사용된다.
void locateROI() 부분 행렬에서 부모 행렬의 크기와 위치를 알려준다.
void adjustROI() 부분 행렬에서 관심영역의 크기와 위치를 조정한다.
Mat operator() 사각형의 부분 행렬을 추출한다.

행렬의 메모리 해제

  • Mat::release() 함수는 행렬 데이터와 관련된 참조 카운터를 감소시킨다. 그리고 참조 카운터가 0에 도달하면, 행렬 데이터를 해제하고, 행렬 데이터와 참조 카운터의 포인터는 모두 null 값으로 설정함으로써 메모리를 해제한다.
  • 이 함수는 행렬 데이터의 해제를 위해서 명시적으로 호출할 수 있지만, Mat 클래스의 파괴자(destructor)에 의해 자동으로 호출되기 때문에 일반적으로 필요하지 않다.

예외처리

  • 영상 처리를 위해서 입력받는 영상 데이터는 기본적으로 채널당 8비트로 인코딩된 데이터이다. 8비트만을 이용하기 때문에 화소의 값에서 제한된 범위를 가진다.
  • 영상 데이터에 특정 연산을 할 경우 –컬러 공간 변환, 밝기/대조 조정, 샤프닝, 보간법 등– 대부분 산술연산 등으로 인해 음수나 소수점 이하의 값, 혹은 8비트의 범위를 벗어나는 값들을 갖게 할 것이다.
  • 이때 8비트만을 결과 값으로 사용하면 결과 영상에 오류가 발생될 수 있고 다음 단계의 영상 분석이나 처리에 영향을 줄 수 있다.
  • 이 문제를 해결하기 위해 포화 산술(saturation arithmetics) 연산이 사용된다. 이것은 8비트 범위일 때 다음과 같은 수식으로 나타낼 수 있다.
    • I(x, y) = min(max(round(r), 0), 255)
  • 즉, 어떤 연산의 결과 값(r)을 8비트로 저장한다고 할 때 비트 제한 범위를 넘으면 0 또는 255 가운데 가까운 값으로 저장한다.
  • OpenCV에서는 행렬에 대해 연산을 할 경우 기본적으로 포화 산술이 적용된다. 또한 기본 자료형에 대해 포화 산술 연산이 가능하도록 saturate_cast() 템플릿 메서드를 구현해 두었다.

예외처리 매크로

타입 이름 내용
define CV_Assert() 실행시간에 조건을 체크하는 매크로. 조건이 false가 되면 예외 발생
define CV_Error() 에러 코드 발생시 msg 문자열 출력
define CV_Error_() 에러 코드 발생시 args로 포맷 매칭하여 문자열 출력