C++ OpenCV实战之零部件的自动光学检测

目录
  • 一、背景
  • 二、基础知识
  • 三、代码实现
    • 1、实现多窗口展示
    • 2、降噪处理
    • 3、背景去除
    • 4、连通图实现
    • 5、计算连通域面积
    • 6、轮廓检测
  • 四、总结

一、背景

首先任务背景是AOI(自动光学检测)

最重要的目的在于:将前景和物体进行分割与分类;

场景示意图:

需要注意,在螺母的传送带上,需要有前光和背光,给物体打光才能够拍摄清晰的图像;

二、基础知识

首先分为以下几步:

1、噪声抑制(预处理)

2、背景移除(分割)

3、二值化

4、连通域、轮廓查找算法

降噪算法

先使用中值滤波对椒盐噪声进行过滤,再使用高斯滤波对物体边缘进行模糊;

背景移除

首先有两种方案可以实现背景移除,也就是减法和除法;

连通图检测计数

首先连通域类型分为4路连通和8路连通:

使用连通图检测算法,可以将不连通的每个物体都用不同颜色划分出来;

三、代码实现

1、实现多窗口展示

如果想要多张图像展示在一个窗口中,也就是实现拼接图片的操作,使用Python代码实现起来可能比较便捷,C++代码需要定义一个类,并且实际编写也比较繁琐;

class Display {
private:
	int cols, rows, width, height;
	String title;
	vector<String> win_names;
	vector<Mat> images;
	Mat canvas;
public:
	Display(String t, int c, int r, int flags) :title(t), cols(c), rows(r) {
		height = 1080;
		width = 1920;
		namedWindow(title, flags);
		canvas = Mat(height, width, CV_8UC3);
		imshow(title, canvas);
	}

	int add_window(String win_name, Mat image, bool flag = true) {
		win_names.push_back(win_name);
		images.push_back(image);
		if (flag) {
			draw();
		}
		return win_names.size();
	}

    // 实现删除窗口
	int delete_window(String win_name) {
		int index = 0;
		for (const auto& it : win_names) {
			if (it == win_name) break;
			index++;
		}
		win_names.erase(win_names.begin() + index);
		images.erase(images.begin() + index);

		return win_names.size();
	}

	void draw() {
		canvas.setTo(Scalar(20, 20, 20));
		int single_width = width / cols;
		int single_height = height / rows;
		int max_win = win_names.size() > cols * rows ? cols * rows : win_names.size();

		int i = 0;
		auto iw = win_names.begin();
		for (auto it = images.begin(); it != images.end()&&i<max_win; it++,i++,iw++) {
			String win_name = *iw;
			Mat img = *it;

			int x = (single_width) * (i % cols);
			int y = (single_height)*floor(i * 1.0 / cols);
			Rect mask(x, y, single_width, single_height);

			rectangle(canvas, mask, Scalar(255, 255, 255), 9);

			Mat resized_img;
			resize(img, resized_img, Size(single_width, single_height));

			Mat sub_canvas(canvas, mask);
			if (resized_img.channels() == 1) {
				cvtColor(resized_img, resized_img, COLOR_GRAY2BGR);
			}
			resized_img.copyTo(sub_canvas);
            putText(sub_canvas, win_name, Point(50, 50), FONT_HERSHEY_COMPLEX, 2, Scalar(0, 0, 255), 3, LINE_AA);
		}
		imshow(title, canvas);
	}
};

// 使用智能指针
shared_ptr<Display> multi_window;

int main(int argc, char** argv)
{

	// 实现多窗口
	String total_path = "imgpath";
	String background_path = "imgpath";

	Mat abc = imread(total_path, 0);

	multi_window = make_shared<Display>("Review for all", 3, 2, WINDOW_NORMAL);
	multi_window->add_window("ABC", abc);
	multi_window->add_window("ABCC", abc);
    multi_window->delete_window("ABC");		// 也支持删除窗口
	multi_window->draw();

	waitKey(0);
	return 0;
}

2、降噪处理

采用中值滤波+高斯滤波结合的降噪方法:

Mat get_background(const Mat& bg){
    Mat img;
    medianBlur(bg,img,3);
    GaussianBlur(bg,img,Size(3,3),0);
    return img;
}

