OpenCV~二维码畸变矫正

这是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

 ​​​​​​

猜你喜欢

转载自blog.csdn.net/qq_29788741/article/details/131954093
今日推荐