assembly-opencv 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- assembly/CornerDetection.py +117 -0
- assembly/DrawImage.py +297 -0
- assembly/EdgeDetection.py +190 -0
- assembly/GeneralUtil.py +103 -0
- assembly/GeometricChanges.py +171 -0
- assembly/ImageEnhance.py +242 -0
- assembly/ImageOperation.py +186 -0
- assembly/ImageSegmentation.py +190 -0
- assembly/MorphologicalChange.py +221 -0
- assembly/PolygonOperation.py +323 -0
- assembly/__init__.py +165 -0
- assembly_opencv-1.0.0.dist-info/METADATA +16 -0
- assembly_opencv-1.0.0.dist-info/RECORD +15 -0
- assembly_opencv-1.0.0.dist-info/WHEEL +5 -0
- assembly_opencv-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from assembly.description.Decoration import func_description, class_description
|
|
5
|
+
|
|
6
|
+
'''
|
|
7
|
+
角点检测算子
|
|
8
|
+
|
|
9
|
+
输入:灰度图
|
|
10
|
+
输出:角点坐标列表
|
|
11
|
+
'''
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@class_description(
|
|
15
|
+
title="角点检测",
|
|
16
|
+
description="角点检测算子是一种图像特征提取技术,用于检测图像中的特征点,如角点、边缘、斑点等。",
|
|
17
|
+
level=9
|
|
18
|
+
)
|
|
19
|
+
class CornerDetection(object):
|
|
20
|
+
|
|
21
|
+
@func_description(
|
|
22
|
+
title="角点检测Harris算法:",
|
|
23
|
+
description="基于图像局部灰度变化,通过计算像素点在x/y 方向的梯度,构建结构张量矩阵(梯度自相关矩阵),再通过响应函数判断是否为角点"
|
|
24
|
+
)
|
|
25
|
+
@staticmethod
|
|
26
|
+
def corner_harris(gray):
|
|
27
|
+
"""
|
|
28
|
+
:name Harris角点检测
|
|
29
|
+
:param gray: 单通道图
|
|
30
|
+
:return list:角点坐标列表
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
image_float = np.float32(gray)
|
|
34
|
+
dst = cv2.cornerHarris(image_float, blockSize=2, ksize=3, k=0.04)
|
|
35
|
+
dst = cv2.dilate(dst, None)
|
|
36
|
+
ret, dst = cv2.threshold(dst, 0.01 * dst.max(), 255, 0)
|
|
37
|
+
dst = np.uint8(dst)
|
|
38
|
+
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
|
|
39
|
+
result = [[stats[i][0], stats[i][1]] for i in range(1, ret)]
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
@func_description(
|
|
43
|
+
title="角点检测Shi-Tomasi算法:",
|
|
44
|
+
description="Harris 算法的改进版,直接利用矩阵 M 的最小特征值判断角点"
|
|
45
|
+
)
|
|
46
|
+
@staticmethod
|
|
47
|
+
def corner_shi_tomasi(gray):
|
|
48
|
+
"""
|
|
49
|
+
:name Shi-Tomasi角点检测
|
|
50
|
+
:param gray: 单通道图
|
|
51
|
+
:return list:角点坐标列表
|
|
52
|
+
"""
|
|
53
|
+
corners = cv2.goodFeaturesToTrack(gray, maxCorners=100, qualityLevel=0.01, minDistance=10)
|
|
54
|
+
corners = np.intp(corners)
|
|
55
|
+
print(corners.reshape(-1, 2).tolist())
|
|
56
|
+
print(corners[0].ravel)
|
|
57
|
+
result = [[i.ravel] for i in corners]
|
|
58
|
+
return result
|
|
59
|
+
|
|
60
|
+
@func_description(
|
|
61
|
+
title="角点检测FAST算法:",
|
|
62
|
+
description="基于像素灰度差异的高效角点检测算法,不直接用于角点检测,但可以用于特征匹配"
|
|
63
|
+
)
|
|
64
|
+
@staticmethod
|
|
65
|
+
def corner_fast(gray, threshold=30, nonmaxSuppression=True):
|
|
66
|
+
"""
|
|
67
|
+
:name FAST角点检测
|
|
68
|
+
:param gray: 单通道图
|
|
69
|
+
:param threshold: 阈值
|
|
70
|
+
:param nonmaxSuppression: 是否关闭非极大值抑制
|
|
71
|
+
:return list:角点坐标列表
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
fast = cv2.FastFeatureDetector_create(threshold=threshold)
|
|
75
|
+
|
|
76
|
+
if nonmaxSuppression:
|
|
77
|
+
# 关闭非极大值抑制
|
|
78
|
+
fast.setNonmaxSuppression(0)
|
|
79
|
+
# 检测图像上的关键点
|
|
80
|
+
kp = fast.detect(gray, None)
|
|
81
|
+
|
|
82
|
+
result = [[point.pt] for point in kp]
|
|
83
|
+
return result
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# def corner_SIFT(gray):
|
|
87
|
+
# # 使用SIFT检测关键点并计算描述符
|
|
88
|
+
# sift = cv2.SIFT_create()
|
|
89
|
+
# keypoints, descriptors = sift.detectAndCompute(gray, None)
|
|
90
|
+
#
|
|
91
|
+
# # 在图像上绘制关键点(实际上是特征点)
|
|
92
|
+
# image_with_keypoints = cv2.drawKeypoints(gray, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
|
|
93
|
+
# return image_with_keypoints
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# 暴露方法
|
|
97
|
+
def corner_detection_fast(gray_img, threshold=30, nonmaxSuppression=True):
|
|
98
|
+
return CornerDetection.corner_fast(gray_img, threshold, nonmaxSuppression)
|
|
99
|
+
|
|
100
|
+
def corner_detection_shi_tomasi(gray_img):
|
|
101
|
+
return CornerDetection.corner_shi_tomasi(gray_img)
|
|
102
|
+
|
|
103
|
+
def corner_detection_harris(gray_img):
|
|
104
|
+
return CornerDetection.corner_harris(gray_img)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == '__main__':
|
|
108
|
+
corner_detection = CornerDetection()
|
|
109
|
+
img = cv2.imdecode(np.fromfile(r"C:\Users\GT-LAPTOP-043\Downloads\黑白格.jpg", dtype=np.uint8),
|
|
110
|
+
cv2.IMREAD_COLOR)
|
|
111
|
+
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
112
|
+
# show_image("gray_img", gray_img, 500, 500)
|
|
113
|
+
print("corner_harris", corner_detection.corner_harris(gray_img))
|
|
114
|
+
print("corner_shi_tomasi", corner_detection.corner_shi_tomasi(gray_img))
|
|
115
|
+
print("corner_fast", corner_detection.corner_fast(gray_img))
|
|
116
|
+
|
|
117
|
+
cv2.destroyAllWindows()
|
assembly/DrawImage.py
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import numpy as np
|
|
3
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
4
|
+
|
|
5
|
+
from assembly.description.Decoration import func_description, class_description
|
|
6
|
+
from assembly.GeneralUtil import show_image
|
|
7
|
+
|
|
8
|
+
'''
|
|
9
|
+
绘制图像
|
|
10
|
+
|
|
11
|
+
输入:原始图
|
|
12
|
+
输出:原始图
|
|
13
|
+
'''
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@class_description(
|
|
17
|
+
title="绘制图像",
|
|
18
|
+
description="在图像上绘制轮廓,包括点,线,矩形,圆等基本图形",
|
|
19
|
+
level=2
|
|
20
|
+
)
|
|
21
|
+
class DrawImage(object):
|
|
22
|
+
|
|
23
|
+
@func_description(
|
|
24
|
+
title="生成空白图像",
|
|
25
|
+
description="生成指定大小和颜色的空白图像"
|
|
26
|
+
)
|
|
27
|
+
@staticmethod
|
|
28
|
+
def generate_blank_image(width, height, color=(0, 0, 0)):
|
|
29
|
+
"""
|
|
30
|
+
:name 生成空白图像
|
|
31
|
+
:param width: 图像宽度
|
|
32
|
+
:param height: 图像高度
|
|
33
|
+
:param color: 图像颜色
|
|
34
|
+
:return img: 空白图像
|
|
35
|
+
"""
|
|
36
|
+
img = np.zeros((height, width, 3), np.uint8)
|
|
37
|
+
img[:] = color
|
|
38
|
+
|
|
39
|
+
return img
|
|
40
|
+
|
|
41
|
+
@func_description(
|
|
42
|
+
title="绘制轮廓",
|
|
43
|
+
description="在图像上绘制轮廓"
|
|
44
|
+
)
|
|
45
|
+
@staticmethod
|
|
46
|
+
def draw_contours(img, contours, contour_color=(0, 255, 0), thickness=2):
|
|
47
|
+
"""
|
|
48
|
+
:name 绘制轮廓
|
|
49
|
+
:param img: 原始图
|
|
50
|
+
:param contours: 轮廓列表
|
|
51
|
+
:param contour_color: 轮廓颜色
|
|
52
|
+
:param thickness: 轮廓线宽
|
|
53
|
+
:return img: 绘制轮廓后的图像
|
|
54
|
+
"""
|
|
55
|
+
img_draw = img.copy()
|
|
56
|
+
cv2.drawContours(img_draw, contours, -1, contour_color, thickness)
|
|
57
|
+
|
|
58
|
+
return img_draw
|
|
59
|
+
|
|
60
|
+
@func_description(
|
|
61
|
+
title="绘制点",
|
|
62
|
+
description="在图像上绘制点"
|
|
63
|
+
)
|
|
64
|
+
@staticmethod
|
|
65
|
+
def draw_points(img, points, point_color=(0, 0, 255), thickness=2):
|
|
66
|
+
"""
|
|
67
|
+
:name 绘制点
|
|
68
|
+
:param img: 原始图
|
|
69
|
+
:param points: 点列表,格式为 [(x1, y1), (x2, y2), ...]
|
|
70
|
+
:param point_color: 点颜色
|
|
71
|
+
:param thickness: 点大小
|
|
72
|
+
:return img: 绘制点后的图像
|
|
73
|
+
"""
|
|
74
|
+
img_draw = img.copy()
|
|
75
|
+
for point in points:
|
|
76
|
+
cv2.circle(img_draw, point, thickness, point_color, -1)
|
|
77
|
+
|
|
78
|
+
return img_draw
|
|
79
|
+
|
|
80
|
+
@func_description(
|
|
81
|
+
title="绘制线",
|
|
82
|
+
description="在图像上绘制线"
|
|
83
|
+
)
|
|
84
|
+
@staticmethod
|
|
85
|
+
def draw_lines(img, lines, line_color=(0, 255, 255), thickness=2):
|
|
86
|
+
"""
|
|
87
|
+
:name 绘制线
|
|
88
|
+
:param img: 原始图
|
|
89
|
+
:param lines: 线列表,格式为 [(x1, y1, x2, y2), (x3, y3, x4, y4), ...]
|
|
90
|
+
:param line_color: 线颜色
|
|
91
|
+
:param thickness: 线宽
|
|
92
|
+
:return img: 绘制线后的图像
|
|
93
|
+
"""
|
|
94
|
+
img_draw = img.copy()
|
|
95
|
+
for line in lines:
|
|
96
|
+
cv2.line(img_draw, (line[0], line[1]), (line[2], line[3]), line_color, thickness)
|
|
97
|
+
|
|
98
|
+
return img_draw
|
|
99
|
+
|
|
100
|
+
@func_description(
|
|
101
|
+
title="绘制矩形",
|
|
102
|
+
description="在图像上绘制矩形"
|
|
103
|
+
)
|
|
104
|
+
@staticmethod
|
|
105
|
+
def draw_rectangles(img, rectangles, rectangle_color=(255, 0, 0), thickness=2):
|
|
106
|
+
"""
|
|
107
|
+
:name 绘制矩形
|
|
108
|
+
:param img: 原始图
|
|
109
|
+
:param rectangles: 矩形列表,格式为 [(x1, y1, w, h), (x2, y2, w, h), ...]
|
|
110
|
+
:param rectangle_color: 矩形颜色
|
|
111
|
+
:param thickness: 矩形线宽
|
|
112
|
+
:return img: 绘制矩形后的图像
|
|
113
|
+
"""
|
|
114
|
+
img_draw = img.copy()
|
|
115
|
+
for rectangle in rectangles:
|
|
116
|
+
cv2.rectangle(img_draw, (rectangle[0], rectangle[1]),
|
|
117
|
+
(rectangle[0] + rectangle[2], rectangle[1] + rectangle[3]), rectangle_color, thickness)
|
|
118
|
+
|
|
119
|
+
return img_draw
|
|
120
|
+
|
|
121
|
+
@func_description(
|
|
122
|
+
title="绘制圆",
|
|
123
|
+
description="在图像上绘制圆"
|
|
124
|
+
)
|
|
125
|
+
@staticmethod
|
|
126
|
+
def draw_circles(img, circles, circle_color=(255, 255, 0), thickness=2):
|
|
127
|
+
"""
|
|
128
|
+
:name 绘制圆
|
|
129
|
+
:param img: 原始图
|
|
130
|
+
:param circles: 圆列表,格式为 [(x, y, r), (x, y, r), ...]
|
|
131
|
+
:param circle_color: 圆颜色
|
|
132
|
+
:param thickness: 圆线宽
|
|
133
|
+
:return img: 绘制圆后的图像
|
|
134
|
+
"""
|
|
135
|
+
img_draw = img.copy()
|
|
136
|
+
for circle in circles:
|
|
137
|
+
cv2.circle(img_draw, (circle[0], circle[1]), circle[2], circle_color, thickness)
|
|
138
|
+
|
|
139
|
+
return img_draw
|
|
140
|
+
|
|
141
|
+
@func_description(
|
|
142
|
+
title="绘制椭圆",
|
|
143
|
+
description="在图像上绘制椭圆"
|
|
144
|
+
)
|
|
145
|
+
@staticmethod
|
|
146
|
+
def draw_ellipses(img, ellipses, ellipse_color=(0, 255, 255), thickness=2):
|
|
147
|
+
"""
|
|
148
|
+
:name 绘制椭圆
|
|
149
|
+
:param img: 原始图
|
|
150
|
+
:param ellipses: 椭圆列表,格式为 [(x, y, w, h), (x, y, w, h), ...]
|
|
151
|
+
:param ellipse_color: 椭圆颜色
|
|
152
|
+
:param thickness: 椭圆线宽
|
|
153
|
+
:return img: 绘制椭圆后的图像
|
|
154
|
+
"""
|
|
155
|
+
img_draw = img.copy()
|
|
156
|
+
for ellipse in ellipses:
|
|
157
|
+
cv2.ellipse(img_draw, (ellipse[0], ellipse[1]), (ellipse[2], ellipse[3]), 0, 0, 360, ellipse_color,
|
|
158
|
+
thickness)
|
|
159
|
+
|
|
160
|
+
return img_draw
|
|
161
|
+
|
|
162
|
+
@func_description(
|
|
163
|
+
title="绘制多边形",
|
|
164
|
+
description="在图像上绘制多边形"
|
|
165
|
+
)
|
|
166
|
+
@staticmethod
|
|
167
|
+
def draw_polygons(img, polygons, polygon_color=(255, 0, 255), thickness=2):
|
|
168
|
+
"""
|
|
169
|
+
:name 绘制多边形
|
|
170
|
+
:param img: 原始图
|
|
171
|
+
:param polygons: 多边形列表,格式为 [[(x1, y1), (x2, y2), ...], [(x1, y1), (x2, y2), ...], ...]
|
|
172
|
+
:param polygon_color: 多边形颜色
|
|
173
|
+
:param thickness: 多边形线宽
|
|
174
|
+
:return img: 绘制多边形后的图像
|
|
175
|
+
"""
|
|
176
|
+
img_draw = img.copy()
|
|
177
|
+
for polygon in polygons:
|
|
178
|
+
cv2.polylines(img_draw, [np.array(polygon, dtype=np.int32)], True, polygon_color, thickness)
|
|
179
|
+
|
|
180
|
+
return img_draw
|
|
181
|
+
|
|
182
|
+
@func_description(
|
|
183
|
+
title="绘制文字",
|
|
184
|
+
description="在图像上绘制文字"
|
|
185
|
+
)
|
|
186
|
+
@staticmethod
|
|
187
|
+
def draw_text(img, text, text_position, text_color=(0, 0, 0), font_size=12, font_bold=False):
|
|
188
|
+
"""
|
|
189
|
+
:name 绘制文字
|
|
190
|
+
:param img: 原始图
|
|
191
|
+
:param text: 文字内容
|
|
192
|
+
:param text_position: 文字位置,格式为 (x, y)
|
|
193
|
+
:param text_color: 文字颜色
|
|
194
|
+
:param font_size: 文字大小
|
|
195
|
+
:param font_bold: 是否加粗
|
|
196
|
+
:return img: 绘制文字后的图像
|
|
197
|
+
"""
|
|
198
|
+
img_draw = img.copy()
|
|
199
|
+
# 转换为Pillow图像
|
|
200
|
+
img_pil = Image.fromarray(cv2.cvtColor(img_draw, cv2.COLOR_BGR2RGB))
|
|
201
|
+
# 加载字体
|
|
202
|
+
font = ImageFont.truetype("../front/simsun.ttc", font_size, index=1 if font_bold else 0) # 替换为实际的字体路径
|
|
203
|
+
# 在Pillow图像上绘制中文
|
|
204
|
+
draw = ImageDraw.Draw(img_pil)
|
|
205
|
+
draw.text(text_position, text, font=font, fill=text_color)
|
|
206
|
+
# 转换回OpenCV格式
|
|
207
|
+
img_draw = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
|
|
208
|
+
|
|
209
|
+
return img_draw
|
|
210
|
+
|
|
211
|
+
@func_description(
|
|
212
|
+
title="绘制边框",
|
|
213
|
+
description="在图像四周增加边框"
|
|
214
|
+
)
|
|
215
|
+
@staticmethod
|
|
216
|
+
def draw_border(img, border_width=5, border_color=(255, 255, 255)):
|
|
217
|
+
"""
|
|
218
|
+
:name 绘制边框
|
|
219
|
+
:param img: 原始图
|
|
220
|
+
:param border_width: 边框宽度
|
|
221
|
+
:param border_color: 边框颜色
|
|
222
|
+
:return img: 绘制边框后的图像
|
|
223
|
+
"""
|
|
224
|
+
img_draw = img.copy()
|
|
225
|
+
img_draw = cv2.copyMakeBorder(img_draw, border_width, border_width, border_width, border_width,
|
|
226
|
+
cv2.BORDER_CONSTANT, value=border_color)
|
|
227
|
+
|
|
228
|
+
return img_draw
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# 暴露外部调用方法
|
|
232
|
+
|
|
233
|
+
def generate_blank_image(width, height, color=(0, 0, 0)):
|
|
234
|
+
return DrawImage.generate_blank_image(width, height, color)
|
|
235
|
+
|
|
236
|
+
def draw_contours(img, contours, contour_color=(0, 255, 0), thickness=2):
|
|
237
|
+
return DrawImage.draw_contours(img, contours, contour_color, thickness)
|
|
238
|
+
|
|
239
|
+
def draw_points(img, points, point_color=(0, 0, 255), radius=5, thickness=-1):
|
|
240
|
+
return DrawImage.draw_points(img, points, point_color, radius, thickness)
|
|
241
|
+
|
|
242
|
+
def draw_lines(img, lines, line_color=(255, 0, 0), thickness=2):
|
|
243
|
+
return DrawImage.draw_lines(img, lines, line_color, thickness)
|
|
244
|
+
|
|
245
|
+
def draw_rectangles(img, rectangles, rectangle_color=(255, 0, 0), thickness=2):
|
|
246
|
+
return DrawImage.draw_rectangles(img, rectangles, rectangle_color, thickness)
|
|
247
|
+
|
|
248
|
+
def draw_circles(img, circles, circle_color=(0, 255, 255), thickness=2):
|
|
249
|
+
return DrawImage.draw_circles(img, circles, circle_color, thickness)
|
|
250
|
+
|
|
251
|
+
def draw_ellipses(img, ellipses, ellipse_color=(0, 255, 255), thickness=2):
|
|
252
|
+
return DrawImage.draw_ellipses(img, ellipses, ellipse_color, thickness)
|
|
253
|
+
|
|
254
|
+
def draw_polygons(img, polygons, polygon_color=(255, 0, 255), thickness=2):
|
|
255
|
+
return DrawImage.draw_polygons(img, polygons, polygon_color, thickness)
|
|
256
|
+
|
|
257
|
+
def draw_text(img, text, text_position, text_color=(0, 0, 0), font_size=12, font_bold=False):
|
|
258
|
+
return DrawImage.draw_text(img, text, text_position, text_color, font_size, font_bold)
|
|
259
|
+
|
|
260
|
+
def draw_border(img, border_width=5, border_color=(255, 255, 255)):
|
|
261
|
+
return DrawImage.draw_border(img, border_width, border_color)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
if __name__ == '__main__':
|
|
266
|
+
draw_image = DrawImage()
|
|
267
|
+
img = draw_image.generate_blank_image(500, 500, (255, 255, 255))
|
|
268
|
+
show_image("img", img)
|
|
269
|
+
|
|
270
|
+
img = draw_image.draw_contours(img, [np.array([[100, 100], [200, 100], [200, 200], [100, 200]])])
|
|
271
|
+
show_image("img", img)
|
|
272
|
+
|
|
273
|
+
img = draw_image.draw_points(img, [[100, 100], [200, 200], [300, 300]])
|
|
274
|
+
show_image("img", img)
|
|
275
|
+
|
|
276
|
+
img = draw_image.draw_lines(img, [(50, 50, 450, 450), (450, 50, 50, 450)])
|
|
277
|
+
show_image("img", img)
|
|
278
|
+
|
|
279
|
+
img = draw_image.draw_rectangles(img, [(100, 100, 100, 100), (200, 200, 100, 100)])
|
|
280
|
+
show_image("img", img)
|
|
281
|
+
|
|
282
|
+
img = draw_image.draw_circles(img, [(100, 100, 50), (200, 200, 100)])
|
|
283
|
+
show_image("img", img)
|
|
284
|
+
|
|
285
|
+
img = draw_image.draw_ellipses(img, [(100, 100, 100, 50), (200, 200, 50, 100)])
|
|
286
|
+
show_image("img", img)
|
|
287
|
+
|
|
288
|
+
img = draw_image.draw_polygons(img, [[(100, 100), (200, 100), (200, 200), (100, 200)],
|
|
289
|
+
[(300, 300), (400, 300), (400, 400), (300, 400)]])
|
|
290
|
+
show_image("img", img)
|
|
291
|
+
|
|
292
|
+
img = draw_image.draw_text(img, "特丝特 特丝特", (100, 100), font_size=24, font_bold=True)
|
|
293
|
+
img = draw_image.draw_text(img, "特丝特 特丝特", (100, 150), font_size=24, font_bold=False)
|
|
294
|
+
show_image("img", img)
|
|
295
|
+
|
|
296
|
+
img = draw_image.draw_border(img, 10, (0, 0, 0))
|
|
297
|
+
show_image("img", img)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from assembly.description.Decoration import func_description, class_description
|
|
5
|
+
from assembly.GeneralUtil import show_image
|
|
6
|
+
|
|
7
|
+
'''
|
|
8
|
+
边缘检测算子
|
|
9
|
+
|
|
10
|
+
输入:灰度图
|
|
11
|
+
输出:边缘轮廓图
|
|
12
|
+
'''
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@class_description(
|
|
16
|
+
title="边缘检测",
|
|
17
|
+
description="边缘检测是图像处理中常用的技术,其目的是识别图像中的明显特征,并从中提取其特征点,从而对图像进行分析、处理、识别等。",
|
|
18
|
+
level=8
|
|
19
|
+
)
|
|
20
|
+
class EdgeDetection(object):
|
|
21
|
+
|
|
22
|
+
@func_description(
|
|
23
|
+
title="边缘检测Canny算法",
|
|
24
|
+
description="最经典的边缘检测算法之一,其核心目标是在噪声图像中提取精确、单像素宽、连续的边缘"
|
|
25
|
+
)
|
|
26
|
+
@staticmethod
|
|
27
|
+
def edge_canny(gray, threshold1=50, threshold2=150, apertureSize=3, kernel=3):
|
|
28
|
+
"""
|
|
29
|
+
:name Canny边缘检测算法
|
|
30
|
+
:param gray: 单通道图
|
|
31
|
+
:param threshold1: 阈值1
|
|
32
|
+
:param threshold2: 阈值2
|
|
33
|
+
:param apertureSize: 孔径大小
|
|
34
|
+
:param kernel: 卷积核大小
|
|
35
|
+
:return binary: 二值化图
|
|
36
|
+
"""
|
|
37
|
+
if kernel and kernel in [3, 5, 7]:
|
|
38
|
+
gray = cv2.GaussianBlur(gray, (kernel, kernel), 0) # 高斯去噪
|
|
39
|
+
# 调用Canny
|
|
40
|
+
edges = cv2.Canny(gray, threshold1=threshold1, threshold2=threshold2, apertureSize=apertureSize)
|
|
41
|
+
return edges
|
|
42
|
+
|
|
43
|
+
@func_description(
|
|
44
|
+
title="边缘检测Sobel算法",
|
|
45
|
+
description="Sobel算子(索贝尔算子)利用像素上、下、左、右邻域的灰度加权算法,根据在边缘点处达到极值这一原理进行边缘检测。"
|
|
46
|
+
)
|
|
47
|
+
@staticmethod
|
|
48
|
+
def edge_sobel(gray, ksize=3):
|
|
49
|
+
"""
|
|
50
|
+
:name Sobel边缘检测算法
|
|
51
|
+
:param gray: 单通道图
|
|
52
|
+
:param ksize: 卷积核大小
|
|
53
|
+
:return binary: 二值化图
|
|
54
|
+
"""
|
|
55
|
+
# 计算 Sobel X 和 Y 方向的梯度
|
|
56
|
+
dst_sobel_x = cv2.Sobel(gray, cv2.CV_16S, 1, 0, ksize=ksize)
|
|
57
|
+
dst_sobel_y = cv2.Sobel(gray, cv2.CV_16S, 0, 1, ksize=ksize)
|
|
58
|
+
# 转换为绝对值并缩放到 8 位
|
|
59
|
+
dst_sobel_x = cv2.convertScaleAbs(dst_sobel_x)
|
|
60
|
+
dst_sobel_y = cv2.convertScaleAbs(dst_sobel_y)
|
|
61
|
+
# 合并 X 和 Y 方向的梯度
|
|
62
|
+
dst = cv2.add(dst_sobel_x, dst_sobel_y)
|
|
63
|
+
return dst
|
|
64
|
+
|
|
65
|
+
@func_description(
|
|
66
|
+
title="边缘检测Scharr算法",
|
|
67
|
+
description="Sobel算子与Scharr算子比较:Sobel算子的缺点是,当结构较小是,精确度不高,Scharr算子具有更高的精度"
|
|
68
|
+
)
|
|
69
|
+
@staticmethod
|
|
70
|
+
def edge_scharr(gray):
|
|
71
|
+
"""
|
|
72
|
+
:name Scharr边缘检测算法
|
|
73
|
+
:param gray: 单通道图
|
|
74
|
+
:return binary: 二值化图
|
|
75
|
+
"""
|
|
76
|
+
# 计算水平方向边缘信息
|
|
77
|
+
scharrx = cv2.Scharr(gray, cv2.CV_64F, 1, 0)
|
|
78
|
+
# 计算垂直方向边缘信息
|
|
79
|
+
scharry = cv2.Scharr(gray, cv2.CV_64F, 0, 1)
|
|
80
|
+
# 求绝对值
|
|
81
|
+
scharrx = cv2.convertScaleAbs(scharrx)
|
|
82
|
+
scharry = cv2.convertScaleAbs(scharry)
|
|
83
|
+
# 水平方向和垂直方向的边缘叠加
|
|
84
|
+
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
|
|
85
|
+
return scharrxy
|
|
86
|
+
|
|
87
|
+
@func_description(
|
|
88
|
+
title="边缘检测Laplacian算法",
|
|
89
|
+
description="拉普拉斯算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。"
|
|
90
|
+
)
|
|
91
|
+
@staticmethod
|
|
92
|
+
def edge_laplacian(gray):
|
|
93
|
+
"""
|
|
94
|
+
:name Laplacian边缘检测算法
|
|
95
|
+
:param gray: 单通道图
|
|
96
|
+
:return binary: 二值化图
|
|
97
|
+
"""
|
|
98
|
+
# 计算边缘信息
|
|
99
|
+
laplace = cv2.Laplacian(gray, cv2.CV_64F)
|
|
100
|
+
# 求绝对值
|
|
101
|
+
laplace = cv2.convertScaleAbs(laplace)
|
|
102
|
+
return laplace
|
|
103
|
+
|
|
104
|
+
@func_description(
|
|
105
|
+
title="边缘检测Roberts算法",
|
|
106
|
+
description="Roberts算子又称为交叉微分算法,是基于交叉差分的梯度算法,通过局部差分计算检测边缘线条。"
|
|
107
|
+
)
|
|
108
|
+
@staticmethod
|
|
109
|
+
def edge_roberts(gray):
|
|
110
|
+
"""
|
|
111
|
+
:name Roberts边缘检测算法
|
|
112
|
+
:param gray: 单通道图
|
|
113
|
+
:return binary: 二值化图
|
|
114
|
+
"""
|
|
115
|
+
# 定义 roberts 卷积核(注意 dtype 必须为 float32 以确保计算精度)
|
|
116
|
+
kernel_roberts_x = np.array([[-1, 0],
|
|
117
|
+
[0, 1]], dtype=np.float32)
|
|
118
|
+
kernel_roberts_y = np.array([[0, -1],
|
|
119
|
+
[1, 0]], dtype=np.float32)
|
|
120
|
+
# 执行卷积(输出类型设为 CV_32F 保留正负值)
|
|
121
|
+
dst = self.dege_filter2D(gray, kernel_roberts_x, kernel_roberts_y)
|
|
122
|
+
return dst
|
|
123
|
+
|
|
124
|
+
@func_description(
|
|
125
|
+
title="边缘检测Prewitt算法",
|
|
126
|
+
description="Prewitt边缘算子是一种边缘样板算子。由理想的边缘算子图像构成,依次用边缘样板去检测图像,与被检测区域最为相似的样板给出最大值,用这个最大值作为算子的输出。"
|
|
127
|
+
)
|
|
128
|
+
@staticmethod
|
|
129
|
+
def edge_prewitt(gray):
|
|
130
|
+
"""
|
|
131
|
+
:name Prewitt边缘检测算法
|
|
132
|
+
:param gray: 单通道图
|
|
133
|
+
:return binary: 二值化图
|
|
134
|
+
"""
|
|
135
|
+
# 定义 Prewitt 卷积核(注意 dtype 必须为 float32 以确保计算精度)
|
|
136
|
+
kernel_prewitt_x = np.array([[-1, 0, 1],
|
|
137
|
+
[-1, 0, 1],
|
|
138
|
+
[-1, 0, 1]], dtype=np.float32)
|
|
139
|
+
kernel_prewitt_y = np.array([[-1, -1, -1],
|
|
140
|
+
[0, 0, 0],
|
|
141
|
+
[1, 1, 1]], dtype=np.float32)
|
|
142
|
+
# 执行卷积(输出类型设为 CV_32F 保留正负值)
|
|
143
|
+
dst = self.dege_filter2D(gray, kernel_prewitt_x, kernel_prewitt_y)
|
|
144
|
+
return dst
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def dege_filter2D(gray, kernel_x, kernel_y):
|
|
148
|
+
'''封装方法 利用filter2D实现边缘检测算法'''
|
|
149
|
+
dst_prewitt_x = cv2.filter2D(gray, cv2.CV_32F, kernel_x)
|
|
150
|
+
dst_prewitt_y = cv2.filter2D(gray, cv2.CV_32F, kernel_y)
|
|
151
|
+
dst_prewitt_x = cv2.convertScaleAbs(dst_prewitt_x)
|
|
152
|
+
dst_prewitt_y = cv2.convertScaleAbs(dst_prewitt_y)
|
|
153
|
+
dst = cv2.add(dst_prewitt_x, dst_prewitt_y)
|
|
154
|
+
return dst
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# 保留方法
|
|
158
|
+
def edge_canny(gray, threshold1=50, threshold2=150, apertureSize=3, kernel=3):
|
|
159
|
+
return EdgeDetection.edge_canny(gray, threshold1, threshold2, apertureSize, kernel)
|
|
160
|
+
|
|
161
|
+
def edge_sobel(gray, ksize=3):
|
|
162
|
+
return EdgeDetection.edge_sobel(gray, ksize)
|
|
163
|
+
|
|
164
|
+
def edge_scharr(gray):
|
|
165
|
+
return EdgeDetection.edge_scharr(gray)
|
|
166
|
+
|
|
167
|
+
def edge_laplacian(gray):
|
|
168
|
+
return EdgeDetection.edge_laplacian(gray)
|
|
169
|
+
|
|
170
|
+
def edge_roberts(gray):
|
|
171
|
+
return EdgeDetection.edge_roberts(gray)
|
|
172
|
+
|
|
173
|
+
def edge_prewitt(gray):
|
|
174
|
+
return EdgeDetection.edge_prewitt(gray)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
if __name__ == '__main__':
|
|
178
|
+
edge_detection = EdgeDetection()
|
|
179
|
+
img = cv2.imdecode(np.fromfile(r"C:\Users\GT-LAPTOP-043\Downloads\黑白格.jpg", dtype=np.uint8),
|
|
180
|
+
cv2.IMREAD_COLOR)
|
|
181
|
+
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
182
|
+
show_image("gray_img", gray_img, 500, 500)
|
|
183
|
+
show_image("edge_canny", edge_detection.edge_canny(gray_img), 500, 500)
|
|
184
|
+
show_image("edge_sobel", edge_detection.edge_sobel(gray_img), 500, 500)
|
|
185
|
+
show_image("edge_scharr", edge_detection.edge_scharr(gray_img), 500, 500)
|
|
186
|
+
show_image("edge_laplacian", edge_detection.edge_laplacian(gray_img), 500, 500)
|
|
187
|
+
show_image("edge_roberts", edge_detection.edge_roberts(gray_img), 500, 500)
|
|
188
|
+
show_image("edge_prewitt", edge_detection.edge_prewitt(gray_img), 500, 500)
|
|
189
|
+
|
|
190
|
+
cv2.destroyAllWindows()
|
assembly/GeneralUtil.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from assembly.description.Decoration import func_description, class_description
|
|
5
|
+
|
|
6
|
+
'''
|
|
7
|
+
常用工具
|
|
8
|
+
|
|
9
|
+
输入:任意
|
|
10
|
+
输出:任意
|
|
11
|
+
'''
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@class_description(
|
|
15
|
+
title="常用工具",
|
|
16
|
+
description="包含通道转化、ROI、Mask等常用工具",
|
|
17
|
+
level=1
|
|
18
|
+
)
|
|
19
|
+
class GeneralUtil(object):
|
|
20
|
+
|
|
21
|
+
@func_description(
|
|
22
|
+
title="BGR转灰度",
|
|
23
|
+
description="BGR图像转换为灰度"
|
|
24
|
+
)
|
|
25
|
+
@staticmethod
|
|
26
|
+
def color_transform_gray(img):
|
|
27
|
+
"""
|
|
28
|
+
:name 转灰度图
|
|
29
|
+
:param img: 原图: img
|
|
30
|
+
:return img: 转化后图片: img
|
|
31
|
+
"""
|
|
32
|
+
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
33
|
+
|
|
34
|
+
@func_description(
|
|
35
|
+
title="BGR转HSV",
|
|
36
|
+
description="BGR图像转换为HSV"
|
|
37
|
+
)
|
|
38
|
+
@staticmethod
|
|
39
|
+
def color_transform_hsv(img):
|
|
40
|
+
"""
|
|
41
|
+
:name 转换颜色空间
|
|
42
|
+
:param img: 原图: img
|
|
43
|
+
:return img: 转化后图片: img
|
|
44
|
+
"""
|
|
45
|
+
return cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@func_description(
|
|
49
|
+
title="读图",
|
|
50
|
+
description="读取图像"
|
|
51
|
+
)
|
|
52
|
+
@staticmethod
|
|
53
|
+
def read_img(img_path):
|
|
54
|
+
"""
|
|
55
|
+
:name 读取图像
|
|
56
|
+
:param img_path: 图片名: library_menu_select
|
|
57
|
+
:return img: 原图: img
|
|
58
|
+
"""
|
|
59
|
+
return cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR)
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def write_img(img, img_path):
|
|
63
|
+
"""
|
|
64
|
+
:name 写入图像
|
|
65
|
+
:param img: 原图: img
|
|
66
|
+
:param img_path: 图片名: library_menu_select
|
|
67
|
+
:return None
|
|
68
|
+
"""
|
|
69
|
+
cv2.imencode('.jpg', img)[1].tofile(img_path)
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def find_contours(img, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE):
|
|
73
|
+
"""
|
|
74
|
+
:name 查找轮廓
|
|
75
|
+
:param img: 原图: img
|
|
76
|
+
:return contours: 轮廓列表: contours
|
|
77
|
+
"""
|
|
78
|
+
contours, _ = cv2.findContours(img, mode, method)
|
|
79
|
+
return contours
|
|
80
|
+
|
|
81
|
+
# 暴露方法
|
|
82
|
+
def color_transform_gray(img):
|
|
83
|
+
return GeneralUtil.color_transform_gray(img)
|
|
84
|
+
|
|
85
|
+
def color_transform_hsv(img):
|
|
86
|
+
return GeneralUtil.color_transform_hsv(img)
|
|
87
|
+
|
|
88
|
+
def read_img(img_path):
|
|
89
|
+
return GeneralUtil.read_img(img_path)
|
|
90
|
+
|
|
91
|
+
def write_img(img, img_path):
|
|
92
|
+
GeneralUtil.write_img(img, img_path)
|
|
93
|
+
|
|
94
|
+
def find_contours(img, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE):
|
|
95
|
+
return GeneralUtil.find_contours(img, mode, method)
|
|
96
|
+
|
|
97
|
+
def show_image(win_name, img, wx=None, wy=None):
|
|
98
|
+
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
|
|
99
|
+
if wx is not None and wy is not None:
|
|
100
|
+
cv2.resizeWindow(win_name, wx, wy)
|
|
101
|
+
cv2.imshow(win_name, img)
|
|
102
|
+
cv2.waitKey(0)
|
|
103
|
+
|