Density(밀도) Analysis

밀도맵에 대해 고민을 본격적으로 해보고 있는데, 먼저 내가 알고 있는 밀도맵이라는 개념은 틀린 것임을 알았다. 밀도맵이 아닌 밀도분석에 의한 결과라고 해야 옳겠다. 밀도맵은 아래처럼 지도의 영역을 통계수치값에 따라 다른 색상으로 구분해 놓은 맵을 말한다.


밀도 분석에 대해 관심을 가지게 된 이유는 이 밀도 분석을 구현해보고자 함이다. 그러기 위해서는 정확히 밀도 분석이라는 것이 무엇인가 부터 정확히 파악해야 어떤식으로 구현을 할지 알 수 있을 것이기 때문이다.

밀도 분석은 어떤 지점의 현상에 대한 측정된 수량(예를들어 인구수)을 지도 전체에 걸쳐 측정된 수량을 재분배를 해주는 것이다. 재분배는 지도를 일정한 간격의 Grid의 Cell의 값으로써 이루어진다. 아래의 그림이 포인트에 대한 밀도분석의 결과를 나타낸 화면이다.


이런 밀도 분석의 목적에 대해서 알아보자. 밀도 분석에 의한 결과를 Density Surface, 즉 밀도폴리곤이라고 하면… 밀도폴리곤은 측정값을 속성으로 하는 포인트나 라인 피쳐가 어디에 집중되었는가를 보여준다. 예를들어서 하나의 포인트가 어떤 마을을 의미하고 그 포인트 속성으로 마을의 전체 주민수를 나타낸다고 해보자. 여기서 우리는 이 주민수 포인트 데이터로부터 지도 전체에 걸친 주민의 분포수를 알고자 하는 것이다. 이 주민의 분포수를 얻는 방법이 바로 밀도 계산인데, 지도 전체에 걸친 인구의 예측 분포를 보여주는 밀도 폴리곤을 생성할 수 있는 것이 바로 밀도 분석, 밀도 계산이다.

여기서 중요한 것은 밀도 폴리곤은 벡터가 아닌 라스터라는 점이다. 밀도 분석에 의해 라스터를 구성하는 각 Cell에 측정된 값들이 계산되어져 입력되는데, 모든 Cell의 값들을 합한값과 입력 데이터로써의 벡터 데이터의 측정값들의 합은 같다.

밀도 분석을 위해 필요한 입력값은 무엇일까? 앞의 설명으로부터 유추가 가능한데.. 한번 정리를 해보면 아래와 같다.

  • 측정값이 들어가 있는 포인트나 폴리라인 벡터 데이터(여기서는 포인트에 관심을 둠)
  • 측값값이 저장된 속성 데이터에 대한 필드명
  • 밀도 분석 방법(Kernel과 Simple 방법이 있음)
  • 검색 반경
  • 셀의 크기

위의 지식을 기반으로 밀도 분석을 구현해 그 결과를 제시해 보겠다.

먼저 입력 데이터는 아래와 같다. 직관적으로 결과를 보이기 위해 하나의 포인트는 1의 값을 갖는다고 했다.

대략 9500개의 포인트를 사용했다. 화면의 가운데 부분에 5000개의 포인트를 밀집 시켰고 이를 중심으로 2000개의 포인트와 2500개의 포인트를 밀집시켰다. 직접 구현한 밀도 분석은 아래와 같다. 처음 이미지는 Simple 방법이고 두번째는 Kernel 방법이다.



Kernel 방법이 훨씬 정확한 결과를 제시하고 있다는 것을 알 수 있다. 아직은 속도나 퀄러티(밀도의 단계가 10단계로 표출되어야하나 그 이하로 표출(위의 경우 9단계)되는 문제가 발생하는 문제가 있다.

기회가 닿는다면 밀도분석에 대한 Simple 방법과 Kernel 방법에 대한 구현 로직에 대해 설명해 보도록 하겠다.

GIS Korea 2007에서 GeoGraph 발표

6월 13일부터 15일까지 양재동의 AT센터에서 GIS Korea 2007이 열렸습니다. 회사 연구소에서 GIS Korean 2007에서 발표했던 제품중 새로운 제품 두개가 있는데, 그 중에 하나가 바로 제가 담당한 GeoGraph입니다. 웹에서 작동하는 방식으로 시연을 했고 회사 부사장님의 강력한 추진력으로 시연 당일 아침에 터치스크린 장치에서 시연해 시연 효과를 높였습니다. 아래는 대회에서 일반 대중에게 처음으로 공개되어져 시연된 GeoGraph를 이용해 만든 데모의 스크린샷입니다.

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

아래는 웹 페이지에서 구현된 GeoGraph를 이용한 프리젠테이션 GIS 솔루션의 첫 페이지입니다.

사용자 삽입 이미지

좀더 선명한 이미지를 보길 원한다면 해당 이미지를 클릭하시면 확대됩니다. 간단이 설명하면, 통계정보나 분석된 결과 데이터를 지도위에 다양한 차트나 표, 이미지 등과 같이 사용자가 좀더 효과적으로 정보를 이해시킬 수 있는 프리젠테이션 GIS 솔루션입니다.

사용자 삽입 이미지

끝으로 위의 사진은 GIS Korea 2007의 신기술 발표회에서 GeoGraph를 내용으로 발표했던 제 모습입니다. ^^V

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

지난주에 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를 그려주었다.