2014년 4월 21일 월요일

OpenCV에서 비디오 파일 읽기

스마트폰에서 촬영한 비디오 파일을 OpenCV에서 읽어 처리하려고 하는 도중 알게 된 살짝 어이없는 사실..

Video I/O API


OpenCV에서 비디오 파일을 처리하기 위해서는 cv::VideoCapture 클래스를 이용한다. 관련 예제들을 참고하면 이런 식이다.

#include "opencv2/opencv.hpp"
namespace cv;

VideoCapture vc;
if ( !vc.open( "path_to_video_file" ) )
    return -1;
namedWindow( "video" );
while (1)
{
    Mat frame;
    vc >> frame;
    imshow( "video", frame );
    if ( waitKey( 30 ) > = 0 ) break;
}

opencv_ffmpeg


위의 코드를 실행해보면 거의 비디오 파일을 열지 못한다. (아주 기초적인 codec만 가능한 것 같음). 이것은 OpenCV에서 AV codec 라이브러리로 사용하는 ffmpeg에 연결되지 못하기 때문인데 해결 방법은 역시 아주 간단하다. (32bit 환경 기준)

  1. OpenCV/3rdparty/ffmpeg 디렉터리에 있는 opencv_ffmpeg.dll 파일을 기존 opencv dll 파일이 있는 디렉터리에 복사한다. (또는 OpenCV/3rdparty/ffmpeg 디렉터리를 path로 지정한다)
  2. 자신이 사용하고 있는 OpenCV 버전을 이용하여 dll 파일명 뒤에 숫자를 붙인다. 예를 들어 OpenCV 2.4.6을 사용하고 있는 경우 opencv_ffmpeg246.dll로 파일명을 바꾸어 준다.

2014년 4월 3일 목요일

3) 컴파일러로 세상과 인사하기

이제까지 컴퓨터 내부에 어떤 부품들이 있는 가와 컴퓨터는 숫자로 모든 것을 처리한다는 것을 배웠지. 이제 프로그램은 무엇이고 컴퓨터는 이것을 어떻게 실행시키는지 알아보자.

기계어 (Machine Language)

CPU는 컴퓨터의 두뇌로서 계산/판단/처리를 하는 중심적인 역할을 한다고 배웠지. CPU에는 여러 부속 장치들이 연결되어 있는데 그 중에 가장 중요한 것이 메모리야. 메모리(memory)는 단어 뜻 그대로 자료를 저장하고 있다가 필요할 때 꺼내 쓸 수 있도록 만든 장치야. 마치 책상에 붙어 있는 책장이나 서랍과 같이 원하는 장소에 물건을 잠시 넣어 놓았다가 필요할 때 즉시 찾아서 볼 수 있는 것을 생각하면 돼.



메모리는 마치 아파트처럼 값을 기억할 수 있는 곳 마다 주소(물론 당연히 이것도 숫자임)가 지정되어 있고 이 주소마다 숫자를 담아둘 수 있게 되어 있어. 메모리에 담겨져 있는 숫자들은 이것이 프로그램일 수도 있고, 사진 혹은 영화 동영상일 수도 있고, 사전 속의 단어장일 수도 있어.
위의 그림처럼 CPU는 메모리에 저장된 값들을 읽어 들여가는데 기본적으로 주소 차례대로 읽어가게 된다. 이렇게 읽어간 숫자를 보고 CPU는 일을 하게 돼. CPU라는 부품을 처음 개발할 때 이미 각 숫자는 어떤 일을 시키려는 것 인지를 정해 놓았어. 즉 명령을 숫자로 내리는 셈인데 이를 기계어라고 해.
어느 날 학교 선생님이 목이 너무 아프셔서 말을 많이 하기 힘든 상황이 되었다고 가정하자. 선생님은 칠판에 다음과 같이 적어서 규칙을 학생들에게 알려준 후 손가락으로 숫자를 표시하여 학생들에게 지시하는 것과 비슷하지.

   1 = 공부(자습) 시작하기
   2 = 쉬는 시간 시작하기
   3 = 점심 식사 시작하기
   4 = 청소하기
   5 = 집에 돌아가기

이제 선생님은 수업 시작할 때는 손가락 1개를 학생들에게 보여주고, 수업 시간이 끝나면 손가락 2개를 펴서 보여주고, 식사 시간이 되면 손가락 3개를 펴서 보여주고.. 이렇게 어떤 일을 해야 할 것 인지를 숫자로 정해 놓을 수 있잖아? 기계어라는 것은 숫자밖에 알지 못하는 CPU에게 일을 시키기 위해서 역시 숫자를 이용해서 명령들을 정의해 놓은 것이야.

컴파일러 (Compiler)

