기계식키보드 Leopold FC700RT 갈축 사용기

😢 이 페이지는 다음 주소로 변경될 예정입니다.

Leopold FC700RT

2013년 2월 한국 다녀올 당시 레오폴드 키보드를 구입해서 왔다. 당시 회사에서 사용했던 이상한 키배열의 삼성 노트북 이후 키보드에 관심이 생겨서 관련 글을 읽다보니 기계식 키보드에 대해 좋은 인상을 받아 구입했다.

구입할 때 직접 타건해보고 구입하지 못하는 상황이었다. 그래서 타건 영상을 보고 타이핑 소리를 가늠해야 했는데 다들 청축은 지나치게 시끄럽고 적축은 오타율이 높다는 얘기를 듣고 갈축을 선택했다. 다른 키보드 경험이 없어 딱히 비교하기 어려운데 간단하게 적어보자면 다음과 같다.

  • 소리가 좋다. 그래서 가끔 사무실이 조용하면 사용하기 민망하다.
  • 기계식 키보드라 그런지 키보드 자체가 무겁다. 덕분에 키보드가 밀리거나 하지 않는다.
  • 키배열이 윈도 배열이라 맥 단축키가 불편할 때가 있다. (바인딩으로 해결 안되는 부분)
  • 타이핑하는 양이 많아질 때 일반 키보드에 비해 손에 무리가 덜 간다.
  • 키는 여전히 하얗지만 본체는 약간 노란 빛이 감돌기 시작했다.

처음엔 집에서 사용했는데 이제 사무실에 가져다놓고 가상머신에서 윈도우 작업할 때 주로 사용하고 있다. 사무실에서 사용할 때 맥 키보드랑 혼용해서 사용하고 있다. 가장 큰 이유는 키보드 바인딩 문제인데 F1~12의 펑션키를 맥 키보드의 기능처럼 쓰게되면 해당 function키가 정상적으로 동작하지 않는다거나 생각처럼 깔끔하게 바인딩이 되질 않아 어쩔 수 없이 혼용하고 있다.

키보드 비교

전반적으로 키보드는 만족스럽지만 키보드 사용량이 그렇게 많지 않다면 크게 유의미하진 않은 것 같다. 만약 내가 vim이나 emacs를 잘 사용할 줄 안다면 더 재미있게 사용할 수 있지 않았을까. 코드든 글이든 타이핑을 많이 하는 사람이라면 사용해보는 것도 나쁘지 않다.

아직 키를 분리해서 청소해보진 않았는데 조만간 날 잡아서 분리하고 청소를 해야겠다.

Mac에서 OpenCV 설치 및 예제 구동하기

😢 이 페이지는 다음 주소로 변경될 예정입니다.

주말에 아티클을 보다가 관심이 생겨 OpenCV를 잠깐 살펴봤다. OpenCV는 Computer Vision 오픈소스 라이브러리로, 제공하는 예제를 통해 Face Tracking 등을 구현해볼 수 있다. 초보자를 위한 튜토리얼은 많은데 생각처럼 잘 안되는 부분들이 있어 이 글을 작성했다. 이 글에서는 Mac OSX, xcode를 사용했다.

OpenCV는 brew를 통해서도 설치할 수 있는데, 내가 놓치고 있는 부분이 있는지 잘 안되서 리포지터리에서 받아 컴파일했다.

먼저 컴파일을 위해 cmake를 brew로 설치한다.

$ brew install cmake

리포지터리를 복제한 후 build, install까지 진행한다.

$ git clone https://github.com/Itseez/opencv.git && cd opencv
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" ..
$ make -j8
$ sudo make install

이렇게 설치는 완료된다. /usr/local/lib에 설치된 libopencv-*.dylib를 확인할 수 있다.

예제 구동 과정

예제 코드를 그대로 실행하면 바로 되어야 하는데, 리포지터리에 올라가 있는 예제 프로젝트는 xcode 버전 문제로 열리지 않았다. 다음과 같은 과정으로 예제 코드를 확인할 수 있다.

  1. XCode를 실행해 Command Line Tool 프로젝트 생성
  2. Project Navigator에서 우클릭, “Add File To…” 클릭
  3. 파일 선택창이 뜨면 “/”를 입력해 네비게이션 패널을 불러와 /usr/local/lib을 입력
  4. libopencv_<어쩌고>.dylib 을 모두 선택. (아래 예제에서는 core, highgui, imgproc, objdetect만 있어도 구동 가능.)
  5. 프로젝트 파일을 눌러 Build Settings에서 “Header Search Paths”에 /usr/local/include, “Library Search Paths”에 /usr/local/lib을 추가.
  6. 예전 버전의 cascade를 내려받음
  7. 프로젝트 파일을 눌러 Build Phases > Copy Files에 위에서 받은 xml 파일을 추가하고 “Destination”을 Products Directory로 설정

