OpenCV로 배우는 영상 처리 및 응용/ 영상 분할 및 특징 처리

허프 변환

  • 직선 검출 방법 중 가장 널리 사용되는 것은 허프 변환(Hough transform)이다.
    • 허프 변환은 영상 내의 선, 원 뿐만 아니라 임의의 형태를 지닌 물체를 감지해 내는 대표적인 기술로서 데이터 손실 및 왜곡이 포함된 영상에서도 직선을 잘 추출한다.

허프 변환의 좌표계

  • 허프 변환은 아래의 수식과 같이 직교 좌표계로 표현되는 영상의 에지 점들을 오른쪽 식의 극좌표계로 옮겨 검출하고자 하는 물체의 파라미터(\rho, \theta )를 추출하는 방법이다.

y = ax + b \leftrightarrow \rho = x \cdot cos \theta + y \cdot sin \theta

  • 직교 좌표계에서는 수직선일 경우 기울기가 무한대가 될 수 있으며, 검출되는 직선의 간격이 동일하지 않아서 검출 속도와 정밀도에서 문제가 될 수 있다.
    • 반면 극좌표계를 사용하면 직선이 원점에서 떨어진 수직 거리(\rho )와 이 수직선이 x축과 이루는 각도(\theta )를 이용해서 직선을 표현할 수 있다.
    • 또한 직선의 수직거리와 각도를 일정한 간격으로 검출함으로써 정밀한 직선 검출이 가능하다.
  • 직교 좌표계에서 하나의 직선상에 놓인 좌표들을 허프 변환 좌표계로 표시하면 아래 그림과 같다.
    • 직선 A 상에 검출된 3개의 지점 a_{1}, a_{2}, a_{3} 가 있다고 가정하자.
    • 먼저 직선 A는 \rho_{1} = x \cdot cos \theta_{1} + y \cdot sin \theta_{1} 로 표현할 수 있다.
    • 이 수식에 따라 직선 A는 허프 변환 좌표계에서 한 점 (\rho_{1}, \theta_{1} )의 좌표로 나타난다.
    • 또한 영상 좌표에서 3개의 지점(a_{1}, a_{2}, a_{3} )은 허프 변환 좌표(\rho_{1}, \theta_{1} )를 같이 공유한다.
  • 또한 직교 좌표계에서 한 점은 허프 변환 좌표계에서는 곡선으로 표현된다. 
    • 즉, a_{1} 좌표에서 그려질 수 있는 수많은 직선이 존재하며, 많은 (\rho_{i}, \theta_{j} )로 표현되어, 결과적으로 아래 그림의 b에서 a_{1} 곡선을 이룬다.

허프 변환의 전체 과정

  • 허프 변환은 다음과 같은 세부적인 과정을 거쳐서 수행된다.
    • 허프 변환 좌표계에서 행렬 구성
    • 영상 내 모든 화소의 직선 여부 검사
    • 직선 인지 좌표에 대한 허프 변환 누적 행렬 구성
    • 허프 누적 행렬의 지역 최대값 선정
    • 임계값 이상인 누적값(직선) 선별
    • 직선 (\rho_{i}, \theta_{j} )을 누적값 기준으로 내림차순 정렬
  • 먼저 영상의 크기에 맞게 허프 변환 좌표계를 위한 행렬을 구성한다. 이 행렬은 검출된 직선을 좌표(\rho, \theta )로 표시해서 값을 누적하기 위한 것이다.
    • \rho 는 -\rho_{max} 에서 +\rho_{max} 까지의 범위를 가지고, \theta 0 ~ \pi 까지의 범위를 가지며, 다음의 수식으로 계산된다.
    • 여기서 height, width는 원본 영상의 크기이며, acc_h, acc_w는 허프 누적 행렬의 크기이다.

-\rho_{max} \leq \rho \leq \rho_{max}, \rho_{max} = height + width

