赞
踩
2D图像基础,滤波,直方图统计,模板匹配
3D处理基础,点云滤波,点云分割
基于c++开发,测试
产品异常产生缺陷,缺陷检测检出产品是否存在缺陷,即使识别次品,避免造成更大的损失。
内部缺陷:气泡,孔洞,内部裂纹(检测技术:x射线,超声波,机械应力波)
外部缺陷:刮痕,破损,脏污(检测技术 2D(图像处理,滤波,分割),3D(点云,深度图))
例如:
环形3D结构光,不同高度具有不同的颜色,依赖光源的稳定性,均匀性等。
3D的数据,点云和深度图。主要以PCB检测为例,比如少锡、多锡、虚焊。通过检测爬锡高度,或者爬坡角度等指标,卡控不良。
缺陷检测的准确率很重要,漏检容易造成很严重的问题。
由于精度高,一般是先对样品扫描,扫描过后再拼接,得到样品的全景图,再进行后续处理。可以检测元器件的偏移,管脚翘脚,少锡,虚焊,浮高等。
缺陷检测的任务可以分为检测,分类,分割。检测包含了分类和坐标回归。分割提取目标轮廓信息。计算复杂度:一般分割>检测>分类。
mobile-net,yolov5,ICNet。
有监督学习,分类
无监督学习,聚类,难度大
深度学习参数少,几乎能适应各种各样的缺陷检测,项目多,存在小样本,小目标问题。对于实时性的要求需要量化模型,进行剪枝,知识蒸馏,也可以采用清凉模型。
3D成像系统 激光线扫,结构光扫描等。
光源位置方向,相机位置方向,可以求得相交位置处像素点的空间位置。
一般是条纹结构光,对拍摄的条纹结构进行解度可以得到物体表面的信息。
受物体材料朗伯反射性能影响。解码包裹相位,光栅序列,求得绝对相位,转换成点云。
点云可以分为有序点云和无序点云。
深度图灰度值表示高度值
mesh渲染,点云图并不连续的,而经过mesh渲染则可以看到连续的表面。
PCL开源库
简述:
计算机视觉场景广泛,以深度学习为主,精度不高。图像处理算法。
机器视觉场景固定,以传统学习为主。图像采集,镜头控制,图像处理等算法。
操作系统 Linux,编程语言python,c++,图像处理基础知识,OpenCV使用。
去除噪声提升图像质量:均值,中值,高斯滤波
高通:比如边缘提取 canny,sobel,laplacian等算子
·
还有自适应中值滤波:
OpenCV 中没有直接提供自适应中值滤波(Adaptive Median Filter)的函数,但你可以自己实现它。自适应中值滤波器与常规中值滤波器不同,它根据像素邻域内的特定条件调整窗口大小,这使得它在去除噪声(特别是“盐和胡椒”噪声)的同时更好地保护图像细节。
自适应中值滤波的基本步骤如下:
以下是一个简单的自适应中值滤波的实现示例:
- #include <opencv2/opencv.hpp>
- #include <algorithm>
-
- using namespace cv;
-
- void adaptiveMedianFilter(const Mat &src, Mat &dst, int maxSize) {
- dst = src.clone();
- for (int i = 0; i < src.rows; i++) {
- for (int j = 0; j < src.cols; j++) {
- int windowSize = 3;
- while (windowSize <= maxSize) {
- int halfSize = windowSize / 2;
- std::vector<uchar> neighbors;
- for (int x = -halfSize; x <= halfSize; x++) {
- for (int y = -halfSize; y <= halfSize; y++) {
- int ni = i + x, nj = j + y;
- if (ni >= 0 && ni < src.rows && nj >= 0 && nj < src.cols) {
- neighbors.push_back(src.at<uchar>(ni, nj));
- }
- }
- }
- std::nth_element(neighbors.begin(), neighbors.begin() + neighbors.size() / 2, neighbors.end());
- uchar median = neighbors[neighbors.size() / 2];
-
- // 判断中值是否是极端值
- auto minMax = std::minmax_element(neighbors.begin(), neighbors.end());
- if (median != *minMax.first && median != *minMax.second) {
- dst.at<uchar>(i, j) = median;
- break;
- }
- windowSize += 2; // 增加窗口大小
- }
- }
- }
- }
-
- int main() {
- Mat image = imread("path/to/your/image.jpg", IMREAD_GRAYSCALE);
- if(image.empty()) {
- std::cout << "Could not open or find the image" << std::endl;
- return -1;
- }
-
- Mat filteredImage;
- adaptiveMedianFilter(image, filteredImage, 7); // 使用最大窗口大小为 7
-
- imshow("Original Image", image);
- imshow("Adaptive Median Filtered Image", filteredImage);
- waitKey(0);
- destroyAllWindows();
-
- return 0;
- }
确保模板内元素和求平均为1。
深度图像
深度图像(depth image)也被称为距离影像(range image),是指将从图像采集器到场景中各点的距离(深度)作为像素值的图像,它直接反映了景物可见表面的几何形状。
深度图像经过坐标转换可以计算为点云数据,有规则及必要信息的点云数据也可以反算为深度图像数据。
深度数据流所提供的图像帧中,每一个像素点代表的是在深度感应器的视野中,该特定的(x, y)坐标处物体到离摄像头平面最近的物体到该平面的距离(以毫米为单位).
图像深度
图像深度 是指存储每个像素所用的位数,也用于量度图像的色彩分辨率。
图像深度 确定彩色图像的每个像素可能有的颜色数,或者确定灰度图像的每个像素可能有的灰度级数。它决定了彩色图像中可出现的最多颜色数,或灰度图像中的最大灰度等级。比如一幅单色图像,若每个像素有8位,则最大灰度数目为2的8次方,即256。一幅彩色图像RGB三通道的像素位数分别为4,4,2,则最大颜色数目为2的4+4+2次方,即1024,就是说像素的深度为10位,每个像素可以是1024种颜色中的一种。
提取形状,数量统计
先是前景分割,再独立分割。
在计算机视觉和图像处理领域,Blob(二值图像区域)分析是一种常用的技术,主要用于识别和分析图像中的连续像素区域(称为blobs),这些区域在形状、大小、亮度等方面具有某种共同特征。Blob分析通常用于物体检测、追踪、形状分析等任务。以下是Blob分析的一些关键步骤和技术:
预处理:包括降噪、增强对比度等,以提高Blob检测的准确性。
二值化:将图像转换为黑白二值图像,通常使用阈值分割。
Blob检测:在二值图像中识别连续的像素区域。常用方法包括连通区域标记(Connected Component Labeling)和轮廓检测(如OpenCV中的findContours
)。
Blob特征提取:计算每个Blob的特征,如面积、周长、重心位置、形状描述子等。
后处理:根据需要对Blobs进行分类、筛选或追踪。
在 C++ 中使用 OpenCV 库的 threshold
函数进行图像阈值处理是一个常见的操作。该函数主要用于将图像转换成二值图像,即将图像中的像素值根据给定的阈值分为两部分。以下是 OpenCV 的 threshold
函数在 C++ 中的使用方法:
double cv::threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
src
: 输入图像,必须是单通道图像,例如灰度图。dst
: 输出图像,它是二值化后的图像。thresh
: 阈值。maxval
: 当像素值超过(或根据阈值类型,可能是低于)阈值时应该被赋予的最大值。type
: 阈值类型,常见的类型包括:THRESH_BINARY
:如果像素值大于阈值,则赋值为maxval
,否则为0。THRESH_BINARY_INV
:如果像素值大于阈值,则赋值为0,否则为maxval
。THRESH_TRUNC
:如果像素值大于阈值,则赋值为阈值,否则保持不变。THRESH_TOZERO
:如果像素值小于阈值,则赋值为0,否则保持不变。THRESH_TOZERO_INV
:如果像素值大于阈值,则赋值为0,否则保持不变。threshhold使用:
- #include <opencv2/opencv.hpp>
- #include <iostream>
-
- using namespace cv;
-
- int main() {
- // 读取图像
- Mat src = imread("path_to_image.jpg", IMREAD_GRAYSCALE);
- if (src.empty()) {
- std::cerr << "Error: Loading image" << std::endl;
- return -1;
- }
-
- Mat dst;
- double thresh = 100; // 设定阈值
- double maxval = 255; // 设定最大值
-
- // 应用阈值处理
- threshold(src, dst, thresh, maxval, THRESH_BINARY);
-
- // 显示图像
- imshow("Original Image", src);
- imshow("Thresholded Image", dst);
-
- waitKey(0);
- return 0;
- }
在 OpenCV 中,morphologyEx
函数用于执行各种形态学操作,如腐蚀、膨胀、开运算、闭运算等。这些操作通常用于图像预处理、特征提取或去除噪声。以下是如何在 C++ 中使用 morphologyEx
函数的简介:
void cv::morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue())
src
: 输入图像。dst
: 输出图像,与输入图像具有相同的大小和类型。op
: 形态学操作类型,如 MORPH_OPEN
、MORPH_CLOSE
、MORPH_GRADIENT
、MORPH_TOPHAT
、MORPH_BLACKHAT
等。kernel
: 结构元素,用于定义操作的性质。可以使用 getStructuringElement
函数创建。anchor
: 锚点位置,默认值为元素的中心。iterations
: 操作的迭代次数。borderType
: 边界类型。borderValue
: 当 borderType
为 BORDER_CONSTANT
时的边界值。形态学例子:
- #include <opencv2/opencv.hpp>
- #include <iostream>
-
- using namespace cv;
-
- int main() {
- // 读取图像
- Mat src = imread("path_to_image.jpg", IMREAD_GRAYSCALE);
- if (src.empty()) {
- std::cerr << "Error: Loading image" << std::endl;
- return -1;
- }
-
- Mat dst;
- int operation = MORPH_OPEN; // 定义形态学操作类型
- Mat element = getStructuringElement(MORPH_RECT, Size(5, 5)); // 创建结构元素
-
- // 应用形态学操作
- morphologyEx(src, dst, operation, element);
-
- // 显示图像
- imshow("Original Image", src);
- imshow("Morphology Operation Result", dst);
-
- waitKey(0);
- return 0;
- }
在这个示例中,首先读取一幅图像。然后定义了一个形态学操作类型(这里使用的是开运算 MORPH_OPEN
)和一个结构元素。使用 morphologyEx
函数对图像进行形态学处理。最后,展示原始图像和处理后的图像。
在 OpenCV 中,floodFill
函数用于执行洪水填充操作。这是一个非常强大的工具,通常用于分割图像的某些部分、改变图像中区域的颜色或者在图像分析中识别和标记连通区域。floodFill
函数基本上是从一个种子点开始,然后向四周扩展,直到满足某些停止条件。
函数原型:
- int cv::floodFill(InputOutputArray image, InputOutputArray mask, Point seedPoint, Scalar newVal, Rect* rect = 0, Scalar loDiff = Scalar(), Scalar upDiff = Scalar(), int flags = 4)
参数说明:
image
: 输入/输出图像,必须是 1 通道或 3 通道图像。mask
: 操作的掩码,更新填充区域的边界。大小必须是 (image.rows + 2) x (image.cols + 2)
,且为 8 位单通道。seedPoint
: 开始填充的种子点。newVal
: 填充区域的新值。rect
: 可选的输出参数,返回被填充区域的最小边界矩形。loDiff
和 upDiff
: 填充颜色的下限和上限差值。flags
: 操作标志,定义填充模式和颜色选择方式。例子:
- #include <opencv2/opencv.hpp>
- #include <iostream>
-
- using namespace cv;
-
- int main() {
- // 读取图像
- Mat image = imread("path_to_image.jpg");
- if (image.empty()) {
- std::cerr << "Error: Loading image" << std::endl;
- return -1;
- }
-
- // 创建掩码
- Mat mask = Mat::zeros(image.rows + 2, image.cols + 2, CV_8UC1);
-
- // 种子点
- Point seedPoint = Point(50, 50); // 需要根据实际情况选择合适的点
-
- // 洪水填充
- floodFill(image, mask, seedPoint, Scalar(255, 0, 0), 0, Scalar(10, 10, 10), Scalar(10, 10, 10), 4);
-
- // 显示图像
- imshow("Flood Fill Image", image);
- waitKey(0);
- return 0;
- }
在这个例子中,首先读取了一幅图像。创建了一个稍大于原图的掩码。然后选择一个种子点,并使用 floodFill
函数进行填充。最后,显示填充后的图像。
根据灰度等级调整对比度,增强局部特征
应该是Otsu方法。
Otsu 图像分割是一种基于阈值的图像分割方法,旨在将图像中的前景和背景分开。这个方法的主要思想是找到一个阈值,将图像中的像素分为两个类别,使得这两个类别之间的类内方差最小,而类间方差最大。这个阈值将图像分成了前景和背景两个部分,从而实现了图像分割。
以下是使用Otsu算法进行图像分割的一般步骤:
首先,将彩色图像转换为灰度图像,因为Otsu算法通常用于灰度图像的分割。
计算每个灰度级别的像素在图像中的频数分布,可以得到直方图。
计算图像的总体平均灰度值和总体方差。
遍历可能的阈值(从0到最大灰度级别),对于每个阈值,将图像分成两个部分:低于阈值的像素属于一个类别,高于阈值的像素属于另一个类别。
对于每个阈值,计算两个类别的类内方差和类间方差。
使用Otsu的准则,选择使类间方差最大化的阈值。通常,这可以通过最大化以下公式来实现:
类间方差 = 类间方差 / 类内方差
将选定的阈值应用于图像,将图像分割成前景和背景。
最终,你可以对分割后的前景和背景区域进行后续处理或分析。
Otsu算法是一种自适应的方法,不需要事先知道图像的特定阈值。它在很多情况下都表现良好,特别是对于具有双峰直方图的图像。然而,在一些情况下,它可能不够精确,因此需要根据具体应用的要求进行调整或使用其他图像分割方法。
例子:
- #include <opencv2/opencv.hpp>
- #include <iostream>
-
- using namespace cv;
- using namespace std;
-
- int main() {
- // 读取图像
- Mat img = imread("path_to_your_image.jpg", IMREAD_GRAYSCALE);
- if (img.empty()) {
- cout << "无法读取图像" << endl;
- return -1;
- }
-
- // 初始化直方图参数
- int histSize = 256; // 直方图大小
- float range[] = { 0, 256 };
- const float* histRange = { range };
-
- Mat hist;
- calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, &histRange);
-
- // 显示直方图
- int hist_w = 512, hist_h = 400;
- int bin_w = cvRound((double)hist_w / histSize);
-
- Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(0, 0, 0));
- normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
-
- for (int i = 1; i < histSize; i++) {
- line(histImage,
- Point(bin_w * (i - 1), hist_h - cvRound(hist.at<float>(i - 1))),
- Point(bin_w * i, hist_h - cvRound(hist.at<float>(i))),
- Scalar(255, 0, 0), 2, 8, 0);
- }
-
- imshow("原始图像", img);
- imshow("直方图", histImage);
-
- waitKey(0);
- return 0;
- }
在这个示例中,我们首先读取一个灰度图像,然后使用 calcHist
函数计算其直方图。直方图的每个“箱”(bin)的宽度通过图像的直方图大小来决定。接着,我们创建了一个用于显示直方图的空白图像,并使用 line
函数在其中绘制直方图。
请确保将 "path_to_your_image.jpg"
替换为你的图像文件的路径。
定位目标
opencv自带函数。但不支持旋转,缩放。他的输出结果是映射图,图中的位置表示模板在图像的相对位置处的二者的相关性。
halcon,点击file,点击browse Hdevelop Example programs,在左边method里选择合适的匹配方法。在右边选择合适的例子,这里选择第3个find ncc。
在pogram window窗口就会出现代码,查看代码,前面是读进一幅图,选择合适区域作为模板。选择并按F5执行,程序会在stop处暂停,接着按F6步进查看每副图像匹配 。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。