Category Archives: 배우기

러셀 서양철학사/ 마키아벨리

  • 마키아벨리는 사보나롤라의 비참한 최후에 큰 인상을 받음. 
    • 무장한 예언자는 정치적 성공을 거두었으나 무장하지 않은 예언자는 정치적으로 패배했다.
  • 마키아벨리가 <군주론>을 집필한 것은 메디치 가문의 호의를 얻으려는 희망 때문
    • (일종의 포트폴리오다)
  • 군주론은 공국들이 어떻게 정권을 쟁취하고 유지하며 잃게 되는지를 역사와 당대에 일어난 사건들 속에서 찾아내려는 저술
    • 15세기 이탈리아는 크고 작은 수많은 사례를 제공했다.
    • 정당하게 정권을 잡은 통치자는 거의 없으며, 심지어 교황들조차 부정한 수단으로 선출되는 일이 허다했음.
  • 마키아벨리가 <군주론>에서 사보나롤라에 대비하여 극찬한 대상은 체사레 보르자.
  • <군주론>은 메디치 가문의 환심을 얻기 위해 쓴 책이므로 <로마사 논고>에서 주장한 견해에 포함된 사상의 일부를 숨김.
  • 마키아벨리의 주장에 따르면 종교가 국가 안에서 두드러진 자리를 차지해야 하는 까닭은 종교가 진리이기 때문이 아니라 사회 결속과 유대감 형성에 필요하기 때문.
  • <군주론>은 통치자의 행동과 관련된 기존의 도덕을 명백히 거부함. 통치자가 늘 선하게 행동한다면 비명횡사할 것이다. 그래서 군주는 여우처럼 교활하고 사자처럼 맹위를 떨쳐야 한다.
  • 마키아벨리는 어떤 정치적인 논증이든 결코 그리스도교나 성경에 근거하여 풀어가지 않았음.
  • 마키아벨리는 대중의 인기를 얻는 정부를 선호하는데, 이는 ‘권리’의 개념에서 비롯되지 않고 대중의 인기를 얻은 정부가 전제 정부보다 잔인성, 비도덕성, 변덕의 정도가 덜하다는 현실적인 관찰에서 나온 결론.
  • 정치적으로 추구해야 하는 선 가운데 특별히 중요한 세 가지는 국가의 독립, 안전, 질서정연한 법체계.
    • 최선의 법체계는 군주, 귀족, 평민들 간에 법적 권리를 실제 처한 현실 속에서 행사하는 권력에 비례하여 배분한 법이다. 그런한 법체계 아래서는 혁명이 성공하기 힘들기에 사회 안정이 유지된다.
  • 정치학에서는 수단도 중요한 문제이다.
    • 만약 목적이 선하다면 마땅히 목적 달성에 적합한 수단을 선택해야 하는데, 수단의 선택 문제는 목적이 선한지, 악한지와 무관하게 순전히 과학적인 방식으로 다루어도 된다.
    • 성공은 목적이 무엇이든 목적을 달성했다는 뜻이다.
  • 정치적 목적을 달성하려면 어떤 종류든 권력이 필요하다.
    • 권력은 흔히 여론에 좌우되고, 여론은 선전선동에 좌우된다.
  • 혼란한 시기일 수록 무지한 대중 앞에서 탁월한 기량과 덕을 갖춘 외양을 보여주는 태도가 더욱 바람직하다.
  • 마키아벨리는 문명인이 비도덕적인 이기주의자가 된다는 사실은 거의 확실하다고 주장.

러셀 서양철학사/ 이탈리아 르네상스 운동

  • 근대적 사고방식은 이탈리아 르네상스 운동과 더불어 나타나기 시작함.
    • 이 시기 이탈리아인들은 몇 명을 제외하면 과학을 존중하는 태도는 없었음.
    • 이런 태도가 결핍되면서 이탈리아인들은 미미한 수준에서만 미신에서 해방되어 점성술이 발전하는 결과를 초래함.
    • 그들은 대부분 중세 철학자들이 지닌 권위를 여전히 흠모하면서 교회의 권위를 고대인들의 권위로 대체했을 뿐.
  • (역사 이야기 생략)
  • 르네상스기는 철학에서 위대한 성취를 이룬 시기는 아니지만, 17세기 위대한 철학의 도래에 꼭 필요한 예비 단계였음.
    • 르네상스 운동은 지성을 옥죄는 덮개가 되어버린 엄격한 스콜락 철학 체계를 무너뜨림.
    • 또한 플라톤 연구를 부흥시킴.
  • 르네상스는 대중의 지지를 얻은 운동은 아니었음.
    • 소수 학자와 예술가들이 참여한 운동으로서 자유사상을 지지한 후원자들, 특히 메디치 가문과 인본주의에 경도된 교황이 장려한 지적 흐름에 속했음.
  • 르네상스 운동은 교육받은 지식인을 중세 문화의 편협성에서 해방 시켰음.
    • 그리스 세계에 대한 지식의 부흥을 이끈 르네상스 운동은 고대 그리스의 업적과 성취에 맞서 다시 경쟁하는 정신적 분위기를 형성함.

러셀 서양철학사/ 일반적 특징

  • 근대의 특징은 교회의 권위가 약화되고 과학의 권위가 향상됨
    • 근대 문화는 성직자보다 속인의 삶과 관계가 더 깊다.
    • 국가 권력은 왕에게로 갔다가 이후 민주제로 이어짐
  • 르네상스 운동에서 과학의 역할은 미미했음.
  • 과학의 갑작스런 등장을 진지하게 논의하게 된 최초의 사건은 코페르니쿠스의 이론을 담은 서적의 출간
  • 과학의 응용적인 측면이 지닌 중요한 가치는 전쟁과 연결되면서 인정 받음.
    • 갈릴레오와 레오나르도는 포술과 축성술의 개선을 정부에 요구하면서 일자를 얻음.
    • 전쟁에서 과학자들이 맡은 역할의 비중은 꾸준히 높아짐.
    • 과학의 승리를 주로 실제적인 유용성에서 비롯되었음.
  • 교회의 권위에서 해방되면서 개인주의가 출현하고 심지어 무정부주의까지 생겨남.
  • 근대 철학은 대부분 개인주의와 주관주의적 경향을 간직함.
  • 기술로서 수용된 과학은 실용성을 추구하는 인간의 마음 속에 이론 철학자와 전혀 다른 사고방식과 시야를 심어 놓음.
    • 과학 기술의 발전에서 영감을 받은 철학이 바로 힘을 강조하는 철학.
    • 여기서 인간이 아닌 모든 존재를 단지 가공되지 않은 재료로 생각하는 경향도 나타남.
    • 이제 목적은 고려하지 않고 오로지 숙련 과정에만 가치를 부여할 따름.

OpenCV로 배우는 영상 처리 및 응용/ 영상 처리 응용 사례 II

SVM을 이용한 차량 번호 검출 프로그램

SVM(Support Vector Machine)의 개념

  • 아래 그림 왼쪽과 같이 흰색 원과 검은색 원이 학습용 데이터로 주어졌고, 새로운 데이터가 입력되었다고 하자.
    • 일반적으로는 각 그룹 내에서 데이터 간 거리를 측정하여 중심점(center)를 구한다. 그리고 두 중심점의 중간에서 최적의 분리 경계면을 구한다. 이 판별 경계를 기준으로 새로운 데이터에 대하여 분류할 수 있다. 이런 방식을 선형 판별법이라고 한다.
  • SVM은 데이터들을 분리하는 분리 경계면 중에서 각 분류 데이터들과의 거리(margin)가 가장 먼 분리 경계면을 찾아냄으로써 데이터를 분리하는 방법이다.
    • 즉 분리 경계와 실제 데이터들 사이의 여유(margin)이 가장 크도록 분리 경계를 설정하는 것이다.
    • 이 여유 공간을 설정함으로써 새로운 데이터에 대한 판별의 정확도를 높이며, 일반화 오류를 줄인다.
  • SVM에서는 각 그룹의 중심점이 아닌 두 그룹 사이의 경계에 있는 데이터(support vector)에 초점을 맞춘다.
    • 즉, 흰색과 검은색의 각 그룹의 경계에서 먼저 H1과 H2 선을 긋고, 그 선 안에서 가운데 새로운 선을 그어 최적의 분리 경계면을 정한다.
    • 여기서 H1과 H2를 구하는 방식은 무한히 존재할 수 있다. 다만 두 선분 사이에 학습 데이터가 존재하지 않는다는 점과 두 선분 사이의 거리가 최대가 된다는 제약 조건을 둠으로써 SVM의 분리 경계면이 하나로 정해지도록 한다.
    • 아래 그림에서 선형 판별법은 test 데이터를 검은색으로 분류하지만, SVM은 흰색으로 분류하게 된다.
  • (이하 예제 코드 설명 내용 생략)

