[펌] “달라붙는 로봇” 발명자 김상배

김상배씨는 아버지에 대한 기억이 없다. 한양대 법정대 교수였던 아버지 김원국씨는 김씨가 태어난지 두달 만에 숨졌다. 친구들과 승용차로 여행을 가다가 경기도 이천의 국도에서 마주오던 버스와 충돌한 것이다. 그래서 그는 형과 함께 홀어머니 슬하에서 자랐다.

그로부터 31년이 지난 현재 김씨는 미국의 스탠퍼드대 기계공학과에서 박사과정을 밟고있다. 내년이면 학위를 받게된다. 연세대 기계공학과를 졸업하고 도미한지 5년 만이다.

김씨는 요즘 유명세로 밤잠을 설친다. 그가 개발한 도마뱀 로봇 때문이다. 동영상 사이트 ‘유튜브’에 소개된 뒤 지난달 포브스지에 기사가 실렸고 13일자 타임지에 ‘올해 최고의 발명품’ 44개 중 하나로 선정돼 언론매체의 인터뷰 요청이 쇄도하고 있다. 내년 초에는 그와 그의 발명품이 PBS의 특별 프로그램에도 소개된다.

그의 도마뱀 로봇은 유리벽을 수직으로 올라갈 수 있어 ‘스티키봇(Stickybot)’으로도 불린다. ‘달라붙는 로봇’이란 의미다. 김씨는 “한번 달라붙으면 절대 떨어지지 않으면서 발걸음을 옮길 때면 너무나 사뿐하게 움직이는 도마뱀의 발바닥에서 영감을 얻었다”고 말했다. 스티키봇의 발바닥은 미세한 섬유조직으로 이뤄져있다. 털모양 섬모의 끝부분은 한 방향 만을 보게끔 경사지게 처리됐다. 섬모의 끝부분이 접지된 상태에서 경사면 방향으로 잡아당기면 마찰력이 엄청나게 커지기 때문에 유리벽에서도 떨어지지 않고 지탱할 수 있다. 대신 반대편으로 잡아당기면 손쉽게 떼어낼 수 있는 원리다.

김씨는 스티키봇에 대해 특허출원을 마친 상태다. 포스트잇과 같은 메모 용지 등에 스티키봇의 아이디어를 접목시키면 엄청난 시장효과를 불러올 수 있다는 평가를 받고 있다. 그는 지난해 개발한 재난구조용 로봇 등 모두 4건의 특허를 갖고있다.

창의력이 어디서 나오는지 궁금했다. 그는 “아버지가 안계셔서 대부분의 결정을 혼자 내리는데 익숙하다 보니 남들보다 여러가지 생각을 하는 습관이 몸에 배었다”고 답했다. 형 상필씨는 현재 미국 퍼듀대 산업공학과에서 박사과정을 밟고있다. 이들 형제의 뒤에는 항상 자식 생각만 하는 어머니가 있다. 서울 합정동에서 홀로 지내는 어머니 이영애씨는 “상배는 어렸을 때 장난감 비행기 대회에 나가 1등을 하는 등 손재주와 창의력이 뛰어났다”며 “하늘에 계신 아버지도 매우 흡족해 할 것”이라고 말했다.

출처: 미디어다음, media.daum.net

너 “또라이”지?

오늘 문제의 원인을 알고 내가 나한테 던진 말이다.

“너.. 또라이지?” ㅋㅋ

