diff --git a/setup.py b/setup.py
index 802e22520910343c5c3eea9a879bf10fd4899c13..c3859050d9fc15c8215e3e376d93ff10eb1afc2e 100644
--- a/setup.py
+++ b/setup.py
@@ -45,6 +45,7 @@ setup_kwds = dict(
             'surfaceMeshCellLayer = gnomon_package_tissueimagemesh.algorithm.cellImageQuantification.surfaceMeshCellLayer',
             'surfaceMeshCellProperty = gnomon_package_tissueimagemesh.algorithm.cellImageQuantification.surfaceMeshCellProperty',
             'wallMeshImageSignal = gnomon_package_tissueimagemesh.algorithm.cellImageQuantification.wallMeshImageSignal',
+            'wallMeshSignalPolarities = gnomon_package_tissueimagemesh.algorithm.cellImageQuantification.wallMeshSignalPolarities',
         ],
         'meshFromImage': [
             'imageSurfaceMesh = gnomon_package_tissueimagemesh.algorithm.meshFromImage.imageSurfaceMesh',
diff --git a/src/gnomon_package_tissueimagemesh/algorithm/cellImageQuantification/wallMeshSignalPolarities.py b/src/gnomon_package_tissueimagemesh/algorithm/cellImageQuantification/wallMeshSignalPolarities.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a6375dcd5be9ccb23d93d88034cd40239441e7f
--- /dev/null
+++ b/src/gnomon_package_tissueimagemesh/algorithm/cellImageQuantification/wallMeshSignalPolarities.py
@@ -0,0 +1,146 @@
+import logging
+from copy import deepcopy
+
+import numpy as np
+import pandas as pd
+
+from dtkcore import d_real, d_inliststring, d_inliststringlist
+
+from gnomon.utils import algorithmPlugin
+from gnomon.utils.decorators import cellImageInput, imageInput, meshInput, cellImageOutput, dataFrameOutput
+from gnomon.core import gnomonAbstractCellImageQuantification
+
+from timagetk import TissueImage3D
+from timagetk.features.pandas_tools import cell_walls_to_dataframe
+
+from timagetk_geometry.signal_quantification.wall_mesh import quantify_wall_topomesh_membrane_signal_intensity, compute_wall_property
+
+
+@algorithmPlugin(version="0.3.0", coreversion="0.81.0", name="Wall Signal Polarities")
+@meshInput('wall_topomesh', data_plugin="gnomonMeshDataPropertyTopomesh")
+@imageInput('img', data_plugin='gnomonImageDataMultiChannelImage')
+@cellImageInput("tissue", data_plugin="gnomonCellImageDataTissueImage")
+@cellImageOutput("out_tissue", data_plugin="gnomonCellImageDataTissueImage")
+@dataFrameOutput('df', data_plugin="gnomonDataFrameDataPandas")
+class wallMeshSignalPolarities(gnomonAbstractCellImageQuantification):
+    """Measure image signal polarities using cell wall meshes.
+
+    The method computes a value of signal on both sides of each cell wall
+    represented in a wall triangle mesh and assess the polarity of the signal
+    at the level of each cell-cell interface.
+
+    """
+
+    def __init__(self):
+        super().__init__()
+
+        self.tissue = {}
+        self.img = {}
+        self.wall_topomesh = {}
+
+        self.out_tissue = {}
+        self.df = {}
+
+        self._parameters = {}
+        self._parameters['membrane_channel'] = d_inliststring("Reference channel", "",[""], "Channel to use as a reference for positioning the cell wall")
+        self._parameters['channels'] = d_inliststringlist("Channels", [""],[""], "Channels on which to quantify signal polarity at the cell walls")
+        self._parameters['wall_distance'] = d_real("Wall distance", 0.6, 0., 10., 2, "Distance used to average the signal at each wall vertex")
+        self._parameters['max_distance'] = d_real("Max distance", 1.5, 0., 20., 2, "Maximal distance when projecting image signal on normal axes")
+        self._parameters['max_radius'] = d_real("Max radius", 1, 0., 20., 2, "Maximal radius when projecting image signal on normal axes")
+
+        self._parameter_groups = {}
+
+    def __del__(self):
+        pass
+
+    def refreshParameters(self):
+        if len(self.img)>0:
+            img = list(self.img.values())[0]
+
+            if len(img.channel_names) == 1:
+                if 'membrane_channel' in self._parameters.keys():
+                    del self._parameters['membrane_channel']
+                if 'channels' in self._parameters.keys():
+                    del self._parameters['channels']
+            else:
+                if 'membrane_channel' not in self._parameters.keys():
+                    self._parameters['membrane_channel'] = d_inliststring("Reference channel", "",[""], "Channel to use as a reference for positioning the cell wall")
+
+                if 'channels' not in self._parameters.keys():
+                    self._parameters['channels'] = d_inliststringlist("channels", [""], [""], "Channels on which to quantify signal polarity at the cell walls")
+
+            membrane_channel = self['membrane_channel']
+            self._parameters['membrane_channel'].setValues(img.channel_names)
+            membrane_channel = membrane_channel if membrane_channel in img.channel_names else img.channel_names[0]
+            self._parameters['membrane_channel'].setValue(membrane_channel)
+
+            channel_names = self['channels']
+            self._parameters['channels'].setValues(img.channel_names)
+            channel_names = [c for c in channel_names if c in img.channel_names]
+            if len(channel_names) == 0:
+                channel_names = img.channel_names
+            self._parameters['channels'].setValue(channel_names)
+
+    def run(self):
+        self.out_tissue = {}
+        self.df = {}
+
+        for time in self.tissue.keys():
+            if not time in self.img.keys():
+                logging.error("Impossible to quantify! No signal image provided")
+                self.df = {}
+                return
+            if not time in self.wall_topomesh.keys():
+                logging.error("Impossible to quantify! No wall mesh provided")
+                self.df = {}
+                return
+            tissue = self.tissue[time]
+
+            out_tissue = TissueImage3D(tissue, not_a_label=0, background=1)
+            out_tissue.cells = deepcopy(tissue.cells)
+            out_tissue.cells.image = out_tissue
+            out_tissue.walls = deepcopy(tissue.walls)
+            out_tissue.walls.image = out_tissue
+
+            img = self.img[time]
+            wall_topomesh = self.wall_topomesh[time]
+
+            cell_centers = out_tissue.cells.barycenter()
+
+            membrane_channel = "" if 'channels' not in self._parameters else self['membrane_channel']
+            channel_names = [""] if 'channels' not in self._parameters else self['channels']
+
+            wall_areas = compute_wall_property(wall_topomesh, 'area')
+            wall_centers = compute_wall_property(wall_topomesh, 'barycenter')
+            wall_normals = compute_wall_property(wall_topomesh, 'normal')
+
+            out_tissue.walls.set_feature('area', wall_areas)
+            for k, dim in enumerate('xyz'):
+                out_tissue.walls.set_feature(f'center_{dim}', {w: c[k] for w, c in wall_centers.items()})
+            for k, dim in enumerate('xyz'):
+                out_tissue.walls.set_feature(f'normal_{dim}', {w: n[k] for w, n in wall_normals.items()})
+
+            wall_signals = quantify_wall_topomesh_membrane_signal_intensity(
+                signal_img=img,
+                all_wall_topomesh=wall_topomesh,
+                cell_centers=cell_centers,
+                membrane_channel=membrane_channel,
+                channel_names=channel_names,
+                compute_polarities=True,
+                wall_distance=self['wall_distance'],
+                wall_sigma=self['max_distance'],
+                line_sigma=self['max_radius']
+            )
+
+            for channel_name in channel_names:
+                signal_name = channel_name if channel_name != "" else "image_signal"
+                for suffix in ["", "_left", "_right", "_polarity"]:
+                    out_tissue.walls.set_feature(f"{signal_name}{suffix}", wall_signals[f"{channel_name}{suffix}"])
+
+            self.out_tissue[time] = out_tissue
+
+            self.df[time] = cell_walls_to_dataframe(out_tissue.walls, cell_ids=out_tissue.cell_ids())
+            self.df[time]['time'] = time
+
+        if len(self.df) > 0:
+            self.df = {0: pd.concat([self.df[time] for time in self.df.keys()])}