C#:用OpenCV實現缺陷檢測

一、簡介

  • 機器視覺應用場景中缺陷檢測的應用是非常廣泛的,通常涉及各個行業、各種缺陷類型。
  • 紡織物的缺陷檢測,缺陷類型包含髒污、油漬、線條破損三種,這三種缺陷與LCD屏幕檢測的缺陷很相似,處理方法也可借鑑。
  • 使用OpenCV中的FindContours函數可以 實現紡織物缺陷檢測(髒污、油漬、線條破損缺陷)。

二、FindContours函數

  • FindContours函數
    找輪廓
void findContours( InputOutputArray image, 
      OutputArrayOfArrays contours,
      OutputArray hierarchy, int mode,
      int method, Point offset = Point());
  • InputOutputArray image:輸入圖像是8位單通道的圖像(256級灰度圖)。
    其中像素點的非0灰度值被當成1(轉化後即爲255),0值保持0,所以輸入圖像被當成一個二值圖像對待。
    可以用 compare() , inRange() , threshold() , adaptiveThreshold() , Canny() 或者其他方法來從灰度圖或者彩色圖中生成二值圖像。該函數在提取輪廓的過程中會改變圖像
    如果第4個參數 mode 爲 CV_RETR_CCOMP 或者
    CV_RETR_FLOODFILL,輸入圖像也可以是32位的整型圖像(CV_32SC1)。

  • OutputArrayOfArrays contours: 檢測到的輪廓
    Each contour is stored as a vector of points. 每個輪廓會被存儲爲vector<Point>
    所以 contours 的類型是vector<vector<Point>>

  • OutputArray hierarchy: 可選的輸出向量,包含圖像的拓撲信息
    It has as many elements as the number of contours. 元素個數 = 輪廓數
    對於第 i 個輪廓contours[i],hierarchy 的以下元素分別表示
    hierarchy[i][0]: the next contour at the same hierarchical level
    hierarchy[i][1]: the previous contour at the same hierarchical level
    hierarchy[i][2]: the first child contour
    hierarchy[i][3]: the parent contour
    hierarchy 的這些元素的原始值爲0,如果不存在,置爲負數

  • int mode: Contour retrieval mode 取回輪廓模式(複雜度依次增加)

三、檢測條件

先進行二值化、高斯濾波、平滑等處理。再進行輪廓分析。

  • 髒污
    輪廓圓弧長度大於1
  • 油漬
    輪廓面積大於50
  • 線條破損
    輪廓圓弧長度大於10


