阅读(4867) (14)

OpenCV更多形态转化

2017-09-01 10:47:03 更新

目标

在本教程中,您将学习如何:

  1. 开盘
  2. 闭幕
  3. 形态梯度
  4. 顶帽
  5. 黑帽

理论

注意
下面的解释属于Bradski和Kaehler 的“ 学习OpenCV ”一书。

在前面的教程中,我们介绍了两种基本的形态学操作:

  • 侵蚀
  • 扩张。

基于这两个,我们可以对我们的图像进行更复杂的转换。在这里,我们简要讨论OpenCV提供的5个操作:

开盘

  • 它是通过图像的侵蚀获得的,随后是扩张。

OpenCV更多形态转化

  • 用于去除小物体(假设物体在黑暗的前景上是明亮的)
  • 例如,请查看下面的示例。左侧的图像是原始图像,右侧的图像是应用打开转换后的结果。我们可以观察到,信中角落的小空间往往会消失。

OpenCV更多形态转化

为了清楚起见,我们7x7在相同的原始图像上执行了打开操作(矩形结构元素),但是反转,例如白色的对象现在是字母。

OpenCV更多形态转化

左图:原图反转,右图:打开

闭幕

  • 它是通过图像的扩张,然后是侵蚀获得的。

OpenCV更多形态转化

  • 有用的是去除小孔(暗区)。

OpenCV更多形态转化

在倒置图像上,我们执行了关闭操作(7x7矩形结构元素):

OpenCV更多形态转化

左图:原图反转,右图:结果关闭

形态梯度

  • 这是图像的扩张和侵蚀的区别。

OpenCV更多形态转化

  • 找到对象的轮廓是有用的,如下所示:

OpenCV更多形态转化

顶帽

  • 输入图像与其打开之间的区别。

OpenCV更多形态转化

OpenCV更多形态转化

黑帽

  • 这是关闭和输入图像之间的区别

OpenCV更多形态转化

OpenCV更多形态转化

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 );
}

说明

  1. 我们来看一下程序的一般结构:
  • 加载图像
  • 创建一个窗口以显示形态操作的结果
  • 创建三个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。在这个例子中,我们使用四个参数(其余的作为默认值):

  1. src:源(输入)图像
  2. dst:输出图像
  3. 操作:要进行的形态转化的种类。请注意,我们有5个选择:
  • 开幕式:MORPH_OPEN:2
  • 关闭:MORPH_CLOSE:3
  • 渐变:MORPH_GRADIENT:4
  • 顶帽:MORPH_TOPHAT:5
  • 黑帽子:MORPH_BLACKHAT:6

正如您可以看到的值范围从<2-6>,这就是为什么我们添加(+2)到轨迹栏输入的值:

  int operation = morph_operator + 2;

结果

  • 在编译上面的代码之后,我们可以执行它,给出一个图像路径作为参数。对于本教程,我们使用输入图像:baboon.png:

OpenCV更多形态转化

这里是显示窗口的两个快照。第一张照片显示了使用操作符打开一个交叉内核后的输出。第二张照片(右侧,显示了使用带有椭圆内核的Blackhat操作符的结果。

OpenCV更多形态转化