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深度学习
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容