acc_h = {\rho_{max} \times 2 \over \Delta \rho}

0 \leq \theta \leq \theta_{max}, \theta_{max} = \pi

acc_w = {\pi \over \Delta \theta}

  • 따라서 허프 행렬의 크기는 거리 간격(\Delta \rho )과 각도 간격(\Delta \theta )에 따라 조절되며, 거리 간격과 각도 간격이 작을수록 행렬의 크기가 커져서 해상도가 높아진다.
    • 예컨대 각도 간격을 2도로 하면 가로(\theta ) 방향으로 90개의 원소가 필요하며, 1도 간격으로 하면, 180개의 원소가 필요하다.

허프 누적 행렬 구성

  • 다음으로 영상 내의 모든 좌표에서 직선인지 여부를 점검한다. 허프 변환에 입력되는 영상은 먼저 이진화나 모폴로지와 같은 다양한 전처리를 수행하여 잡음을 제거하고 직선 성분을 검출한다.
    • 일반적으로 캐니 에지 검출과 같이 이진 영상을 허프 변환의 입력 영상으로 사용한다. 따라서 입력 영상에서 0보다 큰 화소를 직선으로 간주한다.
  • 다음의 hough_coord() 함수는 영상 공간에서 직선으로 인지된 좌표(x, y)를 허프 변환 좌표계로 변환하여 곡선을 구성하는 알고리즘 이다.
void hough_coord(Mat image, Mat& acc_mat, double rho, double theta)
{
  int acc_h = (image.rows + image.cols) * 2 / rho;
  int acc_w = CV_PI / theta;
  acc_mat = Mat(acc_h, acc_w, CV_32S, Scalar(0));

  for (int y = 0; y < image.rows; y++)
  {
    for (int x = 0; x < image.cols; x++)
    {
      Point pt(x, y);

      if (image.at<uchar>(pt) > 0)
      {
        for (int t = 0; t < acc_w; t++)
        {
          double radian = t * theta;
          float r = pt.x * cos(radian) + pt.y * sin(radian);
          r = cvRound(r / rho + acc_mat.rows / 2);
          acc_mat.at<int>(r, t)++;
        }
      }
    }
  }
}
  • 입력 영상의 좌표를 조회하는 2중 반복문 내에서 화소값이 0보다 크면 직선으로 인지한다. 
    • 직선으로 인지되면, 다시 0 ~ acc_w 까지의 반복문을 구성하고, 각도 간격(\Delta \theta )만큼 증가한다. 즉, 0~180도까지 증가한다.
    • 이 과정에서 입력된 좌표(pt)의 x, y와 각도(\theta_{t} )를 허프 변환 수식에 대입해서 \rho_{t} 를 계산한다.
    • 거리와 각도를 좌표로 사용해 허프 누적행렬의 해당 원소값을 1 증가한다.
  • 결과적으로 직선으로 인지된 입력 영상의 각 좌표들에 대해 0~180도로 회전하며 허프 변환 수식에 따라 거리와 각도로 좌표를 계산하고, 이 좌표에 해당하는 허프 누적행렬의 원소에 값을 누적한다.
  • 아래 그림은 3개의 좌표가 있는 에지 영상으로 허프 누적행렬을 구성한 예이다.
    • 영상에서 3개 좌표에 대해 허프 누적행렬은 3개의 곡선이 구성된다. 3개의 곡선이 겹치는 좌표 (\rho_{t1}, \theta_{t1} )에서 누적값이 3으로 가장 많다. 또한 이 \rho_{t1}, \theta_{t1} 좌표는 영상의 3점을 잇는 직선이 된다.
    • 따라서 허프 누적행렬에서 원소의 값이 특정값 이상인 좌표들을 검색하면, 특정값 이상인 길이를 갖는 직선들을 \rho_{t}, \theta_{t} 좌표로 찾을 수 있다.
    • 또한 이 좌표로 허프 변환 수식을 다음과 같이 변경하여 직선을 구성할 수 있다.

