현실감각 0% :: 현실감각 0%

뻘짓거리 2013. 1. 29. 08:41

[c#/openCVSharp] 오브젝트의 회전각 산출



[c#/openCVSharp] 오브젝트의 회전각 산출


2년전인가 3년전인가 이 블로그에 열쇠 영상을 촬영하고 그것을 동일한 각도로 회전하는 예제를 올린적이 있었는데, 최근에 그 소스가 다시 필요해서 찾아보니 픽셀값을 일일이 변환하는 조잡한 코드로 되어있길래 openCV를 이용하여 빠른시간안에 회전각을 산출하는 소스를 다시 만들어 보았다.


private double getObjectAngle(IplImage src)

{

CvMoments cm = null;

try

      {

Cv.Moments(src, out cm, true);

double th = 0.5 * Math.Atan((2 * cm.M11) / (cm.M20 - cm.M02));

return th * (180 / 3.14);

}

      catch

      {

IplImage tmp = Cv.CreateImage(src.Size, BitDepth.U8, 1);

Cv.CvtColor(src, tmp, ColorConversion.RgbToGray);

Cv.Moments(tmp, out cm, true);

double th = 0.5 * Math.Atan((2 * cm.M11) / (cm.M20 - cm.M02));

return th * (180 / 3.14);

}

}



코드를 간단히 설명하자면...

일단 각도 산출에서 가장 중요한것은 모멘트!! Cv.Moments 함수를 이용하여 영상의 모멘트를 우선 구한다. 만약  C++용 오리지널 openCV를 사용하는 사람이라면 Cv.Moments 대신 cvMoments를, out cm 대신 포인터(*cm)를 사용하면 쉽게 해결된다.

그다음엔 아래 수식을 이용하여 세타값을 산출!



모멘트가 있어서 정신사나울 뿐 기울기 구하는 공식이라 생각하고 보면 쉽게 이해된다. 탄젠트 각도는 기울기!! 아크탄젠트 기울기를 하면 각도!! 아 신기한 삼각함수~! 이걸 왜 중고등학교에선 재미없게 가르칠까...ㅋㅋ 밑에 뮤pq 구하는 공식은 모멘트를 구하는 공식인데 이 소스에서는 openCV에서 알아서 구해줬으니 패스~ 그다음에 th에 180/3.14를 곱해줘서 라디안이 아닌 디그리값으로 변경해서 리턴해준다.


밑에 캐치는 다른게 아니라 입력영상이 그레이스케일 영상이 아닐경우 런타임에러가 발생하므로, 입력 영상이 RGB 컬러영상일 경우 알아서 그레이스케일로 전환해서 모멘트를 산출하는 것을 추가한 것이다.

그 다음에 아래 함수로 영상을 회전하면 완 to the 성


private void rotateImage(IplImage src, ref IplImage dst, double angle)

{

CvMat mat = Cv.GetRotationMatrix2D(new CvPoint2D32f(src.Width / 2.0F, src.Height / 2.0F), angle, 1.0);

Cv.WarpAffine(src, dst, mat, Interpolation.Cubic);

}


※ Cv.Moments 함수는 이진화된 영상에 최적화 되어 있으므로, 오브젝트를 최대한 이진화 하여 사용해야 한다.


결과영상 예


Before


After