문제는 MySQL에서 BLOB Type으로 데이터를 저장한 후에 읽어보니 전체 데이터가 아닌 일부만 읽혀지는 것이였다. 테이블에 저장한 그림파일의 크기는 195,881KB. 그런데 읽혀지는 데이터 길이는 65,535KB. 저장할때 잘못된 건지.. 읽어올때 잘못된 것인지 고민하다가 이것저것.. MySQL 환경설정 파일도 건드려 보고 말이다. 환경설정 파일을 보고 MySQL… 이거 제대로 쓸라면 공부할거 너무 많은것 같다.. 라는 부담스런 생각도 들고… 뭐 여튼… 아무리 인터넷을 찾아봐도 BLOB 데이터가 전부 오지 않는 이유는 찾을 수가 없었다. 구글신에게 도움을 요청해도 없다는건…. 뭔가 이유가 “얼토당토” 않은 것이라는 확율이 90%이상이란 말인데… 하지만 여전이 나는 “MySQL 이놈이 분명이 BLOB 데이터의 크기를 제한하고 있는게 분명해. 봐… 65,535KB만 보내주잔아? 즉, 64K만 보내주고 있다구.. 분명 환경설정에서 전송 크기를 늘려주는 환경변수가 있을 것이고 그것만 늘려주면 될것야..”라고 확신하며 그다지 흥미롭지 않은 MySQL 환경 변수만을 뒤지기 시작했으나.. 도대체 이놈이다 싶은 놈이 없었다. 음… 혹시 BLOB의 최대 크기가 64KB아냐? 라는 생각에 찾아보니 그냥 BLOB만 있는게 아니라 TINYBLOB, MEDIUMBLOB, LONGBLOB 라는 Type도 있는게 아닌가.. 각각의 최대 크기를 보니까

  • BLOB는 2^16-1KB
  • TINYBLOB는 2^8-1KB
  • MEDIUMBLOB는 2^24-1KB
  • LONGBLOB는 2^32-1KB

였다. 봐.. 다 “65,535KB보다 크잔아..”라고 자신있게 확신한 후에, 역시 원인은 MySQL의 환경변수에 있어 하고 있는데..  근데 2^16이 몇이지? 라는 생각에 계산기를 뚜드려보니.. 2^16 = 65536 !! 으아~~ ㅜ_ㅜ 저 또라이 맞죠? ㅠ_ㅜ 그데 쓰고보니 또라이는 좀 심했다는 생각에 또 다시 ㅠ_ㅠ

나 이제 퇴근할래.. 지하철 끊기기 전에~

동적화소변화율을 고려한 움직이는 물체검출

지난주에 OpenCV를 이용해 화상카메라로부터 영상을 받아, 움직이는 물체를 검출해 보는 코드를 작성해 보았는데, 여기에 자동으로 움직이는 물체가 있을 시에 그 영상을 캡춰받아 자동으로 저장하도록 해보았다.

회사에서 퇴근하는 아무개님(초상권을 위해 모자이크 처리 ㅡㅡ;)
문제는 영상에서 움직이는 물체가 있는지 없는지의 기준이 필요한데, 그 기준을 동적화소변이율을 사용하였다. 동적화소변이율은 영상을 구성하고 있는 전체 화소값(0~255)에서 변화된 화소값의 차이를 다시 백분율로 계산한 것이다. 이 동적화소변화율은 그냥 어찌 저찌 해서 직접 만들어낸 공식이므로 영상관련 책을 암만… 찾아봐도 않나온다. ㅡ_ㅡ; 그래서 자세한 수식을 제시하면…

동적화소변이율=((모든 바뀐 픽셀 차이값의 합)/(영상을 구성하는 픽셀수*255))*100

사용하고 있는 화상카메라를 기준으로 했을때 동적화소변이율이 0.5% 미만일 경우 화면상에 움직이는 물체가 없다고 판단했을때 정확히 일치했다. 그리고 0.5이상일때부터 영상에 움직이는 물체가 나타나기 시작했다가 1% 이상일때 움직이는 물체가 화면의 중앙에 위치한 상태였다. 동적화소변이율이 1%일때의 영상을 날짜와 시간을 파일명으로 해서 저장하도록 했다.

다음 단계는 움직이는 물체가 “누구(Who)”인지를 자동으로 판별해 내는 것..! 두둥~! 이를 위해 필요한 알고리즘은 무엇인가?

OpenCV를 이용한 움직이는 물체 검출하기

