形状 (バイナリまたは輪郭) の向きを取得しようとしています。形はほぼ長方形ですが、片側に大きな穴があります。オブジェクトのこの非対称性と向きを一致させる必要があります。
私は、このために空間モーメントと中心モーメントを使用するいくつかの記事を見てきました。たとえば 、バイナリ イメージの向き ですが、これで得られる向きが 90 度の倍数でずれていることがあるようです。
次のドキュメントは、いくつかのあいまいさがあると述べています: http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf
これを使用して実装すると
private void GetCenterAndOrientationViaMoments(Contour<Point> cont, Size imageSize)
{
// obtain the orientation of the found object
// first draw the binary blob in a separate image
// I do this for the hole(s) in the image, but I'm not sure if it is needed.
// Possibly I can tak the moments directly from the contour
Image<Gray, byte> instanceImage = new Image<Gray, byte>(imageSize);
instanceImage.FillConvexPoly(cont.ToArray(), new Gray(255));
for (Contour<Point> hole = cont.VNext;
hole != null;
hole = hole.HNext)
instanceImage.FillConvexPoly(hole.ToArray(), new Gray(0));
// calculate the moments
MCvMoments m = instanceImage.GetMoments(true);
// MCvMoments m = cont.GetMoments();
double m00 = m.GetSpatialMoment(0, 0);
double m10 = m.GetSpatialMoment(1, 0);
double m01 = m.GetSpatialMoment(0, 1);
double mu11 = m.GetCentralMoment(1, 1);
double mu20 = m.GetCentralMoment(2, 0);
double mu02 = m.GetCentralMoment(0, 2);
// calculate the center
PointF center = new PointF((float)(m10 / m00), (float)(m01 / m00));
// calculate the orientation
// http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf
double theta = 0;
double mu20_mu02 = (mu20 - mu02);
if ((mu20_mu02 == 0) & (mu11 == 0))
theta = 0;
else if ((mu20_mu02 == 0) & (mu11 > 0))
theta = Math.PI / 4;
else if ((mu20_mu02 == 0) & (mu11 < 0))
theta = -Math.PI / 4;
else if ((mu20_mu02 > 0) & (mu11 == 0))
theta = 0;
else if ((mu20_mu02 < 0) & (mu11 == 0))
theta = -Math.PI / 2;
else if ((mu20_mu02 > 0) & (mu11 > 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02);
else if ((mu20_mu02 > 0) & (mu11 < 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02);
else if ((mu20_mu02 < 0) & (mu11 > 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) + Math.PI / 2;
else if ((mu20_mu02 < 0) & (mu11 < 0))
theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) - Math.PI / 2;
#if DEBUG
int radius = 25;
instanceImage.Draw(new CircleF(center, radius), new Gray(100), 2);
instanceImage.Draw(
new LineSegment2DF(
center,
new PointF(
(float)(center.X + radius * Math.Cos(theta)),
(float)(center.Y + radius * Math.Sin(theta)))),
new Gray(100),
2);
ImageViewer.Show(instanceImage, string.Format("Center and orientation"));
#endif
}
私の向きは正しいのですが、常にオブジェクトの同じ端を指しているわけではありません。つまり、私は時々 180 度です。
この方法では、分布の共分散 ( http://en.wikipedia.org/wiki/Image_moments#Examples_2 ) を使用するため、穴によって引き起こされる非対称性が考慮されていないため、このメソッドは私が望むものを正確に提供できないと推測しています。 、私は正しいですか?
180度のあいまいさを解決する方法はありますか?
よろしく、トム