\rho = x \cdot cos \theta + y \cdot sin \theta \to y = - {cos \theta \over sin \theta} x + {\rho \over sin \theta}

허프 누적 행렬의 지역 최대값 선정

  • 계산된 누적 행렬에서 좌표들을 반환받으면 위 그림과 같이 한 곳에 비슷한 직선이 여러 개 선택되어 반환될 수 있다. 이 경우 정확한 하나의 직선을 찾지 못하게 된다.
    • 또한 비슷한 위치, 비슷한 각도에서 여러 개의 직선이 검출되어서 다른 지점에 있는 직선들을 검출하지 못할 수도 있다.
  • 이 문제를 해결하는 방법으로 마스크를 이용한 방법이 있다. 허프 누적행렬을 작은 블록으로 나누고 각 블록에서 가장 큰 값만을 유지시키고 나머지 값은 제거하는 것이다.
    • 여기서 나누어진 블록을 마스크(mask)라 부르며, 마스크 내에서 가장 큰 값을 지역 최대값 (local maximum)이라 한다.
  • 아래 그림은 허프 누적행렬에 3 x 7 크기의 마스크를 적용하여 지역 최대값을 구한 예이다. 두 개의 점선 사각형으로 마스크를 표시해서 예시를 나타내었다.
    • 누적행렬 좌상단의 예시 1은 17이 가장 큰 값으로 유지되고, 마스크 주위의 나머지 값은 0으로 제거된다. 같은 방식으로 우하단의 예시 2는 11이 가장 큰 값으로 주위의 9, 10이 제거된다.
    • 이렇게 함으로써 비슷한 위치의 직선을 하나만 검출해서 직선 검출의 정확도를 높일 수 있다..
  • 다음은 허프 누적행렬에서 마스크 내의 지역 최대값만을 유지시키는 함수 acc_mask()를 구현한 것이다.
void acc_mask(Mat acc_mat, Mat& acc_dst, Size size, int thresh)
{
  acc_dst = Mat(acc_mat.size(), CV_32S, Scalar(0));
  Point h_m = size / 2;

  for (int r = h_m.y; r < acc_mat.rows - h_m.y; r++)
  {
    for (int t = h_m.x; t < acc_mat.cols - h_m.x; t++)
    {
      Point center = Point(t, r) - h_m;
      int c_value = acc_mat.at<int>(center);

      if (c_value >= thresh)
      {
        double maxVal = 0;

        for (int u = 0; u < size.height; u++)
        {
          for (int v = 0; v < size.width; v++)
          {
            Point start = center + Point(v, u);

            if (start != center && acc_mat.at<int>(start) > maxVal)
            {
              maxVal = acc_mat.at<int>(start);
            }
          }
        }

        Rect rect(center, size);

        if (c_value > maxVal)
        {
          acc_dst.at<int>(center) = c_value;
          acc_mat(rect).setTo(0);
        }
      }
    }
  }
}

임계값 이상인 누적값(직선) 선별

  • 이제 직선들을 가져와 보자. 다음의 thres_lines() 함수는 중복이 제거된 누적행렬의 원소 중에서 임계값보다 큰 값을 선별하여 직선들을 lines 행렬에 저장한다.
    • 여기서 하나의 직선(line)은 3개의 원소를 갖는 Matx13f 형으로 선언하여 간편하게 초기화 한다.
    • 누적행렬의 좌표(r, t)를 수직거리(rho)와 각도(radian)로 계산하여 두 개의 원소를 구성하고, 세 번째 원소로 누적값(value)을 지정한다.
void thres_lines(Mat acc_dst, Mat& lines, double _rho, double theta, int thresh)
{
  for (int r = 0; r < acc_dst.rows; r++)
  {
    for (int t = 0; t < acc_dst.cols; t++)
    {
      float value = (float)acc_dst.at<int>(r, t);

      if (value >= thresh)
      {
        float rho = (float)((r - acc_dst.rows / 2) * _rho);
        float radian = (float)(t * theta);
        Matx13f line(rho, radian, value);
        lines.push_back((Mat)line);
      }     
    }
  }
}

