【OpenCv/EmguCv】指针式仪表读数(一)

1. 预处理

1.1 双边滤波

img.SmoothBilatral(int val1,int val2,int,val3)

(原图)

(双边滤波)

(高斯滤波)

高斯滤波将整张图都变得模糊了,双边滤波则保留了清晰轮廓特征,效果比较好。

1.2 灰度并二值

  img.Convert<Gray, byte>()//灰度化g   

(灰度图)

ThresholdBinary(new Gray(Parameters.BinVal),new Gray(255));//二值化

(二值图)

2. 指针提取

1.1 帧差法提取指针

用当前帧减去上一帧得到运动的指针图像。

    private Image<Gray,byte> SubBackground(Image<Gray,byte>pic)
        {
            Image<Gray, byte> gray = new Image<Gray, byte>(pic.Size);
            if (tag == 0)
            {
                Subbg[0] = pic;//背景帧(上一帧)
                tag = 1;
                return Subbg[0];
            }
            else
            {
                Subbg[1] = pic;
                gray = Subbg[1] - Subbg[0];//当前帧减去背景帧(上一帧)
                Subbg[0] = Subbg[1];
            }

            return gray;
        }

(指针)

2.2 霍夫圆检测

对灰度图进行霍夫圆检测。

    private Image<Bgr, byte> CirclePic(Image<Gray, byte> pic)
        {
            Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
            //霍夫圆检测
            CircleF[] circle = CvInvoke.HoughCircles(pic, Emgu.CV.CvEnum.HoughType.Gradient, 10, 1000);
            foreach (CircleF c in circle)
            {
                CvInvoke.Circle(outpic, new Point((int)c.Center.X, (int)c.Center.Y), (int)c.Radius, new MCvScalar(255, 255, 0), 5);
                center.X = (int)c.Center.X;
                center.Y = (int)c.Center.Y;
                radius = c.Radius;
                outpic.Draw(new CircleF(new PointF(center.X, center.Y), 5), new Bgr(255, 0, 255), 10);
                outpic.Draw(new LineSegment2D(new Point(0, center.Y), new Point(pic.Width, center.Y)), new Bgr(Color.Blue), 2);
                outpic.Draw(new LineSegment2D(new Point(center.X, 0), new Point(center.X, pic.Height)), new Bgr(Color.Blue), 2);
                outpic.Draw(new Point(center.X, center.Y).ToString(), new Point(center.X,center.Y), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 1, new Bgr(255, 0, 255));
            }
            return outpic;
        }

2.3 直线检测

对帧差法提取到的指针图像进行直线检测。

检测到的结果包含多条直线,首先对长度不符合的进行过滤(这里排除长度小于70的线段),过滤后仍然包含多条线段,但是我们只需要一条,所以进行直线合并,只保留一条。

    //返回直线端点的坐标
     public Point AvrPoint(Point[] point)
        {
            Point outpoint = new Point(0, 0);
            int p_x = 0;
            int p_y = 0;
            int n = 0;
            foreach (Point p in point)
            {
                if (p.X != 0 && p.Y != 0)
                {
                    p_x += p.X;
                    p_y += p.Y;
                    n++;
                }
            }
            if (n != 0)
            {
                p_x = p_x / n;
                p_y = p_y / n;
            }
            outpoint = new Point(p_x, p_y);
            return outpoint;
        }

2.4 绘制指针

以圆心为指针的

一端,2.3中求得的线段端点为另一端绘制直线。并在同一张图片上绘制出圆心和圆(刻度盘)

原文地址:https://www.cnblogs.com/cnsec/p/13286767.html