위 과정을 끝내고 나면 main.cpp를 열어 코드를 다음과 같이 작성한다. 이 코드는 opencv 리포지터리에 있는 MacOSX 예제 코드다.

#include <CoreFoundation/CoreFoundation.h>
#include <cassert>

// Example showing how to read and write images
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

const char  * WINDOW_NAME  = "Face Tracker";
const CFIndex CASCADE_NAME_LEN = 2048;
char    CASCADE_NAME[CASCADE_NAME_LEN] = "~/haarcascade_frontalface_alt2.xml";

using namespace std;

int main(int argc, char** argv)
{

    const int scale = 2;

    // locate haar cascade from inside application bundle
    // (this is the mac way to package application resources)
    CFBundleRef mainBundle  = CFBundleGetMainBundle ();
    assert (mainBundle);
    CFURLRef    cascade_url = CFBundleCopyResourceURL (mainBundle, CFSTR("haarcascade_frontalface_alt2"), CFSTR("xml"), NULL);
    assert (cascade_url);
    Boolean     got_it      = CFURLGetFileSystemRepresentation (cascade_url, true,
                                                                reinterpret_cast<UInt8 *>(CASCADE_NAME), CASCADE_NAME_LEN);

    if (! got_it)
        abort ();

    // create all necessary instances
    cvNamedWindow (WINDOW_NAME, CV_WINDOW_AUTOSIZE);
    CvCapture * camera = cvCreateCameraCapture (CV_CAP_ANY);
    CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*) cvLoad (CASCADE_NAME, NULL, NULL, NULL);
    CvMemStorage* storage = cvCreateMemStorage(0);
    assert (storage);

    // you do own an iSight, don't you ?!?
    if (! camera)
        abort ();

   // did we load the cascade?!?
    if (! cascade)
        abort ();

    // get an initial frame and duplicate it for later work
    IplImage *  current_frame = cvQueryFrame (camera);
    IplImage *  draw_image    = cvCreateImage(cvSize (current_frame->width, current_frame->height), IPL_DEPTH_8U, 3);
    IplImage *  gray_image    = cvCreateImage(cvSize (current_frame->width, current_frame->height), IPL_DEPTH_8U, 1);
    IplImage *  small_image   = cvCreateImage(cvSize (current_frame->width / scale, current_frame->height / scale), IPL_DEPTH_8U, 1);
    assert (current_frame && gray_image && draw_image);

    // as long as there are images ...
    while ((current_frame = cvQueryFrame (camera)))
    {
        // convert to gray and downsize
        cvCvtColor (current_frame, gray_image, CV_BGR2GRAY);
        cvResize (gray_image, small_image, CV_INTER_LINEAR);

        // detect faces
        CvSeq* faces = cvHaarDetectObjects (small_image, cascade, storage,
                                            1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
                                            cvSize (30, 30));

        // draw faces
        cvFlip (current_frame, draw_image, 1);
        for (int i = 0; i < (faces ? faces->total : 0); i++)
        {
            CvRect* r = (CvRect*) cvGetSeqElem (faces, i);
            CvPoint center;
            int radius;
            center.x = cvRound((small_image->width - r->width*0.5 - r->x) *scale);
            center.y = cvRound((r->y + r->height*0.5)*scale);
            radius = cvRound((r->width + r->height)*0.25*scale);
            cvCircle (draw_image, center, radius, CV_RGB(0,255,0), 3, 8, 0 );
        }

        // just show the image
        cvShowImage (WINDOW_NAME, draw_image);

        // wait a tenth of a second for keypress and window drawing
        int key = cvWaitKey (100);
        if (key == 'q' || key == 'Q')
            break;
    }

    // be nice and return no error
    return 0;
}

코드를 빌드 및 실행하면 앱이 실행되어 얼굴의 위치를 트래킹하는 모습을 확인할 수 있다. (신기해!)

트러블 슈팅

  • CASCADE_NAME~로 시작하지만 컴파일된 파일을 기준으로 하는 상대 경로.
  • cvLoad()에 에러가 생길 땐 xml 경로, 파일명 문제, 디버깅용 라이브러리를 넣었을 때 등의 문제라고. 내 경우에는 최신 버전의 xml이라서 에러가 났다. 위 과정처럼 구버전의 xml을 쓰면 구동은 되지만 별로 내키지 않는 해결 방법. (코드는 개선되었는데 예제는 예전 방식으로 되어 있다거나 한 것 같다.)