文章目录


​OpenCV—python 形态学处理(腐蚀、膨胀、开闭运算、边缘检测)​

一、形态学操作(morphology operators)

基于形状的一系列图像处理操作的合集;
主要是基于集合论基础上的形态学数学,形态学有四个基本操作:腐蚀、膨胀、开、闭
膨胀与腐蚀是图像处理中最常用的形态学操作手段

函数签名:


Mat getStructuringElement( int shape,   结构形状取值如下:


  • MORPH_RECT   方形
  • MORPH_CROSS  十字交叉
  • MORPH_ELLIPSE  椭圆形


Size ksize,          结构形状大小(取奇数)

Point anchor = Point(-1,-1)); 默认为中心元素


OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_opencv


自定义结构形状:

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_#include_02

膨胀 dilate ()

跟卷积操作类似,假设有 图像A 和 结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点:计算B覆盖下A的最大像素值用来替换锚点的像素(黑色为0,白色为255,千万别搞反了),其中B作为结构体可以是任意形状

头文件 quick_opencv.h:声明类与公共函数

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
...
void morphology_Demo(Mat& image1);
void morphologyEx_Demo(Mat& image1);
void extract_line_Demo(Mat& image1);
void clear_verif_code_Demo(Mat& image1);
};

主函数调用该类的公共成员函数

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;


int main(int argc, char** argv) {
Mat src1 = imread("D:\\Desktop\\ttt.png");
if (src1.empty()) {
printf("Could not load images1...\n");
return -1;
}
imshow("input1", src1);

QuickDemo qk;
qk.morphology_Demo(src1);
qk.morphologyEx_Demo(src1);
qk.extract_line_Demo(src1);
qk.clear_verif_code_Demo(src1);
waitKey(0);
destroyAllWindows();
return 0;
}

源文件 quick_demo.cpp:实现类与公共函数

static void on_struct(int element_size, void* userdata) {
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
int s = element_size * 2 + 1;
Mat kernel = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
dilate(image, dst, kernel, Point(-1, -1), 1);
imshow("morphology", dst);
}

void QuickDemo::morphology_Demo(Mat& image) {
string win_name = "morphology";
namedWindow(win_name, WINDOW_AUTOSIZE);
int element_size = 1;
int max_size = 12;
createTrackbar("Struct Bar", "morphology", &element_size, max_size, on_struct, (void*)(&image));
on_struct(3, &image);
}

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_opencv_03


膨胀(dilate)效果图:

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_锚点_04

腐蚀 erode ()

腐蚀跟膨胀操作的过程类似,最小值替换锚点重叠下图像的像素值

static void on_struct(int element_size, void* userdata) {
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
int s = element_size * 2 + 1;
Mat kernel = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
erode(image, dst, kernel, Point(-1, -1), 1);
imshow("morphology", dst);
}

void QuickDemo::morphology_Demo(Mat& image) {
string win_name = "morphology";
namedWindow(win_name, WINDOW_AUTOSIZE);
int element_size = 1;
int max_size = 12;
createTrackbar("Struct Bar", "morphology", &element_size, max_size, on_struct, (void*)(&image));
on_struct(3, &image);
}

黑色为0,白色为255,千万别搞反了(具体使用膨胀与腐蚀时要看背景)

腐蚀(erode )效果图:

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_锚点_05

这里使用GUI可以动态实时预览,其实使用python的for循环更加简单粗暴,省事。

二、morphologyEx

函数签名介绍

void morphologyEx(


InputArray src,
OutputArray dst,


int op,
  MORPH_OPEN     –开运算(Opening operation)
  MORPH_CLOSE      –闭运算(Closing operation)
  MORPH_GRADIENT  –形态学梯度(Morphological gradient)
  MORPH_TOPHAT    –顶帽(Top hat)
  MORPH_BLACKHAT  –黑帽(Black hat)


InputArray kernel,    结构元素
  MORPH_RECT=0,
  MORPH_CROSS=1,
  MORPH_ELLIPSE=2


Point anchor = Point(-1,-1),结构元素的锚点
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );

开运算和闭运算

开运算与闭运算 是将腐蚀和膨胀按照一定的次序进行处理。但这两者并不是可逆的,会图像造成毁灭性破坏。

  • 开运算:先腐蚀后膨胀,用于移除图像斑点。
    (假设对象是前景色,背景是黑色)
  • 闭运算:先膨胀后腐蚀,用于填充图像洞点,用来连接被误分为许多小块的对象;
    (假设对象是前景色,背景是黑色)