직선을 누적값 기준으로 내림차순 정렬

  • 다음은 선별된 직선들 중에서 긴 직선이 먼저 선택되도록 하기 위해 누적값이 큰 직선부터 저장해야 한다.
    • 이것은 직선들(line)을 누적값 기준으로 내림차순 정렬함으로써 쉽게 구현할 수 있다.
    • 정렬 알고리즘은 직접 구현하지 않고 OpenCV에서 제공하는 cv::sortIdx() 함수를 이용하여 다음의 sort_lines() 함수로 구현한다.
    • cv:sortIdx() 함수는 행렬 원소를 정렬하고, 정렬 원소의 원본 인덱스를 반환한다.
void sort_lines(Mat lines, vector<Vec2f>& s_lines)
{
  Mat acc = lines.col(2), idx;
  sortIdx(acc, idx, SORT_EVERY_COLUMN + SORT_DESCENDING);

  for (int i = 0; i < idx.rows; i++)
  {
    int id = idx.at<int>(i);
    float rho = lines.at<float>(id, 0);
    float radian = lines.at<float>(id, 1);
    s_lines.push_back(Vec2f(rho, radian));
  }
}
  • 앞서 thres_lines() 함수에서 반환받은 직선들(lines)은 수직거리, 각도, 누적값이 저장된 행렬이다.
    • 이 행렬에서 2번열(0번 열부터 시작)이 누적값들이기 때문에 Mat::col() 함수로 2번 열만 가져와 acc 행렬에 저장한다.
    • 그리고 cv::sortIdx() 함수로 acc 행렬을 행단위 내림차순(SORT_EVERY_COLUMN + SORT_DESCENDING) 정렬을 한다. 그러면 두 번째 인수(idx)로 정렬값에 대한 원본 인덱스가 반환되기 때문에 idx에 내림차순으로 정렬된 원본 인덱스가 저장된다.
  • idx 행렬의 전체 원소를 조회해서 원본 인덱스를 id에 저장한다. 그리고 원본 인덱스(id)로 lines 행렬(직선들)에서 한 원소를 가져온다. 여기서 lines 행렬에서 0번 열이 수직거리(rho)이며, 1번 열이 각도(radian)이다.
    • 그리고 수직거리와 각도를 Vec2f 형으로 선언해서 s_lines 벡터에 추가한다. 그러면 s_lines 벡터에 누적값에 따라서 내림차순으로 정렬된 직선 좌표가 저장된다.

코너 검출

  • 영상 내에는 에지나 직선과 같은 다양한 특징 정보들이 있다. 그러나 직선 정보는 영상 구조 파악 및 객체 검출에는 도움이 되지만, 영상 매칭에는 큰 도움이 되지 않는다.
    • 또한 에지는 강도와 방향 정보만 가지므로 영상 매칭을 하기엔 정보가 부족하다.
  • 에지나 직선처럼 영상 처리에 중요한 특징 정보로 사용되는 꼭지점 혹은 코너라 부르는 특징점이 있다. 이 코는 아래 그림과 같이 영상에서 경계가 만나는 지점의 특정한 모양을 갖는 곳을 가리킨다.
    • 이 코너 정보들 중에서 영상의 왜곡에도 불변하는 특징을 가진 지점들이 영상 매칭에 유용하게 사용될 수 있다. 여기서는 코너 검출기 중 하나인 해리스(Harris) 코너 검출기의 원리에 대해 알아볼 것이다.
  • 코너 점은 위 그림과 같이 모든 방향에서 영상의 밝기 변화가 커야 한다.  A, C 지점은 모든 방향으로 밝기의 변화가 크다. 그러나 B, D의 경우는 모든 방향으로 밝기 변화가 거의 없다.
    • 이 아이디어는 모라벡(moravec)에 의해서 다음 식과 같이 영상 변화량(SSD: Sum of Squared Difference)으로 정리된다. 여기서 w(x, y)는 지정된 크기의 윈도우로서 해당 범위만 1의 값을 갖는 마스크이다.