OpenCV로 배우는 영상 처리 및 응용/ 영상 처리 응용 사례 Ⅰ

2차원 히스토그램을 이용한 이미지 검색

  • 영상 검색하는 방법은 크게 문자기반 검색방법(Text-Based Image Retrieval, TBIR)과 내용기반 검색 방법(Content-Based Image Retrieval, CBIR)로 구분할 수 있다.
    • 이중 내용기반 검색방법은 영상의 색상, 질감, 모양과 같은 해당 영상 데이터의 특징을 자동으로 추출하여 검색에 이용한다.

2차원 히스토그램

  • 크기가 다른 영상들에서 히스토그램을 계산하면 영상간의 히스토그램 빈도값이 동등하지 않게 된다. 즉, 크기가 큰 영상은 화소의 개수가 많아서 각 빈도값이 커지므로 영상간의 동등한 비교를 위해 계산된 히스토그램을 0~1 사이의 값으로 정규화한다.
  • 아래 그림과 같이 2차원 히스토그램의 빈도 데이터는 색상(hue)와 채도(saturation)를 축으로 2차원의 좌표를 구성하고, 각각의 좌표에 색상과 채도를 연관지어 빈도가 계산된다.
  • 이와 같은 2차원 히스토그램을 그림으로 표현하면, 2차원 행렬에서 x 좌표는 채도를 y 좌표는 색상을 나타내도록 하고, 빈도값을 그 좌표에서의 밝기로 지정할 수 있을 것이다.

유사도 비교

  • OpenCV에서 두 영상의 히스토그램이 얼마나 비슷한지를 비교해주는 함수가 cv::compareHist()이다.
    • 비교 방식 옵션 중에서 CV_COMP_CORREL를 지정하면 다음의 수식으로 계산된 값을 반환한다. 이 수식은 상호상관 함수의 수식을 응용한 것으로서 두 히스토그램의 비슷한 정도를 나타낸다.

d(H_{1}, H_{2}) = {\sum_{i}(H_{1}(i) - \bar{H}_{1}) (H_{2}(i) - \bar{H}_{2}) \over \sqrt{\sum_{i} (H_{1}(i) - \bar{H}_{1})^{2} \cdot (H_{2}(i) - \bar{H}_{2})^{2}}}

하르 분류기를 이용한 얼굴검출 및 성별 분류

하르 기반 분류기

  • 2001년 Viola와 Jones는 객체 검출 분야에서 가장 대표적인 방법론으로 인정받는 논문 “Rapid Object Detection Using a Boosted Cascade of Simple Features”를 발표했다.
    • 이 논문에서 얼굴과 얼굴이 아닌 것의 차이를 효율적으로 보여줄 수 있는 하르 유사 특징(Haar-like features)을 이용한 방법을 제안하였다.
    • 하르 유사 특징은 하르 웨이브릿(Haar wavelet)과 유사하기 때문에 붙여진 이름으로서 아래 그림과 같이 위치, 모양, 크기에 따라 다양한 형태로 구성되어 있다. 그 특징값은 흰색 영역의 화소값의 합과 검음색 직사각형 영역의 화소값의 합의 차로 정의된다.
  • 하르 기반 캐스케이드 분류기는 하르 유사 특징과 같은 매우 단순한 특징들을 조합하여 객체를 찾아낸다. 캐스케이드(cascade)란 용어에서 알 수 있듯, 여러 개의 검출기를 순차적으로 사용한다.
    • 처음에 간단한 검출기를 적용하고, 진행할 수록 복잡한 검출기를 적용한다.
    • 따라서 단순 검출기를 통과한 후보에만 시간이 많이 걸리는 강력한 검출기가 적용되기 때문에 검출 속도를 크게 향상시킬 수 있다.
  • OpenCV의 캐스케이드 분류기는 1,000개 이상의 얼굴 영상과 10,000개 이상의 얼굴이 아닌 영상을 사용하여 학습되었다.
    • 이 과정은 일반적인 멀티코어 CPU를 장착한 컴퓨터에서 최대 1주일 정도의 시간이 소요되는데, 다행히 OpenCV에서 미리 학습된 다양한 검출기를 제공한다.
    • 따라서 필요한 종류의 Cascade 분류기 파일을 로드함녀 검출기를 사용하여 분류할 수 있다. 이를 통해 전면 얼굴, 옆면 얼굴, 눈, 코 등을 검출할 수 있다.
    • OpenCV의 \sources\data\harrcascades\ 폴더에 xml 파일로 된 다양한 하르 기반 검출기가 있다.
  • (이하 예제 코드 설명 내용 생략)

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} )은 카메라 렌즈의 중심에서 이미지 센서에 내린 수선의 영상 좌표로서 일반적으로 말하는 영상 중심점과는 다른 의미이다.
    • 예컨대 카메라 조립과정에서 오차로 인해 렌즈와 이미지 센서가 수평이 어긋나면 주점과 영상중심은 다른 값을 가질 수 있다.

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

  • 영상을 데이터로 표현하는 것은 크게 두 가지 영역으로 나뉘는데, 앞 장까지 했던 화소값이 직접 표현된 공간영역(spatial domain)과 다른 하나가 우주 공간과 같은 변환영역(transform domain)
  • 변환영역은 직교변환에 의해 얻어진 영상 데이터의 다른 표현이다.
    • 여기서는 화소값이 직접 표현되는 것이 아니고 변환계수(coeffcient)로 표현된다.
    • 대표적인 변환은 DCT(Discrete Cosine Transform)와 DFT(Discrete Fourier Transform)이 있는데, 그 중 오래되었고 잘 알려진 것이 DFT인 이산 푸리에 변환이다.
    • 푸리에 변환은 시간(혹은 공간) 영역에서 주파수 영역으로의 변환으로 ‘모든 파형은 단순한 정형파의 합으로 합성되어 질 수 있다’라는 개념에 기초한 해석학적인 방법

공간 주파수의 이해

  • 일반적으로 주파수라는 말은 아래 그림과 같이 1초 동안 진동하는 횟수로 정의한다. 
    • 라디오 방송 채널이나 휴대폰의 통신 대역에서 사용하는 헤르츠(Hz)는 주파수를 표현하는 단위이다.
  • 그러나 이것은 전파라는 신호에 국한된 표현이라 할 수 있다. 아날로그 신호를 디지털화 하는 과정에서 시간단위로 샘플링하는 횟수를 지정할 때에 Hz는 단위와 함께 샘플링 주파수라는 표현을 사용한다.
    • 또한 우리가 공부하는 영상처리에서도 공간 주파수(spatial frequency)라는 개념을 사용한다.

  • 따라서 좀 더 확장된 의미에서 주파수는 이벤트가 주기적으로 발생하는 빈도라고 할 수 있다.
  • 영상에서 화소 밝기의 변화의 정도를 파형의 형태로 그려보면 아래 그림과 같이 표현할 수 있다. 신호의 주파수와 같은 의미가 되는 것이다.
  • 이렇게 확장된 의미를 영상 신호에 적용하면 영상에서의 주파수는 공간상에서 화소 밝기의 변화율이라 할 수 있다.
    • 이런 의미에서 공간 주파수라는 표현을 사용한다.
    • 공간 주파수는 밝기가 얼마나 빨리 변화하는가에 따라 고주파 영역과 저주파 영역으로 분류한다.
  • 아래 그림은 고주파 포함 영역과 저주파 포함 영역을 설명한다.
    • 상단 부분을 보면 화소 밝기가 거의 변화가 없거나 점진적으로 변화하는 것을 볼 수 있는데 이런 부분은 대부분 저주파 성분을 가진 저주파 공간 영역이라 한다.
    • 반면 하단 부분은 화소의 밝기가 급변하는 것을 볼 수 있는데, 이런 부분은 변화가 거의 없는 저주파 성분 위에 변화가 심한 고주파 성분이 포함되어 있는 고주파 공간 영역이라 할 수 있다.
  • 저주파 공간 영역은 보통 영상에서 배경 부분이나 객체의 내부에 많이 있으며, 고주파 공간 영역은 경계부분이나 객체의 모서리 부분에 많이 있다.

  • 변환을 통하여 영상을 주파수 영역별로 분리할 수 있으면, 각 주파수 영역별 처리가 가능할 것이다.
    • 예컨대 경계부분에 많은 고주파 성분을 제거하여 영상을 생성하면 경계가 흐려진 영상을 만들 수 있고, 저주파 성분을 제거하고 고주파 성분만을 취하여 영상을 만든다면 경계나 모서리만 포함하는 영상 즉, 에지 영상이 만들어질 것이다.
  • 일반적인 영상은 공간 영역상에서 저주파 성분과 고주파 성분이 혼합하여 있기 때문에 저주파 영역과 고주파 영역을 분리해서 선별적으로 처리하기란 쉬운 일이 아니다. 따라서 변환영역의 처리가 필요하다.
  • 변환영역, 즉 주파수 영역에서의 영상처리는 아래 그림과 같은 과정을 거친다.
    • 먼저 영상이 입력되면 주파수 영역으로 변환하며,
    • 주파수 변환으로 얻어진 계수의 특정 주파수 영역에 원하는 영상 처리를 적용한다.
    • 마지막으로 처리가 적용된 후에는 다시 주파수 역변환을 통해 공간영역의 영상으로 변환해서 출력 영상을 생성한다.

