这是c#的代码 只看看思路吧~~
看下效果(左边是原图,右边是矫正后的效果):
【1】需求分析
由于相机拍摄角度,导致二维码形状不是矩形,存在明显的畸变。我们希望将其矫正为正常的矩形或者正方形图案,方便解码或其他图像处理。
初步设想的处理步骤如下:
① 通过预处理将二维码部分轮廓找到;
② 通过轮廓分析手段找到二维码的四个角点;
③ 基于找到的四个角点,使用透视变换将二维码矫正。
【2】实现步骤演示
① 通过简单二值化分割二维码区域,因为目标黑色,背景高亮,所以二值化参数使用ThresholdTypes.BinaryInv
Mat src = Cv2.ImRead("1.jpg");
Cv2.NamedWindow("src", WindowFlags.GuiExpanded);
Cv2.ImShow("src", src);
Mat gray = new Mat(), thres = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
Cv2.Threshold(gray, thres, 80, 255, ThresholdTypes.BinaryInv);
Cv2.NamedWindow("thres", WindowFlags.GuiExpanded);
Cv2.ImShow("thres", thres);
② 通过形态学闭运算将二维码区域连城一片,以便后续轮廓查找
Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15), new Point(-1, -1));
Cv2.MorphologyEx(thres, thres, MorphTypes.Close, element, new Point(-1, -1), 1, BorderTypes.Default, new Scalar());
Cv2.NamedWindow("close", WindowFlags.GuiExpanded);
Cv2.ImShow("close", thres);
③ 轮廓查找筛选(注意左下角有一块干扰轮廓),通过轮廓面积滤除
double area = Cv2.ContourArea(contours[i]);
if (area < 10000)
continue;
④ 满足条件的轮廓(二维码轮廓),查找轮廓凸包,然后对凸包做多边形逼近
Point[] hull = Cv2.ConvexHull(contours[i]);
for (int j = 0; j < hull.Length; j++)
{
if (j != hull.Length - 1)
Cv2.Line(src, hull[j], hull[j + 1], new Scalar(0, 255, 0), 2);
else
Cv2.Line(src, hull[j], hull[0], new Scalar(0, 255, 0), 2);
}
凸包多边形逼近,目的是将凸包的边拟合近似成4条,这样就可以直接获取四边形的角点
Point[] approx = Cv2.ApproxPolyDP(hull, 20, true);
for (int j = 0; j < approx.Length; j++)
{
Console.WriteLine("{0}", approx[j]);
if (j != approx.Length - 1)
Cv2.Line(src, approx[j], approx[j + 1], new Scalar(0, 0, 255), 2);
else
Cv2.Line(src, approx[j], approx[0], new Scalar(0, 0, 255), 2);
srcPoints[j] = approx[j];
}
⑤ 透视变换
原始点4个,从多边形逼近结果直接获取
Point2f[] srcPoints = new Point2f[4];
Point[] approx = Cv2.ApproxPolyDP(hull, 20, true);
for (int j = 0; j < approx.Length; j++)
{
Console.WriteLine("{0}", approx[j]);
if (j != approx.Length - 1)
Cv2.Line(src, approx[j], approx[j + 1], new Scalar(0, 0, 255), 2);
else
Cv2.Line(src, approx[j], approx[0], new Scalar(0, 0, 255), 2);
srcPoints[j] = approx[j];
}
目标点4个,自己构造,qrWidth可以自己设定,也可以通过数学方法计算
Point2f[] dstPoints = new Point2f[4];
int qrWidth = 450;
dstPoints[0] = new Point2f(0, 0);
dstPoints[1] = new Point2f(qrWidth, 0);
dstPoints[2] = new Point2f(qrWidth, qrWidth);
dstPoints[3] = new Point2f(0, qrWidth);
接下来就是透视变换了
Mat result = new Mat();
try
{
Mat TransformMatrix = Cv2.GetPerspectiveTransform(srcPoints, dstPoints); //根据变换前后四个角点坐标,计算变换矩阵
Cv2.WarpPerspective(src, result, TransformMatrix, new Size(qrWidth, qrWidth)); //透视变换函数
}
catch (Exception e)
{
Console.WriteLine(e);
}
//Cv2.NamedWindow("result", WindowFlags.GuiExpanded);
Cv2.ImShow("result", src);
Cv2.WaitKey();
然后得到最终结果如下: whaosoft aiot http://143ai.com