E(u, v) = \sum_{y} \sum_{x} w(x, y) \cdot (I(x+u, y+v) - I(x, y))^{2}

  • 영상 변화량(SSD)은 현재 화소에서 u, v 방향으로 이동했을 때의 밝기 변화량의 제곱을 합한 것이기 때문에, 모든 방향에서 밝기 변화가 커야 큰 값을 갖게 된다.
    • 모라벡은 구현을 위해서 (u, v)를 (1, 0), (1, 1), (0, 1), (-1, 1)의 4개 방향으로 한정시켜서 SSD를 구하고, 그 중에서 최소값을 해당 픽셀의 영상 변화량으로 지정해서 ‘특징 가능성’ 값으로 결정한다.
  • 모라벡 알고리즘은 마스크가 0과 1의 값만 갖는 이진 윈도우를 사용하여 노이즈에 취약하다. 또한 4개 방향으로 한정 시켰기 때문에 45도 간격의 에지만 고려할 수 있다.
    • 이런 문제를 해결하여 좀 더 정밀한 코너 검출을 위해 해리스는 다음과 같은 개선 방안을 제시했다.
    • 먼저 이진 윈도우인 w(u, v) 대신 점진적으로 변화하는 가우시안 마스크 G(x, y)를 적용하여 다음과 같은 수식으로 확장한다. 이를 통해 노이즈에 대한 민감도를 낮춘다.

E(u, v) = \sum_{y} \sum_{x} G(x, y) \cdot (I(x+u, y+v) - I(x, y))^{2}

  • 또한 4개 방향에 대해서만 코너를 검출하는 것을 모든 방향에서 검출할 수 있도록 미분을 도입하여 다음과 같이 변경한다.

I(x+u, y+v) \cong I(x, y) + vd_{y}(x, y) + ud_{x} (x, y) \\ E(u, v) \cong \sum_{y} \sum_{x} G(x, y) \cdot (vd_{y}(x, y) + ud_{x}(x, y))^{2}

  • 여기서 특징 가능성을 직접 계산하는 대신 위의 수식을 다음과 같이 행렬 M의 식으로 정리한다.

E(u, v) \cong \sum_{y} \sum_{x} G(x, y) \cdot (vd_{y}(x, y) + ud_{x}(x, y))^{2} \\ = \sum_{y} \sum_{x} G(x, y) \cdot (v^{2}d_{y}^{2} + u^{2} d_{x}^{2} + 2vud_{x}d_{y}) \\ = \sum_{y} \sum_{x} G(x, y) \cdot (u, v) \left( \begin{array}{rr} d_{x}^{2} & d_{x} d_{y} \\ d_{x} d_{y} & d_{y} \end{array} \right) \left( \begin{array}{r} u \\ v \end{array} \right) \\ = (u v) M \left( \begin{array}{r} u \\ v \end{array} \right) \\ M = \sum_{y} \sum_{x} G(x, y)  \left( \begin{array}{rr} d_{x}^{2} & d_{x} d_{y} \\ d_{x} d_{y} & d_{y} \end{array} \right)

  • 모라벡 알고리즘은 (u, v)를 변화시켜 E(u, v) 맵을 구해서 코너 여부를 판단하는 반면, 해리스 알고리즘은 위 수식의 행렬 M에서 고유벡터를 구하면 경계선 방향에 수직인 벡터 두 개를 얻을 수 있다.
    • 이 행렬 M의 고유값 (\lambda_{1}, \lambda_{2} )으로 다음의 식과 같이 코너 응답 함수(corner response function)를 계산한다. 여기서 k는 상수값으로 일반적으로 0.04~0.06 정도가 적당하다.