이산 푸리에 변환

  • 푸리에 변환은 신호나 영상을 주파수 영역으로 변환하는 가장 일반적인 방법으로 다음의 전제를 기본으로 한다.
    • 주기를 가진 신호는 정현파/여현파의 합으로 표현할 수 있다.
  • 여기서 정현파/여현파는 모든 파형 중에 가장 순수한 파형을 말하는 것으로 사인(sin), 코사인(cos) 함수로 된 신호를 말한다. 즉, 사인 또는 코사인 함수의 선형 조합으로 특정 주기의 신호를 구성할 수 있다.
  • 이 전제를 바꾸어 말하면 아래 그림과 같이 주기를 갖는 신호 g(t) 는 여러 개의 사인 및 코사인 함수 g_{f}(t) 로 분리되는 것이다.
    • 여기서 분리된 신호 g_{1}(t), g_{2}(t), g_{3}(t) 는 기저 함수(basis function)가 되며, 기저 함수에 곱해지는 값 0.3, 0.7, -0.5가 주파수의 계수가 된다.
  • 이 계수가 각 주파수 성분의 크기에 해당하며, 신호를 주파수로 변환하는 것은 각 주파수의 기저 함수들에 대한 계수를 찾는 것이다. 또한 주파수 영역에서의 역변환은 각 기저함수와 그 계수들로부터 원본 신호를 재구성하는 것이다.
  • 주파수 변환을 수식으로 표현하면 다음과 같다. 여기서 g_{f}(t) f 주파수에 대한 기저함수이며 G(t) 는 각 기저함수의 계수이다.

g(t) = \int_{-\infty}^{\infty} G(f) \cdot g_{f}(t)df

  • 연속신호에 대한 변환이기 떄문에 -무한대에서 +무한대까지를 적분하여 모든 주파수에 대한 기저함수와 그 계숟르의 선형 조합이 된다.
    • 따라서 연속신호를 주파수 영역으로의 변환은 존재하는 모든 기저함수에 대해 그 계수인 G(t) 를 구하는 것이다.
  • 기저 함수를 어떻게 정하는가에 따라 주파수 영역 변환의 방법이 달라진다.
    • 일반적으로 다음과 같이 사인이나 코사인 함수를 기저함수로 사용한다.이것은 가장 대표적인 방법인 푸리에 변환에서 사용하는 기저함수이다.
    • 또한 푸리에 변환에서는 허수를 이용한 함수를 기저함수로 사용한다.

g_{f}(t) = cos(2 \pi ft) + j \cdot sin(2 \pi ft) = e^{j 2 \pi ft}

  • 이 기저함수로 원본 신호를 나타내면 다음과 같아. 이것은 원본 신호를 만드는 것이기에 푸리에 역변환에 대한 수식이 된다.

g(t) = \int_{-\infty}^{\infty} G(f) \cdot e^{j 2 \pi ft} df

  • 원본 신호로부터 주파수의 계수 G(f) 를 얻는 식은 다음과 같이 유도된다. 이것은 1차원의 연속 신호에 대한 푸리에 변환이다.

G(f) = \int_{-\infty}^{\infty} g(t) \cdot e^{-j 2 \pi ft} dt

  • 이를 디지털 신호에 적용하려면 이산 푸리에 변환(DFT)을 사용해야 한다. 다음은 이산 푸리에 변환과 그 역변환의 수식이다.

G(k) = \sum_{n=0}^{N-1} g[n] \cdot e^{-j 2 \pi k {n \over N}}, (k = 0, ... N-1)

g[n] = {1 \over N} \sum_{n=0}^{N-1} G[k] \cdot e^{j 2 \pi k {n \over N}}, (n = 0, ... N-1)

  • 여기서 g[n] 은 디지털 신호이며, G(k) 는 주파수 k 에 대한 푸리에 변환 계수이다. 
    • 또한 k, n 은 신호의 원소개수(N)만큼 정수로 주어진다.
    • 연속 신호에서 적분기호가 이산신호에서는 합기호로 바뀐다.
  • 2차원 공간상의 영상에 이산 푸리에 변환을 적용하려면 다음 수식과 같이 1차원 이산 푸리에 변환을 가로방향과 세로방향으로 연속해서 두 번 적용해야 한다. 
    • 수식에서 괄호부분이 가로방향에 대한 1차원 푸리에 변환이다.

G(k, l) = \sum_{m=0}^{M-1} (\sum_{n=0}^{N-1} g[n, m] \cdot e^{-j 2 \pi k {n \over N}}) \cdot e^{-j 2 \pi t {m \over M}} \\ = \sum_{m=0}^{M-1} \sum_{n=0}^{N-1} g[n, m] \cdot e^{-j 2 \pi ({kn \over N} + {lm \over M})}

  • 다음 수식은 2차원 이산 푸리에 역변환에 대한 수식이다.

g[n, m] = {1 \over NM} \cdot \sum_{m=0}^{M-1} (\sum_{n=0}^{N-1} G(k, l) \cdot e^{j 2 \pi k {n \over N}}) \cdot e^{j 2 \pi l {m \over M}} \\ = {1 \over NM} \sum_{m=0}^{M-1} \sum_{n=0}^{N-1} G(k, l) \cdot e^{j 2 \pi ({kn \over N} + {lm \over M})}

  • 푸리에 변환의 기저함수에 허수를 이용했기 때문에 실수부와 함께 허수부에 대한 고려도 해야 한다.
    • 다음은 기저함수를 사인과 코사인 함수로 변경하여 1차원 푸리에 변환을 수식으로 나타내면 다음과 같다.

G(k) = \sum_{n=0}^{N-1} g[n] \cdot (cos(-2 \pi k {n \over N}) + j \cdot sin(-2 \pi k {n \over N}))

  • 그리고 실수부와 허수부를 구분하여 표현하면 다음과 같다. 푸리에 변환과 그 역변환이 사인과 코사인 함수에서 각도의 부호만 반대이다.

G(k)_{Re} = \sum_{n=0}^{N-1} g[n]_{Re} \cdot cos(-2 \pi k {n \over N}) - g[n]_{Im} \cdot sin(-2 \pi k {n \over N})

G(k)_{Im} = \sum_{n=0}^{N-1} g[n]_{Im} \cdot cos(-2 \pi k {n \over N}) + g[n]_{Re} \cdot sin(-2 \pi k {n \over N})

g[n]_{Re} = {1 \over N} \sum_{n=0}^{N-1} G(k)_{Re} \cdot cos(2 \pi k {n \over N}) - G(k)_{Im} \cdot sin(2 \pi k {n \over N})

g[n]_{Im} = {1 \over N} \sum_{n=0}^{N-1} G(k)_{Im} \cdot cos(2 \pi k {n \over N}) + G(k)_{Re} \cdot sin(2 \pi k {n \over N})

  • 푸리에 변환을 수행하면 복소수의 행렬이 결과로 생성된다. 이것을 영상으로 확인하기 위해서는 복수부의 실수부와 허수부를 벡터로 간주하여 다음의 수식과 같이 벡터의 크기를 구하면 된다. 이것을 주파수 스펙트럼이라 한다.
    • 또한 실수부와 허수부의 각도를 이용해서 주파수 위상을 계산할 수도 있다.