숫자로 명령들을 정해 놓긴 했지만, 숫자 무엇이 무슨 명령이고 하는 이걸 다 외워서 프로그램을 만들어야 한다면 정말 어려운 일이야. 컴퓨터가 아주 처음 나왔을 때는 기계어로 프로그램을 만드는 경우도 있긴 했는데 아주 복잡하고 지겨운 일이어서 보통 사람은 잘 할 수가 없었어. 물론 아빠는 할 줄 알았지. 그래서 사람의 입장에서 명령을 만들어내기 쉬운 방법들이 만들어졌어. 영어 단어 몇 가지와 기호들을 가지고 규칙을 정한 것인데 마치 우리가 다른 사람과 대화하기 위해 사용하는 말을 언어라고 하듯이 컴퓨터와 대화를 하기 위해 사용하기 때문에 이런 것들도 언어라고 불러. 앞에서 설명한 기계어도 엄밀하게 따지면 언어 중의 하나라고 볼 수 있어.
이렇게 만들어진 언어들 중에 많이 사용되는 것이 Basic, C/C++, JAVA와 같은 것이 있어. 한국어를 쓰는 우리가 영어, 중국어, 프랑스어 등등 외국어를 배우기도 바쁜데 컴퓨터랑 대화를 하는 데에도 배워야 할 언어가 여러 가지가 있지(OTL). 하지만 컴퓨터 언어를 한 가지 만이라도 제대로 배우고 나면 다른 언어들은 쉽게 사용할 수가 있으니 너무 걱정하지 않아도 돼.
우리는 C/C++ 언어를 배우기로 했으니 앞으로는 C를 기준으로 설명해 줄께. C라는 언어가 먼저 생기도 나중에 이것과 유사하지만 더 강력한 C++이란 언어가 추가로 개발되었는데, 처음 언어를 배우는 지금은 C를 배운다고 생각하고 어느 정도 진도가 나가면 C++은 C와 어떻게 다른 지를 설명해주도록 할께.
이제 우리가 C로 프로그램을 만들면 될 것 같은데, 여전히 컴퓨터(CPU)는 숫자로만 되어 있는 기계어밖에 할 줄 모른다고 했으니 뭔가 방법이 있어야 할 것 같지? 그래서 C로 작성한 프로그램(이걸 원시 코드=source code라고 부른다)을 기계어로 바꾸어주는 프로그램이 있어. 이걸 컴파일러(compiler)라고 해. 컴파일러는 외국 영화를 받아다가 처음부터 끝까지 번역해서 자막을 달아주는 일을 하는 것과 비슷해. 즉, 우리가 C로 프로그램을 만들어서 실행하려고 할 때 프로그램의 시작부터 끝까지를 기계어로 다 바꾸어준 후 컴퓨터(CPU)가 실행할 수 있도록 해주는 것이지. 조금 다른 방식으로 프로그램을 부분 부분 필요한 만큼만 기계어로 바꾸어 가면서 실행해주는 방식도 있는데 이런 것은 인터프리터(interpreter) 방식이라고 해. 꼭 동시 통역을 해주는 사람과 비슷하달까?

세상과 인사하기

우리가 사용할 컴파일러는 마이크로소프트라는 회사에서 만든 Visual C라는 컴파일러야. 마이크로소프트라는 회사는 많은 사람이 매일 사용하는 윈도우, 오피스 등등을 만든 어마무지한 회사야. 컴파일러 자체도 프로그램이기 때문에 돈을 주고 사서 컴퓨터에 설치해야 하는데 설치하는 방법은 생략하도록 할께. 왜냐면 아빠가 다 설치해줬으니까..
컴파일러를 사용하는 방법에 대해서만 공부하려고 해도 무지무지하게 알아야 할 것이 많은데 지금 그걸 다 알 필요는 없고 단지, 아래와 같은 것만 알아 두도록 하자.

    0. Visual C (프로그램 명이 Visual Studio일수도 있다)를 실행한다.
    1. 프로그램을 만들 때는 [File 파일] 메뉴의 [New... 새로만들기...] 아래의 [Project... 프로젝트...]를 실행시키고, Win32 콘솔 응용 프로그램을 선택한다.
    2. 다음과 같은 내용을 입력하고 Ctrl+F5를 눌러 실행시킨다.

void main(void)
{
   printf( "Hello World!\n" );
   exit( 0 );
}

여기까지 내용을 대략 이해하고 위의 프로그램을 실행시킬 수 있으면 이제 프로그래밍 공부를 본격적으로 시작할 수 있게 된 거야. 다음 시간에 C의 기본에 대해 공부해 보자.

2014년 3월 31일 월요일

Ubuntu13.04에서 WPA2 Enterprise 연결하기

ROS Hydro를 사용하기 위해 어쩔 수 없이 Ubuntu 13.04에서 버전업하지 않고 사용 중. 모바일 로봇에 태우기 위해 제어기용 PC에 무선랜을 연결하기로 하였다.


Linux에 무선랜 연결하기

사용OS - Ubuntu 13.04
무선랜카드 - IPTime N150UA Solo



1. 케이스를 뜯고 안테나를 장착한 후 PC USB슬롯에 꼽는다.

2. 하드웨어를 인식하였는지 확인한다.
  $lsusb
ID 148f:7601에 Ralink Technology, Corp.항목이 있어야 한다.

3. 리눅스용 드라이버를 여기서 내려받는다.

4. 압축을 해제한 후 설치한다. 구글링을 하다보면 소스 몇 군데를 수정하라는 글도 있는데, 그냥 해도 되었다.

  $make
  $sudo make install
  $sudo modprobe mt7601Usta

5. 이제 화면 우측 상단위 네트워크 아이콘을 누르면 Wi-Fi 관련 메뉴가 추가되어 있다. 여기서 적당한 AP를 선택하고 연결하면 된다.

6. 문제는 여기까지는 별 어려움없이 없었지만, LAB에 설치한 사설AP는 잘 되면서 학교 전체에서 서비스하는 WPA2 Enterprise 네트워크에는 연결되지 않는다는 점이다. 설정을 제대로 입력하고 연결을 시도하면 끊임없이 WIFI 인증에 실패하였으니 암호를 다시 입력하라는 창이 나온다...

   여러 가지 자료를 찾아본 결과 우분투 13.4 커널에서의 버그인 것 같으며, 버그의 내용은 WiFi Security 입력 정보 중에 CA Certificate가 반드시 있어야만 연결이 가능하다는 설명이다. 보통 윈도우즈나 스마트폰에서는 CA Cert를 빈칸으로 놓고 잘 연결이 되었었는데 참으로 당혹스럽다.

   해결 방법은 간단한데, /etc/NetworkManager/system-connections 디렉터리에 있는 해당 설정 파일을 열고 system-ca-certs=true 라인을 지워주면 된다. 설정 파일은 앞에서 연결을 시도할 때 생성되며 파일 명은 SSID와 같다.


Windows에 무선랜 IP 알려주기

Ubuntu 머신은 로봇에 태우고 움직이고 다니기 때문에 그 앞을 따라 다니면서 작업을 하기가 쉽지 않다. 작업은 윈도우 데스크탑에서 터미널을 열어 하는 것이 좋겠는데, 문제는 WIFI로 학교의 Enterprise 네트워크에 연결시키다보니 IP주소가 바뀌게 되어 아주 귀찮게 되었다. 이참에 한 가지 더 작업을 하였다. Ubuntu에서 WIFI에 연결이 될 때마다 받은 IP 주소를 작업용 윈도우 데스크탑에 알려주도록 스크립트를 추가하였다.

