-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimage-operations.py
281 lines (232 loc) · 9.55 KB
/
image-operations.py
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import cv2
import imutils
import numpy as np
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
FONT = cv2.FONT_HERSHEY_PLAIN
CAPTION_SCALE = 2
CAPTION_THICKNESS = 2
class Image:
"""
Class for functions on image using OpenCV
1. Rotating an image
2. Smoothing an image
3. Counting objects
4. Converting an image to grayscale
5. Edge detection
6. Detecting and Drawing Contours
"""
def __init__(self, image):
width = image.shape[1]
self.image = imutils.resize(image, int(width*0.7))
self.height, self.width, self.depth = self.image.shape
self.position = (20, self.height-10)
def show(self, image=None, title=None):
"""function to display original or argument image
Args:
image (2D list): An image matrix. Defaults to None.
title (String): To be shown in title bar. Defaults to None.
"""
# show image on output window
if title:
title = title+": Press 0 to close window"
else:
title = "Press 0 to close window"
if image is None:
image = self.image.copy()
# add text on image
cv2.putText(image, 'Original Image',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
cv2.imshow(title, image)
cv2.waitKey(0) # to avoid image from disappearing
def rotate(self):
"""
Rotating the image
"""
original = self.image.copy()
# rotate images about axis as center, with scale 0.5
rotated_90 = imutils.rotate(
original.copy(), angle=90, scale=0.5) # 90 degrees
rotated_m90 = imutils.rotate(
original.copy(), angle=-90, scale=0.5) # -90 degrees
rotated_45 = imutils.rotate(
original.copy(), angle=45, scale=0.5) # 45 degrees
rotated_m45 = imutils.rotate(
original.copy(), angle=-45, scale=0.5) # -45 degrees
# add text on images
cv2.putText(rotated_90, 'Rotated 90 degrees',
self.position, FONT, CAPTION_SCALE,
WHITE, CAPTION_THICKNESS)
cv2.putText(rotated_m90, 'Rotated -90 degrees',
self.position, FONT, CAPTION_SCALE,
WHITE, CAPTION_THICKNESS)
cv2.putText(rotated_45, 'Rotated 45 degrees',
self.position, FONT, CAPTION_SCALE,
WHITE, CAPTION_THICKNESS)
cv2.putText(rotated_m45, 'Rotated -45 degrees',
self.position, FONT, CAPTION_SCALE,
WHITE, CAPTION_THICKNESS)
# merge the 4 images together in a 2x2 matrix
return np.concatenate(
(np.concatenate(
(imutils.resize(rotated_90, self.width//2),
imutils.resize(rotated_m90, self.width//2)), axis=1),
np.concatenate(
(imutils.resize(rotated_45, self.width//2),
imutils.resize(rotated_m45, self.width//2)), axis=1)), axis=0)
def smoothen(self, method=None):
"""
Smoothing the image
"""
filter_size = (15, 15) # size of the window for convolution
original = self.image.copy()
# using median blur to smoothen image
blur = cv2.blur(original.copy(), filter_size)
# using gaussian blur to smoothen image
filter_sd = 0 # standard deviaion for filter
gaussian = cv2.GaussianBlur(original.copy(), filter_size, filter_sd)
# using median blur to smoothen image
median = cv2.medianBlur(original.copy(), 15)
# add text on images
cv2.putText(original, 'Original Image',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
cv2.putText(blur, 'Averaging Blur',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
cv2.putText(gaussian, 'Gaussian Blur',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
cv2.putText(median, 'Median Blur',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
# merge the 4 images together in a 2x2 matrix
return np.concatenate(
(np.concatenate(
(imutils.resize(original, self.width//2),
imutils.resize(blur, self.width//2)), axis=1),
np.concatenate(
(imutils.resize(gaussian, self.width//2),
imutils.resize(median, self.width//2)), axis=1)), axis=0)
def detect_edges(self):
"""
Edge detection using Canny algorithm
"""
original = self.image.copy()
# canny edge detection on image with threshold 70, 205
edges = cv2.Canny(self.grayscale(), 70, 205)
cv2.putText(edges, 'Edges',
self.position, FONT, CAPTION_SCALE,
WHITE, CAPTION_THICKNESS)
return edges
def grayscale(self):
"""
Converting image to grayscale
"""
# convert (blue, green, red) image to grayscale
return cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
def fill_shapes(self, image):
"""
Use thresholding to completely fill the shapes
"""
# getting threshold values by trial and error
return cv2.threshold(image, 230, 255, cv2.THRESH_BINARY_INV)[1]
def draw_contours(self, image):
"""
Detect contours and then draw on original image
"""
# get contours from filled shapes image
# CV_RETR_EXTERNAL: retrieves only the extreme outer contours
# CV_CHAIN_APPROX_SIMPLE: compresses horizontal, vertical, and diagonal
# segments and leaves only their end points.
# For example, an up-right rectangular contour is encoded with 4 points
contours = cv2.findContours(image,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
objects = self.image.copy()
# draw border around each contour
for c in contours:
cv2.drawContours(objects, [c], -1, (0, 0, 0), 3)
# add text on image with count of objects
caption = 'Contours. Number of objects: ' + str(len(contours))
cv2.putText(objects, caption,
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
return objects
def show_contours(self, gray, filled_shapes, objects):
"""
function for showing entire detecting and highlighting procedure in
a single image
"""
original = self.image
# convert to BRG to enable showing all images together
gray = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
filled_shapes = cv2.cvtColor(filled_shapes, cv2.COLOR_GRAY2BGR)
# add text on images
cv2.putText(original, 'Original Image',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
cv2.putText(gray, 'Grayscale Image',
self.position, FONT, CAPTION_SCALE,
BLACK, CAPTION_THICKNESS)
cv2.putText(filled_shapes, 'Image after Thresholding',
self.position, FONT, CAPTION_SCALE,
WHITE, CAPTION_THICKNESS)
# merge the 4 images together in a 2x2 matrix
image = np.concatenate(
(np.concatenate(
(imutils.resize(original, self.width//2),
imutils.resize(gray, self.width//2)), axis=1),
np.concatenate(
(imutils.resize(filled_shapes, self.width//2),
imutils.resize(objects, self.width//2)), axis=1)), axis=0)
cv2.imshow("Contouring Procedure", image)
cv2.waitKey(0)
def main():
image = Image(cv2.imread("shapes.jpg"))
choice = 1
while (choice):
while(True):
print("\n***Choose from following operations***\n")
print("1.Show Image\n2.Rotation\n3.Smoothening")
print("4.Convert to Grayscale\n5.Detect Edges\n6.Thresholding")
print("7.Draw Contours/Count Objects\n0.Exit")
try:
choice = int(input("Enter choice: "))
break
except Exception:
print("Please enter valid choice!!\n")
if not choice:
break
if choice == 1:
image.show(title="Shapes")
continue
if choice == 2:
image.show(image.rotate(), "Rotated")
continue
if choice == 3:
image.show(image.smoothen(), "Smoother Image")
continue
if choice == 4:
image.show(image.grayscale(), "Grayscale Image")
continue
if choice == 5:
image.show(image.detect_edges(), "Edges detected")
continue
if choice == 6:
image.show(image.fill_shapes(
image.grayscale()), "Filled shapes")
continue
if choice == 7:
print("\nSteps for contour detection:")
print("1. Color to Grayscale conversion")
print("2. Thresholding to fill the shapes")
print("3. Detecting, Counting and Highlighting Objects (contours)")
gray_image = image.grayscale()
filled_shapes = image.fill_shapes(gray_image)
objects = image.draw_contours(filled_shapes)
# show steps 1-3 in a single image
image.show_contours(gray_image, filled_shapes, objects)
continue
if __name__ == "__main__":
main()