|G(k, l)| = \sqrt{Re(k, l)^{2} + Im(k, l)^{2}}

\theta (k, l) = tan^{-1} [ {Im(k, l) \over Re (k, l)} ]

  • 여기서 주파수 스펙트럼 영상은 저주파 영역의 계수값이 고주파 영역에 비해 상대적으로 너무 크다.
    • 이로 인해 계수값을 일반적인 방법으로 정규화해서 영상으로 표현하면 최저 주파 영역만 흰색으로 나타나고 나머지 영역은 거의 검은색으로 나타나서 고주파 영역의 계수를 영상으로 확인하기가 곤란하다.
    • 이런 문제를 해결하기 위해 계수값에 로그 함수를 먼저 적용하고 정규화한다.
void log_mag(Mat complex_mat, Mat& dst)
{
Mat planes[2];
split(complex_mat, planes); // 2채널 복소행렬 분리
magnitude(planes[0], planes[1], dst); // 크기 계산
log(dst + 1, dst);
normalize(dst, dst, 0, 255, CV_MINMAX); // 정규화 수행
dst.convertTo(dst, CV_8U);
}
  • 위의 log_mag() 함수는 DFT를 수행한 행렬에서 주파수 스펙트럼을 계산하고, 로그 함수를 적용한다.
    • 여기서 첫 번째 인수인 DFT 결과 행렬(complex_mat)은 실수부와 허수부를 갖는 2채널 행렬이다.
    • 따라서 cv::split() 함수로 2채널 행렬을 1채널 행렬 2개로 분리해서 크기를 구한다.
  • 또한 DFT 수행 후의 주파수 스펙트럼 영상은 저주파 영역이 영상의 모서리 부분에 위치하고 고주파 부분이 중심부에 있다.
    • 즉, 아래 그림의 왼쪽과 같이 푸리에 변환 영상에서 사각형의 각 모서리를 중심으로 원형의 밴드를 형성하여 주파수 영역이 분포한다. 
    • 이 때문에 해당 주파수 영역에서 어떤 처리를 하려면 상당한 불편함이 있다. (여기서 원형의 밴드는 이해를 돕기 위해 표현한 것으로 실제 DFT 스펙트럼 영상에서 나타나는 것은 아니다.)
  • 이 문제는 1사분면과 3사분면의 영상을 맞바꾸고, 2사분면과 4사분면의 영상을 맞바꿈으로서 해결할 수 있다.
    • 결과적으로 아래 그림의 오른쪽과 같이 영상의 중심이 최저주파 영역, 그리고 바깥쪽이 고주파 영역이 되며, 그림과 같이 원형의 밴드로 주파수 영역을 쉽게 구분할 수 있다.
    • 이런 과정을 셔플링(shuffling) 혹은 시프트(shift) 연산이라고 한다.
  • 다음의 shuffling() 함수는 입력 행렬에 셔플링을 수행해서 반환하는 함수이다.
    • q1~q4의 Rect 객체를 통해서 각 사분면의 영역을 지정한다.
    • 그리고 원본 행렬(mag_img)과 반환 행렬(dst) 모두에서 각 사분면을 관심영역으로 지정하여 참조한다.
    • Mat::copyTo() 함수를 통해서 참조된 원본 행렬을 참조된 반환 행렬로 복사하여 사분면의 맞교환을 수행한다.
void shuffling(Mat mag_img, Mat& dst)
{
int cx = mag_img.cols / 2;
int cy = mag_img.rows / 2;

Rect q1(cx, 0, cx, cy); // 1사분면 사각형
Rect q2(0, 0, cx, cy); // 2사분면 사각형
Rect q3(0, cy, cx, cy); // 3사분면 사각형
Rect q4(cx, cy, cx, cy); // 4사분면 사각형

dst = Mat(mag_img.size(), mag_img.type());
mag_img(q1).copyTo(dst(q3));
mag_img(q3).copyTo(dst(q1));
mag_img(q2).copyTo(dst(q4));
mag_img(q4).copyTo(dst(q2));
}
  • N x M 크기의 영상에서 2차원 푸리에 변환은 N2 x M2 만큼의 시간 복잡도를 요구한다.
    • 따라서 영상의 크기가 커지면 수행속도는 기하급수적으로 증가한다.
    • 이러한 이유에서 푸리에 변환을 빠르게 수행하는 알고리즘의 필요성이 대두되었다.

고속 푸리에 변환(FFT: Fast Fourier Transform)

  • 이산 푸리에 변환은 원본 신호의 한 원소에 곱해지는 기저 함수의 원소들을 원소 길이만큼 반복적으로 곱해야하기 때문에 신호가 커질수록 계산 속도는 기하급수적으로 증가한다.
    • 고속 푸리에 변환은 이 과정을 삼각함수의 주기성을 이용해 작은 단위로 분리해서 반복적으로 수행하고 합치도록 하여 효율성을 높이는 방법이다.
  • 다음은 삼각함수의 주기성을 이용하는 방법을 간단히 설명한다. 먼저 푸리에 변환 수식에서 짝수 번째 부분(2n)과 홀수 번쨰 부분(2n+1)을 분리하여 수식을 다음과 같이 정리한다.

G(k) = \sum_{n=0}^{L-1} g[2n] \cdot e^{-j 2 \pi k {2n \over 2L}} + \sum_{n=0}^{L-1} g[2n+1] \cdot e^{-j 2 \pi k {2n + 1 \over 2L}}

G(k) = \{ \sum_{n=0}^{L-1} g[2n] \cdot e^{-j 2 \pi k {n \over L}} \} + \{ \sum_{n=0}^{L-1} g[2n+1] \cdot e^{-j 2 \pi k {n \over L}} \} \cdot e^{-j 2 \pi k {1 \over 2L}}

  • 여기서 짝수 신호와 홀수 신호를 다음과 같이 지정해 보자

G_{even}(k) = \sum_{n=0}^{L-1} g[2n] \cdot e^{-j 2 \pi k {n \over L}}

G_{odd}(k) = \sum_{n=0}^{L-1} g[2n+1] \cdot e^{-j 2 \pi k {n \over L}} 

  • 그러면 푸리에 변환 수식은 다음과 같이 나타낼 수 있다.

G(k) = G_{even}(k) + G_{odd}(k) \cdot e^{-j 2 \pi k {1 \over 2L}}

  • 위 수식의 공통 지수부분에서 한 주기(L)를 더한 수식을 정리해 보자. 이것은 삼각 함수의 주기성으로 인해 다음과 같이 뒷부분 지수를 제거할 수 있다.

e^{-j 2 \pi (k+L) {n \over L}} \\ = e^{-j 2 \pi k {n \over L}} \cdot e^{-j 2 \pi  {Ln \over L}} \\ = e^{-j 2 \pi k {n \over L}} \cdot e^{-j 2 \pi n} \\ = e^{-j 2 \pi k {n \over L}}

  • 이 주기성을 이용하여 G(k+L)을 계산하면 다음과 같다.

G(k+L) = G_{even}(k+L) + G_{odd}(k+L) \cdot e^{-j 2 \pi (k+L) {1 \over 2L}} \\ = G_{even}(k) + G_{odd}(k) \cdot e^{-j 2 \pi (k+L) {1 \over 2L}}

  • 여기서 e^{-j 2 \pi (k+L) {1 \over 2L}} 의 지수를 분리하여 정리하면 다음과 같다.

e^{-j 2 \pi (k+L) {1 \over 2L}} \\ = e^{-j 2 \pi k {1 \over 2L}} \cdot e^{-j 2 \pi  {L \over 2L}} \\ = e^{-j 2 \pi k {1 \over 2L}} \cdot e^{-j \pi} \\ = -e^{-j 2 \pi k {1 \over 2L}}

  • 따라서 최종적으로 G(k+L)은 다음과 같다.