/etc/NetworkManager/dispatcher.d 디렉터리에 적당한 이름의 파일을 아래와 같이 추가한다.

#!/bin/sh -e
# Script to dispatch NetworkManager events
#
# Runs ifupdown scripts when NetworkManager fiddles with interfaces.
# See NetworkManager(8) for further documentation of the dispatcher events.

if [ "$1" = "ra0" ] && [ "$2" = "up" ]; then
        hostname | nc -u -q 1 foo.bar 9999
fi

당연히 윈도우 머신은 고정 IP 이거나 DNS에 등록된 것이어야 한다. 그 주소를 위 스크립트의 foo.bar 위치에 쓰고 UDP 9999번 포트로 자신(Ubuntu)의 호스트명을 전송하게 한다. 위 스크립트는 WIFI가 연결되어 인터페이스 ra0 이 UP 상태가 될 때마다 실행하도록 한 것이다.

윈도우 쪽에는 9999번 UDP 포트를 리스닝하고 있다가 이를 감지해서 hosts 파일을 업데이트해주는 service를 제작하여 등록해 놓는다. (이건 쉽게 만들 수 있으므로 자세한 설명은 생략^^;)

2014년 3월 27일 목요일

2) 무엇이든지 결국은 다 숫자다.

컴퓨터의 세계에서는 모두 ON과 OFF, 즉 1과 0으로만 모든 것이 처리된다고 했지? 이것을 수학에서 배운 것으로 표현하기 위해 2진수라는 것을 배웠다.

비트(Bit)란?

2진수 한 개(한 자리)를 컴퓨터에서는 Bit라는 용어를 사용해. Bit는 Binary Digit에서 앞의 2글자와 맨 뒤의 한 글자를 따온거야. Binary는 "2개로 이루어진" 혹은 "2진수의" 뜻을 가진 형용사고 Digit는 "숫자"라는 명사야. 이 틈에 영어 공부도 하니 참 좋네. 2진수가 한 개만 딸랑 있는 경우 1비트, 2진수가 8자리 숫자로 있는 경우 8비트, 이런 식이지.

2진수는 자리 수가 늘어날 때마다 2배씩 커지게 되는데, 이걸 수학적으로 보면 2의 거듭제곱과 같아. 거듭제곱에 대해서 복습하면, "2의 n제곱은 2를 n번 곱한 것"으로 2ⁿ과 같이 수학에서 표시하는데, 컴퓨터 자판으로 글을 쓸 때 제곱수(n)을 위첨자(superscript, 작은 글자를 위에 붙여서 쓰는 것)로 일일이 쓰는 것이 어렵기때문에 2^n과 같이 ^(caret, 꺽쇠)를 이용한다.

예) 2⁴= 2^4 = 2x2x2x2 = 8

2진수 8자리를 가지고 표현할 수 있는 범위는 0b00000000부터 0b11111111 까지인데 이걸 10진수로 바꾸어 보면 0부터 255까지, 모두 256개의 숫자를 셀 수 있어. 사람 손가락이 10개이기 때문에 그런지 몰라도 아무리 공부를 못해도 1에서 10까지는 더하고, 빼거나 기억하는 것이 가능하다고 보면 컴퓨터도 한 번에 기억하고 계산할 수 있는 숫자의 범위가 있어. 다시 말하지만 컴퓨터는 2진수를 기준으로 한다는 것을 잊지 않았으면, 한 번에 8자리 숫자를 처리하는 컴퓨터는 8비트 컴퓨터, 한 번에 32자리 숫자를 처리하는 컴퓨터는 32비트 컴퓨터라고 한다. 8비트 컴퓨터는 CPU가 0~255 사이의 숫자를 읽고 계산하고 할 수 있어. 물론 이것보다 큰 숫자를 계산하기 위해서는 여러 번에 걸쳐서 나누어서 하게 되지.
요즘 쓰는 컴퓨터들은 64비트 CPU를 사용해. 30여년 전에 스티브 잡스라는 사람이 애플이라는 회사를 만들어서 처음 PC를 만들어 팔았을 때 8비트 CPU를 사용했었는데 그때에 비하면 8배가 커진 셈인데, 실제로는 그보다 훨씬 더 용량도 커지고 계산도 빨라졌어. 그 덕분에 요즘의 실감나는 게임도 만들어지는 거임ㅋㅋ. 비트라는 단위가 워낙 크기가 작기 때문에 2진수 8개가 모인 8비트를 1바이트(Byte)라고 하고, 일반적으로 바이트라는 단위를 많이 사용하지.

데이터 형(Data Types)

자, 이제 프로그래밍의 기본적인 부분에 대해 알아보자. 컴퓨터로 프로그램을 만들어서 할 수 있는 게 무엇일 까 생각해보자. 우리가 자주 쓰는 프로그램들이 무엇이 있을까? 계산기, 게임, 워드프로세서, 게임, 인터넷, 게임, 등등이 있는 데 모든 프로그램은 결국은 아래 그림의 3가지 단계로 일을 하는 것을 알 수 있어.


어떤 정보(데이터 혹은 명령어)를 입력하고, 이에 대해 처리하고, 그 결과를 출력하는 3가지 단계이지. 그렇다면 입력, 처리, 출력하는 정보들은 도대체 실제로는 어떤 것일까?

정답은 이 글의 제목에 써 놓았는데 전부 다 숫자라는 점을 알아야 해. 그리고 또 그 숫자는 내부적으로 2진수로 되어있는 것이지. 하지만 프로그램을 만들 때 0과 1만 가지고 입력시키고 또 그 결과를 출력해 보면 사람이 알아볼 수가 없어. 매트릭스라는 유명한 영화를 보면 함선에 타고 있는 기술자들은 화면에 이상한 글자들이 쏟아져 내려오는 것을 보고 주인공이 위험에 빠져있다는 얘기를 하는 장면이 나오는데 굳이 말하자면 그 사람은 숫자만 보고 그것이 의미하는 글자나 그림으로 바로 해석을 할 수 있다는 뜻이 돼. 정말 좋겠다.

