一.距离变换
1.概念和功能
距离变换是一种图像处理技术,用于计算图像中每个像素到最近的零像素(背景像素)的距离。它常用于图像分割、形态学操作和形状分析等领域。它计算图像中每个像素到最近的零像素(背景像素)的距离。这个距离可以是欧氏距离、曼哈顿距离等。距离变换后的图像中,前景像素的值代表它们到最近的背景像素的距离。
具体来说,距离变换在缺陷检测中有以下几个重要作用:
1.前景与背景的分离: 距离变换能够突出前景区域,使其与背景更明显地分离开。前景区域的像素值会表示其到最近背景像素的距离,这样可以更容易地识别和处理前景对象。
2.前景对象的中心检测: 距离变换的结果图像中,距离值最大的像素往往位于前景对象的中心位置。因此,通过距离变换,可以有效地检测出前景对象的中心点,为后续的形态学处理和轮廓检测提供可靠的信息。
3.分水岭算法的预处理: 距离变换常用于分水岭算法的预处理步骤,通过距离变换可以生成标记图像,这些标记可以帮助分水岭算法准确地分割图像中的各个对象。
4.形态学重建: 距离变换可以结合形态学操作进行形态学重建,用于去除图像中的小噪声和伪影,使前景对象更加清晰。
2.函数语法
示例:
// 距离变换
cv::Mat dist_transform;
cv::distanceTransform(op, dist_transform, cv::DIST_L2, 3);
cv::normalize(dist_transform, dist_transform, 0, 1.0, cv::NORM_MINMAX);// 阈值处理
cv::Mat fore;
cv::threshold(dist_transform, fore, 0.3, 1.0, cv::THRESH_BINARY);
fore.convertTo(fore, CV_8U);
1. cv::distanceTransform
功能:用于计算二值图像中每个前景像素到最近背景像素的距离。
函数语法:
void cv::distanceTransform(InputArray src, OutputArray dst, int distanceType, int maskSize, int dstType = CV_32F);
src | 输入图像,通常是一个二值图像。 其中非零像素被视为前景,零像素被视为背景。 |
dst | 输出图像,包含每个像素到最近背景像素的距离。 默认情况下,输出图像是一个32位浮点图像( |
distanceType | 距离类型,指定距离的计算方式。常用的类型有:
|
maskSize | 掩码大小,影响距离计算的精度。可以是3、5或cv::DIST_MASK_PRECISE (在精确距离变换中使用)。常用值为3。 |
dstType | 输出图像的类型。默认值为 可以更改为其他类型,如 |
2.cv::normalize
功能:用于将数组的值归一化到指定的范围内。它可以应用于图像处理中的多种场景,例如将距离变换的结果归一化到 [0, 1] 或 [0, 255],从而便于可视化和后续处理。
函数语法:
void cv::normalize(
InputArray src,
OutputArray dst,
double alpha,
double beta,
int norm_type = cv::NORM_L2,
int dtype = -1,
InputArray mask = noArray()
);
src | 输入数组或图像 |
dst | 输出数组或图像,与输入数组具有相同的大小和类型,或者具有指定的类型。 |
alpha | 归一化后数组中最小值的目标值。 如果 norm_type 是 cv::NORM_MINMAX,这个参数表示归一化后的最小值。 |
beta | 归一化后数组中最大值的目标值。 如果 norm_type 是 cv::NORM_MINMAX,这个参数表示归一化后的最大值。 |
norm_type | 归一化类型。可以是以下之一:
|
dtype | (可选)输出数组的类型。如果为 -1,则输出数组的类型与输入数组相同。 |
mask | (可选)可选的操作掩码。仅对掩码内的元素进行归一化处理。 |
只用前5个就够了
3.fore.convertTo
功能:将矩阵转换为另一种数据类型的函数。此函数通常用于图像处理中的数据类型转换,以确保图像处理操作使用正确的数据类型。
函数语法:
void cv::Mat::convertTo(OutputArray m, int rtype, double alpha , double beta)
m | 输出矩阵,类型由 rtype 指定。 |
rtype | 输出矩阵的类型。可以是 CV_8U (8 位无符号整数)、CV_32F (32 位浮点数)等。 |
alpha | 可选的比例因子,默认值为 1。输出矩阵的每个元素是输入矩阵相应元素乘以 alpha 。 |
beta | 可选的加数,默认值为 0。输出矩阵的每个元素是输入矩阵相应元素乘以 alpha 再加上 beta 。 |
二.缺陷检测
通过计算轮廓面积和最小外接圆的面积比值来判断是否存在缺陷
1.cv::minEnclosingCircle 最小外接圆
功能:找到一个最小的圆,使得圆能够完全包围给定的轮廓。
函数语法:
void cv::minEnclosingCircle(InputArray points, Point2f& center, float& radius);
points | 输入的点集,可以可以是一个点的向量或Mat。 |
center | 输出参数,存储最小外接圆的圆心坐标。 |
radius | 输出参数,存储最小外接圆的半径。 |
2.完整代码示例
#include <opencv2/opencv.hpp>
#include <iostream>int main() {// 读取图像cv::Mat o = cv::imread("pill3.jpg", cv::IMREAD_GRAYSCALE);if (o.empty()) {std::cerr << "Could not open or find the image!" << std::endl;return -1;}// 二值化处理cv::Mat binary;cv::threshold(o, binary, 0, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);// 形态学开运算cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));cv::Mat op;cv::morphologyEx(binary, op, cv::MORPH_OPEN, kernel, cv::Point(-1, -1), 1);// 距离变换cv::Mat dist_transform;cv::distanceTransform(op, dist_transform, cv::DIST_L2, 3);cv::normalize(dist_transform, dist_transform, 0, 1.0, cv::NORM_MINMAX);// 阈值处理cv::Mat fore;cv::threshold(dist_transform, fore, 0.3, 1.0, cv::THRESH_BINARY);fore.convertTo(fore, CV_8U);// 形态学去噪cv::Mat kernel2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));cv::Mat op2;cv::morphologyEx(fore, op2, cv::MORPH_OPEN, kernel2, cv::Point(-1, -1), 1);// 提取轮廓std::vector<std::vector<cv::Point>> contours;cv::findContours(op2, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);// 缺陷检测int count = 0;cv::Mat img = o.clone();for (size_t i = 0; i < contours.size(); i++) {cv::Point2f center;float radius;cv::minEnclosingCircle(contours[i], center, radius);double area = cv::contourArea(contours[i]);double area_circle = 3.14 * radius * radius;if (area / area_circle >= 0.5) {cv::putText(img, "OK", center, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 2);}else {cv::putText(img, "bad", center, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 2);}count++;}cv::putText(img, "sum=" + std::to_string(count), cv::Point(20, 30), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255));// 显示结果cv::imshow("result", img);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
结果如图: