Opencv中MatchTemplate方法进行模板匹配非常实用,但是匹配目标有旋转的情况就无法匹配了,实际应用中需要将模板旋转操作,才能匹配到角度,以下是一种模板旋转及掩膜生成的方法

/// <summary>
/// 图像旋转,并获旋转后的图像边界旋转矩形
/// </summary>
/// <param name="image"></param>
/// <param name="angle"></param>
/// <param name="imgBounding"></param>
/// <returns></returns>
public static Mat ImageRotate(Mat image, double angle, ref RotatedRect imgBounding, ref Mat maskMat)
{
    Mat newImg = new Mat();
    Point2f pt = new Point2f((float)image.Cols / 2, (float)image.Rows / 2);
    Mat M = Cv2.GetRotationMatrix2D(pt, -angle, 1.0);
    var mIndex = M.GetGenericIndexer<double>();

    double cos = Math.Abs(mIndex[0, 0]);
    double sin = Math.Abs(mIndex[0, 1]);
    int nW = (int)((image.Height * sin) + (image.Width * cos));
    int nH = (int)((image.Height * cos) + (image.Width * sin));
    mIndex[0, 2] += (nW / 2) - pt.X;
    mIndex[1, 2] += (nH / 2) - pt.Y;

    Cv2.WarpAffine(image, newImg, M, new CVSize(nW, nH));
    //获取图像边界旋转矩形
    Rect rect = new CVRect(0, 0, image.Width, image.Height);
    Point2f[] srcPoint2Fs = new Point2f[4]
        {
            new Point2f(rect.Left,rect.Top),
             new Point2f (rect.Right,rect.Top),
               new Point2f (rect.Right,rect.Bottom),
                  new Point2f (rect.Left,rect.Bottom)
        };

    Point2f[] boundaryPoints = new Point2f[4];
    var A = M.Get<double>(0, 0);
    var B = M.Get<double>(0, 1);
    var C = M.Get<double>(0, 2);    //Tx
    var D = M.Get<double>(1, 0);
    var E = M.Get<double>(1, 1);
    var F = M.Get<double>(1, 2);    //Ty

    for (int i = 0; i < 4; i++)
    {
        boundaryPoints[i].X = (float)((A * srcPoint2Fs[i].X) + (B * srcPoint2Fs[i].Y) + C);
        boundaryPoints[i].Y = (float)((D * srcPoint2Fs[i].X) + (E * srcPoint2Fs[i].Y) + F);
        if (boundaryPoints[i].X < 0)
            boundaryPoints[i].X = 0;
        else if (boundaryPoints[i].X > nW)
            boundaryPoints[i].X = nW;
        if (boundaryPoints[i].Y < 0)
            boundaryPoints[i].Y = 0;
        else if (boundaryPoints[i].Y > nH)
            boundaryPoints[i].Y = nH;
    }

    Point2f cenP = new Point2f((boundaryPoints[0].X + boundaryPoints[2].X) / 2,
                                 (boundaryPoints[0].Y + boundaryPoints[2].Y) / 2);
    double ang = angle;

    double width1 = Math.Sqrt(Math.Pow(boundaryPoints[0].X - boundaryPoints[1].X, 2) +
        Math.Pow(boundaryPoints[0].Y - boundaryPoints[1].Y, 2));
    double width2 = Math.Sqrt(Math.Pow(boundaryPoints[0].X - boundaryPoints[3].X, 2) +
        Math.Pow(boundaryPoints[0].Y - boundaryPoints[3].Y, 2));
    imgBounding = new RotatedRect(cenP, new Size2f(width1, width2), (float)ang);
    Mat mask = new Mat(newImg.Size(), MatType.CV_8UC3, Scalar.Black);
    DrawRotatedRect(mask, imgBounding, Scalar.White, 1);
    Cv2.FloodFill(mask, new CVPoint(imgBounding.Center.X, imgBounding.Center.Y), Scalar.White);      
    Cv2.CvtColor(mask, maskMat, ColorConversionCodes.BGR2GRAY);
    Mat _maskRoI = new Mat();
    Cv2.CvtColor(mask, _maskRoI, ColorConversionCodes.BGR2GRAY);
    Mat dst = new Mat();
    Cv2.BitwiseAnd(newImg, newImg, dst, _maskRoI);
    return dst;

}
public static void DrawRotatedRect(Mat mat, RotatedRect rr, Scalar scalar, int thickness = 2)
{
    //通过4个个顶点画4条线形成矩形
    var P = rr.Points();
    for (int j = 0; j <= 3; j++)
    {
        Cv2.Line(mat, (CVPoint)P[j], (CVPoint)P[(j + 1) % 4], scalar, thickness);
    }
}

更多推荐