아무리 숫자라고 하더라도 2진수만으로는 할 수 없기 때문에 실제 프로그램에서는 10진수 혹은 16진수를 사용하고, 또 8비트 컴퓨터라고 255까지만 계산해주어서는 안되기 때문에 2진수 여러 자리 수를 사용하여 데이터 형(Data Type)이라는 것을 정해 놓았어. 이것은 프로그램 언어마다 조금씩 다른데 프로그램 언어가 무엇인지는 다음 번에 이야기하고, 우리는 C++을 배우려고 하는 것이니까 C++을 기준으로 알려 줄께.

데이터 형 종류
명칭
비트 수
부호 있는 정수(signed integer)
char
8
short
16
long
32
부호 없는 정수(unsigned integer)
unsigned char
8
unsigned short
16
unsigned long
32
실수(floating point)
float
32
double
64

복잡해 보이지만 큰 숫자 혹은 정확한 숫자가 필요할 때에는 비트 수가 큰(용량을 많이 차지하는) 데이터 형을 쓰고 반대로 작은 숫자들로만 처리가 가능한 때에는 비트 수가 작은 데이터 형을 쓰게 돼. 컴퓨터 안에 있는 메모리, 디스크와 같이 데이터를 저장하는 곳은 무한정 많은 양을 담을 수 있는 것이 아니고 용량이 정해져 있기 때문에 처리하고자 하는 일이 무엇인 가를 잘 따져서 적합한 데이터 형을 써야 해. 예를 들어 학생들의 과목 별 시험 점수를 처리하고자 할 때는 0점부터 100점까지로 범위가 정해져 있기 때문에 8비트 크기의 정수(char)를 쓰면 충분하다는 거지.

8비트의 숫자는 0에서 255까지를 표현할 수 있다고 했는데, 음수를 넣고 싶으면 어떻게 할 까? 한 가지 방법은 8비트 중에 1개의 비트를 부호(0이면 양수, 1이면 음수)를 결정하는데 사용하고 남은 7비트를 숫자로 쓰면 되겠지. 실제 컴퓨터에서 음수를 표현하는 방법은 조금 다르지만 비슷한데 어찌되었던간에 256가지를 구별할 수 있기 때문에 부호있는 8비트 정수는 -128에서 127까지를 사용해. 점점 복잡해진다@.@ㅋ

아스키 코드(ASCII Code)

숫자에 대해서만 쭉 공부해봤는데 정작 컴퓨터에서 보는 대부분의 정보는 글자로 되어있잖아? 이건 어떻게 하는 걸 까? 옛날 사람들이 이 고민을 다 해서 좋은 것을 만들어 놓았지. 다름 아니라 우리가 쓰는 글자(character)들을 각각 순서를 매긴 다음에 번호를 붙여서 쓰는거야. 컴퓨터를 처음 만든 사람들이 미국 사람들이다 보니 자기들이 쓰는 글자인 영어 알파벳을 가지고 번호를 매겨 놓았고 이것은 기본적으로 지금도 그대로 쓰고 있어. 알파벳이 A부터 Z까지 모두 26개이기 때문에 번호를 붙이는 일이 그리 어렵지 않았지. 이렇게 만들어 놓은 것은 아스키코드(ASCII Code)라고 해. 이름이 이상한데, American Standard Code for Information Interchange의 앞 글자를 딴 거야(자세한 설명).


원래 ASCII 코드는 0에서 127까지로 정해져 있어서 8비트 정수(1바이트) 하나 당 한 글자씩 넣을 수 있어. 쉽게 생각하면 10글자를 저장하는데 10바이트가 필요한 식이지. 그 이후에 영어가 아닌 다른 언어를 쓰는 나라들도 자신의 글자에 맞는 값을 정해서 사용했어. 물론 우리 나라에서도 한글을 표시하기 위해 코드를 정해서 쓰고 있어.

문제

1) 16비트 CPU가 최대로 처리할 수 있는 숫자를 10진수와 16진수로 각각 나타내시오.

2) 위의 아스키코드 표의 코드 숫자는 10진수이다. 다음의 16진수를 ASCII코드 표를 찾아 글자로 바꾸시오.
0x53 0x65 0x61 0x6E 0x20 0x26 0x20 0x52 0x75 0x62 0x69

3) 팔만대장경은 52,330,152개의 한문 글자, 성경은 3,566,400개의 영어 글자로 되어 있다고 한다. 한문 1글자를 기록하는데 2바이트, 영어 1글자를 기록하는데 1바이트가 필요하다고 하면 팔만대장경과 성경을 컴퓨터에 입력하기 위해 각각 얼마의 용량이 필요한가?

2014년 3월 25일 화요일

1) 컴퓨터의 내부를 알자

프로그램 만드는 것에 대해 가르쳐 주려고 생각하니, 할 수 없이 수학에서 배운 내용을 같이 설명할 수 밖에 없다. 역시 뭘 하든 수학을 잘 해야 해. 컴퓨터 내부에는 어떤 부품이 들어 있고 이 것들이 각각 어떤 일을 어떤 방식으로 하는 지에 대해서 어느 정도 감이 있어야 앞으로 공부할 내용들에 대해 이해할 수 있을 꺼야.

컴퓨터의 내부 구조


컴퓨터에 대한 책은 거의 대부분 위와 같은 그림에 대한 설명으로 시작하게 되는데, 컴퓨터는 하늘색 사각형 안에 그려져 있는 부분을 말하는 것이고(이걸 본체라고 함) 나머지 부품들은 컴퓨터에 연결해서 우리가 사용하는 것들이야. 여기서 가장 중요한 것이 CPU라고 하는 것인데 컴퓨터에서 일어나는 모든 일들이 이것을 중심으로 동작하고 있다고 생각하면 틀리지 않아. CPU는 미국에 있는 인텔(Intel)이라는 회사에서 만드는 것들이 가장 많이 사용되고 있는데 이 회사에서 계속 연구를 해서 점점 더 빠르고 강력한 제품들을 내놓고 있고 그 때마다 이름이 붙여지지.

