接上一篇,上次说到通过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;
}