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


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

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

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

    效果图

    源代码(c#)

      1 using Emgu.CV;
      2 using Emgu.CV.CvEnum;
      3 using Emgu.CV.Structure;
      4 using Emgu.CV.Util;
      5 using System;
      6 using System.Drawing;
      7 using System.IO;
      8 using System.Windows.Forms;
      9 
     10 namespace DefectDetection2
     11 {
     12     public partial class Form1 : Form
     13     {
     14         public Form1()
     15         {
     16             InitializeComponent();
     17         }
     18 
     19         private string[] FileNmae = null;//读取文件夹下的文件
     20         private int times = 0;//上一张/下一张按钮点击次数(对应图片数组的索引)
     21         private int ErodeVaule = 1, DelitVaule = 1;//膨胀/腐蚀运算
     22         private Image<Bgr, byte> picture = null;//原始图片
     23         private int BinVaule = 0;//二值化阈值
     24         private int y = 0, cr_min = 0, cb_min = 0, cr_max = 0,cb_max=0;//YCC颜色阈值
     25         private double area1 = 0, area2 = 0;//缺陷面积
     26 
     27         /// <summary>
     28         /// Erode值
     29         /// </summary>
     30         /// <param name="sender"></param>
     31         /// <param name="e"></param>
     32         private void domainUpDown1_SelectedItemChanged(object sender, EventArgs e)
     33         {
     34             ErodeVaule = Convert.ToInt16(domainUpDown1.Text);
     35         }
     36 
     37         /// <summary>
     38         /// Delite值
     39         /// </summary>
     40         /// <param name="sender"></param>
     41         /// <param name="e"></param>
     42         private void domainUpDown2_SelectedItemChanged(object sender, EventArgs e)
     43         {
     44             DelitVaule = Convert.ToInt16(domainUpDown2.Text);
     45         }
     46 
     47         /// <summary>
     48         /// 选择图片
     49         /// </summary>
     50         /// <param name="sender"></param>
     51         /// <param name="e"></param>
     52         private void button1_Click(object sender, EventArgs e)
     53         {
     54             OpenFileDialog ofd = new OpenFileDialog();
     55             if (ofd.ShowDialog() == DialogResult.OK)
     56             {
     57                 pictureBox2.Image = Image.FromFile(ofd.FileName);
     58                 picture = new Image<Bgr, byte>(ofd.FileName);
     59                 Image <Bgr ,byte >pic= new Image<Bgr, byte>(PicSubtraction(ContourFilling(ToBin(picture)), ContourFilling2(ToBin(picture))).Bitmap);
     60                 pictureBox1.Image = ContourFilling3(pic).Bitmap;
     61                 label4.Text = Path.GetFileName(ofd.FileName);
     62             }
     63         }
     64 
     65         /// <summary>
     66         /// 上一张
     67         /// </summary>
     68         /// <param name="sender"></param>
     69         /// <param name="e"></param>
     70         private void button2_Click(object sender, EventArgs e)
     71         {
     72             FileNmae = Directory.GetFiles(@"D:workHCI工件样品");
     73             times--;
     74             if (times < 0)
     75                 times = FileNmae.Length - 1;
     76             picture = new Image<Bgr, byte>(FileNmae[times]);
     77             pictureBox2.Image = Image.FromFile(FileNmae[times]);
     78             label4.Text = Path.GetFileName(FileNmae[times]);
     79             Image<Bgr, byte> pic = new Image<Bgr, byte>(PicSubtraction(ContourFilling(ToBin(picture)), ContourFilling2(ToBin(picture))).Bitmap);
     80             pictureBox1.Image = ContourFilling3(pic).Bitmap;
     81         }
     82 
     83         /// <summary>
     84         /// 下一张
     85         /// </summary>
     86         /// <param name="sender"></param>
     87         /// <param name="e"></param>
     88         private void button3_Click(object sender, EventArgs e)
     89         {
     90             FileNmae = Directory.GetFiles(@"D:workHCI工件样品");
     91             times++;
     92             if (times > FileNmae.Length - 1)
     93                 times = 0;
     94             picture = new Image<Bgr, byte>(FileNmae[times]);
     95             pictureBox2.Image = Image.FromFile(FileNmae[times]);
     96             label4.Text = Path.GetFileName(FileNmae[times]);
     97             Image<Bgr, byte> pic = new Image<Bgr, byte>(PicSubtraction(ContourFilling(ToBin(picture)), ContourFilling2(ToBin(picture))).Bitmap);
     98             pictureBox1.Image = ContourFilling3(pic).Bitmap;
     99         }
    100 
    101         /// <summary>
    102         /// 二值化
    103         /// </summary>
    104         /// <param name="pic">输入Bgr图片</param>
    105         /// <returns></returns>
    106         private Image<Gray, byte> ToBin(Image<Bgr, byte> pic)
    107         {
    108             Image<Gray, byte> outpic = pic.Convert<Gray, byte>();
    109             outpic = outpic.ThresholdBinary(new Gray(100), new Gray(255));
    110             outpic = outpic.Erode(ErodeVaule);
    111             outpic = outpic.Dilate(DelitVaule);
    112             return outpic;
    113         }
    114 
    115         /// <summary>
    116         /// 补全轮廓并填充
    117         /// </summary>
    118         /// <param name="pic">输入灰度图</param>
    119         /// <returns></returns>
    120         private Image<Bgr, byte> ContourFilling(Image<Gray, byte> pic)
    121         {
    122             Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
    123             pic = pic.Canny(100, 255);
    124             Image<Gray, byte> outcon = new Image<Gray, byte>(pic.Size);
    125             VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();
    126             CvInvoke.FindContours(pic, con, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
    127             Point[][] con1 = con.ToArrayOfArray();
    128             PointF[][] con2 = Array.ConvertAll(con1, new Converter<Point[], PointF[]>(PointToPointF));
    129             PointF[] hull = new PointF[con[0].Size];
    130             for (int i = 0; i < con.Size; i++)
    131             {
    132                 hull = CvInvoke.ConvexHull(con2[i], true);
    133                 for (int j = 0; j < hull.Length; j++)
    134                 {
    135                     Point p1 = new Point((int)(hull[j].X + 0.5), (int)(hull[j].Y + 0.5));
    136                     Point p2;
    137                     if (j == hull.Length - 1)
    138                     {
    139                         p2 = new Point((int)(hull[0].X + 0.5), (int)(hull[0].Y + 0.5));
    140                     }
    141                     else
    142                         p2 = new Point((int)(hull[j + 1].X + 0.5), (int)(hull[j + 1].Y + 0.5));
    143                     CvInvoke.Line(outpic, p1, p2, new MCvScalar(255, 0, 255, 255), 2, 0, 0);
    144                 }
    145             }
    146 
    147             Image<Gray, byte> gray = new Image<Gray, byte>(pic.Size);
    148             gray = outpic.Convert<Gray, byte>();
    149             gray = gray.ThresholdBinary(new Gray(100), new Gray(255));
    150             gray = gray.Canny(100, 255);
    151             VectorOfVectorOfPoint con3 = new VectorOfVectorOfPoint();
    152             CvInvoke.FindContours(gray, con3, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
    153             for (int i = 0; i < con3.Size; i++)
    154             {
    155                 CvInvoke.DrawContours(outpic, con3, i, new MCvScalar(255, 0, 0), -1);
    156             }
    157 
    158             return outpic;
    159         }
    160 
    161         /// <summary>
    162         /// 填充缺陷轮廓
    163         /// </summary>
    164         /// <param name="pic"></param>
    165         /// <returns></returns>
    166         private Image<Bgr, byte> ContourFilling2(Image<Gray, byte> pic)
    167         {
    168             Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
    169             pic = pic.Canny(100, 255);
    170             Image<Gray, byte> outcon = new Image<Gray, byte>(pic.Size);
    171             VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();
    172             CvInvoke.FindContours(pic, con, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
    173             for (int i = 0; i < con.Size; i++)
    174             {
    175                 CvInvoke.DrawContours(outpic, con, i, new MCvScalar(0, 255, 255, 0), -1);
    176             }
    177             for (int i = 0; i < con.Size; i++)
    178             {
    179                 CvInvoke.DrawContours(outpic, con, i, new MCvScalar(0, 255, 255, 0),10);
    180             }
    181             return outpic;
    182         }
    183 
    184         /// <summary>
    185         /// 叠加图像
    186         /// </summary>
    187         /// <param name="pic1">输入Bgr图像1</param>
    188         /// <param name="pic2">输入Bgr图像2</param>
    189         /// <returns></returns>
    190         private Image<Bgr, byte> PicSubtraction(Image<Bgr, byte> pic1, Image<Bgr, byte> pic2)
    191         {
    192             Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic1.Size);
    193             pic1 = ContourFilling(ToBin(picture));
    194             pic2 = ContourFilling2(ToBin(picture));
    195             CvInvoke.AddWeighted(pic1, 0.5, pic2, 0.5, 1, outpic);
    196 
    197             return outpic;
    198         }
    199 
    200         /// <summary>
    201         /// Point转换为PointF
    202         /// </summary>
    203         /// <param name="pt">输入Point</param>
    204         /// <returns></returns>
    205         private PointF[] PointToPointF(Point[] pt)
    206         {
    207             PointF[] aaa = new PointF[pt.Length];
    208             int num = 0;
    209             foreach (var point in pt)
    210             {
    211                 aaa[num].X = point.X;
    212                 aaa[num++].Y = (int)point.Y;
    213             }
    214             return aaa;
    215         }
    216 
    217         /// <summary>
    218         /// 填充缺陷轮廓
    219         /// </summary>
    220         /// <param name="pic">输入Bgr图像</param>
    221         /// <returns></returns>
    222         private Image<Bgr, byte> ContourFilling3(Image<Bgr, byte> pic)
    223         {
    224             Image<Bgr, byte> outpic = new Image<Bgr, byte>(pic.Size);
    225             Image<Ycc, byte> ycc = pic.Convert<Ycc, byte>();
    226             for(int i=0;i<ycc.Height;i++)
    227                 for(int j=0;j<ycc.Width;j++)
    228                 {
    229                     if (ycc[i, j].Cr > 35 && ycc[i, j].Cr < 148 &&
    230                         ycc[i, j].Cb > 48 && ycc[i, j].Cb < 141)
    231                     {
    232                         ycc[i, j] = new Ycc(0, 0, 0);
    233                     }
    234                     else ycc[i, j] = new Ycc(255, 255, 255);
    235                 }
    236             Image<Gray, byte> gray = ycc.Convert<Gray, byte>();
    237             gray = gray.ThresholdBinary(new Gray(100 ), new Gray(255));
    238             gray = gray.Canny(100, 60);
    239             Image<Gray, byte> outcon = new Image<Gray, byte>(pic.Size);
    240             VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();
    241             CvInvoke.FindContours(gray, con, outcon, RetrType.External, ChainApproxMethod.ChainApproxNone);
    242             int n=0;
    243 
    244                 for (int i = 0; i < con.Size; i++)
    245                 {
    246                     if (CvInvoke.ContourArea(con[i]) >0)
    247                     {
    248                         n++;
    249 
    250                     }
    251                 }
    252             textBox1.Text = "" + n.ToString() + "个缺陷"+"      ";
    253             n = 0;
    254             for (int i = 0; i <con .Size ; i++)
    255             {
    256                 if (CvInvoke.ContourArea(con[i]) >0)
    257                 {
    258                     CvInvoke.DrawContours(outpic, con, i, new MCvScalar(0, 255, 0), 5);
    259                     textBox1.Text = textBox1.Text + "" + (++n).ToString() + "个缺陷的面积为" + CvInvoke.ContourArea(con[i]);
    260                 }
    261             }
    262             CvInvoke.AddWeighted(outpic , 0.5,picture , 0.5, 0, outpic);
    263             return outpic;
    264         }
    265 
    266     }
    267 }
  • 相关阅读:
    软件工程第五次作业——例行报告
    “Hello world!”团队—团队选题展示(视频展示说明)
    “Hello world!”团队—文案+美工
    “Hello world!”团队—选题展示
    “Hello world!”贡献分分配规则
    “hello world!”团队第三次会议
    软件工程第四次作业——例行报告
    【AtCoder】ARC092 D
    Set和数组的互换
    优先队列的基本用法(java和c++)
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13902008.html
Copyright © 2020-2023  润新知