CPU

CPU는 (미리 만들어서 넣어 놓은) 프로그램을 실행시키는 일을 하는데, 그 과정은 기억장치(RAM)에서 명령을 한 개 읽어 와서 그걸 처리하고 다시 다음 명령을 한 개 읽어 와서 그걸 처리하고... 이걸 계속 반복하는 식이야. 아주 간단하지. CPU가 읽고 처리하는 명령어라고 하는 것이 모두 숫자로 이루어져 있어. 사실 요즘 우리가 사용하는 전자 장치들은 모두 숫자들을 조합해서 만들어지는 것이지. 컴퓨터의 부품들을 보면 아주 많은 전선들이 서로 연결되어 있는 것을 볼 수 있는데, 각각의 전선에 전기가 흐르는 경우가 1, 흐르지 않는 경우가 0이 되는 거야. 1과 0 이렇게 두 가지 만으로 구분되는 것이지.
위의 그림처럼 어떤 부품에 전선이 8개 붙어 있는 데 빨간 번개 표시가 전기가 들어와 있는 상태라고 하면 위로부터 1, 0, 1, 1, 0, 1, 0, 1 이렇게 8개의 정보를 나타내고 있는 것이야. CPU가 처리해야 할 명령을 이런 수의 조합으로 읽게 되고, 그 다음 명령은 일정 시간이 지난 후에 각각의 전선에서 전기의 유무를  다시 읽고, 또 일정 시간이 지난 후에 각각의 전기 유무를 다시 읽고... 이런 식으로 진행되는 것이야. 전선의 전기 유무의 조합이 사람 눈으로는 도저히 구별할 수 없을 정도로 매우 빠른 박자를 타고 바뀌는데, 이 박자의 빠르기가 우리가 이야기하는 CPU의 속도를 말하는 거야. 1GHz(기가헤르쯔) 속도의 CPU는 1초에 10억 번 숫자의 조합을 바꾸어가면서 처리할 수 있는 거지!

2진수와 16진수

이와 같이 0과 1 두 가지만 가지고 표현하는 수를 2진수라고 해(예전에 이미 배운 것임). 2진수라는 것을 알아야 하는 이유는 앞에서 얘기한 것처럼 컴퓨터 내부에 존재하는 정보는 전기가 있다/없다의 2가지 상태를 조합해서 존재하는 것이기 때문에 수학에서 배운 2진수를 사용하면 참 편하기 때문이지.
일반적으로 우리가 사용하는 숫자(10진수)는 한 자리에 10개의 숫자(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)를 사용하고 11번째 숫자가 없기 때문에 자리 수를 올려 10, 11, 12, 13, ... 이런 식으로 쓰잖아? 2진수는 한 자리에 2개의 숫자(0, 1)만 사용하기 때문에 자리 수가 올라가는 속도가 장난이 아니야. 2진수로 0부터 숫자를 표시해 보면 아래와 같아.
2진수10진수
00
11
102
113
1004
1015
1106
1117
10008
10019
101010
101111
2진수는 컴퓨터의 내부 사정을 가장 정확하게 표현할 수 있는 장점이 있지만, 이걸 진짜 쓰려면 공간도 많이 차지하고 또 사람 입장에서는 엄청 헷갈리기 때문에 2진수를 4자리 씩 묶어서 16진수로 사용하는 것이 일반적이야. 2진수가 4자리이면 2*2*2*2=16이지? 수학에서 경우의 수 배울 때를 생각하면 알 수 있어. 16진수는 한 자리에 16개의 숫자를 사용하는데 0에서 9까지는 보통 숫자와 같고 그 뒤의 6개는 알파벳 A에서 F까지를 사용하지.
2진수10진수16진수
000
111
1022
1133
10044
10155
11066
11177
100088
100199
101010A
101111B
110012C
110113D
111014E
111115F
100001610
2진수, 16진수는 써 놓고 보면 이게 2진수인지 10진수인지 또 16진수인지 알 수 없기 때문에 컴퓨터 프로그래밍을 할 때에는 2진수는 앞에 0b, 16진수는 앞에 0x를 붙여서 쓰도록 되어 있어. 10진수는 평소처럼 그냥 편하게 쓰면 되. 예를 들면 13(10진수)는 0b1101(2진수) 혹은 0xD(16진수)처럼 되는 것이지.

수학 계산을 익숙하게 할 수 있으려면 구구단 정도는 외우고 있어야 하는 것처럼, 프로그램을 만드는 일을 하려면 16진수를 능수능란하게 읽고 쓸 수 있어야 해. 2진수 혹은 16진수를 10진수로 바꾸어 보는 연습을 하면 2의 거듭제곱이 되는 수가 자주 나오는데 이것도 눈에 익혀두어야 해.

문제

1. 다음의 10진수를 2진수로 표시하시오.
   (1)  21  (2) 42  (3) 128 (4) 255
2. 다음의 16진수를 10진수로 표시하시오.
   (1) 0x20  (2) 0xABC (3) 0x1000 (4) 0xFFFF
3. 위의 '어떤 부품' 그림에서 나타낸 값을 10진수로 표시하시오.

2014년 3월 22일 토요일

VS2010 MFC App에서 OpenCV 메모리 누수 문제

MFC App에 OpenCV를 링크에서 사용할 때 Debug 모드에서 프로그램 종료 시 메모리 누수(memory leak) 리포트를 볼 수 있다. 증상을 보면 실제 메모리가 누수되는 것이 아니고 _CrtDumpMemoryLeaks()가 호출되는 시점이 OpenCV DLL이 정리되는 시점보다 빨라서 발생하는 false alarm으로 보인다. 따라서 무시하고 개발을 강행하고 나서 Release build를 사용해도 되겠으나 그렇게 하면 내가 작성한 코드에서의 버그에 의해 발생하는 메모리 누수를 디버깅하기 어렵게 된다.

