文章目录
OpenCV—python 形态学处理(腐蚀、膨胀、开闭运算、边缘检测)
一、形态学操作(morphology operators)
基于形状的一系列图像处理操作的合集;
主要是基于集合论基础上的形态学数学,形态学有四个基本操作:腐蚀、膨胀、开、闭
膨胀与腐蚀是图像处理中最常用的形态学操作手段
函数签名:
Mat getStructuringElement(
int
shape, 结构形状取值如下:
- MORPH_RECT 方形
- MORPH_CROSS 十字交叉
- MORPH_ELLIPSE 椭圆形
Size
ksize, 结构形状大小(取奇数)
Point
anchor = Point(-1,-1)); 默认为中心元素
自定义结构形状:
膨胀 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);
}
膨胀(dilate)效果图:
腐蚀 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 )效果图:
这里使用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);
}
演示效果:
提取表格
通过提取线条,等操作提取表格,操作流程:
- 输入图像彩色图像 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—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);
}