--- a +++ b/10x/batch.py @@ -0,0 +1,309 @@ +import os +import sys +import pickle + +import numpy as np +import matplotlib + +import skimage as ski +from skimage import io, filter, color, exposure, morphology, feature, draw, measure, transform + +from scipy.spatial import distance +from scipy import ndimage + + + + + + + +# Things to measure for each image +in_count = [] +out_count = [] +in_size = [] +out_size = [] +in_area_density = [] +out_area_density = [] +in_point_density = [] +out_point_density = [] +var_point_density = [] +cov_point_density = [] +var_area_density = [] +cov_area_density = [] +fs_area = [] +pairwise = [] +name = [] +imageid = [] + + + + + + + +F = open("filelist%i.p" % int(sys.argv[1]), "r") +files = pickle.load(F) +F.close() + + + + + + + + +for f in files : + + print "Thread %s, image %s" % (sys.argv[1], f) + + ## ID + name.append(int(f.split("data/Sheep")[1].split("-")[0].split(".jpg")[0])) + imageid.append(int(f.split("data/Sheep")[1].split("-")[2].split(".jpg")[0])) + + + + + + + + # Process for nuclei + + A = io.imread(f) + print "Loaded image." + + binary = filter.threshold_adaptive(exposure.adjust_sigmoid(A[:, :, 0], cutoff=0.4, gain = 30), 301).astype(bool) + print "Binarised." + + clean = morphology.binary_closing(binary, morphology.disk(3)).astype(bool) + clean = morphology.remove_small_objects(clean, 200) + clean = morphology.remove_small_objects( (1-clean).astype(bool), 200) + print "Cleaned." + + + + + + + + + + # Find contour of inflammatory zone + + local_density = filter.gaussian_filter(clean, 61) + local_density -= local_density.min() + local_density /= local_density.max() + + ent = filter.gaussian_filter(filter.rank.entropy(local_density, morphology.disk(3)), 75) + ent -= ent.min() + ent /= ent.max() + + info = ent * (1 + local_density) + + bw = (info) > filter.threshold_otsu(info) + + C = measure.find_contours(bw, 0.5) + centroid = [] + vals = [] + + for c in C : + centroid.append(np.linalg.norm([c[:, 1].mean() - bw.shape[1] / 2, c[:, 0].mean() - bw.shape[0] / 2])) + vals.append(local_density.T[c.astype(int)].sum()) + + cent = C[np.argmin(centroid / np.array(vals))] + contour = matplotlib.path.Path(cent) + + print "Contour of inflammatory zone found." + + + + + + + + + # Segmentation + + dist = ndimage.distance_transform_edt(clean) + peaks = feature.peak_local_max(dist, indices=False, labels = clean) + markers = ndimage.label(peaks)[0] + labels = morphology.watershed(-dist, markers, mask=clean) + print "Image segmented." + + + + + + + + + + + + # Properties of each nucleus + nuclei = measure.regionprops(labels) + contour = matplotlib.path.Path(cent, closed=True) + + incount = 0 + outcount = 0 + insize = [] + outsize = [] + outer_nuclei = [] + + # Number of nuclei, and their sizes, inside and outside the focus + for n in nuclei : + if contour.contains_point(n.centroid) : + incount += 1 + insize.append((labels == n.label).sum()) + else : + outcount += 1 + outsize.append((labels == n.label).sum()) + outer_nuclei.append(n) + + in_count.append(incount) + out_count.append(outcount) + in_size.append(np.mean(insize)) + out_size.append(np.mean(outsize)) + print "Nuclei identified." + + + + + + + + + + + + + # Using the shoelace algorithm, compute the area of the focus + x = contour.vertices[:, 0] + y = contour.vertices[:, 1] + x = np.append(x, contour.vertices[0, 0]) + y = np.append(y, contour.vertices[0, 1]) + fsarea = np.abs(np.sum(x[:-1] * y[1:] - x[1:] * y[:-1])) / (2. * 3456 * 5184) + fs_area.append(fsarea) + + + + + + + + + + + + + + # Area densities inside and outside the focus + in_area_density.append(incount * np.mean(insize) / fsarea) + out_area_density.append(outcount * np.mean(outsize) / (1. - fsarea)) + + # Point densities inside and outside the focus + in_point_density.append(incount / fsarea) + out_point_density.append(outcount / (1. - fsarea)) + print "Densities calculated." + + + + + + + + + + + + + + # Variance and CoV of outside the focus + mask = np.zeros_like(clean) + for c in cent : + mask[int(np.round(c[0])), int(np.round(c[1]))] = 1 + mask = ndimage.binary_fill_holes(ndimage.maximum_filter(mask, 35)) + + areadensity = filter.gaussian_filter(clean, 51) + var_area_density.append(np.var(areadensity[mask == 0])) + cov_area_density.append(np.std(areadensity[mask == 0] / np.mean(areadensity[mask == 0]))) + + pointdensity = np.zeros_like(clean) + for n in nuclei : + pointdensity[int(np.round(n.centroid[0])), int(np.round(n.centroid[1]))] = 1 + pointdensity = filter.gaussian_filter(pointdensity, 51) + + var_point_density.append(np.var(pointdensity[mask == 0])) + cov_point_density.append(np.std(pointdensity[mask == 0] / np.mean(pointdensity[mask == 0]))) + print "Variances calculated. " + + + + + + + + + + + # Pairwise distances between nuclei outside the focal area + distances = distance.squareform(distance.pdist([n.centroid for n in outer_nuclei])) + + for i in range(len(distances)) : + distances[i, i] = np.inf + + pairwise.append(np.min(distances, axis=0).mean()) + print "Pairwise distances calculated." + + + + + + + + + + + + + + + + +in_count = [] +out_count = [] +in_size = [] +out_size = [] +in_area_density = [] +out_area_density = [] +in_point_density = [] +out_point_density = [] +var_point_density = [] +cov_point_density = [] +var_area_density = [] +cov_area_density = [] +fs_area = [] +pairwise = [] + +results = {} +results["in_count"] = in_count +results["out_count"] = out_count +results["in_size"] = in_size +results["out_size"] = out_size +results["in_area_density"] = in_area_density +results["out_area_density"] = out_area_density +results["in_point_density"] = in_point_density +results["out_point_density"] = out_point_density +results["name"] = name +results["ID"] = imageid +results["var_point_density"] = var_point_density +results["cov_point_density"] = cov_point_density +results["var_area_density"] = var_area_density +results["cov_area_density"] = cov_area_density +results["fs_area"] = fs_area +results["pairwise"] = pairwise + +F = open("results/thread_%s" % sys.argv[1], "w") +pickle.dump(results, F) +F.close() +print "Thread %s finished." % sys.argv[1] +