이 문제에 대해 검색을 해보니 제시되고 있는 해결 방법은 아래와 같이 3가지로 요약된다.

  1. MFC DLL을 링크하도록 OpenCV를 rebuild하여 사용한다. (opencv_core에 afx.h를 include하는 등의 약간의 소스 수정 포함 - 자료 출처)
  2. MFC를 static library로 사용한다.
  3. OpenCV를 delay load로 사용한다.
위의 방법들을 실제로 시도해보았으나 OpenCV 이외의 함께 사용하는 3rd party library들의 상황에 따라 여의치 않은 문제가 있다. 그래서 가장 변경 범위가 적은 3번 방법을 사용하여 보았으나 그래도 메모리 누수 리포트가 발생한다.

하나하나 원인을 점검하다 보니, Visual Studio에서 default로 만든 MFC Application이 유니코드로 되어 있어 C런타임이 MSCVR?UD.dll 로 연결되나, OpenCV는 MSVCR?D.dll로 연결되기 때문이 아닌가 싶다. OpenCV를 유니코드 프로젝트로 다시 빌드하는 것은 std::string 부분에서 많은 에러가 나서 포기하고, 어쩔 수 없이 내 MFC Application을 MBCS로 전환하니 메모리 누수 (리포트) 현상이 사라졌다. 요약하면,
  
  1. OpenCV를 사용하기 위해 Unicode App로 작성하는 것을 포기
  2. opencv_core 등의 dll을 링커(Linker)/입력(Input) 항목의 '지연 로드된 DLL(Delay Loaded DLLs)'에 등록한다.

ClearPath Protocol Tester

ClearPath사의 무인 자동차 플랫폼인 Husky A200를 실험용으로 사용하였다.


제조사에서는 C++ 및 Python으로 배포되는 SDK를 이용하거나 ROS 공식 빌드에 포함된 Husky 관련 패키지를 사용하도록 안내하고 있다. 하지만 실험 내용과 실험용으로 개발하는 소프트웨어 구성 및 사용하는 센서들의 조합 등의 문제 때문에 Husky를 직접 제어하는 것이 필요하게 되었다.

ClearPath 홈페이지에 등록하여 내려받을 수 있는 직렬 통신 규약(clearpath_control_protocol_v1.1)에서 규정된 모든 command/request/data 메시지를 주고 받을 수 있도록 tool을 제작하였다.




사용법은 설명이 따로 필요없을 것 같다. Request Message의 경우 Hz 값에 0을 넣으면 1회 조회, 1~65534는 해당 주기로 반복 조회 설정, 65535는 반복 조회 해제가 된다.

MS Office 내에서 수식편집기 입력방법

파워포인트/워드에서 수식 입력할 때 Toolbar(리본) 버튼을 누르면서 작업을 하면 마우스와 키보드를 오가면서 시간이 많이 낭비된다.
구글링을 통해 키보드만으로 수식을 입력하는 방법을 찾아보았다. 이상하지만, 아무리 찾아도 오피스의 수식 입력기 단축키에 대해 공식적으로 정리된 매뉴얼은 없는 것 같다...

수식 입력기 호출하기

Alt키를 눌러 리본 메뉴에 표시되는 내용을 확인해도 알 수 있지만, Alt+N+E+I 단축키로 수식입력기를 호출한다.(워드의 경우) 그러나, 파워포인트의 경우 미리 정의된 몇 가지 수식들을 선택하는 팝업까지 표출될 뿐 결국 마우스를 사용해야 했다.

발견된 몇 가지 원칙

  1. 직관적으로 납득이 갈 만한 수학 기호들을 사용한다.
  2. 항목 별로 수식 모양을 완성하기 위해서는 스페이스 바를 누른다. 앞서 입력한 내용이 수식 완성에 해당하는 것이라면 공백 문자가 추가되지 않고 수식 모양이 바뀐다.
  3. 탈출문자(esacpe character)로 역슬래시(backslash)를 사용한다.
위의 원칙을 가지고 이런 저런 시도를 해보면 어렵지 않게 익숙해지게 된다.

간단한 수식 만들기

※ 아래의 □는 스페이스바를 누르는 것을 의미한다

  • 분수: x/y□  (x+a)/(y+c)□
  • 아래 첨자: x_y□
  • 위 첨자: x^y□
  • 제곱근: \sqrt□ \sqrt(x+y)□
  • 적분: \int□
  • 시그마: \sum□
  • 삼각함수: \sin□  \sin^-1□ 등
  • 행렬: \matrix□ \matrix(@&)□ [\matrix(@&)]□

특수 기호 입력하기

  • 악센트: \hat□□  \dot□□ \ddot□□ \vec□□ \tilde□□
  • 그리스문자: \Alpha□ \alpha□ 등
  • 기타기호: \pm□ \infty□ \ne□ \times□ \div□ \bullet□ 등

등호(=)를 기준으로 정렬하기


연립 방정식과 같이 수식을 여러 줄 표시할 때 등호를 기준으로 가로 정렬을 하고 싶을 경우에는
  1. 함께 정렬할 수식에서 줄 바꿈할 때 Shift+Enter를 사용한다. 이것은 아래 줄의 수식을 위 줄과 같은 그룹으로 인식한다.
  2. 정렬할 등호 앞에 &(ampersand)를 추가한다. 즉, A &= 1 와 같이 입력한다.
  3. 수식을 Professional type으로 변경한다. 이것은 수식 리본 메뉴에서 [도구]의 [2차원 형식] 버튼을 사용하거나, 수식 위를 우클릭하여 나타나는 팝업 메뉴에서 [수학옵션][전문가용] 메뉴를 사용한다.


출처

ROS 시작하기

