OpencvForUnity 图像的透视矫正提取

接上一篇,上次说到通过Imgproc.convexHull得到轮廓凸包失败,得到的角点数很多,不是我想要的数据然后经过测试后,发现用Imgproc.approxPolyDP进行轮廓拟合后也可以得到凸点数。

    MatOfPoint2f approx = new MatOfPoint2f();
    MatOfPoint2f mp2f = new MatOfPoint2f(srcCorners[index].toArray());
    double peri = Imgproc.arcLength(mp2f, true);//计算轮廓的周长
    Imgproc.approxPolyDP(mp2f, approx, peri * 0.04, true);//对图像轮廓进行多边形拟合(作用是用多边形包围轮廓,可以得到严格的矩形,有助于找到角点)
    print(approx.toArray().Length);//多边形轮廓角点数

    for (int i = 0; i < approx.toArray().Length; i++)
    {
        //圈出轮廓角点
        Imgproc.circle(inputMat, approx.toArray()[i], 7, new Scalar(255, 0, 0));
    }

得到轮廓角点后就可以开始进行透视矫正变换了,在矩阵转换这里参考了https://blog.csdn.net/u010407393/article/details/77892129,他用的是霍夫变换进行直线检测,计算霍夫曼线交叉点 并剔除不合理的点来获得轮廓角点的。

	corners.Add(new Vector2((float)approx.toList()[0].x, (float)approx.toList()[0].y));
    corners.Add(new Vector2((float)approx.toList()[1].x, (float)approx.toList()[1].y));
    corners.Add(new Vector2((float)approx.toList()[2].x, (float)approx.toList()[2].y));
    corners.Add(new Vector2((float)approx.toList()[3].x, (float)approx.toList()[3].y));

    Vector2 center = Vector2.zero;
    for (int i = 0; i < corners.Count; i++)
    {
        center += corners[i];
    }
    center *= 0.25f;
    SortCorners(ref corners, center);

    //计算转换矩阵
    Vector2 tl = corners[0];
    Vector2 tr = corners[1];
    Vector2 br = corners[2];
    Vector2 bl = corners[3];

    //得到变换矩阵
    Mat srcMat = new Mat(4, 1, CvType.CV_32FC2);
    Mat dstMat = new Mat(4, 1, CvType.CV_32FC2);
    srcMat.put(0, 0, tl.x, tl.y, tr.x, tr.y, bl.x, bl.y, br.x, br.y);
    dstMat.put(0, 0, 0.0, inputMat.rows(), inputMat.cols(), inputMat.rows(), 0.0, 0.0, inputMat.rows(), 0);
    Mat perspectiveTransform = Imgproc.getPerspectiveTransform(srcMat, dstMat);

    Mat finalMat = inputMat.clone();

    //进行透视转换
    Imgproc.warpPerspective(inputMat, finalMat, perspectiveTransform, new Size(inputMat.rows(), inputMat.cols()));

    Texture2D tmpTex = new Texture2D(finalMat.width(), finalMat.height(), TextureFormat.RGBA32, false);
    Utils.matToTexture2D(finalMat, tmpTex);
    rawImage.texture = tmpTex;

  private Vector2 ComputeIntersect(List a, List b)
    {
        int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3];
        int x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3];
        float d = ((float)(x1 - x2) * (y3 - y4)) - (x3 - x4) * (y1 - y2);
        Vector2 temp = Vector2.zero;
        if (d == 0)
        {
            temp.x = -1;
            temp.y = -1;
        }
        else
        {
            temp.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
            temp.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
        }
        return temp;
    }

private void CullIllegalPoint(ref List corners, float minDis)
{
    Vector2 a = Vector2.zero;
    Vector2 b = Vector2.zero;
    List removeList = new List();
    for (int i = 0; i < corners.Count; i++)
    {
        a = corners[i];
        for (int j = i + 1; j < corners.Count; j++)
        {
            b = corners[j];
            if (Vector2.Distance(a, b) < minDis)
            {
                removeList.Add(b);
            }
        }
    }
    for (int i = 0; i < removeList.Count; i++)
    {
        corners.Remove(removeList[i]);
    }
}

private void SortCorners(ref List corners, Vector2 center)
{
    List top = new List();
    List bot = new List();
    for (int i = 0; i < corners.Count; i++)
    {

        if (corners[i].y > center.y)
            top.Add(corners[i]);
        else
            bot.Add(corners[i]);
    }
    if (top.Count < 2)
    {
        Vector2 temp = GetMaxFromList(bot);
        top.Add(temp);
        bot.Remove(temp);
    }
    if (top.Count > 2)
    {
        Vector2 temp = GetMinFromList(top);
        top.Remove(temp);
        bot.Add(temp);
    }
    Vector2 tl = top[0].x > top[1].x ? top[1] : top[0];
    Vector2 tr = top[0].x > top[1].x ? top[0] : top[1];
    Vector2 bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
    Vector2 br = bot[0].x > bot[1].x ? bot[0] : bot[1];
    corners.Clear();
    corners.Add(tl);
    corners.Add(tr);
    corners.Add(br);
    corners.Add(bl);
}

private Vector2 GetMaxFromList(List list)
{
    Vector2 temp = list[0];
    for (int i = 0; i < list.Count; i++)
    {
        if (list[i].y > temp.y)
        {
            temp = list[i];
        }
    }
    return temp;
}

private Vector2 GetMinFromList(List list)
{
    Vector2 temp = list[0];
    for (int i = 0; i < list.Count; i++)
    {
        if (list[i].y < temp.y)
        {
            temp = list[i];
        }
    }
    return temp;
}

你可能感兴趣的:(OpencvForUnity)