C#:用OpenCV實現(xiàn)缺陷檢測

一描馅、簡介

  • 機(jī)器視覺應(yīng)用場景中缺陷檢測的應(yīng)用是非常廣泛的把夸,通常涉及各個行業(yè)、各種缺陷類型铭污。
  • 紡織物的缺陷檢測恋日,缺陷類型包含臟污膀篮、油漬、線條破損三種岂膳,這三種缺陷與LCD屏幕檢測的缺陷很相似誓竿,處理方法也可借鑒。
  • 使用OpenCV中的FindContours函數(shù)可以 實現(xiàn)紡織物缺陷檢測(臟污谈截、油漬筷屡、線條破損缺陷)。

二簸喂、FindContours函數(shù)

  • FindContours函數(shù)
    找輪廓
void findContours( InputOutputArray image, 
      OutputArrayOfArrays contours,
      OutputArray hierarchy, int mode,
      int method, Point offset = Point());
  • InputOutputArray image:輸入圖像是8位單通道的圖像(256級灰度圖)毙死。
    其中像素點的非0灰度值被當(dāng)成1(轉(zhuǎn)化后即為255),0值保持0喻鳄,所以輸入圖像被當(dāng)成一個二值圖像對待扼倘。
    可以用 compare() , inRange() , threshold() , adaptiveThreshold() , Canny() 或者其他方法來從灰度圖或者彩色圖中生成二值圖像。該函數(shù)在提取輪廓的過程中會改變圖像除呵。
    如果第4個參數(shù) 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: 可選的輸出向量袄简,包含圖像的拓?fù)湫畔?br> It has as many elements as the number of contours. 元素個數(shù) = 輪廓數(shù)
    對于第 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泛啸,如果不存在绿语,置為負(fù)數(shù)

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

三、檢測條件

先進(jìn)行二值化候址、高斯濾波吕粹、平滑等處理。再進(jìn)行輪廓分析岗仑。

  • 臟污
    輪廓圓弧長度大于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>結(jié)果圖</returns> //也可設(shè)置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; //輪廓查找結(jié)果變量
            HierarchyIndex[] hierarchy; //輪廓拓?fù)浣Y(jié)構(gòu)變量

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

            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>結(jié)果圖</returns> //也可設(shè)置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; //輪廓查找結(jié)果變量
            HierarchyIndex[] hierarchy; //輪廓拓?fù)浣Y(jié)構(gòu)變量

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

            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>結(jié)果圖</returns> //也可設(shè)置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; //輪廓查找結(jié)果變量
            HierarchyIndex[] hierarchy; //輪廓拓?fù)浣Y(jié)構(gòu)變量

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

            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深度學(xué)習(xí)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荠雕,一起剝皮案震驚了整個濱河市稳其,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炸卑,老刑警劉巖既鞠,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盖文,居然都是意外死亡嘱蛋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洒敏,“玉大人龄恋,你說我怎么就攤上這事⌒谆铮” “怎么了郭毕?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長函荣。 經(jīng)常有香客問我铣卡,道長,這世上最難降的妖魔是什么偏竟? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮敞峭,結(jié)果婚禮上踊谋,老公的妹妹穿的比我還像新娘。我一直安慰自己旋讹,他們只是感情好殖蚕,可當(dāng)我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沉迹,像睡著了一般睦疫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞭呕,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼迹缀。 笑死胁艰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腋么。 我是一名探鬼主播咕娄,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼珊擂!你這毒婦竟也來了圣勒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤摧扇,失蹤者是張志新(化名)和其女友劉穎圣贸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扛稽,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡旁趟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锡搜。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡橙困,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耕餐,到底是詐尸還是另有隱情凡傅,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布肠缔,位于F島的核電站夏跷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏明未。R本人自食惡果不足惜槽华,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趟妥。 院中可真熱鬧猫态,春花似錦、人聲如沸披摄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疚膊。三九已至义辕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寓盗,已是汗流浹背灌砖。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留傀蚌,地道東北人周崭。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像喳张,于是被迫代替她去往敵國和親续镇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容