작년 8월쯤 (회사 입사때쯤이라 기억하고 있음)에 마소 잡지를 뒤적이던 중에 OpenCV라는 오픈소스의 Computer Vision 라이브러리를 알게 되었다. 이게 “물건”이구나라는 것을 느꼈고, 다운로드 받아 대충이라도 살펴 보았지만, 잠시 시간의 흐름과 함께 내 관심밖으로 밀려나갔다. 그러던중에… 요즘 오픈소스인 Ogre3D도 분석해보고 하던차에, OpenCV가 생각났다. GIS에서 위성영상이나 항공영상으로부터 데이터를 추출하는 등, 이미지 처리 분야는 매우 중요하고 앞으로 더욱 중요해질 것이다.

먼저 OpenCV가 뭐에 쓰는 물건인지는 알아서들 알아내시고…(뜨헉~ -_-;) 이번엔 OpenCV의 기능중 빙산의 일각인 화상카메라로부터 영상을 취득한 후에, 취득한 영상에서 움직이는 물체를 검출해보는 기능을 작성해 보았다. 매우 다양하고 효율적인 방법이 많이 있을지 모르겠지만, 당장 생각나는 방법은 현재 프레임 영상과 바로 이전 프레임 영상에 대한 같은 위치의 화소값을 비교해서 다르면 움직이는 물체에 대한 화소일 것이라는 아이디어로 접근해 보았다.

저거 내 왼손~

하지만 동일한 위치의 화소값이 두 프레임 이미지가 정확히 일치라는 비교는 무리가 있었다. 화상카메라에서 취득하는 영상은, 비록 움직이는 물체가 없을지라도 미세하게나마 연속된 프레임일지라도 다르게 취득되었다. 그래서 동일한 위치의 화소값의 차이가 어느 정도의 차이가 날때 움직이는 물체다.. 라는 기준으로 접근을 해 보았다. 결과는 처음치곤 만족할 만했다.

아래는 프레임 영상을 받아서 실제 움직이는 물체를 검출해주는 소스코드이다.

void OnFrame(IplImage* image) {	
    HDC hDC = GetDC(m_hWnd);
    SetDIBitsToDevice(hDC, 0, 0, image->width, image->height, 0, 0, 0, 
	image->height, image->imageData, (BITMAPINFO *)&m_bmpInfo,
         DIB_RGB_COLORS);	
    SetDIBitsToDevice(hDC, 330, 0, image->width, image->height, 0, 0, 0,
        image->height, image->imageData, (BITMAPINFO *)&m_bmpInfo,
        DIB_RGB_COLORS);

    IplImage* gray=cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
    cvCvtColor(image, gray, CV_BGR2GRAY);

    if(bHasOldImage) {
	HRGN hRgn = CreateRectRgn(330, 0, 330+320, 240);
	SelectClipRgn(hDC, hRgn);
	float CriticalValue = 15.0f;
	    for(int x=0; xwidth; x+=6) {  
		for(int y=0; yheight; y+=6) {   
		    uchar c1 = ((uchar*)(gray->imageData + 
			gray->widthStep*y))[x];   
		    uchar c2 = ((uchar*)(m_oldGrayImage->imageData +
                            m_oldGrayImage->widthStep*y))[x];
			
		    if(fabs(float((float)c1-(float)c2))>CriticalValue) 
		    {
			int X = 330+x;    
			int Y = image->height-1-y;    
			Rectangle(hDC, X-3, Y-3, X+3, Y+3);   
		    }  
		}
	    }
	DeleteObject(hRgn);
    }

    m_oldGrayImage=cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
    cvCvtColor(image, m_oldGrayImage, CV_BGR2GRAY );
    bHasOldImage = true;
    ReleaseDC(m_hWnd, hDC);
}

대략 설명해 본다면, 우선 OnFrame 함수는 OpenCV에서 화상카메라로부터 영상이 들어올때 실행되는 Callback 함수이다. 영상은 24비트로 들어오는데 속도와 계산을 간단하게 하기 위해서 8비트인 Gray로 변환하기 위해 cvGray를 사용하였다. 연속되는 프레임 영상의 같은 위치의 화소값을 비교하여 움직이는 물체에 대한 화소인지의 비교한 차이값으로 15를 사용하였음을 알 수 있다. 차이값이 15이상인 화소의 위치에 White Box를 그려주었다.