Goal

使用腐蚀和膨胀操作,不过对于腐蚀和膨胀的原理解释的非常好。

Theory

Morphology Operations

Dilation adds pixels to the boundaries of the object in an image, while erosion does exactly the opposite. The amount of pixels added or removed, respectively depends on the size and shape of the structuring element used to process the image. In general the rules followed from these two operations have as follows:

膨胀添加像素到图像的物体中,而腐蚀则相反。添加或者消除像素的多少,取决与结构元素的大小和类型。更详细的解释如下:

Dilation: The value of the output pixel is the maximum value of all the pixels that fall within the structuring element's size and shape. For example in a binary image, if any of the pixels of the input image falling within the range of the kernel is set to the value 1, the corresponding pixel of the output image will be set to 1 as well. The latter applies to any type of image (e.g. grayscale, bgr, etc).

                                                       Image Processing5(Extract horizontal and vertical lines by using morphological operations)
                                                                         Dilation on a Binary Image
                                                         Image Processing5(Extract horizontal and vertical lines by using morphological operations)
                                                                      Dilation on a Grayscale Image

膨胀:输出的像素值就是结构元素所覆盖范围内的最大值。

Erosion: The vise versa applies for the erosion operation. The value of the output pixel is the minimum value of all the pixels that fall within the structuring element's size and shape. Look the at the example figures below:

                                                         Image Processing5(Extract horizontal and vertical lines by using morphological operations)
                                                                     Erosion on a Binary Image
                                                        Image Processing5(Extract horizontal and vertical lines by using morphological operations)
                                                                Erosion on a Grayscale Image

腐蚀:腐蚀则相反,输出的像素值就是结构元素所覆盖范围内的最小值。

Structuring Elements

A structuring element is a matrix consisting of only 0's and 1's that can have any arbitrary shape and size. Typically are much smaller than the image being processed, while the pixels with values of 1 define the neighborhood. The center pixel of the structuring element, called the origin, identifies the pixel of interest – the pixel being processed.

结构元素仅包含了0和1的矩阵,并且有大小和形状任意。一般比要处理的图像小(这个很显然)。

A structuring element can have many common shapes, such as lines, diamonds, disks, periodic lines, and circles and sizes. You typically choose a structuring element the same size and shape as the objects you want to process/extract in the input image. For example, to find lines in an image, create a linear structuring element as you will see later.

                                                                  Image Processing5(Extract horizontal and vertical lines by using morphological operations)
                                                A Diamond-Shaped Structuring Element and its Origin

结构元素可以啥形状都行。通常根据要查找的形状定义一个结构化的元素。

Code

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

void show_wait_destroy(const char* winname, cv::Mat img);

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    //加载图像
    CommandLineParser parser(argc, argv, "{@input | lena.jpg | input image}"); // 参数名称,默认的参数,帮助信息
    Mat src = imread(parser.get<String>("@input"), IMREAD_COLOR);
    if (src.empty())
    {
        cout << "Could not open or find the image!\n" << endl;
        cout << "Usage: " << argv[0] << " <Input image>" << endl;
        return -1;
    }

    // Show source image
    imshow("src", src);
    //! [load_image]

    //! [gray]
    // Transform source image to gray if it is not already

    Mat gray;

    if (src.channels() == 3)
    {
        cvtColor(src, gray, COLOR_BGR2GRAY); //输入,输出,转换类型
    }
    else
    {
        gray = src;
    }

    // Show gray image
    show_wait_destroy("gray", gray);
    //! [gray]

    //! [bin]
    // Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbol

    Mat bw;
    adaptiveThreshold(~gray, bw, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);//源,目标,最大值,选取threshold的方法,邻域大小,常数

    // Show binary image
    show_wait_destroy("binary", bw);
    //! [bin]

    //! [init]
    // Create the images that will use to extract the horizontal and vertical lines

    Mat horizontal = bw.clone();
    Mat vertical = bw.clone();
    //! [init]

    //! [horiz]
    // Specify size on horizontal axis

    int horizontal_size = horizontal.cols / 30;

    // Create structure element for extracting horizontal lines through morphology operations
    Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontal_size, 1));

    // Apply morphology operations
    erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
    dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));

    //Show extracted horizontal lines
    show_wait_destroy("horizontal", horizontal);
    //! [horiz]

    //! [vert]
    // Specify size on vertical axis

    int vertical_size = vertical.rows / 30;

    // Create structure element for extracting vertical lines through morphology operations
    Mat verticalStructure = getStructuringElement(MORPH_RECT, Size(1, vertical_size));

    // Apply morphology operations
    erode(vertical, vertical, verticalStructure, Point(-1, -1));
    dilate(vertical, vertical, verticalStructure, Point(-1, -1));

    // Show extracted vertical lines
    show_wait_destroy("vertical", vertical);
    //! [vert]

    //! [smooth]
    // Inverse vertical image

    bitwise_not(vertical, vertical);//输入,输出:按照位反
    show_wait_destroy("vertical_bit", vertical);

    // Extract edges and smooth image according to the logic
    // 1. extract edges
    // 2. dilate(edges)
    // 3. src.copyTo(smooth)
    // 4. blur smooth img
    // 5. smooth.copyTo(src, edges)

    // Step 1
    Mat edges;
    adaptiveThreshold(vertical, edges, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, -2);
    show_wait_destroy("edges", edges);

    // Step 2
    Mat kernel = Mat::ones(2, 2, CV_8UC1);
    dilate(edges, edges, kernel);
    show_wait_destroy("dilate", edges);

    // Step 3
    Mat smooth;
    vertical.copyTo(smooth);

    // Step 4
    blur(smooth, smooth, Size(2, 2));

    // Step 5
    smooth.copyTo(vertical, edges);//掩码

    // Show final result
    show_wait_destroy("smooth - final", vertical);
    //! [smooth]

    return 0;
}

void show_wait_destroy(const char* winname, cv::Mat img) {
    imshow(winname, img);
    moveWindow(winname, 500, 0); //窗口,X,Y
    waitKey(0);
    destroyWindow(winname); //销毁窗口
}

由于补充注释已经很清楚了,这里不再解释。

CMakeLists.txt文件如下

cmake_minimum_required(VERSION 2.8)

set(CMAKE_CXX_FLAGS "-std=c++11")
project( DisplayImage )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( DisplayImage main.cpp )
target_link_libraries( DisplayImage ${OpenCV_LIBS} )

install(TARGETS DisplayImage RUNTIME DESTINATION bin)

结果如下:

Image Processing5(Extract horizontal and vertical lines by using morphological operations)

相关文章: