基EmguCv/OpenCv的零件的缺陷检测

基EmguCv/OpenCv的零件的缺陷检测
思路:

  1. 对图像去噪和二值化处理;
  2. 提取外部轮廓,并填充;
  3. 提取内部轮廓并以另一种颜色填充;
  4. 外轮廓和内轮廓叠加,得到缺陷区域;
  5. 对缺陷区域做二值化处理,并提取轮廓计算缺陷面积;
  6. 标记处缺陷位置。

存在的缺陷:只能检测外测缺陷,无法检测内部缺陷

效果图
这里写图片描述
这里写图片描述
这里写图片描述
源代码(c#)

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace DefectDetection2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private string[] FileNmae = null;//读取文件夹下的文件
        private int times = 0;//上一张/下一张按钮点击次数(对应图片数组的索引)
        private int ErodeVaule = 1, DelitVaule = 1;//膨胀/腐蚀运算
        private Image<Bgr, byte> picture = null;//原始图片
        private int BinVaule = 0;//二值化阈值
        private int y = 0, cr_min = 0, cb_min = 0, cr_max = 0,cb_max=0;//YCC颜色阈值
        private double area1 = 0, area2 = 0;//缺陷面积

        /// <summary>
        /// Erode值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void domainUpDown1_SelectedItemChanged(object sender, EventArgs e)
        {
            ErodeVaule = Convert.ToInt16(domainUpDown1.Text);
        }

        /// <summary>
        /// Delite值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void domainUpDown2_SelectedItemChanged(object sender, EventArgs e)
        {
            DelitVaule = Convert.ToInt16(domainUpDown2.Text);
        }

        /// <summary>
        /// 选择图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                pictureBox2.Image = Image.FromFile(ofd.FileName);
                picture = new Image<Bgr, byte>(ofd.FileName);
                Image <Bgr ,byte >pic= new Image<Bgr, byte>(PicSubtraction(ContourFilling(ToBin(picture)), ContourFilling2(ToBin(picture))).Bitmap);
                pictureBox1.Image = ContourFilling3(pic).Bitmap;
                label4.Text = Path.GetFileName(ofd.FileName);
            }
        }

        /// <summary>
        /// 上一张
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            FileNmae = Directory.GetFiles(@"D:\work\HCI\工件样品");
            times--;
            if (times < 0)
                times = FileNmae.Length - 1;
            picture = new Image<Bgr, byte>(FileNmae[times]);
            pictureBox2.Image = Image.FromFile(FileNmae[times]);
            label4.Text = Path.GetFileName(FileNmae[times]);
            Image<Bgr, byte> pic = new Image<Bgr, byte>(PicSubtraction(ContourFilling(ToBin(picture)), ContourFilling2(ToBin(picture))).Bitmap);
            pictureBox1.Image = ContourFilling3(pic).Bitmap;
        }

        /// <summary>
        /// 下一张
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            FileNmae = Directory.GetFiles(@"D:\work\HCI\工件样品");
            times++;
            if (times > FileNmae.Length - 1)
                times = 0;
            picture = new Image<Bgr, byte>(FileNmae[times]);
            pictureBox2.Image = Image.FromFile(FileNmae[times]);
            label4.Text = Path.GetFileName(FileNmae[times]);
            Image<Bgr, byte> pic = new Image<Bgr, byte>(PicSubtraction(ContourFilling(ToBin(picture)), ContourFilling2(ToBin(picture))).Bitmap);
            pictureBox1.Image = ContourFilling3(pic).Bitmap;
        }

        /// <summary>
        /// 二值化
        /// </summary>
        /// <param name="pic">输入Bgr图片</param>
        /// <returns></returns>
        private Image<Gray, byte> ToBin(Image<Bgr, byte> pic)
        {
            Image<Gray, byte> outpic = pic.Convert<Gray, byte>();
            outpic = outpic.ThresholdBinary(new Gray(100), new Gray(255));
            outpic = outpic.Erode(ErodeVaule);
            outpic = outpic.Dilate(DelitVaule);
            return outpic;
        }

        /// <summary>
        /// 补全轮廓并填充
        /// </summary>
        /// <param name="pic">输入灰度图</param>
        /// <returns></returns>
        private Image<Bgr, byte> ContourFilling(Image<Gray, byte> pic)
        {
            Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
            pic = pic.Canny(100, 255);
            Image<Gray, byte> outcon = new Image<Gray, byte>(pic.Size);
            VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();
            CvInvoke.FindContours(pic, con, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
            Point[][] con1 = con.ToArrayOfArray();
            PointF[][] con2 = Array.ConvertAll(con1, new Converter<Point[], PointF[]>(PointToPointF));
            PointF[] hull = new PointF[con[0].Size];
            for (int i = 0; i < con.Size; i++)
            {
                hull = CvInvoke.ConvexHull(con2[i], true);
                for (int j = 0; j < hull.Length; j++)
                {
                    Point p1 = new Point((int)(hull[j].X + 0.5), (int)(hull[j].Y + 0.5));
                    Point p2;
                    if (j == hull.Length - 1)
                    {
                        p2 = new Point((int)(hull[0].X + 0.5), (int)(hull[0].Y + 0.5));
                    }
                    else
                        p2 = new Point((int)(hull[j + 1].X + 0.5), (int)(hull[j + 1].Y + 0.5));
                    CvInvoke.Line(outpic, p1, p2, new MCvScalar(255, 0, 255, 255), 2, 0, 0);
                }
            }

            Image<Gray, byte> gray = new Image<Gray, byte>(pic.Size);
            gray = outpic.Convert<Gray, byte>();
            gray = gray.ThresholdBinary(new Gray(100), new Gray(255));
            gray = gray.Canny(100, 255);
            VectorOfVectorOfPoint con3 = new VectorOfVectorOfPoint();
            CvInvoke.FindContours(gray, con3, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
            for (int i = 0; i < con3.Size; i++)
            {
                CvInvoke.DrawContours(outpic, con3, i, new MCvScalar(255, 0, 0), -1);
            }

            return outpic;
        }

        /// <summary>
        /// 填充缺陷轮廓
        /// </summary>
        /// <param name="pic"></param>
        /// <returns></returns>
        private Image<Bgr, byte> ContourFilling2(Image<Gray, byte> pic)
        {
            Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
            pic = pic.Canny(100, 255);
            Image<Gray, byte> outcon = new Image<Gray, byte>(pic.Size);
            VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();
            CvInvoke.FindContours(pic, con, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
            for (int i = 0; i < con.Size; i++)
            {
                CvInvoke.DrawContours(outpic, con, i, new MCvScalar(0, 255, 255, 0), -1);
            }
            for (int i = 0; i < con.Size; i++)
            {
                CvInvoke.DrawContours(outpic, con, i, new MCvScalar(0, 255, 255, 0),10);
            }
            return outpic;
        }

        /// <summary>
        /// 叠加图像
        /// </summary>
        /// <param name="pic1">输入Bgr图像1</param>
        /// <param name="pic2">输入Bgr图像2</param>
        /// <returns></returns>
        private Image<Bgr, byte> PicSubtraction(Image<Bgr, byte> pic1, Image<Bgr, byte> pic2)
        {
            Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic1.Size);
            pic1 = ContourFilling(ToBin(picture));
            pic2 = ContourFilling2(ToBin(picture));
            CvInvoke.AddWeighted(pic1, 0.5, pic2, 0.5, 1, outpic);

            return outpic;
        }

        /// <summary>
        /// Point转换为PointF
        /// </summary>
        /// <param name="pt">输入Point</param>
        /// <returns></returns>
        private PointF[] PointToPointF(Point[] pt)
        {
            PointF[] aaa = new PointF[pt.Length];
            int num = 0;
            foreach (var point in pt)
            {
                aaa[num].X = point.X;
                aaa[num++].Y = (int)point.Y;
            }
            return aaa;
        }

        /// <summary>
        /// 填充缺陷轮廓
        /// </summary>
        /// <param name="pic">输入Bgr图像</param>
        /// <returns></returns>
        private Image<Bgr, byte> ContourFilling3(Image<Bgr, byte> pic)
        {
            Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
            Image<Ycc, byte> ycc = pic.Convert<Ycc, byte>();
            for(int i=0;i<ycc.Height;i++)
                for(int j=0;j<ycc.Width;j++)
                {
                    if (ycc[i, j].Cr > 35 && ycc[i, j].Cr < 148 &&
                        ycc[i, j].Cb > 48 && ycc[i, j].Cb < 141)
                    {
                        ycc[i, j] = new Ycc(0, 0, 0);
                    }
                    else ycc[i, j] = new Ycc(255, 255, 255);
                }
            Image<Gray, byte> gray = ycc.Convert<Gray, byte>();
            gray = gray.ThresholdBinary(new Gray(100 ), new Gray(255));
            gray = gray.Canny(100, 60);
            Image<Gray, byte> outcon = new Image<Gray, byte>(pic.Size);
            VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();
            CvInvoke.FindContours(gray, con, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
            int n=0;

                for (int i = 0; i < con.Size; i++)
                {
                    if (CvInvoke.ContourArea(con[i]) >0)
                    {
                        n++;

                    }
                }
            textBox1.Text = "共" + n.ToString() + "个缺陷"+"      ";
            n = 0;
            for (int i = 0; i <con .Size ; i++)
            {
                if (CvInvoke.ContourArea(con[i]) >0)
                {
                    CvInvoke.DrawContours(outpic, con, i, new MCvScalar(0, 255, 0), 5);
                    textBox1.Text = textBox1.Text + "第" + (++n).ToString() + "个缺陷的面积为" + CvInvoke.ContourArea(con[i]);
                }
            }
            CvInvoke.AddWeighted(outpic , 0.5,picture , 0.5, 0, outpic);
            return outpic;
        }

    }
}
posted @ 2017-02-17 10:49  SEC.VIP_网络安全服务  阅读(356)  评论(0编辑  收藏  举报