G(k+L) = G_{even}(k) - G_{odd}(k) \cdot e^{-j 2 \pi k {1 \over 2L}}

  • 이것은 G(k+L)의 값이 G(k)의 값들을 이용해서 구할 수 있다는 것이다.
  • 아래 그림은 삼각함수의 주기성이 어떻게 적용되어 반복계산을 줄이는지를 보인다.
    • 8개의 원소를 갖는 원본 신호 g[n]을 짝수 신호와 홀수 신호로 구분하여 푸리엔 변환을 한다.
    • 짝수 DFT 결과와 홀수 DFT 결과로 최종 변환 신호 G[n]을 구성하는 방법을 보인다.
  • 짝수 원소와 홀수 원소를 한 번 분리하는 것으로는 수행속도를 줄이지 못한다.
    • 각 그룹 내 원소들을 연속적으로 분리할 수 있을 것이다. 즉 아래 그림과 같이 짝수 원소 그룹내에서 짝수 원소와 홀수 원소를 다시 분리하고, 홀수 원소 그룹 내에서 짝수 원소와 홀수 원소를 분리한다.
    • 이렇게 연속적으로 분리하면 최종적으로 입력 신호를 2개 원소씩 묶을 수 있다.
  • 여기서 입력 신호에 대해 짝수부와 홀수부로 계속적으로 분리하여 최종적으로 두 원소만 갖게끔 신호를 재배열해야 한다. 이것을 스크램블(scramble)이라고 한다.
    • 스크램블은 보통 비트의 순서를 바꾸는 방법을 설명하지만 속도면에서 비효율적이며, 다음의 scramble() 함수로 구현한다.
Mat scramble(Mat signal)
{
Mat dst = signal.clone();

for (int i = 0, j = 0; i < dst.cols - 1; i++)
{
if (i > j)
{
swap(dst.at<Vec2f>(i), dst.at<Vec2f>(j));
}

int m = dst.cols >> 1;

while ((j >= m) && (m >= 2))
{
j -= m;
m >>= 1;
}

j += m;
}

return dst;
}
  • 다음은 버터플라이(butterfly) 과정이다. 이것은 스크램블 결과 원소에서 이웃한 두 원소에 대해 이산 푸리에 변환을 수행하는 것이다.
    • 여기서 Wk는 푸리에 변환의 기저함수인 삼각함수의 수식이다.
    • 버터플라이는 아래 그림과 같이 흐름도의 모양이 나비와 비슷해서 붙여진 이름이다.
  • 버터플라이 과정은 원본 신호 길이를 두 개 원소 신호로 분리하며, 분리 횟수만큼 연속적으로 반복한다.
    • 여기서 원본 신호를 연속적으로 짝수부와 홀수부로 분리하기 때문에 원본 신호의 원소 개수는 2의 자승이 되어야 한다.
    • 영상의 크기가 반드시 2의 자승이 되는 것이 아니기 때문에 이 문제를 해결하는 방법으로 원본 영상의 가로와 세로 크기를 2의 자승이 되게 넓히고, 빈 공간을 검은색(0)으로 채우는 방법을 사용한다. 이것을 영삽입(zero-padding)이라 한다.
  • 영삽입이 가능한 것은 원본 영상의 평행이동이 푸리에 변환 결과에 영향을 미치지 않기 때문이다.
    • 즉, 아래 그림의 오른쪽 영상에서 원본 영상이 어느 위치로 평행이동되든지 상관없이 푸리에 변환 결과에서 스펙트럼은 동일하다.
  • 다음의 zeropadding() 함수는 입력 영상에 영삽입을 수행해서 반환하는 함수이다. 그 과정은 2에 대한 로그함수인 log2() 함수로 영상의 가로와 세로가 2의 몇 승인지를 계산한다.
    • 계산된 승수는 소수점을 포함하며, ceil() 함수로 소수점 부분을 올림처리한다.
    • 그리고 다시 계산된 승수에 << 연산으로 2의 자승을 만든다.
    • 이렇게 하면 원본 영상보다 소수점 올림난큼 큰 2의 자승 크기(m, n)을 계산할 수 있다.
Mat zeropadding(Mat img)
{
int m = 1 << (int)ceil(log2(img.rows));
int n = 1 << (int)ceil(log2(img.cols));
Mat dst(m, n, img.type(), Scalar(0));

Rect rect(Point(0, 0), img.size());
img.copyTo(dst(rect));
dst.convertTo(dst, CV_32F);

return dst;
}

FFT를 이용한 주파수 영역 필터링

주파수 영역 필터링의 과정

  • 영상을 주파수 영역으로 변환하면 화소의 밝기가 서서히 변화하는 저주파 영역과 급격하게 변화하는 고주파 영역을 공간 영역에 비하여 쉽게 분리할 수 있다.
    • 이렇게 분리된 주파수 영역에 대해 각 주파수 영역을 강화하거나 약화하거나 혹은 제거하는 등의 처리를 통해 다양한 영상 처리를 할 수 있다.
  • 앞서 배운 내용으로 영상에 2차원 푸리에 변환을 수행할 수 있다. 이를 통해 아래 그림과 같이 영상을 주파수 영역으로 쉽게 변환할 수 있다.
    • 주파수 영역에서 필터링 과정은 푸리에 변환 계수에 필터 행렬을 원소간(element-wise)에 곱하여 수행된다.
    • 여기서 푸리에 변환 계수는 복소수이기 때문에 필터의 곱셈도 실수부와 허수부의 두 채널에 수행해야 한다.
    • 마지막으로 필터링된 푸리에 변환 계수를 푸리에 역변환(IFFT)함으로써 다시 공간영역의 영상으로 만들 수 있다.
  • 이러한 일련의 과정을 주파수 성분 조작이라 한다. 또한 필터를 어떻게 구성하느냐에 따라 저주파 통과 필터링, 고주파 통과 필터링, 대역 통과 필터링 등을 쉽게 구현할 수 있다.

저주파 및 고주파 통과 필터링

  • 저주파 통과 필터링은 DFT 변환 영역에서 저주파 영역의 계수들은 통과시키고, 그 외의 영역 즉, 고주파 영역의 계수는 차단하는 것을 말한다.
    • 아래 그림의 왼쪽처럼 푸리에 변환을 하고, 셔플링을 수행해서 주파수 스펙트럼 영상을 보면 중심 부분이 저주파 영역이며, 외곽으로 갈수록 고주파 영역이다. 여기서 원형의 점선은 주파수 밴드를 시각적으로 표현한 것이다.
    • 필터링은 주파수 계수에 필터 행렬의 원소가 곱해져서 수행된다. 따라서 저주파 통과 필터의 모양은 아래 그림의 중간 그림처럼 중심에서 지정된 반지름만큼 원형으로 1의 값을 갖게 하고, 외곽 부분을 0으로 지정하면 된다. 그림에서 흰색은 1의 값이며, 검은색은 0의 값이다.
    • 고주파 통과 필터링은 저주파 통과 필터와는 반대로 고주파 영역의 계수들을 통과시키고 저주파 영역의 계수들은 차단하는 것이다. 아래 그림의 오른쪽과 같이 중심에서 지정된 반지름 크기의 원형으로 0의 값을 갖게 하고 가장자리 부분을 1로 지정하면 된다.
    • 주파수 계수와 필터의 원소가 곱해지기 때문에 0의 값을 갖는 부분은 주파수 계수가 제거되어 차단되고, 1의 값을 갖는 부분은 그대로 유지되어 통과된다.

버터워스, 가우시안 필터링

  • 앞선 대역 통과 필터는 특정한 대역에서 급격하게 값을 제거하기 때문에 결과 영상의 화질이 좋지 못하다.
    • 특히 저주파 통과 필터링의 경우 영상에서 객체의 경계부분이 완만해지기는 하지만, 경계부분 주위로 잔물결 같은 무늬 (ringing pattern)가 나타나서 화질이 더욱 떨어진다.
    • 이 문제를 해결하는 것은 필터 원소의 값을 차단 주파수에서 급격하게 0으로 만들지 않고 완만한 경사를 이루도록 구성하면 된다.
    • 대표적으로 버터워즈 필터링(Butterworth filter)과 가우시안 필터(Gaussian filter)가 있다.
  • 가우시안 필터는 필터 우너소의 구성을 가우시안 함수의 수식 분포를 갖게 함으로써 차단 주파수 부분을 점진적으로 구성한 것이다.
    • 가우시안 함수의 수식에서 표준편차(\sigma )를 주파수를 차단할 반지름의 위치(R )로 간주하자.
    • 그러면 아래 그림의 오른쪽과 같이 포물선의 곡선을 갖는 주파수 공간 필터가 구성된다.
    • 또한 가우시안 함수의 수식은 {1 \over 2 \pi \sigma^{2}} 를 곱해야 하지만, 원소 값의 스케일을 최댓값이 1이 되도록 하기 위해 생략한다.