Mat smoothen_img(const Mat& noise_img){
    Mat img;
    medianBlur(noise_img,img,5);
    GaussianBlur(img,img,Size(3,3),0);
    return img;
}

3、背景去除

分为两种方式,一种为减法,一种为除法;

Mat remove_background_divide(Mat image, Mat background) {
	Mat tmp;
	Mat fg, bg;
	image.convertTo(fg, CV_32F);
	background.convertTo(bg, CV_32F);
	tmp = 1 - (fg / bg);
	tmp.convertTo(tmp, CV_8U, 255);
	return tmp;
}

Mat remove_background_minus(Mat image, Mat background) {
	return background - image;
}

从结果图上看,使用除法的方式能更好的保留白色部分的信息,因此选用除法的方式;

4、连通图实现

对二值化后的图像进行连通域划分,并且用随机颜色绘制到Mask图上;

void connection_check(Mat image) {
	Mat labels;
	int num = connectedComponents(image, labels);
	if (num <= 1) {
		cout << "No stuff detect!!" << endl;
		return;
	}
	else
	{
		cout << num << " objects detected!!" << endl;
	}

	Mat display = Mat::zeros(image.rows, image.cols, CV_8UC3);
	for (int i = 1; i < num; i++) {
		Mat mask = (labels == i);
		display.setTo(random_color_generator(seed), mask);
	}
	multi_window->add_window("Segment", display);
}

5、计算连通域面积

OpenCV中也自带了对面积区域的计算:

void connection_heavy_check(Mat image) {
    Mat labels, stats, centroids;
    int num =connectedComponentsWithStats(image, labels, stats, centroids);
    if (num <= 1) {
        cout << "No stuff detect!!" << endl;
        return;
    }
    else
    {
        cout << num << " objects detected!!" << endl;
    }
    Mat display = Mat::zeros(image.rows, image.cols, CV_8UC3);
    for (int i = 1; i < num; i++) {
        // 得到连通域的质心点
        Point2i pt(centroids.at<double>(i, 0), centroids.at<double>(i, 1));
        // 打印标签和连通域坐标和面积
        cout << "Stuff #" << i << ", Position: " << pt << " ,Area: " << stats.at<int>(i, CC_STAT_AREA) << endl;
        Mat mask = (labels == i);
        display.setTo(random_color_generator(seed), mask);
        stringstream ss;
        ss << stats.at<int>(i, CC_STAT_AREA);
        putText(display, ss.str(), pt, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255), 2);
    }
    multi_window->add_window("Segment more", display);
}

6、轮廓检测

实现对物体轮廓的检测;

