Spaces:
Sleeping
Sleeping
Commit
•
82813c6
1
Parent(s):
ad50614
Upload morphsnakes .py
Browse files- morphsnakes .py +156 -0
morphsnakes .py
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
====================
|
3 |
+
Morphological Snakes
|
4 |
+
====================
|
5 |
+
|
6 |
+
*Morphological Snakes* [1]_ are a family of methods for image segmentation.
|
7 |
+
Their behavior is similar to that of active contours (for example, *Geodesic
|
8 |
+
Active Contours* [2]_ or *Active Contours without Edges* [3]_). However,
|
9 |
+
*Morphological Snakes* use morphological operators (such as dilation or
|
10 |
+
erosion) over a binary array instead of solving PDEs over a floating point
|
11 |
+
array, which is the standard approach for active contours. This makes
|
12 |
+
*Morphological Snakes* faster and numerically more stable than their
|
13 |
+
traditional counterpart.
|
14 |
+
|
15 |
+
There are two *Morphological Snakes* methods available in this implementation:
|
16 |
+
*Morphological Geodesic Active Contours* (**MorphGAC**, implemented in the
|
17 |
+
function ``morphological_geodesic_active_contour``) and *Morphological Active
|
18 |
+
Contours without Edges* (**MorphACWE**, implemented in the function
|
19 |
+
``morphological_chan_vese``).
|
20 |
+
|
21 |
+
**MorphGAC** is suitable for images with visible contours, even when these
|
22 |
+
contours might be noisy, cluttered, or partially unclear. It requires, however,
|
23 |
+
that the image is preprocessed to highlight the contours. This can be done
|
24 |
+
using the function ``inverse_gaussian_gradient``, although the user might want
|
25 |
+
to define their own version. The quality of the **MorphGAC** segmentation
|
26 |
+
depends greatly on this preprocessing step.
|
27 |
+
|
28 |
+
On the contrary, **MorphACWE** works well when the pixel values of the inside
|
29 |
+
and the outside regions of the object to segment have different averages.
|
30 |
+
Unlike **MorphGAC**, **MorphACWE** does not require that the contours of the
|
31 |
+
object are well defined, and it works over the original image without any
|
32 |
+
preceding processing. This makes **MorphACWE** easier to use and tune than
|
33 |
+
**MorphGAC**.
|
34 |
+
|
35 |
+
References
|
36 |
+
----------
|
37 |
+
|
38 |
+
.. [1] A Morphological Approach to Curvature-based Evolution of Curves and
|
39 |
+
Surfaces, Pablo Márquez-Neila, Luis Baumela and Luis Álvarez. In IEEE
|
40 |
+
Transactions on Pattern Analysis and Machine Intelligence (PAMI),
|
41 |
+
2014, :DOI:`10.1109/TPAMI.2013.106`
|
42 |
+
.. [2] Geodesic Active Contours, Vicent Caselles, Ron Kimmel and Guillermo
|
43 |
+
Sapiro. In International Journal of Computer Vision (IJCV), 1997,
|
44 |
+
:DOI:`10.1023/A:1007979827043`
|
45 |
+
.. [3] Active Contours without Edges, Tony Chan and Luminita Vese. In IEEE
|
46 |
+
Transactions on Image Processing, 2001, :DOI:`10.1109/83.902291`
|
47 |
+
|
48 |
+
"""
|
49 |
+
import os
|
50 |
+
|
51 |
+
import numpy as np
|
52 |
+
import matplotlib.pyplot as plt
|
53 |
+
from skimage import data, img_as_float
|
54 |
+
from skimage.segmentation import (morphological_chan_vese,
|
55 |
+
morphological_geodesic_active_contour,
|
56 |
+
inverse_gaussian_gradient,
|
57 |
+
checkerboard_level_set)
|
58 |
+
from cv2 import imread
|
59 |
+
from cv2 import imshow
|
60 |
+
from cv2 import waitKey
|
61 |
+
import cv2
|
62 |
+
def store_evolution_in(lst):
|
63 |
+
"""Returns a callback function to store the evolution of the level sets in
|
64 |
+
the given list.
|
65 |
+
"""
|
66 |
+
|
67 |
+
def _store(x):
|
68 |
+
lst.append(np.copy(x))
|
69 |
+
|
70 |
+
return _store
|
71 |
+
|
72 |
+
images = sorted(os.listdir('./mini/'))
|
73 |
+
# print(images)
|
74 |
+
for k, img in enumerate(images):
|
75 |
+
# Morphological ACWE
|
76 |
+
image1 = imread(f'./mini/{img}', 0)
|
77 |
+
image = image1.copy()
|
78 |
+
# Initial level set
|
79 |
+
init_ls = checkerboard_level_set(image.shape, 6)
|
80 |
+
# List with intermediate results for plotting the evolution
|
81 |
+
evolution = []
|
82 |
+
callback = store_evolution_in(evolution)
|
83 |
+
ls = morphological_chan_vese(image, num_iter=35, init_level_set=init_ls,
|
84 |
+
smoothing=3, iter_callback=callback)
|
85 |
+
|
86 |
+
fig, axes = plt.subplots(2, 2, figsize=(8, 8))
|
87 |
+
ax = axes.flatten()
|
88 |
+
|
89 |
+
ax[0].imshow(image, cmap="gray")
|
90 |
+
ax[0].set_axis_off()
|
91 |
+
ax[0].contour(ls, [0.5], colors='r')
|
92 |
+
ax[0].set_title("Morphological ACWE segmentation", fontsize=12)
|
93 |
+
withe = np.ones_like(image, dtype='uint8') * 255
|
94 |
+
|
95 |
+
ret1,thresh1 = cv2.threshold(withe,70,255,0)
|
96 |
+
ret,thresh = cv2.threshold(image1,70,255,0)
|
97 |
+
|
98 |
+
new = np.bitwise_and(cv2.bitwise_not(ls),thresh)[140:420,70:420]
|
99 |
+
|
100 |
+
for i in range(new.shape[0]):
|
101 |
+
for j in range(new.shape[1]):
|
102 |
+
if new[i][j] > 0:
|
103 |
+
new[i][j] -= 130
|
104 |
+
|
105 |
+
|
106 |
+
cv2.imwrite(f'./output/{img}', new)
|
107 |
+
|
108 |
+
|
109 |
+
# ax[1].imshow(ls, cmap="gray")
|
110 |
+
# ax[1].set_axis_off()
|
111 |
+
# contour = ax[1].contour(evolution[2], [0.5], colors='g')
|
112 |
+
# contour.collections[0].set_label("Iteration 2")
|
113 |
+
# contour = ax[1].contour(evolution[7], [0.5], colors='y')
|
114 |
+
# contour.collections[0].set_label("Iteration 7")
|
115 |
+
# contour = ax[1].contour(evolution[-1], [0.5], colors='r')
|
116 |
+
# contour.collections[0].set_label("Iteration 35")
|
117 |
+
# ax[1].legend(loc="upper right")
|
118 |
+
# title = "Morphological ACWE evolution"
|
119 |
+
# ax[1].set_title(title, fontsize=12)
|
120 |
+
|
121 |
+
|
122 |
+
# Morphological GAC
|
123 |
+
# image = img_as_float(data.coins())
|
124 |
+
#gimage = inverse_gaussian_gradient(image)
|
125 |
+
|
126 |
+
# Initial level set
|
127 |
+
#init_ls = np.zeros(image.shape, dtype=np.int8)
|
128 |
+
#init_ls[10:-10, 10:-10] = 1
|
129 |
+
# List with intermediate results for plotting the evolution
|
130 |
+
#evolution = []
|
131 |
+
#callback = store_evolution_in(evolution)
|
132 |
+
#ls = morphological_geodesic_active_contour(gimage, num_iter=230,
|
133 |
+
# init_level_set=init_ls,
|
134 |
+
# smoothing=1, balloon=-1,
|
135 |
+
# threshold=0.69,
|
136 |
+
# iter_callback=callback)
|
137 |
+
|
138 |
+
# ax[2].imshow(new, cmap="gray")
|
139 |
+
# ax[2].set_axis_off()
|
140 |
+
#ax[2].contour(ls, [0.5], colors='r')
|
141 |
+
#ax[2].set_title("Morphological GAC segmentation", fontsize=12)
|
142 |
+
|
143 |
+
#ax[3].imshow(ls, cmap="gray")
|
144 |
+
#ax[3].set_axis_off()
|
145 |
+
#contour = ax[3].contour(evolution[0], [0.5], colors='g')
|
146 |
+
#contour.collections[0].set_label("Iteration 0")
|
147 |
+
#contour = ax[3].contour(evolution[100], [0.5], colors='y')
|
148 |
+
#contour.collections[0].set_label("Iteration 100")
|
149 |
+
#contour = ax[3].contour(evolution[-1], [0.5], colors='r')
|
150 |
+
#contour.collections[0].set_label("Iteration 230")
|
151 |
+
#ax[3].legend(loc="upper right")
|
152 |
+
#title = "Morphological GAC evolution"
|
153 |
+
#ax[3].set_title(title, fontsize=12)
|
154 |
+
|
155 |
+
# fig.tight_layout()
|
156 |
+
# plt.show()
|