f(x, y) = exp(-{dx^{2} + dy^{2} \over 2 R^{2}}) \\ dx = x - center x \\ dy = y - center y

  • 버터워즈 필터는 다음의 수식으로 필터 원소의 구성이 가능하다. 여기서 차단 주파수 반지름 위치(R )와 지수의 승수인 n 값을 어떻게 지정하느냐에 따라 차잔 필터의 반지름과 포물선의 곡률이 달라진다.

f(x, y) = -{1 \over 1 + ({\sqrt{dx^{2} + dy^{2}} \over R})^{2n}} \\ dx = x - center x \\ dy = y - center y

이산 코사인 변환

  • 1974년 미국 텍사스 대학에서 라오 교수팀이 이산 코사인 변환(DCT: Discrete Cosine Transform)이라는 새로운 직교변환에 관한 논문을 발표하면서 멀티미디어 혁명이 시작되었다.
    • 라오 팀은 영상 신호의 에너지 집중 특서잉 뛰어나서 영상 압축에 효과적인 주파수 변환 방법을 찾는 것이 목표였고 그 결과가 바로 DCT인 것이다.
  • 이산 푸리에 변환(DFT)은 실수부에 코사인 함수가 곱해지며, 허수부에 사인 함수가 곱해져서 이루어진다. 반면 이산 코사인 변환은 이산 푸리에 변환에서 실수부만 취하고, 허수부분을 제외함으로써 코사인 함수만으로 구성된 직교 방법이다. 이를 이산 여현변환이라고도 한다.
  • 다음은 1차원 이산 코사인 변환의 수식이다.

F(k) = C(k) \cdot \sum_{n=0}^{N-1} g[n] \cdot cos ({(2n + 1) k \pi \over 2N})

g[n] = \sum_{k=0}^{N-1} C(k) \cdot F(k) \cdot cos ({(2n + 1) k \pi \over 2N})

$latex k = 0, 1, … N-1 \\ C(k) \Rightarrow k = 0 \Rightarrow \sqrt{1 / N}, k \neq 0 \Rightarrow \sqrt{2 / N} &s=2$

  • F(k) 는 주파수 영역 신호이며, g(k) 은 공간 영역의 신호이다.

F(k, l) = C(k) \cdot C(l) \cdot \sum_{n=0}^{N-1} \sum_{m=0}^{m-1} g[n, m] \cdot cos ({(2n + 1) k \pi \over 2N}) \cdot cos ({(2m + 1) l \pi \over 2M})

g(n, m) = \sum_{k=0}^{N-1} \sum_{l=0}^{m-1} C(k) \cdot C(l) \cdot F(k, l) \cdot cos ({(2n + 1) k \pi \over 2N}) \cdot cos ({(2m + 1) l \pi \over 2M})

k = 0, 1, ... N-1 \\ C(k) \Rightarrow k = 0 \Rightarrow \sqrt{1 / N}, k \neq 0 \Rightarrow \sqrt{2 / N}

l = 0, 1, ... , M-1 \\ C(l) \Rightarrow l = 0 \Rightarrow \sqrt{1 / N}, l \neq 0 \Rightarrow \sqrt{2 / N}

  • DCT는 일반적으로 전체 영상을 한 번에 변환시키는 것이 아니라 영상을 작은 블록으로 나누어서 블록 단위로 수행한다.
    • 이 블록의 크기를 키울수록 압축의 효율이 높아지지만, 변환의 구현이 어려워지고 속도도 느려진다.
    • 일반적으로 8 x 8 크기가 성능과 구현 용이성간의 상호보환(trade-off)되어 표준으로 사용된다.
  • 8 x 8 크기의 한 블록을 DCT 변환하면 아래 그림과 같이 64개의 주파수 계수가 구성된다. (0, 0) 위치를 DC 계수라 하며, 나머지 계수들을 AC 계수라 한다.
    • DC 계수는 공간 영역의 화소값의 평균에 해당하는 값으로서 에너지가 집중되어 있고, 영상의 주요 성분을 포함하고 있다.
    • 각 주파수 계수는 영상의 밝기 변화 특성을 나타낸다. 왼쪽 상단으로 갈수록 저주파 영역이며, 오른쪽 하단으로 갈수록 고주파 영역이다. 저주파 영역으로 갈수록 밝기 변화가 적으며, 고주파 영역으로 갈수록 밝기 변화의 정도가 증가한다.
  • 블록의 크기를 N x M이라 할 때, 코사인 함수 부분이 블록의 한 화소에서 N x M 만큼 계산하고, 블록의 모든 화소에서 코사인 함수를 계산하게 되면 O(N2 x M2)의 계산 복잡도가 된다.
    • 그리고 원본 영상을 N x M 크기의 블록으로 나누어 모든 블록에 DCT를 수행한다. 따라서 DCT 변환의 전체 계산복잡도는 다음의 수식과 같다.

DCT 변환의 계산 복잡도 = $latex O(N^{2} \times M^{2} \times Total_{block}) \\ Total_{block} = H_{block} \times W_{block} \\ H_{block} = {ImageHeight \over N} \\ W_{block} = {ImageWidth \over M} &s=2$

  • 512 x 512 영상에 8 x 8 블록으로 DCT 를 수행하면, 한 블록의 DCT 복잡도가 4,096번이며, 전체 블록의 개수가 4,096개이므로 16,777,216번의 코사인 함수를 계산해야 한다. 게다가 코사인 함수의 계산이 상대적으로 느리기 때문에 상당한 시간이 소요된다.
    • 다행히 DCT 정변환과 역변환에서 코사인 함수 부분이 동일하고 한 블록에 수행되는 모든 코사인 함수 값은 블록마다 반복적으로 사용되므로 블록에 사용되는 코사인 함수값들을 미리 계산에서 행렬에 저장해 두면 효율적이다.
    • (관련 코드 생략)

러셀 서양철학사/ 교황 체제의 쇠락

  • 13세기로 접어들면서 철학, 신학, 정치, 사회 모든 측면을 아우른 위대한 종합에 이르렀는데, 여러 요소들이 결합하는 과정을 거쳐 천천히 이루어짐.
    • 첫째 요소는 그리스 철학이었고, 다음 요소는 알렉산드로스 대왕의 정복 결과로 유입된 동양의 종교들이었음.
    • 오르페우스교와 신비 종교의 장점을 받아들인 동양의 종교들은 그리스어 문화권 세계의 사고방식을 변모시켰으며 결국 라틴어 문화권 세계의 사고 방식도 바꾸었음.
    • 죽었다가 부활한 신, 신의 육체를 의미하는 것을 먹는 성찬 의식, 세례식과 유사한 어던 의식을 통해 새 생명으로 거듭 태어나는 제2의 탄생은 이교 로마 세계의 대다수 종파들에게 신학의 일부로 수용됨.
    • 이와 같은 동양 종교적 요소들은 적어도 이론상으로 금욕적인 육체에서도 벗어난 해방의 윤리와 결합함.
    • 속인들과 분리되어 있으며 마법의 힘을 많든 적든 소유하고 정치적 영향력을 적지 않게 발휘하는 사제제도가 시리아, 이집트, 바빌로니아, 페르시아에서 들어옴
    • 대체로 사후 삶에 대한 믿음과 연결된 장업하고 감동을 주는 종교 의식도 같은 곳에서 들어 옴.
    • 특히 세계를 거대한 두 세력의 싸움터로 생각하는 이원론이 페르시아에서 들어왔는데, 한 무리는 선한 세력으로 아후라 마즈다가 이끌고 다른 무리는 악한 세력으로 아흐리만이 이끌었음.
    • 암흑 마법은 아흐리만과 영들의 세계에 사는 추종자들의 도움으로 생기는 조화였음.
    • 사탄은 아흐리만의 한 발현체.
  • 이렇게 유입된 야만족의 사상과 관습은 신플라톤 학파의 철학 속에서 몇몇 헬레니즘의 요소와 종합 됨.
    • 오르페우스교, 파타고라스 사상, 플라톤의 철학 일부분에서 그리스인들은 동양의 관점과 쉽게 결합되는 관점들을 발전시켰는데, 아마 이것들이 훨씬 이전 시대의 동방의 영향을 받아 형성되었기 때문일 것으로 생각 됨.
    • 이교 철학의 발전은 플로티노스와 포르피리오스와 더불어 막을 내림.
  • 그리스도교는 여러 종교에서 힘의 원천이 되는 요소들을 찾아 결합 함.
    • 그리스도교는 유대인들에게서 성서와 한 종교 이외의 모든 종교는 거짓이며 악하다는 교리를 받아들임.
    • 그러나 유대인들의 극단적인 배타성과 모세 율법의 불편은 피함.
    • 후기 유대교는 이미 사후의 삶에 대한 믿음을 배웠는데, 그리스도교는 천국과 지옥에 대해 그리고 천국에 이르고 지옥을 피하는 길에 대해 명확한 규정을 내림
    • 부활절은 유대교의 유월절과 이교도 신의 부활 축전을 결합한 결과물
  • 페르시아의 이원론도 흡수하는데, 궁극적으로 전능한 선의 원리를 더 단호히 확신하고 이교도의 신들은 사탄의 추종자라는 의견을 덧붙임.
    • 초기 그리스도교는 철학이나 종교 의식의 측면에서 적대자들과 필적할만한 무리가 아니었으나, 점차 이러한 결함을 고쳐 나감.
  • (이하 역사 이야기 생략)

