opencv-066-图像形态学(开闭操作时候结构元素应用演示)

知识点

OpenCV中图像形态学开操作与闭操作,根据结构元素的不同可以实现不同的二值图像处理效果,我们可以通过下面的结构元素对图像进行开操作,提取二值图像中水平与垂直线,这个方法比霍夫直线检测要好用得多, 在一些应用场景中会特别有用,图像分析、OCR布局分析中形态学操作十分重要,我们通过两个例子来说明开闭操作的作用。

1 开操作提取水平线,实现填空题横线位置提取
结构元素大小为20x1

步骤:

  1. 转灰度
  2. 转二值,可选降噪
  3. 形态学操作,提取水平线
  4. 轮廓发现,确定位置

2 闭操作实现不同层次的轮廓填充
结构元素分为三种:

  • 矩形结构元素35x35大小

  • 矩形结构元素30x30大小

  • 圆形结构元素30x30大小

代码(c++,python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;


void open_demo();

void close_demo();

/*
* 图像形态学(开闭操作时候结构元素应用演示)
*/
int main() {
//open_demo();
close_demo();

waitKey(0);
return 0;
}

void close_demo() {
// 读取图像
Mat src = imread("../images/morph3.png");
imshow("input", src);

// 二值图像
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);

// 闭操作
//Mat se = getStructuringElement(MORPH_ELLIPSE, Size(30, 30), Point(-1, -1));
//Mat se = getStructuringElement(MORPH_RECT, Size(30, 30), Point(-1, -1));
Mat se = getStructuringElement(MORPH_RECT, Size(35, 35), Point(-1, -1));
morphologyEx(binary, binary, MORPH_CLOSE, se);
imshow("close_demo rect=35,35", binary);
}

void open_demo() {
// 读取图像
Mat src = imread("../images/fill.png");
imshow("input", src);

// 二值图像
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow("binary", binary);

// 开操作
Mat se = getStructuringElement(MORPH_RECT, Size(25, 1), Point(-1, -1));
morphologyEx(binary, binary, MORPH_OPEN, se);
imshow("open_op", binary);

// 绘制填空位置
vector<vector<Point>> contours;
vector<Vec4i> hierarhy;
findContours(binary, contours, hierarhy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(-1, -1));
for (size_t t = 0; t < contours.size(); t++) {
Rect roi = boundingRect(contours[t]);
roi.y = roi.y - 10;
roi.height = 12;
rectangle(src, roi, Scalar(0, 0, 255));
}

// 显示结果
imshow("open_demo", src);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import cv2 as cv
import numpy as np


def open_demo():
src = cv.imread("D:/images/fill.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)

# 图像二值化
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
cv.imwrite("D:/binary1.png", binary)
cv.imshow("binary1", binary)

# 开操作
se1 = cv.getStructuringElement(cv.MORPH_RECT, (20, 1), (-1, -1))
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, se1)
cv.imshow("binary", binary)
cv.imwrite("D:/binary2.png", binary)

# 提取轮廓
out, contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[c])
y = y - 10
h = 12
cv.rectangle(src, (x, y), (x+w, y+h), (0, 0, 255), 1, 8, 0)
cv.imshow("result", src)


def close_demo():
src = cv.imread("D:/images/morph3.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)

# 图像二值化
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)

# 闭操作
se = cv.getStructuringElement(cv.MORPH_ELLIPSE, (15, 15), (-1, -1))
binary = cv.morphologyEx(binary, cv.MORPH_CLOSE, se)
cv.imwrite("D:/close.png", binary)
cv.imshow("close", binary)


close_demo()
cv.waitKey(0)
cv.destroyAllWindows()

结果

开操作应用

闭操作应用

代码地址

github