Spaces:
Sleeping
Sleeping
""" | |
==================== | |
Morphological Snakes | |
==================== | |
*Morphological Snakes* [1]_ are a family of methods for image segmentation. | |
Their behavior is similar to that of active contours (for example, *Geodesic | |
Active Contours* [2]_ or *Active Contours without Edges* [3]_). However, | |
*Morphological Snakes* use morphological operators (such as dilation or | |
erosion) over a binary array instead of solving PDEs over a floating point | |
array, which is the standard approach for active contours. This makes | |
*Morphological Snakes* faster and numerically more stable than their | |
traditional counterpart. | |
There are two *Morphological Snakes* methods available in this implementation: | |
*Morphological Geodesic Active Contours* (**MorphGAC**, implemented in the | |
function ``morphological_geodesic_active_contour``) and *Morphological Active | |
Contours without Edges* (**MorphACWE**, implemented in the function | |
``morphological_chan_vese``). | |
**MorphGAC** is suitable for images with visible contours, even when these | |
contours might be noisy, cluttered, or partially unclear. It requires, however, | |
that the image is preprocessed to highlight the contours. This can be done | |
using the function ``inverse_gaussian_gradient``, although the user might want | |
to define their own version. The quality of the **MorphGAC** segmentation | |
depends greatly on this preprocessing step. | |
On the contrary, **MorphACWE** works well when the pixel values of the inside | |
and the outside regions of the object to segment have different averages. | |
Unlike **MorphGAC**, **MorphACWE** does not require that the contours of the | |
object are well defined, and it works over the original image without any | |
preceding processing. This makes **MorphACWE** easier to use and tune than | |
**MorphGAC**. | |
References | |
---------- | |
.. [1] A Morphological Approach to Curvature-based Evolution of Curves and | |
Surfaces, Pablo Márquez-Neila, Luis Baumela and Luis Álvarez. In IEEE | |
Transactions on Pattern Analysis and Machine Intelligence (PAMI), | |
2014, :DOI:`10.1109/TPAMI.2013.106` | |
.. [2] Geodesic Active Contours, Vicent Caselles, Ron Kimmel and Guillermo | |
Sapiro. In International Journal of Computer Vision (IJCV), 1997, | |
:DOI:`10.1023/A:1007979827043` | |
.. [3] Active Contours without Edges, Tony Chan and Luminita Vese. In IEEE | |
Transactions on Image Processing, 2001, :DOI:`10.1109/83.902291` | |
""" | |
import os | |
from PIL import Image | |
import numpy as np | |
import matplotlib.pyplot as plt | |
from skimage import data, img_as_float | |
from skimage.segmentation import (morphological_chan_vese, | |
morphological_geodesic_active_contour, | |
inverse_gaussian_gradient, | |
checkerboard_level_set, clear_border) | |
from skimage.morphology import binary_closing, binary_opening, binary_erosion,disk | |
from scipy import ndimage as ndi | |
from skimage.filters import roberts, sobel | |
from cv2 import imread | |
from cv2 import imshow | |
from cv2 import waitKey | |
import cv2 | |
def store_evolution_in(lst): | |
"""Returns a callback function to store the evolution of the level sets in | |
the given list. | |
""" | |
def _store(x): | |
lst.append(np.copy(x)) | |
return _store | |
images = sorted(os.listdir('./1.3.6.1.4.1.14519.5.2.1.6279.6001.861997885565255340442123234170/')) | |
# print(images) | |
for k, img in enumerate(images): | |
# Morphological ACWE | |
image1 = imread(f'./1.3.6.1.4.1.14519.5.2.1.6279.6001.861997885565255340442123234170/{img}', 0) | |
image = image1.copy() | |
clenimage = image1.copy() | |
# Initial level set | |
init_ls = checkerboard_level_set(image.shape, 6) | |
# List with intermediate results for plotting the evolution | |
evolution = [] | |
callback = store_evolution_in(evolution) | |
ls = morphological_chan_vese(image, num_iter=35, init_level_set=init_ls, | |
smoothing=3, iter_callback=callback) | |
fig, axes = plt.subplots(2, 2, figsize=(8, 8)) | |
ax = axes.flatten() | |
ax[0].imshow(image, cmap="gray") | |
ax[0].set_axis_off() | |
ax[0].contour(ls, [0.5], colors='r') | |
ax[0].set_title("Morphological ACWE segmentation", fontsize=12) | |
ret,thresh = cv2.threshold(image1,70,255,0) | |
image1 = clear_border(cv2.bitwise_not(thresh)) | |
selem = disk(2) | |
image1 = binary_erosion(image1,selem) | |
selem = disk(10) | |
image1 = binary_closing(image1,selem) | |
edges = roberts(image1) | |
image1 = ndi.binary_fill_holes(edges) | |
percentage_white = np.sum(image1== 1) | |
# print(percentage_white) | |
if (percentage_white / (image1.shape[0]*image1.shape[1])) >= 0.1: | |
ax[1].imshow(image1, cmap=plt.cm.bone) | |
ax[1].set_axis_off() | |
# contour = ax[1].contour(evolution[2], [0.5], colors='g') | |
# contour.collections[0].set_label("Iteration 2") | |
# contour = ax[1].contour(evolution[7], [0.5], colors='y') | |
# contour.collections[0].set_label("Iteration 7") | |
# contour = ax[1].contour(evolution[-1], [0.5], colors='r') | |
# contour.collections[0].set_label("Iteration 35") | |
# ax[1].legend(loc="upper right") | |
# title = "Morphological ACWE evolution" | |
# ax[1].set_title(title, fontsize=12) | |
# Morphological GAC | |
# image = img_as_float(data.coins()) | |
#gimage = inverse_gaussian_gradient(image) | |
# Initial level set | |
#init_ls = np.zeros(image.shape, dtype=np.int8) | |
#init_ls[10:-10, 10:-10] = 1 | |
# List with intermediate results for plotting the evolution | |
#evolution = [] | |
#callback = store_evolution_in(evolution) | |
#ls = morphological_geodesic_active_contour(gimage, num_iter=230, | |
# init_level_set=init_ls, | |
# smoothing=1, balloon=-1, | |
# threshold=0.69, | |
# iter_callback=callback) | |
ZERO_VALUE = -2000 | |
get_high_vals = (image1 == 0) | |
clenimage[get_high_vals] = ZERO_VALUE | |
ax[2].imshow(clenimage, cmap="gray") | |
ax[2].set_axis_off() | |
#ax[2].contour(ls, [0.5], colors='r') | |
#ax[2].set_title("Morphological GAC segmentation", fontsize=12) | |
# print(type(image)) | |
# ret3,th3 = cv2.threshold(image,200,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) | |
ret1,th1 = cv2.threshold(clenimage,150,255,cv2.THRESH_BINARY) #T | |
selem = disk(2) #T | |
th1 = binary_erosion(th1,selem) | |
im = Image.fromarray(th1) | |
# print(type(th1)) | |
img = img.split('.')[0] | |
im.save(f'{img}.jpg') | |
ax[3].imshow(th1, cmap="gray") | |
ax[3].set_axis_off() | |
#contour = ax[3].contour(evolution[0], [0.5], colors='g') | |
#contour.collections[0].set_label("Iteration 0") | |
#contour = ax[3].contour(evolution[100], [0.5], colors='y') | |
#contour.collections[0].set_label("Iteration 100") | |
#contour = ax[3].contour(evolution[-1], [0.5], colors='r') | |
#contour.collections[0].set_label("Iteration 230") | |
#ax[3].legend(loc="upper right") | |
#title = "Morphological GAC evolution" | |
#ax[3].set_title(title, fontsize=12) | |
# fig.tight_layout() | |
# plt.show() | |