러셀 서양철학사/ 프란체스코 수도회의 스콜라 철학자들

  • 프란체스코 수도회 수도자들은 도미니코 수도회 수도자들 보다는 덜하지만 정통 그리스도교 신앙을 지켰다.
    • 두 수도회 사이의 경쟁이 치열해서 프란체스코 수도회 수도자들은 성 토마스의 권위를 받아들이려 하지 않았다.
    • 프란체스코 수도회 철학자들 가운데 중요한 세 사람은 로저 베이컨, 둔스 스코투스, 오컴의 윌리엄.
  • 로저 베이컨은 수학과 과학에 대한 열정을 지닌 만물박사였음.
    • 로저 베이컨은 백과사전적 지식의 소유자였으나 체계성은 없었음.
    • 당대의 철학자들과 달리 실험의 가치를 높게 평가했으며, 무지개 이론으로 실험의 중요한 가치를 보여 줌.
  • 로저 베이컨은 무지의 원인이 네 가지 있다고 말 함
    • 첫째, 부정하고 부적합한 권위의 사례
    • 둘째, 관습의 영향
    • 셋째, 무식한 군중의 의견
    • 넷째, 외견상의 지혜를 과시하며 무지를 은폐하는 것.
    • 이 중 넷째가 가장 치명적이고 인간이 저지르는 모든 악의 근원이라 말함
  • 베이컨은 아리스토텔레스를 존경함.
  • 베이컨은 아베로에스를 추종하여 능동지성이 본질의 측면에서 영혼과 분리되는 실체라 주장.
  • 베이컨은 근대에 이르러 지식의 원천으로 실험을 논증보다 훨씬 더 중시했기 때문에 찬사를 받음.
    • 베이컨의 관심 영역이나 주제를 다루는 방식은 전형적인 스콜라 철학자들과 아주 달랐음.
  • 둔스 스코투스는 프란체스코 수도회와 아퀴나스의 논쟁을 계속 이어감.
  • 둔스 스코두스는 온건한 실재론자였음.
    • 그는 자유의지가 있다고 믿었으며,존재는 본질과 다르지 않다고 주장하기도 했음.
  • 스코두스는 존재와 본질 사이에 아무 차이도 없기 떄문에 ‘개별화의 원리’ 즉 한 사물을 다른 사물과 동일하지 않게 만드는 원리는 질료가 아니라 형상이어야 한다고 주장.
    • 개체들의 속성들 가운데 몇몇은 본질적 속성이고 다른 몇몇은 우연적 속성이다.
    • 같은 종에 속한 개체가 둘 있다면 두 개체는 언제나 본질에서 차이가 있는가 아니면 두 개체 안의 본질이 꼭 같을 수 있는가에 대해 성 토마스는 물질적 실체에 대해 후자의 견해를 받아들이고, 정신적 실체에 대해서는 전자의 견해를 받아들인 반면
    • 스코투스는 다른 두 개체 사이에는 언제나 본질의 차이가 있게 마련이라고 주장함.
    • 성 토마스의 견해는 순수 질료가 공간 속 위치의 차이로만 구별되는 균등한 부분들로 구성되어 있다는 이론에 의존하기 때문에 정신과 육체로 이루어진 어떤 사람은 육체의 공간적 위치를 통해서만 다른 사람과 물질적으로 다르다고 할 수 있는 반면
    • 스코투스는 만약 사물이 구별된다면 성질의 차이로 구별되어야 한다고 주장. 이런 견해는 플라톤에 더 가깝다.
  • 개별화의 원리 문제를 현대적으로 진술하면 여러 단계를 밟아야 함
    • 라이프니츠가 밟은 첫 단계는 본질적 속성과 우연적 속성의 구분을 제거하는 절차인데, 주의 깊게 진술하려 시도하면 곧 비현실적인 가공의 구분에 지나지 않는다는 사실이 드러남.
    • 따라서 우리는 ‘본질’ 대신 ‘해당 사물에 대해 참이라고 말할 수 있는 모든 명제’를 사용한다.
    • 라이프니츠는 ‘구별불가능자의 동일성’ 원리 떄문에 두 사물이 똑같아지는 일은 불가능하다고 주장.
    • 라이프니츠의 원리는 물질 입자 두 개는 시공간상의 위치에서만 다를 수 있다고 주장하는 물리학자들의 비판을 받았으며, 시공간을 관계로 환원하는 상대성 이론으로 더욱 곤란한 지경에 이르게 된 관점
  • 오컴의 윌리엄은 성 토마스 이후 가장 중요한 스콜라 철학자
    • 오컴은 정작 그의 저작에서 발견되지 않는 ‘오컴의 면도날’이란 격률로 유명.
    • ‘존재들은 필요 없이 늘어나서는 안된다’
      • (에너지 최소화의 원리, 엔트로피 법칙과도 연결지을 수 있을 듯)
    • (러셀의 평) 나는 오컴의 격률이 논리적 분석에서 풍성한 열매를 맺는 원리라는 사실을 알게 되었다.
  • 오컴은 형이상학에서는 유명론의 지지자가 아니었으나 논리학에서는 유명론을 지지함.
  • 오컴에게 논리학은 자연철학을 위한 도구로서 형이상학에서 독립할 수 있는 학문 분야였음.
  • 논리학은 추론적인 과학에 대한 분석인데, 과학은 사물과 관련이 있지만 논리학은 사물과 관련이 없다.
    • 사물들은 모두 개체이지만, 명사들 가운데는 보편자도 있다.
    • 논리학은 보편자들을 다루지만, 과학은 보편자들에 대해 논하지 않고 보편 개념들을 사용한다.
    • 논리학은 명사들이나 개념들에 관심이 있는데 그것들을 물리 사태로서 다루지 않고 의미를 지닌 것으로 다룬다.
    • 인간은 종개념이다(Man is a species)라는 명제가 논리학의 명제가 아닌 까닭은 그 명제가 성립하려면 인간에 대한 지식이 필요하기 때문.
    • 논리학은 정신이 자기 내부에서 꾸며낸, 즉 이성의 존재를 토앟지 않고서는 존재할 수 없는 것들을 다룬다.
    • 개념은 자연에 따른 기호이며, 낱말은 규약에 따른 기호이다.
    • 우리는 한 사물로서 낱말에 대해 말하는 경우와 의미를 지닌 것으로서 낱말에 대해 말하는 경우를 구분하지 않으면 안 된다.
  • 사물을 가리키는 명사는 ‘1차 개념 명사’이다.
    • 과학의 명사들은 1차 개념에 속하고, 논리학의 명사들은 2차 개념에 속한다.
    • 형이상학의 명사들은 1차 개념에 속한 낱말이 지시하는 사물과 2차 개념에 속한 낱말이 지시하는 사물을 둘 다 지시한다는 점에서 고유한 특징을 나타낸다.
    • 형이상학에는 정확히 여섯 가지 명사, 즉 존재, 사물, 어떤 것, 하나, 참, 선이 있다.
    • 이러한 명사들은 모두 서로 술어가 될 수 있다는 고유한 특징을 가진다.
    • 그러나 논리학은 형이상학의 명사들과 상관없이 독자적으로 연구를 수행할 수 있다.
  • 오성(understanding)의 대상은 사물이지 정신이 생산한 형상이 아니다.
    • 형상은 이해되는 무엇은 아니지만 그것에 의해 사물을 이해하게 된다.
    • 논리학에서 보편자는 여러 다른 명사나 개념들의 술어가 될 수 있는 명사나 개념일 따름이다.
    • 보편개념, 유개념, 종개념은 2차 개념에 속한 명사들이므로, 사물을 의미할리 없다.
    • 그러나 하나와 존재는 환위할 수 있기 때문에, 만약 보편자가 존재하게 되면, 보편자는 하나이자 개별 사물이 된다.
    • 이에 대해 오컴은 아퀴나스의 견해에 동의하고, 아베로에스, 아비세나, 아우구스티누스 지지자들의 견해에 반대한다.
    • 아퀴나스와 오컴은 둘 다 개별 사물, 개별 정신, 이해의 활동만 존재한다고 주장한다.
    • 사실 두 철학자는 모두 사물에 앞선 보편자(universale ante rem)를 인정하지만, 오로지 창조를 설명하기 위해 인정할 뿐이다.
    • 창조할 수 있으려면 창조 이전에 신의 정신 속에 보편자가 존재해야 한다는 것이다.
    • 그러나 이것은 신학에 속한 문제이지, 오로지 사물 다음의 보편자(universale post rem)와 관련된 인간의 지식에 대한 설명에 속한 문제가 아니다.
    • 인간의 지식을 설명하는 경우 오컴은 보편자를 결코 사물로 인정하지 않는다.
  • 오컴에 따르면 장차 일어날 우연한 사건에 관한 명제는 참도 거짓도 아니다.
    • 그는 이러한 견해를 신의 전지와 조화시키려 하지 않는다. 
    • 그는 여기서도 다른 곳과 마찬가지로 논리학을 형이상학과 신학에서 떨어뜨려 자유롭게 놓아둔다.
  • 감각 영혼과 지성 영혼은 인간 안에서 실제로 구별되는가라는 질문에 오컴은 증명하기는 힘들겠지만 구별된다고 대답한다.
  • 오컴의 작업은 논리학이나 인간의 지식을 형이상학이나 신학과 관련 없이 연구할 수 이다고 주장함으로써 과학적 연구를 촉진했다.
  • 오컴의 윌리엄 이후 위대한 스콜라 철학자는 더는 없다. 위대한 철학자들을 위한 시대는 르네상스 후기에 막을 열었다.

 

