阅读(4867)
赞(14)
OpenCV更多形态转化
2017-09-01 10:47:03 更新
目标
在本教程中,您将学习如何:
- 使用OpenCV函数cv :: morphologyEx应用形态转换,如:
- 开盘
- 闭幕
- 形态梯度
- 顶帽
- 黑帽
理论
- 注意
- 下面的解释属于Bradski和Kaehler 的“ 学习OpenCV ”一书。
在前面的教程中,我们介绍了两种基本的形态学操作:
- 侵蚀
- 扩张。
基于这两个,我们可以对我们的图像进行更复杂的转换。在这里,我们简要讨论OpenCV提供的5个操作:
开盘
- 它是通过图像的侵蚀获得的,随后是扩张。
- 用于去除小物体(假设物体在黑暗的前景上是明亮的)
- 例如,请查看下面的示例。左侧的图像是原始图像,右侧的图像是应用打开转换后的结果。我们可以观察到,信中角落的小空间往往会消失。
为了清楚起见,我们7x7在相同的原始图像上执行了打开操作(矩形结构元素),但是反转,例如白色的对象现在是字母。
左图:原图反转,右图:打开
闭幕
- 它是通过图像的扩张,然后是侵蚀获得的。
- 有用的是去除小孔(暗区)。
在倒置图像上,我们执行了关闭操作(7x7矩形结构元素):
左图:原图反转,右图:结果关闭
形态梯度
- 这是图像的扩张和侵蚀的区别。
找到对象的轮廓是有用的,如下所示:
顶帽
- 输入图像与其打开之间的区别。
黑帽
- 这是关闭和输入图像之间的区别
Code
本教程代码如下所示。您也可以从这里下载
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
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* );
int main( int argc, char** argv )
{
String imageName("../data/baboon.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
src = imread(imageName, IMREAD_COLOR); // Load an image
if( src.empty() )
{ return -1; }
namedWindow( window_name, WINDOW_AUTOSIZE ); // Create window
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 );
createTrackbar( "Element:n 0: Rect - 1: Cross - 2: Ellipse", window_name,
&morph_elem, max_elem,
Morphology_Operations );
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* )
{
// Since MORPH_X : 2,3,4,5 and 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 );
}
说明
- 我们来看一下程序的一般结构:
- 加载图像
- 创建一个窗口以显示形态操作的结果
- 创建三个Trackbars供用户输入参数:
第一个跟踪栏操作符返回要使用的形态学操作(morph_operator)。
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 元素返回morph_elem,它表示我们的内核是什么样的结构:
createTrackbar( "Element:n 0: Rect - 1: Cross - 2: Ellipse", window_name,
&morph_elem, max_elem,
Morphology_Operations );
最终的trackbar 内核大小返回要使用的内核的大小(morph_size)
createTrackbar( "Kernel size:n 2n +1", window_name,
&morph_size, max_kernel_size,
Morphology_Operations );
- 每当我们移动任何滑块时,将调用用户的功能Morphology_Operations来实现新的形态学操作,并且它将根据当前的跟踪栏值来更新输出图像。
void Morphology_Operations( int, void* )
{
// Since MORPH_X : 2,3,4,5 and 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 );
}
我们可以观察到进行形态变换的关键功能是cv :: morphologyEx。在这个例子中,我们使用四个参数(其余的作为默认值):
- src:源(输入)图像
- dst:输出图像
- 操作:要进行的形态转化的种类。请注意,我们有5个选择:
- 开幕式:MORPH_OPEN:2
- 关闭:MORPH_CLOSE:3
- 渐变:MORPH_GRADIENT:4
- 顶帽:MORPH_TOPHAT:5
- 黑帽子:MORPH_BLACKHAT:6
正如您可以看到的值范围从<2-6>,这就是为什么我们添加(+2)到轨迹栏输入的值:
int operation = morph_operator + 2;
- element:要使用的内核。我们使用函数cv :: getStructuringElement来定义我们自己的结构。
结果
- 在编译上面的代码之后,我们可以执行它,给出一个图像路径作为参数。对于本教程,我们使用输入图像:baboon.png:
这里是显示窗口的两个快照。第一张照片显示了使用操作符打开一个交叉内核后的输出。第二张照片(右侧,显示了使用带有椭圆内核的Blackhat操作符的结果。