R = \lambda_{1}, \lambda_{2} - k \cdot (\lambda_{1} + \lambda_{2})^{2}

  • 다만 고유값을 계산하려면 고유값 분해의 복잡한 과정을 거쳐야 하기 때문에 해리스 검출기에서는 직접 고유값을 구하지 않고 다음과 같이 행렬식(det)과 대각합(trace)를 통해서 코너 응답 함수로 사용한다.

M = \left( \begin{array}{rr} d_{x}^{2} & d_{x} d_{y} \\ d_{x} d_{y} & d_{y} \end{array} \right) = \left( \begin{array}{rr} a & c \\ c & b \end{array} \right)

R = det(M) - k \cdot trace(M)^{2} = (ab - c^{2}) - k \cdot (a + b)^{2}

  • 해리스 코너 검출 방법은 영상의 평행이동, 회전 변환에는 불변(invariant)하는 특징이 있고, 어파인(affine) 변환이나 조명(illumination) 변화에도 어느 정도 강인성이 있다. 하지만 영상의 크기(scale) 변화에는 영향을 받는다.
  • 실제 해리스 코너 검출기를 구현하려면 다음과 같은 과정을 거친다.
    • 소벨 마스크로 미분 행렬 계산 (dx, dy )
    • 미분 행렬의 곱 계산 (dx^{2}, dy^{2}, dxy )
    • 곱 행렬에 가우시안 마스크 적용
    • 코너 응답합수 C = det(M) - k \cdot trace(M)^{2} 계산
    • 비최대치 억제

k-최근접 이웃 분류기

k-최근접 이웃 분류기의 이해

  • 최근접 이웃 알고리즘은 기존에 가지고 있는 데이터들을 일정한 규칙에 의해 분류된 상태에서 새로운 입력 데이터의 종류를 예측하는 분류 알고리즘이다.
    • 이 방법은 기존의 학습된 여러 클래스의 샘플들을 각각 좌표로 표시하여 두고, 새로운 미지으 샘플이 입력될 때, 학습 클래스의 샘플들과 새 샘플의 거리가 가장 가까운(nearest) 클래스로 분류한다.
    • 여기서 ‘가장 가까운 거리’는 미지의 샘플과 학습 클래스 샘플간의 유사도가 가장 높은 것을 의미한다. 이 거리 측정 방법은 샘플의 형태와 종류에 따라 다양한데, 대표적으로 유클리드 거리(euclidean distance), 해밍 거리(hamming distance), 차분 절대값 등을 이용한다.
  • 최근접 이웃 방법 중에서 가장 많이 사용되는 것은 학습된 클래스들에서 여러 개(k개)의 이웃을 선출하고 이를 이용하여 미지의 샘플들을 분류하는 방법이다.
    • 즉, 미지의 샘플과 가까운 이웃으로 선출된 여러 개의 클래스 샘플들 중에서 가장 많은 수를 가진 클래스로 미지의 샘플들을 분류하는 방법이다. 이러한 분류 과정을 k-최근접 이웃 분류(k-Nearest Neighbors: k-NN)라고 한다.

k-NN 응용

  • 숫자 영상에서 숫자를 인식하는 예제. 아래 5단계를 따른다.
    • 학습 영상의 생성 
    • 학습 영상에서 셀 영상 분리
    • 숫자 객체 위치 검색 및 분리
    • 숫자 객체 중앙 배치 및 크기 정규화
    • 최종 예제 프로그램
    • (위 내용 중 3, 4 번째 항목만 내용 정리)

