현실감각 0% :: '회전각 산출' 태그의 글 목록

뻘짓거리 2013.01.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





  • 방문자 2014.12.22 16:11

    안녕하세요 블로그 잘 보고 있습니다. 다름이 아니라 이미지의 회전각을 구하기 위해 저 위의 Before 이미지를 이용해서 회전 각을 구하고 cvWarpAffine 함수를 이용해서 회전된 이미지를 구해보고 있습니다. 제가 지금 오리지날CV를 이용해서 구하고 있는데
    double th = 0.5 * atan((2.0 * cm->mu11) / (cm->mu20 - cm->mu02));
    이런식으로 사용하고 있습니다. 혹시 Before 이미지에서 나온 각 값을 알 수 있을까요?
    현재 저는 before 이미지에서는 angle 값이 0.133716로 나오고 있습니다.
    회전이 잘 안되는데 어디서 잘못된건지 막막하네요 ㅎㅎㅎ;;;

    • 현실감각0% 2014.12.31 05:23 신고

      답변이 많이 늦었습니다 ㅠㅠ 메일로 보내주셨으면 더 빨리 봤을텐데 ㅎㅎ 일단 수식 자체는 맞게 쓰셨고요. 위 수식처럼 하면 라디안값이 나옵니다. 만약 디그리값이 필요하시다면 산출하신 th에 57.3248을 곱하시면 -359~360도 사이의 값이 나오게됩니다.
      종종 수식상의 문제(?)라고 해야하나요. 분모와 분자의 크기가 반대가 되는 경우에는 ±90도가 되는 문제가 있는데 이경우에는 분자와 분모 크기를 비교하는 예외처리를 통해 90도를 더하거나 빼서 쓰심 될겁니다.
      그리고 제가 예제로 쓴 영상은 원본이미지가 아닌 크롭한 이미지라서 아마 결과값이 잘 안나올거에요 ㅎㅎㅎ
      만약 테스트영상이 필요하시다면 http://www.crazymind.net/30 여기의 열쇠영상을 쓰시면 도움이 되실겁니다.

  • 하켱 2015.01.07 14:19 신고

    앗 저야 말로 늦게 봤네요 답글 정말 감사합니다 ㅠㅠ 이거 한번 보고 다시 도전해 보도록 하겠습니다.

  • 궁금이 2015.06.03 19:03

    위 코드 설명 좀 부탁합니다.
    ???
    C++ 코드 좀 수할 수 있나요