基本概念-图像腐蚀
图像腐蚀是一种用于去除图像中小的对象或者突出物体边缘的形态学操作。
图像腐蚀(erosion)的基本概念
图像腐蚀通常用于二值图像,其基本原理是从图像中“侵蚀”掉一些像素点,这些像素点通常是边界上的或者是孤立的小点。在二值图像中,通常用白色表示前景,黑色表示背景。腐蚀操作会使得前景区域缩小。
腐蚀操作可以用一个称为结构元素(或核)的小矩阵来定义。这个结构元素通常是对称的,并且中心像素是结构元素的位置。腐蚀过程检查结构元素覆盖下的每个像素是否都为前景像素(通常是白色),只有当所有像素都是前景像素时,中心像素才会保留为前景;否则,中心像素将被标记为背景(通常是黑色)。
图像腐蚀(Erosion)是形态学操作的一种基本形式,主要用于消除小对象、分离相邻物体以及平滑边界。腐蚀操作通常用于图像预处理阶段,如去噪、连接组件的分离等。
形态学腐蚀原理
腐蚀操作的基本思想是从图像中去除突出的小部分或“凸起”的部分。具体来说,腐蚀会从每个前景像素(通常为白色或非零值)中减去一个结构元素(Structuring Element)的尺寸,如果结构元素在该像素周围的所有位置都能完全包含在前景区域内,则该像素被认为是腐蚀操作的结果的一部分。
结构元素
结构元素(Structuring Element)是一个定义了如何进行腐蚀操作的小型网格。最常见的结构元素是一个3x3或更大的方形网格,其中心像素代表当前正在处理的图像中的像素。结构元素可以有不同的形状,如圆形、十字形、椭圆形等。
腐蚀操作
在OpenCV中,可以使用erode函数来执行图像的腐蚀操作。
函数原型
void erode(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
double borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue()
);
参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。
•borderValue:边界值,默认为morphologyDefaultBorderValue()。
示例代码1
下面是一个使用OpenCV C++实现图像腐蚀的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void erodeImage(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
erode(src, dst, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
/*if (argc != 2)
{
cout << "Usage: ./ErodeImage <Image Path>" << endl;
return -1;
}*/
// 加载图像
Mat img = imread("897.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat eroded;
// 执行腐蚀操作
erodeImage(img, eroded, kernel, 1);
// 显示结果
namedWindow("Origal Imagine", WINDOW_NORMAL);
imshow("Origal Imagine", img);
namedWindow("Eroded Image", WINDOW_NORMAL);
imshow("Eroded Image", eroded);
waitKey(0);
destroyAllWindows();
return 0;
}
代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储腐蚀后的图像。
4. 执行腐蚀操作:使用 erode 函数对图像进行腐蚀操作。
5. 显示结果:使用 imshow 函数显示原始图像和腐蚀后的图像。
注意事项
•结构元素的形状:不同的结构元素形状会导致不同的腐蚀效果。矩形结构元素通常用于去除孤立的噪声点,而十字形结构元素则可能更适合于特定的应用场景。
•迭代次数:增加迭代次数会使腐蚀效果更加明显,但过度的腐蚀可能会导致有用的细节丢失。
•边界处理:腐蚀操作默认会处理图像的边界,可以选择不同的边界处理方式来影响腐蚀的效果。
•数据类型:确保输出图像的数据类型与输入图像相同。
运行结果1
应用场景
•去噪:在二值化图像或边缘检测之后,可以使用腐蚀操作去除小的孤立噪声点。
•分离连通组件:在处理连通组件时,可以使用腐蚀操作来分离紧密相连的对象。
•平滑边界:可以使用腐蚀操作来平滑图像的边界,使其更加光滑。
通过这些示例和详细解释,你应该能够理解如何在OpenCV中使用C++实现图像的腐蚀操作。
示例代码2
在OpenCV中,使用erode
函数可以很方便地对图像进行腐蚀操作。下面是一个简单的例子,展示了如何使用C++来实现图像腐蚀:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
// 加载图像
cv::Mat src = cv::imread("888.png", cv::IMREAD_GRAYSCALE);
if (src.empty())
{
std::cout << "Error: Image cannot be loaded!" << std::endl;
return -1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
// 腐蚀图像
cv::Mat dst;
cv::erode(src, dst, element);
// 显示结果
cv::namedWindow("Original Image", cv::WINDOW_NORMAL);
cv::imshow("Original Image", src);
cv::namedWindow("Eroded Image", cv::WINDOW_NORMAL);
cv::imshow("Eroded Image", dst);
// 等待按键并退出
cv::waitKey(0);
return 0;
}
在这个例子中:
使用cv::imread读取图片。
使用cv::getStructuringElement创建一个3x3大小的矩形结构元素。
使用cv::erode函数对原图像进行腐蚀。
使用cv::imshow显示原始图像和腐蚀后的图像。
腐蚀的程度取决于结构元素的形状和大小。不同的形状(如圆形、十字形等)以及更大的尺寸都会影响腐蚀的效果。如果需要更精细的控制,可以调整结构元素的大小和形状。
运行结果2
基本概念-图像膨胀
图像膨胀(dilation)是另一种常用的形态学操作,它与图像腐蚀相对。膨胀主要用于扩展图像中的对象边界,填补前景物体中的小孔洞,或者连接靠近的物体。在二值图像处理中,膨胀通常会使得前景区域扩大。
图像膨胀(Dilation)是形态学操作的一种基本形式,主要用于扩大前景区域(通常为白色或非零值),填补孔洞,连接接近的物体,并扩展边界。膨胀操作通常用于图像处理和分析中,如去噪、连接组件的合并等。
形态学膨胀原理
膨胀操作的基本思想是在每个前景像素周围加上一个结构元素(Structuring Element),如果结构元素中的任何部分落在前景区域内,则该像素被认为是膨胀操作的结果的一部分。
图像膨胀的基本概念
与腐蚀相反,膨胀操作同样需要一个结构元素。对于每个像素位置,如果结构元素覆盖下的任何像素是前景像素(通常是白色),那么中心像素也会被标记为前景。因此,膨胀可以增加前景区域的大小,使得边界向外扩张。
结构元素
结构元素是一个定义了如何进行膨胀操作的小型网格。最常见的结构元素是一个3x3或更大的方形网格,其中心像素代表当前正在处理的图像中的像素。结构元素可以有不同的形状,如圆形、十字形、椭圆形等。
膨胀操作
在OpenCV中,可以使用dilate函数来执行图像的膨胀操作。这个函数接受几个参数,包括输入图像、输出图像、结构元素、锚点位置、迭代次数等。
函数原型
void dilate(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
double borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue()
);
参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。•borderValue:边界值,默认为morphologyDefaultBorderValue()。
示例代码3
下面是一个使用OpenCV C++实现图像膨胀的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void dilateImage(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
dilate(src, dst, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
/*if (argc != 2)
{
cout << "Usage: ./DilateImage <Image Path>" << endl;
return -1;
}*/
// 加载图像
Mat img = imread("999.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat dilated;
// 执行膨胀操作
dilateImage(img, dilated, kernel, 1);
// 显示结果
namedWindow("Original Image", cv::WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Dilated Image", cv::WINDOW_NORMAL);
imshow("Dilated Image", dilated);
waitKey(0);
destroyAllWindows();
return 0;
}
代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储膨胀后的图像。
4. 执行膨胀操作:使用 dilate 函数对图像进行膨胀操作。
5. 显示结果:使用 imshow 函数显示原始图像和膨胀后的图像。
注意事项
•结构元素的形状:不同的结构元素形状会导致不同的膨胀效果。矩形结构元素通常用于扩大前景区域,而十字形结构元素则可能适合特定的应用场景。
•迭代次数:增加迭代次数会使膨胀效果更加明显,但过度的膨胀可能会导致前景区域过大,甚至连接本来应该分离的物体。
•边界处理:膨胀操作默认会处理图像的边界,可以选择不同的边界处理方式来影响膨胀的效果。
•数据类型:确保输出图像的数据类型与输入图像相同。
应用场景
•去噪:在二值化图像或边缘检测之后,可以使用膨胀操作去除小的孔洞或连接分离的物体。
•连接连通组件:在处理连通组件时,可以使用膨胀操作来连接紧密相连的对象。
•平滑边界:可以使用膨胀操作来平滑图像的边界,使其更加光滑。
运行结果3
示例代码4
在OpenCV中,使用dilate
函数可以实现图像的膨胀操作。下面是一个简单的示例代码,展示了如何使用C++来实现图像膨胀:
#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
// 加载图像
cv::Mat src = cv::imread("875.jpeg", cv::IMREAD_GRAYSCALE);
if (src.empty())
{
std::cout << "Error: Image cannot be loaded!" << std::endl;
return -1;
}
// 定义结构元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
// 膨胀图像
cv::Mat dst;
cv::dilate(src, dst, element);
// 显示结果
cv::namedWindow("Original Image", cv::WINDOW_NORMAL);
cv::imshow("Original Image", src);
cv::namedWindow("Dilated Image", cv::WINDOW_NORMAL);
cv::imshow("Dilated Image", dst);
// 等待按键并退出
cv::waitKey(0);
return 0;
}
在这个例子中:
cv::imread用于读取图片。
cv::getStructuringElement用于创建一个3x3大小的矩形结构元素。
cv::dilate函数用来执行膨胀操作。
cv::imshow用于显示原始图像和膨胀后的图像。
结构元素的选择
结构元素的选择会影响膨胀的结果。常见的结构元素形状有矩形、椭圆和十字形等。结构元素的大小也会影响最终的效果。较大的结构元素会导致更大的膨胀效果,可能会合并原本分离的物体。
迭代次数
在调用cv::dilate函数时,还可以指定迭代次数,这决定了膨胀操作被执行的次数。每次迭代都会根据结构元素再次扩展前景区域。更多的迭代次数意味着更大的膨胀效果。
注意事项
膨胀和腐蚀都是针对二值图像的操作,因此在进行这些操作之前,通常需要先将图像转换为灰度图,并可能需要进行阈值化处理。
结构元素的选择和迭代次数应该根据具体的应用场景来调整,以达到最佳效果。
运行结果4
综合实验代码5
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
void Erosion(int, void*);
void Dilation(int, void*);
//#pragma comment(lib, "opencv_world450d.lib") //引用引入库
int main(int argc, char** argv)
{
src = imread("93.jpeg",IMREAD_COLOR);
if (src.empty())
{
cout << "Could not open or find the image!\n" << endl;
return -1;
}
namedWindow("Erosion Demo", WINDOW_NORMAL);
namedWindow("Dilation Demo", WINDOW_NORMAL);
moveWindow("Dilation Demo", src.cols, 0);
createTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
&erosion_elem, max_elem,
Erosion);
createTrackbar("Kernel size:\n 2n +1", "Erosion Demo",
&erosion_size, max_kernel_size,
Erosion);
createTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
&dilation_elem, max_elem,
Dilation);
createTrackbar("Kernel size:\n 2n +1", "Dilation Demo",
&dilation_size, max_kernel_size,
Dilation);
Erosion(0, 0);
Dilation(0, 0);
waitKey(0);
return 0;
}
void Erosion(int, void*)
{
int erosion_type = 0;
if (erosion_elem == 0) { erosion_type = MORPH_RECT; }
else if (erosion_elem == 1) { erosion_type = MORPH_CROSS; }
else if (erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement(erosion_type,
Size(2 * erosion_size + 1, 2 * erosion_size + 1),
Point(erosion_size, erosion_size));
erode(src, erosion_dst, element);
imshow("Erosion Demo", erosion_dst);
}
void Dilation(int, void*)
{
int dilation_type = 0;
if (dilation_elem == 0) { dilation_type = MORPH_RECT; }
else if (dilation_elem == 1) { dilation_type = MORPH_CROSS; }
else if (dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement(dilation_type,
Size(2 * dilation_size + 1, 2 * dilation_size + 1),
Point(dilation_size, dilation_size));
dilate(src, dilation_dst, element);
imshow("Dilation Demo", dilation_dst);
}