四、程序源碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Sunny.UI;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace Ky_FindContours
{
    public partial class Form1 : UIForm
    {
        public Form1()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);

        }
        private Image image = null;
        private Mat dst = new Mat();
        private Mat src_img;
        string filePath = "";
        private List<Mat> reList = new List<Mat>();
        private int step = 1;

        private void openImage_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "選擇操作的圖片";
            openFileDialog.Filter = "圖片 *.jpg|*.jpg|圖像*.png|*.png";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                filePath = openFileDialog.FileName;
                image = Image.FromFile(filePath);
                src_img = Cv2.ImRead(filePath);
                Mat tem1 = new Mat();
                src_img.CopyTo(tem1);
                if (reList.Count > 0)
                {
                    reList[0] = tem1;

                }
                else
                {
                    reList.Add(tem1);
                }

            }
            if (filePath != "")
            {
                picBoxShowDel.Image = image;
                picShowOri.Image = image;
            }

        }

        /// <summary>
        /// 髒污缺陷檢測
        /// </summary>
        /// <param name="img">測試圖像</param>
        /// <returns>結果圖</returns> //也可設置bool類型表示OK或NG
        static Mat DirtyDetection(Mat img)
        {
            Mat result = img.Clone();
            Mat gray = new Mat();
            Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
            Cv2.GaussianBlur(gray, gray, new OpenCvSharp.Size(7, 7), 0);
            Cv2.Canny(gray, gray, 10, 30);
            OpenCvSharp.Point[][] contours; //輪廓查找結果變量
            HierarchyIndex[] hierarchy; //輪廓拓撲結構變量

            Cv2.FindContours(gray, out contours, out hierarchy, RetrievalModes.External,
                            ContourApproximationModes.ApproxNone);
            //Console.WriteLine("contour_size = {0}", contours.Length); //輸出輪廓個數

            for (int i = 0; i < contours.Length; i++)
            {
                double length = Cv2.ArcLength(contours[i], true);
                if (length >= 1)
                    Cv2.DrawContours(result, contours, i, new Scalar(0, 0, 255), 2);
            }
            return result;
        }

        /// <summary>
        /// 油污缺陷檢測
        /// </summary>
        /// <param name="img">測試圖像</param>
        /// <returns>結果圖</returns> //也可設置bool類型表示OK或NG
        static Mat OilDetection(Mat img)
        {
            Mat result = img.Clone();
            Mat imgLab = new Mat();
            Cv2.CvtColor(img, imgLab, ColorConversionCodes.BGR2Lab);
            Mat[] labArray = Cv2.Split(imgLab); //L, a, b
            Mat blur = new Mat();
            Mat thres = new Mat();
            Cv2.GaussianBlur(labArray[2], blur, new OpenCvSharp.Size(3, 3), 0); //b通道
            Cv2.Threshold(blur, thres, 130, 255, ThresholdTypes.Binary);
            Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1));
            Cv2.MorphologyEx(thres, thres, MorphTypes.Open, element, new OpenCvSharp.Point(-1, -1), 1,
                             BorderTypes.Default, new Scalar());

            OpenCvSharp.Point[][] contours; //輪廓查找結果變量
            HierarchyIndex[] hierarchy; //輪廓拓撲結構變量

            Cv2.FindContours(thres, out contours, out hierarchy, RetrievalModes.External,
                            ContourApproximationModes.ApproxNone);
            //Console.WriteLine("contour_size = {0}", contours.Length); //輸出輪廓個數

            for (int i = 0; i < contours.Length; i++)
            {
                double area = Cv2.ContourArea(contours[i]);
                if (area >= 50)
                    Cv2.DrawContours(result, contours, i, new Scalar(0, 0, 255), 2);
            }
            return result;
        }

        /// <summary>
        /// 線條破損缺陷檢測
        /// </summary>
        /// <param name="img">測試圖像</param>
        /// <returns>結果圖</returns> //也可設置bool類型表示OK或NG
        static Mat LineDefectDetection(Mat img)
        {
            Mat result = img.Clone();
            Mat imgLab = new Mat();
            Cv2.CvtColor(img, imgLab, ColorConversionCodes.BGR2Lab);
            Mat[] labArray = Cv2.Split(imgLab); //L, a, b
            Mat blur = new Mat();
            Mat edged = new Mat();
            Cv2.GaussianBlur(labArray[2], blur, new OpenCvSharp.Size(3, 3), 0); //b通道
            Cv2.Canny(blur, edged, 5, 10);
            OpenCvSharp.Point[][] contours; //輪廓查找結果變量
            HierarchyIndex[] hierarchy; //輪廓拓撲結構變量

            Cv2.FindContours(edged, out contours, out hierarchy, RetrievalModes.External,
                            ContourApproximationModes.ApproxNone);
            //Console.WriteLine("contour_size = {0}", contours.Length); //輸出輪廓個數

            for (int i = 0; i < contours.Length; i++)
            {
                double length = Cv2.ArcLength(contours[i], true);
                if (length >= 10)
                    Cv2.DrawContours(result, contours, i, new Scalar(0, 0, 255), 2);
            }
            return result;
        }

        private void uiButton1_Click(object sender, EventArgs e)
        {
            Mat zw_result = DirtyDetection(src_img); //髒污缺陷檢測
            picBoxShowDel.Image = zw_result.ToBitmap();
        }

        private void uiButton2_Click(object sender, EventArgs e)
        {
            Mat yw_result = OilDetection(src_img); //油污缺陷檢測
            picBoxShowDel.Image = yw_result.ToBitmap();
        }

        private void uiButton3_Click(object sender, EventArgs e)
        {
            Mat yw_result = LineDefectDetection(src_img); //線條破損缺陷檢測
            picBoxShowDel.Image = yw_result.ToBitmap();
        }
    }
}

五、參考資料

博客:https://blog.51cto.com/stq054188/5543992
來源公衆號:OpenCV與AI深度學習
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章