详情见 ​​OpenCV—python 形态学处理(腐蚀、膨胀、开闭运算、边缘检测)​

形态学梯度- Morphological Gradient 顶帽黑帽

膨胀减去腐蚀
又称为基本梯度(其它还包括-内部梯度、方向梯度)

void QuickDemo::morphologyEx_Demo(Mat& image) {
Mat dst_open, dst_close, dst_grad, dst_top, dst_black;
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
morphologyEx(image, dst_open, MORPH_OPEN, kernel, Point(-1, -1), 1);
morphologyEx(image, dst_close, MORPH_CLOSE, kernel, Point(-1, -1), 1);
morphologyEx(image, dst_grad, MORPH_GRADIENT, kernel, Point(-1, -1), 1);
morphologyEx(image, dst_top, MORPH_TOPHAT, kernel, Point(-1, -1), 1);
morphologyEx(image, dst_black, MORPH_BLACKHAT, kernel, Point(-1, -1), 1);
imshow("dst_open", dst_open);
imshow("dst_close", dst_close);
imshow("dst_grad", dst_grad);
imshow("dst_top", dst_top);
imshow("dst_black", dst_black);
}

演示效果:

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_锚点_06

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_python_07

提取表格

通过提取线条,等操作提取表格,操作流程:

  • 输入图像彩色图像 imread
  • 模糊降噪(高斯模糊、均值平滑、双边滤波等)
  • 转换为灰度图像(单通道图) – cvtColor 具体使用灰度图还是BGR其中一个通道看图像的背景颜色及对比度
  • 转换为二值图像 – adaptiveThreshold
  • 定义结构元素
  • 开操作 (腐蚀+膨胀)提取 水平与垂直线
  • 获取水平与垂直线掩码
  • 查找轮廓(或者根据轮廓在图像中的位置筛选需要的轮廓)

void adaptiveThreshold( InputArray src,     输入单通道图像

OutputArray dst,   输出二值图像(与输入图像同样的尺寸和类型)

double maxValue,  颜色值最大值

int adaptiveMethod, 自适应阈值算法。(ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C)

int thresholdType,  可选择THRESH_BINARY或者THRESH_BINARY_INV两种

int blockSize,     邻域块大小,用来计算区域阈值

double C      与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。

);

void QuickDemo::extract_line_Demo(Mat& image) {
int height = image.rows;
int width = image.cols;
Mat gray_img, binary_img;
Mat horiz_img, vert_img;
cvtColor(image, gray_img, COLOR_BGR2GRAY);
bitwise_not(gray_img, gray_img);
GaussianBlur(gray_img, gray_img, Size(3, 3), 10);
adaptiveThreshold(gray_img, binary_img, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 15, -2);

int horiz_size = (int)(width / 15); // horiz_size值越大,检测出长线条,筛选掉段线条
int vert_size = (int)(height / 15); // 同上

Mat horiz = getStructuringElement(MORPH_RECT, Size(horiz_size, 1), Point(-1, -1));
erode(binary_img, horiz_img, horiz);
dilate(horiz_img, horiz_img, horiz);
imshow("horiz_img", horiz_img);

Mat vert = getStructuringElement(MORPH_RECT, Size(1, vert_size), Point(-1, -1));
morphologyEx(binary_img, vert_img, MORPH_OPEN, vert, Point(-1, -1)); //开操作=腐蚀+膨胀
imshow("vert_img", vert_img);

Mat net_img,mask_img;
bitwise_or(horiz_img, vert_img, mask_img);
imshow("mask_img", mask_img);
}

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_python_08

表格提取:​​OpenCV—Python 表格提取​

小示例:使用形态学去除验证码噪声与杂线条

void QuickDemo::clear_verif_code_Demo(Mat& image) {
Mat gray_img, binary_img;
cvtColor(image, gray_img, COLOR_BGR2GRAY);
//threshold(gray_img, binary_img, 250, 255, THRESH_BINARY); //s8bq
//threshold(gray_img, binary_img, 250, 255, THRESH_BINARY); //2M89
threshold(gray_img, binary_img, 200, 255, THRESH_BINARY); //xa4k4s
bitwise_not(binary_img, binary_img);
Mat rect_line = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(binary_img, binary_img, MORPH_OPEN, rect_line, Point(-1, -1));
imshow("binary_img", binary_img);
}

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_opencv_09

OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_python_10


OpenCV + CPP 系列(十四)形态学操作(膨胀、腐蚀,开运算、闭运算)_python_11