形态学操作

2018-02-09  本文已影响0人  samychen

  图像形态学操作是基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学。主要有四个操作:膨胀,腐蚀,开,闭。

形态学操作——膨胀

  膨胀与腐蚀跟卷积操作类似,假设有图像A和结构元素B,B在A上面移动,其中B定义其中心是锚点,计算B覆盖下的A的最大像素值用来替代锚点的像素,其中B作为结构元素可以是任意形状。

形态学操作——腐蚀

  腐蚀过程和膨胀过程类似,唯一不同的是以最小像素值替代锚点像素。


膨胀与腐蚀.png

  opencv提供了状态条TrackBar来动态调整结构元素大小。
createTrackBar(const String& trackbarname,const String windowname,int * value,int count,Trackbarcallback func,void * userdata=0) 回调函数如果为NULL,就只会update,不会调用callback函数。

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int elementsize = 3;
int maxsize = 21;
Mat src, dst, dst_;
void callback(int, void *);

int main(int argc, int ** argv)
{
    int ksize = 0;
    src = imread("F:/cat.png");
    if (!src.data) {
        printf("无法加载图片\n");
        return -1;
    }
    namedWindow("input img", CV_WINDOW_AUTOSIZE);
    imshow("show img", src);
    char TrackbarName[50];
    sprintf_s(TrackbarName, "Alpha x %d", elementsize);
    namedWindow("output result", CV_WINDOW_AUTOSIZE);
    createTrackbar(TrackbarName, "output result", &elementsize, maxsize, callback);
    callback(0, 0);
    //Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
    //dilate(src, dst, kernel);
    //erode(src, dst_, kernel);
    //namedWindow("dilate result", CV_WINDOW_AUTOSIZE);
    //namedWindow("erode result", CV_WINDOW_AUTOSIZE);
    //imshow("dilate", dst);
    //imshow("erode", dst_);
    waitKey(0);
    return 0;
}

void callback(int, void *)
{
    int s = elementsize * 2 + 1;
    Mat sturctEle = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
    dilate(src, dst, sturctEle);
    //erode(src, dst_, sturctEle);
    imshow("dilate", dst);
    //imshow("erode", dst_);
    return;
}

输出结果演示


image.png

形态学操作——开操作

  先腐蚀后膨胀,可以去掉小的对象


image.png

形态学操作——闭操作

  先膨胀后腐蚀,可以填充小对象


image.png

形态学梯度

  膨胀减去腐蚀


image.png

形态学操作——顶帽

  顶帽是原图像与开操作图像之间的差值图像


image.png

形态学操作——黑帽

  黑帽是闭操作图像与原图像之间的差值图像


image.png
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
Mat src, dst;
int main(int argc, int ** argv)
{
    src = imread("F:/black_hole.png");
    if (!src.data) {
        printf("无法加载图片\n");
        return -1;
    }
    namedWindow("input img", CV_WINDOW_AUTOSIZE);
    imshow("show img", src);
    Mat kernel = getStructuringElement(MORPH_RECT, Size(15, 15), Point(-1, -1));
    //morphologyEx(src, dst, CV_MOP_OPEN, kernel);
    //morphologyEx(src, dst, CV_MOP_CLOSE, kernel);
    //morphologyEx(src, dst, CV_MOP_GRADIENT, kernel);
    //morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);
    morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);

    namedWindow("output result", CV_WINDOW_AUTOSIZE);
    imshow("erode", dst);
    waitKey(0);
    return 0;
}

morphologyEx(Mat src,Mat dst,int opt,kernel)
其中opt是形态学操作,可以为CV_MOP_OPEN,CV_MOP_CLOSE,CV_MOP_GRADIENT,CV_MOP_TOPHAT,CV_MOP_BLACKHAT

形态学应用

提取水平和垂直线

  可以通过自定义结构元素实现结构元素对输入图像一些对象敏感,一些对象不敏感,这样就会让敏感对象改变而不敏感对象保留输出。通过使用膨胀与腐蚀,使用不同的结构元素来得到不同的结果。

操作步骤:

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
Mat src, dst;
int main(int argc, int ** argv)
{
    src = imread("F:/line.png");
    if (!src.data) {
        printf("无法加载图片\n");
        return -1;
    }
    namedWindow("input img", CV_WINDOW_AUTOSIZE);
    Mat gray;
    cvtColor(src, gray, CV_BGR2GRAY);
    imshow("gray img", gray);
    Mat binImg;
    adaptiveThreshold(~gray, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
    imshow("binary img", binImg);

    Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols/16, 1), Point(-1, -1));
    Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows/16), Point(-1, -1));
    Mat temp;
    //erode(binImg, temp, hline);
    //dilate(temp, dst, hline);
    erode(binImg, temp, vline);
    dilate(temp, dst, vline);
    bitwise_not(dst, dst);
    imshow("final result", dst);
    waitKey(0);
    return 0;
}


水平线.png 垂直线.png

扩展:去除打码平台无用的线条

image.png
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
Mat src, dst;
int main(int argc, int ** argv)
{
    src = imread("F:/number.png");
    if (!src.data) {
        printf("无法加载图片\n");
        return -1;
    }
    namedWindow("input img", CV_WINDOW_AUTOSIZE);
    Mat gray;
    cvtColor(src, gray, CV_BGR2GRAY);
    imshow("gray img", gray);
    Mat binImg;
    adaptiveThreshold(~gray, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
    imshow("binary img", binImg);
    Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols/16, 1), Point(-1, -1));
    Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows/16), Point(-1, -1));
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    Mat temp;

    erode(binImg, temp, kernel);
    dilate(temp, dst, kernel);
    bitwise_not(dst, dst);
    imshow("final result", dst);
    waitKey(0);
    return 0;
}


上一篇下一篇

猜你喜欢

热点阅读