숫자 객체 위치 검색 및 분리

  • 각 셀에서 숫자 객체가 동일한 위치에 놓여야 학습의 효과와 분류의 정확도가 높아진다. 따라서 아래 그림과 같이 숫자객체를 셀 영역의 중앙에 위치시킨다.
    • 이를 위해 먼저 숫자객체의 위치를 바르게 찾고, 숫자객체를 분리해야 한다.
  • 숫자 객체의 위치 인식은 아래 그림과 같이 투영(projection) 히스토그램을 활용한다.
    • 투영은 다음 식과 같이 영상의 화소값들을 수직 혹은 수평으로 합산하여 나타내는 히스토그램이다.
    • OpenCV에서 제공하는 cv:reduce() 함수가 행렬 원소를 가로방향 혹은 세로 방향을 감축하기 때문에 투영의 수식과 일치한다. 따라서 이 함수를 이용해서 투영을 구현한다.

hsto_v(x) = \sum_{y=0}^{h-1} f(x, y) \\ hsto_v(y) = \sum_{x=0}^{w-1} f(x, y)

숫자 객체 중앙 배치 및 크기 정규화

  • 다음은 숫자객체를 셀 영역의 중앙에 위치시켜야 한다.
    • 먼저 아래 그림의 오른쪽 그림에서 숫자객체의 가로와 세로 길이 중 긴것을 택하여 그 크기(big)로 정방영상(square)을 만든다.
    • 다음으로 정방영상과 숫자객체의 크기 차이(dx, dy)를 계산한다.
    • 이것은 두 행렬(square, number) 크기의 차분으로 구할 수 있다.
    • 이때 중앙사각형의 시작위치(start)는 이 차분을 좌우, 상하로 양분해야 하기 때문에 2로 나누어준다.
    • 다음으로 시작위치(start)에서 숫자객체 크기로 사각형을 만들면 정방영상의 중앙을 가리키는 중앙사각형(middle)을 만들 수 있다.
    • 그리고 정방영상에서 중앙사각형을 관심영역으로 참조한 후 이 영역에 숫자객체(number)를 복사하면 숫자 객체가 셀 영역의 중앙에 배치된다.

영상 워핑과 영상 모핑

  • 영상 워핑은 하나의 영상에서 비선형적인 특정한 규칙에 따라 입력 영상을 재추출(resampling)하여 영사으이 형태를 변형시키는 기술이다.
    • 이 기술은 나사(NASA)에서 인공위성이나 우주선으로부터 전송된 영상이 렌즈의 변형이나 신호의 왜곡 등으로 인해 일그러지는 경우가 많아서 이를 복원하는 용도로 처음 사용되었다.
    • 영상을 여러 다른 방향으로 늘이거나 크기를 조절하는 기법으로 순수한 스케일링과 달리 크기 변화의 정도가 영상 전체에 대해 균일하지 않은 것이 특징이다.
    • 특히 고무판 위에 여상이 있는 것과 같이 임의의 형태로 구부리는 것과 같은 효과를 낸다는 의미에서 고무 시트 변환(Rubber Sheet Transform)이라고도 한다.
    • 영상 워핑 기술은 렌즈 왜곡 보정, 스테레오 영상 정합, 파노라마 영상 합성 등에 사용될 수 있다.
  • 영상 모핑은 조지 루카스가 설립한 특수 효과 전문회사인 ILM이 개발한 기법으로 변형(metamorphosis)란 단어에서 유래되었다.
    • 이것은 하나의 영상에서 형체가 전혀 다른 영상으로 변하도록 하는 기법을 말한다. 즉, 아래 그림과 같이 두 개의 서로 다른 영상 사이의 변화하는 과정을 서서히 나타내는 것이다.
    • 워핑의 기법을 이용해서 모핑을 수행할 수 있다.
  • 영상 워핑의 종류와 방법은 다양하게 있다. 다음의 규칙에 따라 원본 영상의 좌표를 목적 영상의 좌표로 재배치하면 워핑 영상이 완성 된다.

x' = x + ratio \cdot (pt2.x - pt1.x) \\ y' = y 

