def process_single_image(filename, image_format, scale_metadata_path,
threshold_radius, smooth_radius,
brightness_offset, crop_radius, smooth_method):
image = imageio.imread(filename, format=image_format)
scale = _get_scale(image, scale_metadata_path)
if crop_radius > 0:
c = crop_radius
image = image[c:-c, c:-c]
pixel_threshold_radius = int(np.ceil(threshold_radius / scale))
pixel_smoothing_radius = smooth_radius * pixel_threshold_radius
thresholded = pre.threshold(image, sigma=pixel_smoothing_radius,
radius=pixel_threshold_radius,
offset=brightness_offset,
smooth_method=smooth_method)
quality = shape_index(image, sigma=pixel_smoothing_radius,
mode='reflect')
skeleton = morphology.skeletonize(thresholded) * quality
framedata = csr.summarise(skeleton, spacing=scale)
framedata['squiggle'] = np.log2(framedata['branch-distance'] /
framedata['euclidean-distance'])
framedata['scale'] = scale
framedata.rename(columns={'mean pixel value': 'mean shape index'},
inplace=True)
framedata['filename'] = filename
return image, thresholded, skeleton, framedata
python类skeletonize()的实例源码
def _floodfill(self, img):
back = Back._scharr(img)
# Binary thresholding.
back = back > 0.05
# Thin all edges to be 1-pixel wide.
back = skm.skeletonize(back)
# Edges are not detected on the borders, make artificial ones.
back[0, :] = back[-1, :] = True
back[:, 0] = back[:, -1] = True
# Label adjacent pixels of the same color.
labels = label(back, background=-1, connectivity=1)
# Count as background all pixels labeled like one of the corners.
corners = [(1, 1), (-2, 1), (1, -2), (-2, -2)]
for l in (labels[i, j] for i, j in corners):
back[labels == l] = True
# Remove remaining inner edges.
return skm.opening(back)
def boundaries(regions, thin=False):
"""
Extracts region boundaries from a labelled image.
Args:
regions: numpy (H, W) array
Regions extracted from `image`
thin: bool
Whether to skeletonize or not the boundaries.
Return:
result: numpy (H, W) array
Region boundaries as a binary mask.
"""
# +1 to ignore superpixel 0 treated as background
result = find_boundaries(regions+1)
if thin:
result = skeletonize(result)
return result
def mark_boundaries(image, regions, color=(0,0,0), thin=False):
"""
Mark region boundaries in a given image.
Args:
image: numpy (H, W) array
RGB image
regions: numpy (H, W) array
Regions extracted from `image`
color: RGB tuple from 0 to 1
Color to mark boundaries. Default black.
thin: bool
Whether to skeletonize or not the boundaries.
Return:
result: numpy (H, W) array
Image with region boundaries overlaid on it.
"""
bounds = boundaries(regions, thin=thin)
result = image.copy()
result[bounds] = color
return result
def test_skeleton(test_thresholded):
skeleton = morphology.skeletonize(test_thresholded)
return skeleton
def place_routers_on_skeleton(d, cmethod):
wireless = np.where(d["graph"] == Cell.Wireless, 1, 0)
# perform skeletonization
skeleton = skeletonize(wireless)
med_axis = medial_axis(wireless)
skel = skeleton
# skel = med_axis
# get all skeleton positions
pos = []
for i in range(skel.shape[0]):
for j in range(skel.shape[1]):
if skel[i][j]:
pos.append((i, j))
budget = d['budget']
shuffle(pos)
max_num_routers = min([int(d['budget'] / d['price_router']), len(pos)])
print("Num of routers constrained by:")
print(" budget: %d" % int(int(d['budget'] / d['price_router'])))
print(" skeleton: %d" % len(pos))
for i in tqdm(range(max_num_routers), desc="Placing Routers"):
new_router = pos[i]
a, b = new_router
# check if remaining budget is enough
d["graph"][a][b] = Cell.Router
d, ret, cost = _add_cabel(d, new_router, budget)
budget -= cost
if not ret:
break
return d
def place_routers_on_skeleton_iterative(d, cmethod):
budget = d['budget']
R = d['radius']
max_num_routers = int(d['budget'] / d['price_router'])
coverage = np.where(d["graph"] == Cell.Wireless, 1, 0).astype(np.bool)
pbar = tqdm(range(max_num_routers), desc="Placing Routers")
while budget > 0:
# perform skeletonization
# skeleton = skeletonize(coverage)
skeleton = medial_axis(coverage)
# get all skeleton positions
pos = np.argwhere(skeleton > 0).tolist()
# escape if no positions left
if not len(pos):
break
# get a random position
shuffle(pos)
a, b = pos[0]
# place router
d["graph"][a][b] = Cell.Router
d, ret, cost = _add_cabel(d, (a, b), budget)
if not ret:
print("No budget available!")
break
budget -= cost
# refresh wireless map by removing new coverage
m = wireless_access(a, b, R, d['graph']).astype(np.bool)
coverage[(a - R):(a + R + 1), (b - R):(b + R + 1)] &= ~m
pbar.update()
pbar.close()
return d
def run(self, ips, snap, img, para = None):
img[:] = skeletonize(snap>0)
img *= 255
def polylinesFromBinImage(img, minimum_cluster_size=6,
remove_small_obj_size=3,
reconnect_size=3,
max_n_contours=None, max_len_contour=None,
copy=True):
'''
return a list of arrays of un-branching contours
img -> (boolean) array
optional:
---------
minimum_cluster_size -> minimum number of pixels connected together to build a contour
##search_kernel_size -> TODO
##min_search_kernel_moment -> TODO
numeric:
-------------
max_n_contours -> maximum number of possible contours in img
max_len_contour -> maximum contour length
'''
assert minimum_cluster_size > 1
assert reconnect_size % 2, 'ksize needs to be odd'
# assert search_kernel_size == 0 or search_kernel_size > 2 and search_kernel_size%2, 'kernel size needs to be odd'
# assume array size parameters, is not given:
if max_n_contours is None:
max_n_contours = max(img.shape)
if max_len_contour is None:
max_len_contour = sum(img.shape[:2])
# array containing coord. of all contours:
contours = np.zeros(shape=(max_n_contours, max_len_contour, 2),
dtype=np.uint16) # if not search_kernel_size else np.float32)
if img.dtype != np.bool:
img = img.astype(bool)
elif copy:
img = img.copy()
if remove_small_obj_size:
remove_small_objects(img, remove_small_obj_size,
connectivity=2, in_place=True)
if reconnect_size:
# remove gaps
maximum_filter(img, reconnect_size, output=img)
# reduce contour width to 1
img = skeletonize(img)
n_contours = _populateContoursArray(img, contours, minimum_cluster_size)
contours = contours[:n_contours]
l = []
for c in contours:
ind = np.zeros(shape=len(c), dtype=bool)
_getValidInd(c, ind)
# remove all empty spaces:
l.append(c[ind])
return l
def skeleton_from_image_discrete(image, sigma = 1, absolute_threshold = None, threshold_factor = 0.95, with_head_tail = False, verbose = False):
"""Detect skeleton points of wormshape in image
Arguments:
image (array): the image to detect venterline of worm from
sigma (float or None): width of Gaussian smoothing on image, if None use raw image
absolute_threshold (float or None): if set use this as the threshold, if None the threshold is set via Otsu
threshold_level (float): in case the threshold is determined by Otsu multiply by this factor
verbose (bool): plot results
Returns:
array (nx2): unsorted skeleton points
"""
### smooth image
if sigma is not None:
imgs = filters.gaussian_filter(np.asarray(image, float), sigma);
else:
imgs = image;
### get worm foreground
if absolute_threshold is not None:
level = absolute_threshold;
else:
level = threshold_factor * threshold_otsu(imgs);
imgth = imgs < level;
### skeletonize
skel = skeletonize(imgth);
y,x = np.where(skel);
if verbose:
plt.imshow(imgth, interpolation = 'none');
plt.scatter(x,y,c = 'k', s = 40);
if with_head_tail:
# find end points:
adj = skeleton_to_adjacency(skel);
nhs = np.array([len(v) for v in adj.values()]);
ht = np.where(nhs == 1)[0];
if verbose:
xy = np.vstack([x,y]).T;
if ht.shape[0] > 0:
xyht = xy[ht];
plt.scatter(xyht[:,0], xyht[:,1], s = 60, c = 'r');
return np.vstack([x,y]).T, ht;
else:
return np.vstack([x,y]).T;
def skeletonize_image(image, method=None, dilation=None, binarization=None,
invert=False):
"""Extract a 1 pixel wide representation of image by morphologically
thinning the white contiguous blobs (connected components).
If image is not black and white, a binarization process is applied
according to binarization, which can be 'sauvola', 'isodata', 'otsu',
'li' (default, ref: binarize()).
A process of dilation can also be applied by specifying the number
of pixels in dilate prior to extracting the skeleton.
The method for skeletonization can be 'medial', '3d', 'regular', or a
'combined' version of the three. Defaults to 'regular'.
A 'thin' operator is also available. For reference,
see http://scikit-image.org/docs/dev/auto_examples/edges/plot_skeleton.html
"""
# if image is all one single color, return it
if len(np.unique(image)) == 1:
return image
# scikit-image needs only 0's and 1's
mono_image = binarize_image(image, method=binarization) / 255
if invert:
mono_image = invert_image(mono_image)
if dilation:
dilation = (2 * dilation) + 1
dilation_kernel = np.ones((dilation, dilation), np.uint8)
mono_image = cv2.morphologyEx(mono_image, cv2.MORPH_DILATE,
dilation_kernel)
with warnings.catch_warnings(record=True):
warnings.filterwarnings('ignore', category=UserWarning)
if method == '3d':
skeleton = morphology.skeletonize_3d(mono_image)
elif method == 'medial':
skeleton = morphology.medial_axis(mono_image,
return_distance=False)
elif method == 'thin':
skeleton = morphology.thin(mono_image)
elif method == 'combined':
skeleton = (morphology.skeletonize_3d(mono_image)
| morphology.medial_axis(mono_image,
return_distance=False)
| morphology.skeletonize(mono_image))
else:
skeleton = morphology.skeletonize(mono_image)
return convert(skeleton)