目录
[1. cv::distanceTransform](#1. cv::distanceTransform)
[1.cv::minEnclosingCircle 最小外接圆](#1.cv::minEnclosingCircle 最小外接圆)
一.距离变换
1.概念和功能
距离变换是一种图像处理技术,用于计算图像中每个像素到最近的零像素(背景像素)的距离。它常用于图像分割、形态学操作和形状分析等领域。它计算图像中每个像素到最近的零像素(背景像素)的距离。这个距离可以是欧氏距离、曼哈顿距离等。距离变换后的图像中,前景像素的值代表它们到最近的背景像素的距离。
具体来说,距离变换在缺陷检测中有以下几个重要作用:
1.前景与背景的分离: 距离变换能够突出前景区域,使其与背景更明显地分离开。前景区域的像素值会表示其到最近背景像素的距离,这样可以更容易地识别和处理前景对象。
2.前景对象的中心检测: 距离变换的结果图像中,距离值最大的像素往往位于前景对象的中心位置。因此,通过距离变换,可以有效地检测出前景对象的中心点,为后续的形态学处理和轮廓检测提供可靠的信息。
3.分水岭算法的预处理: 距离变换常用于分水岭算法的预处理步骤,通过距离变换可以生成标记图像,这些标记可以帮助分水岭算法准确地分割图像中的各个对象。
4.形态学重建: 距离变换可以结合形态学操作进行形态学重建,用于去除图像中的小噪声和伪影,使前景对象更加清晰。
2.函数语法
示例:
cpp
// 距离变换
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
功能:用于计算二值图像中每个前景像素到最近背景像素的距离。
函数语法:
cpp
void cv::distanceTransform(
InputArray src,
OutputArray dst,
int distanceType,
int maskSize,
int dstType = CV_32F);
|------------------|------------------------------------------------------------------------------------------------------------------------------------------|
| src | 输入图像,通常是一个二值图像。 其中非零像素被视为前景,零像素被视为背景。 |
| dst | 输出图像,包含每个像素到最近背景像素的距离。 默认情况下,输出图像是一个32位浮点图像(CV_32F
)。 |
| distanceType | 距离类型,指定距离的计算方式。常用的类型有: cv::DIST_L1
:曼哈顿距离(每个像素的邻居为上下左右四个方向)。 cv::DIST_L2
:欧氏距离(每个像素的邻居为周围八个方向)。 cv::DIST_C
:棋盘距离(类似于曼哈顿距离,但允许对角线方向移动) |
| maskSize | 掩码大小,影响距离计算的精度。可以是3、5或cv::DIST_MASK_PRECISE
(在精确距离变换中使用)。常用值为3。 |
| dstType | 输出图像的类型。默认值为CV_32F
,表示32位浮点图像。 可以更改为其他类型,如CV_8U
(8位无符号整数)等。 |
[参数含义]
2.cv::normalize
功能:用于将数组的值归一化到指定的范围内。它可以应用于图像处理中的多种场景,例如将距离变换的结果归一化到 [0, 1] 或 [0, 255],从而便于可视化和后续处理。
函数语法:
cpp
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 | 归一化类型。可以是以下之一: cv::NORM_INF
:归一化为无穷范数(最大绝对值)。 cv::NORM_L1
:归一化为 L1 范数(绝对值之和)。 cv::NORM_L2
:归一化为 L2 范数(平方和的平方根)。 cv::NORM_MINMAX
:线性变换,将数组值线性缩放到 [alpha, beta] 范围。 |
| dtype | (可选)输出数组的类型。如果为 -1,则输出数组的类型与输入数组相同。 |
| mask | (可选)可选的操作掩码。仅对掩码内的元素进行归一化处理。 |
[参数含义]
只用前5个就够了
3.fore.convertTo
功能:将矩阵转换为另一种数据类型的函数。此函数通常用于图像处理中的数据类型转换,以确保图像处理操作使用正确的数据类型。
函数语法:
cpp
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 最小外接圆
功能:找到一个最小的圆,使得圆能够完全包围给定的轮廓。
函数语法:
cpp
void cv::minEnclosingCircle(InputArray points, Point2f& center, float& radius);
|----------|------------------------|
| points
| 输入的点集,可以可以是一个点的向量或Mat。 |
| center
| 输出参数,存储最小外接圆的圆心坐标。 |
| radius
| 输出参数,存储最小外接圆的半径。 |
[参数含义]
2.完整代码示例
cpp
#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;
}
结果如图: