[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