void get_contour(Mat image) {
    vector<vector<Point>> contours;
    findContours(image, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    Mat display = Mat::zeros(image.rows, image.cols, CV_8UC3);
    if (contours.size() == 0) {
        cout << "No contour detect!!" << endl;
        return;
    }
    else
    {
        cout << contours.size() << " contour detected!!" << endl;
    }
    for (int i = 0; i < contours.size(); i++) {
        drawContours(display, contours, i, random_color_generator(seed), 2);
    }
    multi_window->add_window("CONTOURS", display);
}

从上结果图可知,检测到的轮廓并不包含内部轮廓,如果想检测所有轮廓应该将findContours函数中的类型参数改为RETR_LIST即可;

四、总结

本次项目中涉及的技术点如下:

  • 多窗口展示
  • 背景去除
  • 连通图的实现
  • 轮廓边缘检测

并且在实际的C++代码中,还涉及了智能指针等高阶知识;

工业质检项目作为视觉领域较为成熟的落地项目,其大部分都是基于深度学习的方式实现了,但如果能掌握一些OpenCV的方法,也可以在项目中起到优化效果的作用;

到此这篇关于C++ OpenCV实战之零部件的自动光学检测的文章就介绍到这了,更多相关C++ OpenCV光学检测内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈opencv自动光学检测、目标分割和检测(连通区域和findContours)

    步骤如下: 1.图片灰化: 2.中值滤波 去噪 3.求图片的光影(自动光学检测) 4.除法去光影 5.阈值操作 6.实现了三种目标检测方法 主要分两种连通区域和findContours 过程遇到了错误主要是图片忘了灰化处理,随机颜色的问题.下面代码都已经进行了解决 这是findContours的效果 下面是连通区域的结果 #include <opencv2\core\utility.hpp> #include <opencv2\imgproc.hpp> #include <o

  • C++ OpenCV实现二维码检测功能

    目录 前言 一.二维码检测 二.二维码识别 三.二维码绘制 四.源码 总结 前言 本文将使用OpenCV C++ 进行二维码检测. 一.二维码检测 首先我们要先将图像进行预处理,通过灰度.滤波.二值化等操作提取出图像轮廓.在这里我还添加了形态学操作,消除噪点,有效将矩形区域连接起来. Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); Mat blur; GaussianBlur(gray, blur, Size(3, 3), 0); Mat bin;

  • opencv3/C++实现霍夫圆/直线检测

    霍夫直线检测 参数说明: cv::HoughLinesP( InputArray src, // 输入图像(8位灰度图像) OutputArray lines, // 输出直线两点坐标(vector<Vec4i>) double rho, // 生成极坐标时候的像素扫描步长 double theta, //生成极坐标时候的角度步长(一般取CV_PI/180) int threshold, // 累加器阈值,获得足够交点的极坐标点才被看成是直线 double minLineLength=0;//

  • C++利用opencv实现人脸检测

    小编所有的帖子都是基于unbuntu系统的,当然稍作修改同样试用于windows的,经过小编的绞尽脑汁,把刚刚发的那篇python 实现人脸和眼睛的检测的程序用C++ 实现了,当然,也参考了不少大神的博客,下面我们就一起来看看: Linux系统下安装opencv我就再啰嗦一次,防止有些人没有安装没调试出来喷小编的程序是个坑, sudo apt-get install libcv-dev sudo apt-get install libopencv-dev 看看你的usr/share/opencv

  • C++ opencv图像处理实现图片边缘检测示例

    目录 边缘检测简介 一.边缘检测步骤 二.Canny 1.函数 2.代码 二.Sobel 1.函数 2.代码 三.Scharr 1.函数 2.代码 四.Laplacian 1.函数 2.代码 总结 边缘检测简介 边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点. 图像边缘检测大幅度地减少了数据量,并且剔除量不相关的信息,保留了图像重要的结构属性. 一.边缘检测步骤 1.图像获取 2.图像滤波 3.图像增强 4.图像检测 5.图像定位 二.Canny 1.

  • C++ OpenCV实战之零部件的自动光学检测

    目录 一.背景 二.基础知识 三.代码实现 1.实现多窗口展示 2.降噪处理 3.背景去除 4.连通图实现 5.计算连通域面积 6.轮廓检测 四.总结 一.背景 首先任务背景是AOI(自动光学检测) 最重要的目的在于:将前景和物体进行分割与分类: 场景示意图: 需要注意,在螺母的传送带上,需要有前光和背光,给物体打光才能够拍摄清晰的图像: 二.基础知识 首先分为以下几步: 1.噪声抑制(预处理) 2.背景移除(分割) 3.二值化 4.连通域.轮廓查找算法 降噪算法 先使用中值滤波对椒盐噪声进行过

  • Python+Opencv实战之人脸追踪详解

    目录 前言 人脸追踪技术简介 使用基于 dlib DCF 的跟踪器进行人脸跟踪 使用基于 dlib DCF 的跟踪器进行对象跟踪 小结 前言 人脸处理是人工智能中的一个热门话题,人脸处理可以使用计算机视觉算法从人脸中自动提取大量信息,例如身份.意图和情感:而目标跟踪试图估计目标在整个视频序列中的轨迹,其中只有目标的初始位置是已知的,将这两者进行结合将产生许多有趣的应用.由于外观变化.遮挡.快速运动.运动模糊和比例变化等多种因素,人脸追踪非常具有挑战性. 人脸追踪技术简介 基于判别相关滤波器 (d

  • Python OpenCV实战之与机器学习的碰撞

    目录 0. 前言 1. 机器学习简介 1.1 监督学习 1.2 无监督学习 1.3 半监督学习 2. K均值 (K-Means) 聚类 2.1 K-Means 聚类示例 3. K最近邻 3.1 K最近邻示例 4. 支持向量机 4.1 支持向量机示例 小结 0. 前言 机器学习是人工智能的子集,它为计算机以及其它具有计算能力的系统提供自动预测或决策的能力,诸如虚拟助理.车牌识别系统.智能推荐系统等机器学习应用程序给我们的日常生活带来了便捷的体验.机器学习的蓬勃发展,得益于以下三个关键因素:1) 海

  • C++ OpenCV实战之文档照片转换成扫描文件

    目录 一.背景 二.基础知识 三.方案一:自动检测点 1.读取图片文件(进行了指定尺寸缩放) 2.创建直线类并计算两条直线的交点 3.图像边缘检测Canny 4.通过霍夫变换进行直线检测 5.求单应性矩阵 6.降噪和二值化 四.方案二:用户点选目标区域 1.命令行解析 2.鼠标事件 3.主函数实现 4.结果展示 五.总结 一.背景 前段时间都是基于Python的OpecCV进行一些学习和实践,但小的知识点并没有应用到实际的项目中:并且基于Python的版本的移植性.效率性都较差,在包含硬件的项目

  • Python Opencv实战之文字检测OCR

    目录 1.相关函数的讲解 2.代码展示 Detecting Words Detecting ONLY Digits 3.问题叙述 4.image_to_data()配置讲解 5.项目拓展 6.总结与评价 1.相关函数的讲解 image_to_data()的输出结果是表格形式,输出变量的类型依旧是字符串. 你会得到一个这样的列表['level', 'page_num', 'block_num', 'par_num', 'line_num', 'word_num', 'left', 'top', '

  • python利用opencv如何实现答题卡自动判卷

    目录 1.设定答题卡模板 2.读取答题卡图像并对图像进行灰度化处理 3.高斯模糊图像去噪点 4.使用大津法二值分割图像 5.使用开运算去噪点 6.使用canny边缘检测算法 7.筛选答题区域轮廓,透视变换矫正目标区域 使用摄像头实时判卷部分 总结 1.设定答题卡模板 该图像为答题卡的答题区域,黑色边框是为了能够在各种环境中轻易的检测,左部分和上部分的黑色矩形,是为能够定位到答题选项的坐标而设置,同时题目数量为20×3共60道选择题,在进行批改试卷之前,需要手动输入该次考试的正确答案作为模板来对识

  • Python+OpenCV实战之利用 K-Means 聚类进行色彩量化

    目录 前言 利用 K-Means 聚类进行色彩量化 完整代码 显示色彩量化后的色彩分布 前言 K-Means 聚类算法的目标是将 n 个样本划分(聚类)为 K 个簇,在博文<OpenCV与机器学习的碰撞>中,我们已经学习利用 OpenCV 提供了 cv2.kmeans() 函数实现 K-Means 聚类算法,该算法通过找到簇的中心并将输入样本分组到簇周围,同时通过简单的示例了解了 K-Means 算法的用法.在本文中,我们将学习如何利用 K-Means 聚类进行色彩量化,以减少图像中颜色数量.

  • C++ OpenCV实战之图像全景拼接

    目录 前言 一.OpenCV Stitcher 1.功能源码 2.效果 二.图像全景拼接 1.特征检测 2.计算单应性矩阵 3.透视变换 4.图像拼接 5.功能源码 6.效果 三.源码 总结 前言 本文将使用OpenCV C++ 进行图像全景拼接.目前使用OpenCV对两幅图像进行拼接大致可以分为两类. 一.使用OpenCV内置API Stitcher 进行拼接. 二.使用特征检测算法匹配两幅图中相似的点.计算变换矩阵.最后对其进行透视变换就可以了. 一.OpenCV Stitcher imag

  • OpenCV实战之AI照片背景替换

    目录 导语 正文 1)附主程序 2)展示其他 总结 导语 不少人在生活中都有抠人像图换背景的需求.那怎么抠图呢? 相信不少人第一时间就想到了 PS 抠图大法,为了学会 PS 抠图很多人还花费不少精力,而且学会后大家想必都有共同感触:PS 抠图在制作抠图选区这个步骤太耗费时间!!就跟我减肥似的! 今天木木子就手把手教大家编写一款抠图人像技术—— 这款小程序实现一键智能抠取人像图的功能,非常强大! 比 PS 慢慢抠图效率可提升了太多了,而且还能让不会 PS 的群体也能轻松学会抠人像图. 吹了这么多,

随机推荐