• 基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:workHCI工件样品");
                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:workHCI工件样品");
                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;
            }
    
        }
    }
    
  • 相关阅读:
    基于ARM的指纹采集仪的设计与实现
    基于单片机和CPLD的数字频率计的设计
    转来的
    单片机式语音播报伏特表
    汽车驾驶模拟器单片机系统设计
    基于AT89C51的智能矿井环境质量监控系统
    我的理解OpenAPI原理
    关联规则中的支持度与置信度
    LVS-NAT实现负载均衡
    在IIS上部署Analysis Services
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286846.html
Copyright © 2020-2023  润新知