"""
This module administrates the contours
8 June 2018.
"""
import numpy as np
from collections import OrderedDict
import csv
def load_contours(name):
""" Open a cotours csv file and read it """
contours = OrderedDict()
# Load the contours
with open(name, "r") as f:
fr = csv.reader(f)
frl = list(fr)
for line in frl:
try:
values = [float(item) for item in line]
except ValueError:
key = line[0]
contours[key] = []
else:
contours[key].append(values)
return contours
def read_poly(file_name):
"""
Simple poly-file reader, that creates a python dictionary
with information about vertices, edges and holes.
It assumes that vertices have no attributes or boundary markers.
It assumes that edges have no boundary markers.
No regional attributes or area constraints are parsed.
Taken and adapted from: ...
"""
output = {'vertices': None, 'holes': None, 'segments': None}
# open file and store lines in a list
file = open(file_name, 'r')
lines = file.readlines()
file.close()
lines = [x.strip('\n').split() for x in lines]
# Store vertices
vertices= []
N_vertices, dimension, attr, bdry_markers = [int(x) for x in lines[0]]
# We assume attr = bdrt_markers = 0
for k in range(N_vertices):
label, x, y = [items for items in lines[k+1]]
vertices.append([float(x), float(y)])
output['vertices']=np.array(vertices)
# Store segments
segments = []
N_segments, bdry_markers = [int(x) for x in lines[N_vertices+1]]
for k in range(N_segments):
label, pointer_1, pointer_2 = [items for items in lines[N_vertices+k+2]]
segments.append([int(pointer_1)-1, int(pointer_2)-1])
output['segments'] = np.array(segments)
# Store holes
N_holes = int(lines[N_segments+N_vertices+2][0])
holes = []
for k in range(N_holes):
label, x, y = [items for items in lines[N_segments + N_vertices + 3 + k]]
holes.append([float(x), float(y)])
output['holes'] = np.array(holes)
return output
def move_element(dic, key, newpos):
""" Move the element with key 'key' of a dictionary 'dic' to the
position 'newpos' """
newdic = OrderedDict()
for i, (k, v) in enumerate(dic.items()):
if k != key:
newdic[k] = v
if i == newpos:
newdic[key] = dic[key]
return newdic
def fill_random(c, n):
""" Fill a contour given by the array c with a maximum of n random
points """
# Contour's enclosing box
left, right = c[:, 0].min(), c[:, 0].max()
bottom, top = c[:, 1].min(), c[:, 1].max()
# Dimensions
width = right - left
height = top - bottom
# Generate random points in the box
x = np.random.uniform(low=left, high=right, size=n)
y = np.random.uniform(low=bottom, high=top, size=n)
points = np.array([x, y]).T
# 'Planar' polygon object for the contour
polygon = pl.Polygon(c.tolist())
# Check if the points are inside the polygon
good_points = []
for p in points:
if polygon.contains_point(p):
good_points.append(p)
return polygon, np.array(good_points)
def remove_points(points):
""" Remove points from 'points' that fall inside fascicles """
survivors = []
# Iterate over input points
for p in points:
discard = False
# Iterate over fascicles
for k, fp in polygons.items():
if "Fascicle" in k:
# Discard it and end this sub-loop if the point is inside the
# fascicle's polygon
if fp.contains_point(p):
discard = True
break
# If it survived the loop, save it
if not discard:
survivors.append(p)
return np.array(survivors)
def reduce_points(c, n):
""" Reduce the number of points of contours 'c' by a factor of n in
order to reduce the computational burden. Only for contours with
more than n points """
for k, a in c.items():
if len(a) > n:
c[k] = a[::n]
return c
def c2pslg(c):
""" Convert the contours of a nerve stored in the dictionary 'c' to a
dictionary describing a Planar Straight Line Graph (PSLG) """
# newc = {'vertices': None, 'holes': None, 'segments': None}
newc = {}
# Total number of points
nt = np.array([len(a) for a in c.values()]).sum()
# Counter of processed points
npr = 0
# Generate the information
vertices = []
holes = []
segments = []
# Iterate over all the contours
for k, a in c.items():
n = len(a)
i = 0
# Append vertices and segments
for (x, y) in a:
vertices.append([x, y])
# Only if there's more than one point here, add segments
if n > 1:
if i < n-1:
segments.append([npr+i, npr+i+1])
i += 1
else:
segments.append([npr+i, npr])
# Update npr
npr += n
# Holes
if "Fascicle" in k:
# Add the centroid (hand-maded for speed-up)
a = np.array(a)
holes.append([a[:, 0].mean(), a[:, 1].mean()])
newc['vertices'] = np.array(vertices)
# Condition: for there to be a 'holes' entry, there must be holes
if len(holes) > 0:
newc['holes'] = np.array(holes)
newc['segments'] = np.array(segments)
return newc