基本概念
•开运算:先腐蚀后膨胀,用于去除小的噪声点。
•闭运算:先膨胀后腐蚀,用于连接接近的物体。
开运算示例代码
#include "pch.h"
#include<iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void opening(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
Mat temp;
erode(src, temp, kernel, Point(-1, -1), iterations);
dilate(temp, dst, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
/*if (argc != 2)
{
cout << "Usage: ./Opening <Image Path>" << endl;
return -1;
}*/
// 加载图像
Mat img = imread("877.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat opened;
// 执行开运算
opening(img, opened, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Opened Image", WINDOW_NORMAL);
imshow("Opened Image", opened);
waitKey(0);
destroyAllWindows();
return 0;
}
运行结果
闭运算示例代码
#include "pch.h"
#include<iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void closing(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
Mat temp;
dilate(src, temp, kernel, Point(-1, -1), iterations);
erode(temp, dst, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
//if (argc != 2)
//{
// cout << "Usage: ./Closing <Image Path>" << endl;
// return -1;
//}
// 加载图像
Mat img = imread("666.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat closed;
// 执行闭运算
closing(img, closed, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Closed Image", WINDOW_NORMAL);
imshow("Closed Image", closed);
waitKey(0);
destroyAllWindows();
return 0;
}
运行结果
开运算
开运算(Opening)是形态学操作的一种组合形式,它通常用于去除图像中的小噪声点和细化图像中的物体边界。开运算首先对图像进行腐蚀(Erosion),然后再对腐蚀后的图像进行膨胀(Dilation)。
开运算原理
开运算的基本步骤如下:
1. 腐蚀:首先对输入图像进行一次腐蚀操作,这会缩小前景区域(通常为白色或非零值),去除小的噪声点。
2. 膨胀:接着对腐蚀后的图像进行一次膨胀操作,这会恢复因腐蚀而丢失的部分,但不会恢复被完全去除的小噪声点。
OpenCV中的开运算在OpenCV中,可以使用erode函数进行腐蚀操作,使用dilate函数进行膨胀操作。为了简化开运算的过程,OpenCV还提供了morphologyEx函数,可以直接执行开运算。
函数原型
void 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()
);
其中,op 参数可以设置为 MORPH_OPEN 来执行开运算。
参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•op:形态学操作类型,对于开运算为 MORPH_OPEN。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。
•borderValue:边界值,默认为morphologyDefaultBorderValue()。
示例代码
下面是一个使用OpenCV C++实现图像开运算的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void opening(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
morphologyEx(src, dst, MORPH_OPEN, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
/*if (argc != 2)
{
cout << "Usage: ./Opening <Image Path>" << endl;
return -1;
}*/
// 加载图像
Mat img = imread("888.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat opened;
// 执行开运算
opening(img, opened, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Opened Image", WINDOW_NORMAL);
imshow("Opened Image", opened);
waitKey(0);
destroyAllWindows();
return 0;
}
//代码解释
//1. 加载图像:使用 imread 函数以灰度模式加载图像。
//2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
//3. 初始化输出矩阵:创建一个新的矩阵来存储开运算后的图像。
//4. 执行开运算:使用 morphologyEx 函数对图像进行开运算。
//5. 显示结果:使用 imshow 函数显示原始图像和开运算后的图像。
//
//注意事项
//•结构元素的形状:不同的结构元素形状会导致不同的开运算效果。矩形结构元素通常用于去除小的噪声点,而十字形结构元素则可能适合特定的应用场景。
//•迭代次数:增加迭代次数会使开运算效果更加明显,但过度的开运算可能会导致有用的信息丢失。
//•边界处理:开运算默认会处理图像的边界,可以选择不同的边界处理方式来影响开运算的效果。
//•数据类型:确保输出图像的数据类型与输入图像相同。
//
//应用场景
//•去噪:在二值化图像或边缘检测之后,可以使用开运算去除小的噪声点。
//•细化物体边界:开运算可以细化图像中的物体边界,使其更加平滑。
//•去除小的孔洞:开运算可以去除图像中的小孔洞,使前景区域更加连续。
运行结果
闭运算
闭运算(Closing)是形态学操作的一种组合形式,它通常用于连接接近的物体和填补物体内部的小孔洞。闭运算首先对图像进行膨胀(Dilation),然后再对膨胀后的图像进行腐蚀(Erosion)。
闭运算原理
闭运算的基本步骤如下:
1. 膨胀:首先对输入图像进行一次膨胀操作,这会扩大前景区域(通常为白色或非零值),填补物体内部的小孔洞。
2. 腐蚀:接着对膨胀后的图像进行一次腐蚀操作,这会恢复因膨胀而扩大的边界,但不会恢复物体内部的孔洞。
OpenCV中的闭运算
在OpenCV中,可以使用dilate函数进行膨胀操作,使用erode函数进行腐蚀操作。为了简化闭运算的过程,OpenCV还提供了morphologyEx函数,可以直接执行闭运算。
函数原型
void 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()
);
其中,op 参数可以设置为 MORPH_CLOSE 来执行闭运算。
参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•op:形态学操作类型,对于闭运算为 MORPH_CLOSE。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。
•borderValue:边界值,默认为morphologyDefaultBorderValue()。
示例代码
下面是一个使用OpenCV C++实现图像闭运算的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void closing(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
morphologyEx(src, dst, MORPH_CLOSE, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
//if (argc != 2)
//{
// cout << "Usage: ./Closing <Image Path>" << endl;
// return -1;
//}
// 加载图像
Mat img = imread("00.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat closed;
// 执行闭运算
closing(img, closed, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Closed Image", WINDOW_NORMAL);
imshow("Closed Image", closed);
waitKey(0);
destroyAllWindows();
return 0;
}
代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储闭运算后的图像。
4. 执行闭运算:使用 morphologyEx 函数对图像进行闭运算。
5. 显示结果:使用 imshow 函数显示原始图像和闭运算后的图像。
注意事项
•结构元素的形状:不同的结构元素形状会导致不同的闭运算效果。矩形结构元素通常用于填补物体内部的小孔洞,而十字形结构元素则可能适合特定的应用场景。
•迭代次数:增加迭代次数会使闭运算效果更加明显,但过度的闭运算可能会导致有用的信息丢失。
•边界处理:闭运算默认会处理图像的边界,可以选择不同的边界处理方式来影响闭运算的效果。•数据类型:确保输出图像的数据类型与输入图像相同。
应用场景
•连接接近的物体:闭运算可以连接彼此接近的物体,使其成为一个整体。
•填补物体内部的小孔洞:闭运算可以填补物体内部的小孔洞,使前景区域更加完整。
•平滑边界:闭运算可以平滑图像的边界,使其更加光滑。
运行结果
•顶帽变换:原图像减去开运算的结果,用于突出细节。
•黑帽变换:闭运算的结果减去原图像,用于突出阴影区域。
顶帽变换
顶帽变换(Top Hat Transformation)是形态学操作的一种形式,它主要用于增强图像中的细节和突出边缘或纹理特征。顶帽变换通过从原始图像中减去开运算(Opening)的结果来实现。
顶帽变换原理
顶帽变换的基本步骤如下:
1. 开运算:对输入图像进行一次开运算操作,这会去除小的噪声点和平滑边界。
2. 减法操作:将开运算的结果从原始图像中减去,得到的结果就是顶帽变换后的图像。
OpenCV中的顶帽变换
在OpenCV中,可以使用morphologyEx函数直接执行顶帽变换。
函数原型
void 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()
);
其中,op 参数可以设置为 MORPH_TOPHAT 来执行顶帽变换。
参数说明
•src:输入图像。
dst:输出图像,与输入图像具有相同的大小和类型。
•op:形态学操作类型,对于顶帽变换为 MORPH_TOPHAT。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。
•borderValue:边界值,默认为morphologyDefaultBorderValue()。
示例代码
下面是一个使用OpenCV C++实现图像顶帽变换的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void topHat(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
morphologyEx(src, dst, MORPH_TOPHAT, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
//if (argc != 2)
//{
// cout << "Usage: ./TopHat <Image Path>" << endl;
// return -1;
//}
// 加载图像
Mat img = imread("81.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat tophat;
// 执行顶帽变换
topHat(img, tophat, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Top Hat Image", WINDOW_NORMAL);
imshow("Top Hat Image", tophat);
waitKey(0);
destroyAllWindows();
return 0;
}
代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储顶帽变换后的图像。
4. 执行顶帽变换:使用 morphologyEx 函数对图像进行顶帽变换。
5. 显示结果:使用 imshow 函数显示原始图像和顶帽变换后的图像。
注意事项
•结构元素的形状:不同的结构元素形状会导致不同的顶帽变换效果。矩形结构元素通常用于突出细节,而十字形结构元素则可能适合特定的应用场景。
•迭代次数:增加迭代次数会使顶帽变换效果更加明显,但过度的顶帽变换可能会导致有用的信息丢失。
•边界处理:顶帽变换默认会处理图像的边界,可以选择不同的边界处理方式来影响顶帽变换的效果。
•数据类型:确保输出图像的数据类型与输入图像相同。
应用场景
•增强细节:顶帽变换可以增强图像中的细节,突出边缘或纹理特征。
•突出噪声:顶帽变换可以突出图像中的小噪声点或细小特征。
•图像预处理:在进行后续图像处理之前,可以使用顶帽变换来增强图像中的重要特征。
运算结果
顶帽变换示例代码
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void topHat(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
morphologyEx(src, dst, MORPH_TOPHAT, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
//if (argc != 2)
//{
// cout << "Usage: ./TopHat <Image Path>" << endl;
// return -1;
//}
// 加载图像
Mat img = imread("81.png", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat tophat;
// 执行顶帽变换
topHat(img, tophat, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Top Hat Image", WINDOW_NORMAL);
imshow("Top Hat Image", tophat);
waitKey(0);
destroyAllWindows();
return 0;
}
运行结果
黑帽变换
黑帽变换(Black Hat Transformation)是形态学操作的一种形式,它主要用于突出图像中的阴影或低强度区域。黑帽变换通过从闭运算(Closing)的结果中减去原始图像来实现。
黑帽变换原理
黑帽变换的基本步骤如下:
1. 闭运算:对输入图像进行一次闭运算操作,这会连接接近的物体并填补物体内部的小孔洞。
2. 减法操作:将闭运算的结果减去原始图像,得到的结果就是黑帽变换后的图像。
黑帽变换的主要目的是突出那些比周围区域暗的小区域,即“暗斑”或“阴影”。
OpenCV中的黑帽变换
在OpenCV中,可以使用morphologyEx函数直接执行黑帽变换。
函数原型
void 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()
);
其中,op 参数可以设置为 MORPH_BLACKHAT 来执行黑帽变换。
参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•op:形态学操作类型,对于黑帽变换为 MORPH_BLACKHAT。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。
•borderValue:边界值,默认为morphologyDefaultBorderValue()。
示例代码
下面是一个使用OpenCV C++实现图像黑帽变换的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void blackHat(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
morphologyEx(src, dst, MORPH_BLACKHAT, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
/*if (argc != 2)
{
cout << "Usage: ./BlackHat <Image Path>" << endl;
return -1;
}*/
// 加载图像
Mat img = imread("80.jpeg", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat blackhat;
// 执行黑帽变换
blackHat(img, blackhat, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Black Hat Image", WINDOW_NORMAL);
imshow("Black Hat Image", blackhat);
waitKey(0);
destroyAllWindows();
return 0;
}
代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储黑帽变换后的图像。
4. 执行黑帽变换:使用 morphologyEx 函数对图像进行黑帽变换。
5. 显示结果:使用 imshow 函数显示原始图像和黑帽变换后的图像。
注意事项
•结构元素的形状:不同的结构元素形状会导致不同的黑帽变换效果。矩形结构元素通常用于突出细节,而十字形结构元素则可能适合特定的应用场景。
•迭代次数:增加迭代次数会使黑帽变换效果更加明显,但过度的黑帽变换可能会导致有用的信息丢失。
•边界处理:黑帽变换默认会处理图像的边界,可以选择不同的边界处理方式来影响黑帽变换的效果。
•数据类型:确保输出图像的数据类型与输入图像相同。
应用场景
•突出阴影:黑帽变换可以突出图像中的阴影或低强度区域,这对于检测阴影或暗斑非常有用。
•增强对比度:黑帽变换可以帮助增强图像中的对比度,使得某些特征更加明显。
•图像预处理:在进行后续图像处理之前,可以使用黑帽变换来增强图像中的重要特征。
运行结果
通过黑帽变换,我们可以突出图像中的阴影或低强度区域。这种变换特别适用于:
•阴影检测:突出图像中的阴影部分。
•特征增强:增强图像中的关键特征,便于后续处理。
•去噪:去除图像中的小噪声点。
黑帽变换示例代码
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void blackHat(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{
morphologyEx(src, dst, MORPH_BLACKHAT, kernel, Point(-1, -1), iterations);
}
int main(int argc, char** argv)
{
//if (argc != 2)
//{
// cout << "Usage: ./BlackHat <Image Path>" << endl;
// return -1;
//}
// 加载图像
Mat img = imread("87.jpeg", IMREAD_GRAYSCALE);
if (!img.data)
{
cout << "Error opening image" << endl;
return -1;
}
// 定义结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
// 初始化输出矩阵
Mat blackhat;
// 执行黑帽变换
blackHat(img, blackhat, kernel, 1);
// 显示结果
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img);
namedWindow("Black Hat Image" ,WINDOW_NORMAL);
imshow("Black Hat Image", blackhat);
waitKey(0);
destroyAllWindows();
return 0;
}
运行结果
实验代码
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
//#pragma comment(lib, "opencv_world450d.lib") //引用引入库
/// 全局变量
Mat src, dst;
int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;
const char* window_name = "Morphology Transformations Demo";
void Morphology_Operations(int, void*);
/** @函数 main */
int main(int argc, char** argv)
{
/// 装载图像
src = imread("13.jpeg",IMREAD_COLOR);
if (!src.data)
{
return -1;
}
/// 创建显示窗口
namedWindow(window_name, WINDOW_NORMAL);
/// 创建选择具体操作的 trackbar
createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations);
/// 创建选择内核形状的 trackbar
createTrackbar("Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations);
/// 创建选择内核大小的 trackbar
createTrackbar("Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations);
/// 启动使用默认值
Morphology_Operations(0, 0);
waitKey(0);
return 0;
}
void Morphology_Operations(int, void*)
{
// 由于 MORPH_X的取值范围是: 2,3,4,5 和 6
int operation = morph_operator + 2;
Mat element = getStructuringElement(morph_elem, Size(2 * morph_size + 1, 2 * morph_size + 1), Point(morph_size, morph_size));
/// 运行指定形态学操作
morphologyEx(src, dst, operation, element);
imshow(window_name, dst);
}