ratio \Rightarrow x < pt1.x \Rightarrow {x \over pt1.x},  x > pt1.x \Rightarrow {width - x \over width = pt1.x}

  • 일반적으로 카메라로 찍은 영상은 여러 이유에 의해 왜곡된다. 여기서 왜곡되는 요인을 카메라 외부 파라미터와 내부 파라미터로 구분할 수 있다.
    • 카메라는 3차원인 세상의 실세계 영상을 2차원의 평면 영상으로 맺히게 하기 때문에 기하학적인 왜곡이 발생하게 된다. 이것은 카메라 외부 파라미터에 의한 왜곡에 해당하며, 대표적으로 원근 투시 왜곡이 있다.
    • 또한 캡쳐된 영상은 렌즈, 초점거리, 렌즈와 이미지 센서가 이루는 각 등과 같은 카메라 내부의 기구적인 부분에 의해 상당한 영향을 받는데, 이러한 요인을 내부 파라미터 요인이라 한다.
  • 영상 좌표로부터 실세계의 3차원 좌표를 계산하거나 실세계의 3차원 좌표를 영상에 투영된 위치로 계산해야 하는 경우가 있다. 이때 카메라 내부 요인을 제거해야만 보다 정확한 좌표의 계산이 가능하다.
    • 여기서 내부 요인의 파라미터 값을 구하는 과정을 카메라 캘리브레이션(camera calibration)이라 한다.
    • 카메라 영상은 3차원 공간상의 점들을 2차원 영상 평면에 투영함으로써 얻어지는데, 핀홀(pinhole) 카메라 모델에서 이러한 변환 관계는 다음과 같이 모델링 한다.

s \left( \begin{array}{rrr} u \\ v \\ 1 \end{array} \right) = A \cdot M \cdot \left[ \begin{array}{rrrr} X \\ Y \\ Z \\ 1 \end{array} \right] \\ = \left[ \begin{array}{rrr} f_{x} & 0 & C_{x} \\ 0 & f_{y} & C_{y} \\ 0 & 0 & 1  \end{array} \right] \cdot \left[ \begin{array}{rrrr} r_{11} & r_{12} & r_{13} & t_{1} \\ r_{21} & r_{22} & r_{23} & t_{2} \\ r_{31} & r_{32} & r_{33} & t_{3} \end{array} \right] \cdot \left[ \begin{array}{rrrr} X \\ Y \\ Z \\ 1 \end{array} \right]

  • 여기서 X, Y, Z는 실세계의 3차원 좌표이며, u, v는 2차원 영상 평면에 투영된 좌표이다.
    • A는 카메라 내부 파라미터(intrinsic parameters)이고, M은 카메라 외부 파라미터이다.
    • 카메라 내부 파라미터의 요인으로는 초점거리(focal length)와 주점(principal point) 등이 있다.
  • 초점거리(f_{x}, f_{y} )는 아래 그림에서와 같이 렌즈에서 이미지 센서까지의 거리를 말한다.
    • 보통의 디지털 카메라에서는 mm 단위로 표현되지만 카메라 모델에서는 픽셀(pixel) 단위로 표현된다.
    • 초점거리가 두 개의 값으로 표현되는 이유는 이미지 센서의 가로 방향과 세로 방향의 셀 간격이 다를 수 있기 때문이다.
  • 주점(C_{x}, C_{y} )은 카메라 렌즈의 중심에서 이미지 센서에 내린 수선의 영상 좌표로서 일반적으로 말하는 영상 중심점과는 다른 의미이다.
    • 예컨대 카메라 조립과정에서 오차로 인해 렌즈와 이미지 센서가 수평이 어긋나면 주점과 영상중심은 다른 값을 가질 수 있다.
[ssba]

The author

지성을 추구하는 디자이너/ suyeongpark@abyne.com

댓글 남기기

This site uses Akismet to reduce spam. Learn how your comment data is processed.