러셀 서양철학사/ 성 토마스 아퀴나스

  • 토마스 아퀴나스는 스콜라 철학자들 가운데 가장 위대한 인물
    • (러셀의 평) 철학을 가르치는 모든 카톨릭 교육 기관은 토마스 아퀴나스의 체계를 가르쳐야 한다.
  • 아퀴나스는 많은 점에서 아리스토텔레스와 가까웠음.
    • 아퀴나스는 선대 철학자들과 달리 아리스토텔레스에 대한 충분한 지식을 실제로 갖고 있었음.
    • 그는 아리스토텔레스가 플라톤 철학보다 그리스도교 철학의 기초로서 더 적합하다고 설득함
  • 아퀴나스의 가장 중요한 저작은 <이교도 반박 대전>
    • 지혜 자체는 우주의 목적과 관계고 있고, 우주의 목적은 지성의 선 즉, 진리라고 주장.
    • 이 점에서 지혜의 추구는 추구하는 일들 가운데 가장 완벽하고 숭고하며 유익하고 즐거운 일이다.
  • 아퀴나스는 자신의 목적이 카톨릭교의 신앙이 공언하는 진리를 선포하는 것이라고 말함.
    • 여기서 아퀴나스가 자연 이성을 수단으로 사용할 수 밖에 없는 이유는 이교도가 성서의 권위를 수용하지 않기 때문이라고 설명.
    • 자연 이성은 신의 일을 아는데는 부족해서 신앙의 어떤 부분을 증명하기도 하지만 다른 부분은 입증하지 못한다.
    • 자연 이성은 신의 존재와 영혼의 불멸성을 증명할 수 있지만, 삼위일체설이나 육화나 최후의 심판을 증명하지는 못한다.
    • 증명할 수 있는 것은 무엇이든 증명한 범위 내에서는 그리스도교 신앙과 일치하며, 계시 안에 드러나는 어떤 것도 이성과 반대되지 않는다.
  • 아퀴나스는 신의 존재를 아리스토텔레스가 말했던 부동의 원동자 논증을 통해 증명을 시도.
  • 신의 본성은 아닌 것을 통해서만 우리에게 알려진다.
    • 신은 움직여지지 않기 때문에 영원하다.
    • 신은 수동의 가능태를 포함하지 않기 때문에 불변한다.
  • 신 안에서 본질과 존재는 동일하다.
  • 신 안에서 우연은 없다.
  • 신은 선할 뿐만 아니라 선 자체이다.
  • 신의 지성 활동은 신의 본질이다.
  • 신은 만물을 동시에 이해한다. 신의 인식은 습관이 아닐 뿐만 아니라 추론적 지식이나 논증적 지식도 아니다. 신은 진리 자체이다.
  • 플라톤과 아리스토텔레스를 괴롭현던 문제인 신은 개별 사물을 인식하기도 하는가 아니면 신은 보편자와 일반적 진리만 인식하는가에 대해 아퀴나스는 논증 7가지를 열거하고 차례로 논박을 시도함.
    • 신이개별자들의 원인으로서 개별자들을 안다고 응수
    • 신이 미래에 우연히 일어날 일을 아는 까닭은 신 자신은 시간 속에 존재하지 않기 때문
    • 신이 하찮은 사물이라도 알고 있는 까닭은 완전히 하찮은 것은 아무것도 없으며, 무엇이든 약간이라도 고귀한 점이 있기 때문.
  • 신의 의지는 곧 자신의 본질이므로 신의 의지가 향하는 중요한 대상은 신의 본질이다.
  • 신은 고대인들의 견해와 반대로 무에서 세계를 창조했다.
  • 지성 능력을 가진 모든 실체는 비물질적이며 소멸하지 않는다.
    • 천사들은 육체가 없지만 인간의 영혼은 육체와 결합되어 있다.
  • 보편자는 영혼 바깥에서 존속하지 못하지만, 지성은 보편자를 이해함으로써 영혼 바깥에 있는 사물을 이해한다.
  • 인간은 육체에 좋은 것들을 얻음으로써 행복에 이르지 못하며, 더욱이 행복은 감각 속에 자리 잡지 않는다.
    • 인간은 도덕적인 덕을 실천함으로써 궁극의 행복에 도달한다.
  • 신의 섭리는 악, 우연, 자유의지, 우연한 기회나 요행을 배제하지 않는다.
  • 죄, 예정설, 신의 선택 문제에 대해 아퀴나스는 아우구스티누스와 유사한 견해를 가짐.
    • 인간은 도덕적 죄로 말미암아 영원무궁한 세계에 이르려는 최후의 목적을 상실하기 떄문에 영원한 형벌은 인간이 받을 당연한 응보이다.
    • 어느 누구도 은총을 받지 못하면 죄에서 자유로워질 수 없다.
  • 신을 아는 세 가지 길이 있는데, 이성으로 통하는 길과 계시로 통하는 길, 오직 계시로 미리 알려진 중요한 것을 직관함으로써 통하는 길이 그것.
  • 아퀴나스의 철학은 일반적인 요점의 측면에서 아리스토텔레스의 철학과 일치한다.
    • 아퀴나스의 독창성은 변경을 최소화하면서 아리스토텔레스의 철학을 그리스도교 교리에 맞게 개조한 작업에서 나타남.
  • (러셀의 평)
    • 아퀴나스의 철학 체계 안에 진정한 철학 정신을 드러내는 부분은 거의 없다.
    • 그는 결과를 미리 알 수 없는 탐구에는 발을 들려 놓지 않는다.
    • 그는 철학을 시작하기 전에 벌써 진리를 알고 있다. 진리는 카톨릭 신앙 안에서 선언된다.
    • 나는 아퀴나스가 그리스와 근대 양 시대의 최고 철학자들과 어깨를 견줄만하다고 생각하지 않는다.