From 85a66bb2b1e87821836c6daad3cb9b499e8c6461 Mon Sep 17 00:00:00 2001
From: Swainlab <peter.swain@ed.ac.uk>
Date: Fri, 11 Aug 2023 20:26:59 +0100
Subject: [PATCH] added moment_of_inertia to cell functions

---
 src/aliby/pipeline.py                         | 26 +++++++-------
 src/extraction/core/functions/cell.py         | 36 +++++++++++++++++++
 .../core/functions/custom/localisation.py     |  5 +--
 src/extraction/core/functions/loaders.py      |  4 +--
 4 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/src/aliby/pipeline.py b/src/aliby/pipeline.py
index c31d0fc2..e5d5bc66 100644
--- a/src/aliby/pipeline.py
+++ b/src/aliby/pipeline.py
@@ -126,7 +126,7 @@ class PipelineParameters(ParametersABC):
                 use_explog=True,
             )
         }
-        # update default values using inputs
+        # update default values for general using inputs
         for k, v in general.items():
             if k not in defaults["general"]:
                 defaults["general"][k] = v
@@ -306,7 +306,7 @@ class Pipeline(ProcessABC):
         # extract from configuration
         expt_id = config["general"]["id"]
         distributed = config["general"]["distributed"]
-        pos_filter = config["general"]["filter"]
+        position_filter = config["general"]["filter"]
         root_dir = Path(config["general"]["directory"])
         self.server_info = {
             k: config["general"].get(k)
@@ -329,15 +329,15 @@ class Pipeline(ProcessABC):
         config["general"]["directory"] = directory
         self.setLogger(directory)
         # pick particular positions if desired
-        if pos_filter is not None:
-            if isinstance(pos_filter, list):
+        if position_filter is not None:
+            if isinstance(position_filter, list):
                 position_ids = {
                     k: v
-                    for filt in pos_filter
+                    for filt in position_filter
                     for k, v in self.apply_filter(position_ids, filt).items()
                 }
             else:
-                position_ids = self.apply_filter(position_ids, pos_filter)
+                position_ids = self.apply_filter(position_ids, position_filter)
         if not len(position_ids):
             raise Exception("No images to segment.")
         # create and run pipelines
@@ -356,26 +356,26 @@ class Pipeline(ProcessABC):
             ]
         return results
 
-    def apply_filter(self, position_ids: dict, pos_filter: int or str):
+    def apply_filter(self, position_ids: dict, position_filter: int or str):
         """
         Select positions.
 
-        Either pick a particular one or use a regular expression to parse
-        their file names.
+        Either pick a particular position or use a regular expression
+        to parse their file names.
         """
-        if isinstance(pos_filter, str):
+        if isinstance(position_filter, str):
             # pick positions using a regular expression
             position_ids = {
                 k: v
                 for k, v in position_ids.items()
-                if re.search(pos_filter, k)
+                if re.search(position_filter, k)
             }
-        elif isinstance(pos_filter, int):
+        elif isinstance(position_filter, int):
             # pick a particular position
             position_ids = {
                 k: v
                 for i, (k, v) in enumerate(position_ids.items())
-                if i == pos_filter
+                if i == position_filter
             }
         return position_ids
 
diff --git a/src/extraction/core/functions/cell.py b/src/extraction/core/functions/cell.py
index 0e7b9fe8..4d97f23a 100644
--- a/src/extraction/core/functions/cell.py
+++ b/src/extraction/core/functions/cell.py
@@ -193,3 +193,39 @@ def min_maj_approximation(cell_mask) -> t.Tuple[int]:
     # + distance from the center of cone top to edge of cone top
     maj_ax = np.round(np.max(dn) + np.sum(cone_top) / 2)
     return min_ax, maj_ax
+
+
+def moment_of_inertia(cell_mask, trap_image):
+    """
+    Find moment of inertia - a measure of homogeneity.
+
+    From iopscience.iop.org/article/10.1088/1742-6596/1962/1/012028
+    which cites ieeexplore.ieee.org/document/1057692.
+    """
+    # set pixels not in cell to zero
+    trap_image[~cell_mask] = 0
+    x = trap_image
+    if np.any(x):
+        # x-axis : column=x-axis
+        columnvec = np.arange(1, x.shape[1] + 1, 1)[:, None].T
+        # y-axis : row=y-axis
+        rowvec = np.arange(1, x.shape[0] + 1, 1)[:, None]
+        # find raw moments
+        M00 = np.sum(x)
+        M10 = np.sum(np.multiply(x, columnvec))
+        M01 = np.sum(np.multiply(x, rowvec))
+        # find centroid
+        Xm = M10 / M00
+        Ym = M01 / M00
+        # find central moments
+        Mu00 = M00
+        Mu20 = np.sum(np.multiply(x, (columnvec - Xm) ** 2))
+        Mu02 = np.sum(np.multiply(x, (rowvec - Ym) ** 2))
+        # find invariants
+        Eta20 = Mu20 / Mu00 ** (1 + (2 + 0) / 2)
+        Eta02 = Mu02 / Mu00 ** (1 + (0 + 2) / 2)
+        # find moments of inertia
+        moi = Eta20 + Eta02
+        return moi
+    else:
+        return np.nan
diff --git a/src/extraction/core/functions/custom/localisation.py b/src/extraction/core/functions/custom/localisation.py
index 07c22587..08f034e8 100644
--- a/src/extraction/core/functions/custom/localisation.py
+++ b/src/extraction/core/functions/custom/localisation.py
@@ -1,8 +1,9 @@
-""" How to do the nuc Est Conv from MATLAB
+"""
+How to do the nuc Est Conv from MATLAB
 Based on the code in MattSegCode/Matt Seg
 GUI/@timelapseTraps/extractCellDataStacksParfor.m
 
-Especially lines 342 to  399.
+Especially lines 342 to 399.
 This part only replicates the method to get the nuc_est_conv values
 """
 import typing as t
diff --git a/src/extraction/core/functions/loaders.py b/src/extraction/core/functions/loaders.py
index ff83b20c..ce33f845 100644
--- a/src/extraction/core/functions/loaders.py
+++ b/src/extraction/core/functions/loaders.py
@@ -11,8 +11,8 @@ from extraction.core.functions.math_utils import div0
 
 """
 Load functions for analysing cells and their background.
-Note that inspect.getmembers returns a list of function names and functions,
-and inspect.getfullargspec returns a function's arguments.
+Note that inspect.getmembers returns a list of function names and
+functions, and inspect.getfullargspec returns a function's arguments.
 """
 
 
-- 
GitLab