ROS Tutorial(http://wiki.ros.org/ROS/Tutorials/)에 있는 용어 및 필수 개념에 대해 요약

노드(nodes) 다른 노드와 통신을 하기 위해 ROS를 사용하는 실행 파일
메시지(messages) 토픽(topic)에 가입(subscribe) 혹은 게시(publish)할 때 사용되는 ROS의 데이터 형식
토픽(topic) 노드 사이에서 메시지를 주고 받게 해 주는 매개체
서비스(services) 요청(request)을 다른 노드에 보내거나, 다른 노드로부터 응답(response)을 받음
마스터(master) 노드에 이름으로 지정할 수 있게 해주는 서비스

rospack 패키지에 대한 정보 조회
find 패키지가 설치된 위치의 디렉터리 경로를 표시
roscd 패키지나 스택의 디렉터리로 이동
rosls 절대 경로를 지정하지 않고 패키지 디렉터리에서 ls 실행
roscp [package_name] [file_to_copy_path] [copy_path]

rosout ROS에서 stdout/stderr 역할을 함
roscore 마스터 + rosout + 파라미터 서버
rosnode 노드에 대한 정보 표시 도구
ping 노드에 대한 연결 테스트
list 활성화된 노드 목록 표시
info 노드에 대한 상세 정보 표시
machine 특정 기계에서 실행 중인 노드 목록을 표시하거나, 기계 자체 목록 표시
kill 실행 중인 노드를 종료 시킴
cleanup 연결이 끊어진 노드에 대해 등록된 정보를 삭제
rosrun (패키지에 대한 경로를 지정할 필요 없이) 소속된 패키지 이름과 노드 명 만으로 노드를 실행시킴
rostopic 토픽에 대한 정보 조회
bw 토픽에서 사용 중인 밴드폭 표시
echo 메시지를 화면에 표시
hz 토픽의 게시 주기를 표시
list 활성화된 토픽들의 목록 표시
pub 토픽에 데이터 게시
type 토픽의 형식 표시
rosmsg ROS 메시지 형식에 대한 정보 표시 도구
show 메시지 설명 표시
list 모든 메시지 목록 표시
md5 메시지의 md5 체크섬 표시
package 패키지 내의 메시지 목록 표시
packages 메시지를 포함하는 패키지 목록 표시
rosservice
list 활성화된 서비스에 대한 정보 표시
call 인자(argument)와 함께 서비스를 호출
type 서비스 형식을 표시
find 서비스 형식으로 서비스를 찾음
uri 서비스의 ROSRPC uri를 표시
rosparam ROS 파라미터 서버에 데이터를 저장하거나 조작한다
set
get
load
dump
delete
list
roslaunch 노드를 launch file에서 정의된 바에 의해 실행
rosed 절대 경로를 지정하지 않고 패키지 디텍터리 내의 파일을 편집

msg ROS 메시지의 필드를 기술하는 텍스트 파일. 서로 다른 언어에서 메시지에 대한 소스 코드를 생성하는데 사용한다.
srv 서비스를 기술하는 파일. 요청과 응답 2가지 부분으로 구성된다.

rosbag 토픽의 내용을 로그로 기록 및 재생한다.
roswtf ROS 관련 오류를 분석하여 표시한다.

행렬의 선형대수 용어

논문을 읽을 때나 쓸 때나 사용되는 수식의 대부분은 행렬 연산이다. 방법은 알아도 행렬 연산과 관련된 용어가 기억나지 않아서 곤란하게 된다. 학부 때 공부했던 Advanced Engineering Mathematics Chapter 6~7 (Erwin Kreyszig)의 내용 중에서 행렬의 기본적인 용어에 대해 공부해보자.

  • matrix - rectangular array of numbers enclosed in brackets
  • row - horizontal line in matrix
  • column - vertical line in matrix
  • row|column vector - matrix which consists of a single row|column
  • square matrix - matrix which has as many rows as columns
  • rectangular matrix - matrix that is not square
  • main(principal) diagonal - diagonal entries a11, a22, a33, ..., ann of square matrix
  • transposition - transpose of A of mxn matrix [ajk] is nxm matrix that has the first row of A is as its first column, the second row of A as its second column, and so on.
  • matrix addition - for matrices A and B of the same size, A+B is obtained by adding the corresponding entries
  • scalar multiplication - product of mxn matrix A and any scalar c, written cA, is obtained by multiplying each entry in A by c
  • zero matrix - matrix with all entries zero
  • matrix multiplication - product C=AB(in this order) of an mxn matrix A and an rxp matrix B is defined if and only if r=n and is defined as the mxp matrix C with entries cjk=aj1b1k+aj2b2k+...+ajnbnk. "multiplication of rows into columns". The matrix B is premultiplied, or multiplied from the left, by A. A is postmultiplied, or multiplied from the right, by B
  • triangular matrix - upper triangular matrices are square matrices that can have nonzero entries only on and above the main diagonal, whereas any entry below the diagonal must be zero. lower triangular matrices can have nonzero entris only on and below the main diagonal.
  • diagonal matrix - square matrix that can have nonzero entries only on the main diagonal
  • scalar matrix - all the diagonal entries of a diagonal matrix S are equal
  • unit(identity) matrix - scalar matrix whose entries on the main diagonal are all 1
  • inner product - single entry given by matrix multiplication if a is a row vector and b a column vector, both with n components
  • stochastic matrix - a square matrix with nonnegative entries and row sums all equal to 1
  • Markov process - a stochastic process for which the probability of entering a certain state depends only on the last state occupied (and on the matrix governing the process)
  • linear system - a linear system of m equations in n unknowns x1, x2, ..., xn is a set of equations of ai1x1 + ... ainxn=bi
  • coefficients - number ajk of the system
  • homogeneous system - linear system if the bi are all zero
  • nonhomogenouse system - linear system if at least one bi is not zero
  • solution - a set of numbers x1, ..., xn that satisfies all the m equations
  • solution vector - a vector x whose components constitute a solution of linear system
  • augmented matrix - augmenting coefficients matrix A by the column b
  • Gauss elimination - a systematic elimination process and a standard method for solving linear systems
  • pivot equation - an equation used in eliminating the other equations by Gauss's method
  • partial pivoting - exchanging the order of equations
  • total pivoting - the order of the equations and unknowns are changed
  • back substitution
  • elementary row operation - interchange of two rows, addition of a constatnt multiple of one row to another row, multiplication of a row by a nonzero constant c
  • row-equivalent system - a linear system S1 is row-equivalent to a linear system S2 if S1 can be obtained from S2 by elementary row operations
  • overdetermined - if a linear system has more equations than unknowns
  • determined - if a linear system has as many equations as unknowns
  • underdetermined - if a linear system has fewer equations than unknowns
  • echelon form - the form of the system and of the matrix in the last step of the Gauss elimination
  • linearly independent - vectors a(1), ..., a(n) is linearly independent if it has the only m-tuple of scalars with all cj's zero that holds the equation of linear combination c1a(1)+c2a(2)+...+cma(m)=0
  • linearly depdenent - vectors a(1),,,,a(n) can be expressed at least one of them as a linear combination of the others
  • rank of matrix - the maximum number of lineraly independent row vectors of a matrix
  • vector space - a nonempty set V of vectors such that with any two vectors a and b in V all their linear combinations αa+βb are elements of V, and these vectors satisfy the laws - commutative, distributive, associative.
  • dimension of vector space - the maximum number of lineary independent vectors in a vector space
  • basis - a linearly independent set in vector space V consisting of a maximum possible number of vectors in V
  • span - the set of all linear combinations of given vectors a(1),...,a(p) with the same number of components
  • subspace - a nonempty subset of vector space V that itself forms a vector space with respect to the two algebraic operations defined for the vectors of V
  • row|column space - the span of the row|column vectors of a matrix
  • solution(null) space - vector space (of dimension n-r) formed by solutions of homogeneous linear system(mxn) whose rank is r
  • nullity - dimension of null space of linear homogeneous system
  • determinant - a scalar associated with an nxn matrix A, D=aj1Cj1+aj2Cj2+...+ajnCjn=a1kC1k+a2kC2k+...+ankCnk where Cjk=(-1)^(j+k)*Mjk
  • submatrix - matrix Mjk is obtained from matrix A by deleting the row and column of the entry ajk
  • minor - submatrix Mjk in determinant D
  • cofactor - Cjk in determinant D
  • inverse - inverse of an nxn matrix A=[ajk] is denoted by A^-1 and is an nxn matrix such that A*A^-1=A^-1*A=I where I is the nxn unit matrix. inverse of A exists if and only if rank A=n or det A≠0
  • nonsingular matrix - matrix which has an inverse
  • singular matrix - matrix which has no inverse
  • mapping(transformation or operator) - To each vector x in vector space X, a unique vector y in vector space Y can be assigned
  • image - the vector y in Y assigned to vector x in X
  • linear mapping(linear transformation) - if for all vectors v and x in X and scalars c, F(v+x)=F(v)+F(x) and F(cx)=cF(x)
  • eigenvalue(characteristic value) - a scalar value λ for which a solution x≠0 of the vector equation Ax=λx. The eigenvalues of a square matrix A are the roots of the characteristic equation of A.
  • eigenvector(characteristic vector) - a vector solution x≠0 of the vector equation Ax=λx
  • spectrum - the set of the eigenvalues
  • spectral radius - the largest absolute values of the eigenvalues
  • eigenspace - a vector space formed by the set of all eigenvectors corresponding to an eigenvalue, together with 0
  • eigenvalue problem - the problem of determining the eigenvalues and eigenvectors of a matrix
  • characteristic determinant(characteristic polynomial) - D(λ)=det(A-λI)
  • characteristic equation - D(λ)=0
  • algebraic multiplicity - the order Mλ of an eigenvalue λ as a root of the characteristic polynomial
  • geometric multiplicity - the number mλ of linear independent eigenvectors corresponding to λ
  • defect - the difference Δλ=Mλ-mλ
  • symmetric matrix - square matrix whose transpose equals the matrix : A^T=A
  • skew-symmetric matrix - square matrix whose transpose equals the minus matrix : A^T=-A
  • orthogonal - square matrix if its transposition gives the inverse of itself : A^T=A^-1
  • orthogonal transformation - y=Ax with A an orthogonal matrix. orthogonal transformation preserves the value of inner product of vectors and also the length or norm of a vector
  • similarity transformation - A=P^-1AP where P is nonsingular nxn matrix

어안렌즈 카메라 모델링

일반적으로 많이 사용하는 pin hole camera model은 광선의 직진성을 가정하며, 대부분의 camera calibration tool들은 이를 기반으로 동작한다. 이러한 경우 perspective projection을 모델링한 camera matrix 및 렌즈/센서의 제조 상 오차를 반영한 distortion coefficient로 수식화 할 수 있다.

어안 렌즈(Fish eye lens)의 경우 광선이 직진하지 않고 굴절하기 때문에 distortion coefficient 중의 radial distortion 만으로 정확한 calibration 결과를 얻기 어렵다.

 

위의 그림에서 어안 렌즈를 대표적인 수식으로 표현하면 d = f * θ 가 되는데 이를 f-theta 모델이라고 한다. pin hole 카메라는 d = f * tanθ 로 나타낼 수 있다.

f-theta 모델의 어안 렌즈로 촬영한 영상을 가공하기 위해서는 위의 식을 기반으로 모델 좌표와 이미지 좌표의 대응 관계를 유도해야 한다. 예를 들어, 수평 방향으로 촬영한 영상으로부터 top view를 얻기 위해서는

 

Focal length가 f인 어안 렌즈로 촬영된 이미지 상의 점 m과, 카메라의 지면으로부터의 높이가 R일 때 대응하는 지면 상의 점 M과의 관계는, m과 M의 3차원 좌표가 각각 m(u,f,v) M(x,y,R)이라 할 때,

F-theta 모델
에서, d는 이미지 평면 원점에서 (u,v)까지의 거리이고 theta는 좌표 원점과 M 및 M'으로 이루어지는 삼각형을 이용하면
를 알 수 있고 이를 대입하여 풀면,
와 같이 구할 수 있다.