Mercurial > repos > imgteam > landmark_registration
changeset 4:aee73493bf53 draft
planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tools/landmark_registration/ commit ba383a4f617791d0c84737a179e5b4b66cecc334
author | imgteam |
---|---|
date | Mon, 18 Jul 2022 18:41:19 +0000 |
parents | 9ccd642e7ae2 |
children | 12997d4c5b00 |
files | landmark_registration.py landmark_registration.xml test-data/lmk_fix.tsv test-data/lmk_mov.tsv test-data/points.tsv test-data/points_pwlt.tsv |
diffstat | 6 files changed, 149 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/landmark_registration.py Sat Feb 26 17:14:05 2022 +0000 +++ b/landmark_registration.py Mon Jul 18 18:41:19 2022 +0000 @@ -10,12 +10,39 @@ import numpy as np import pandas as pd +from scipy import spatial from scipy.linalg import lstsq from skimage.measure import ransac from skimage.transform import AffineTransform -def landmark_registration(pts_f1, pts_f2, out_f, res_th=None, max_ite=None, delimiter="\t"): +class pwlTransform(object): + + def __init__(self): + self.triangulation = None + self.affines = None + + def estimate(self, src, dst): + self.triangulation = spatial.Delaunay(src) + success = True + self.affines = [] + for tri in self.triangulation.simplices: + affine = AffineTransform() + success &= affine.estimate(src[tri, :], dst[tri, :]) + self.affines.append(affine) + return success + + def __call__(self, coords): + simplex = self.triangulation.find_simplex(coords) + simplex[simplex == -1] = 0 # todo: dealing with points outside the triangulation + out = np.empty_like(coords, np.float64) + for i in range(len(self.triangulation.simplices)): + idx = simplex == i + out[idx, :] = self.affines[i](coords[idx, :]) + return out + + +def landmark_registration(pts_f1, pts_f2, out_f, pts_f=None, res_th=None, max_ite=None, delimiter="\t"): points1 = pd.read_csv(pts_f1, delimiter=delimiter) points2 = pd.read_csv(pts_f2, delimiter=delimiter) @@ -31,6 +58,21 @@ model_robust, inliers = ransac((src, dst), AffineTransform, min_samples=3, residual_threshold=res_th, max_trials=max_ite) pd.DataFrame(model_robust.params).to_csv(out_f, header=None, index=False, sep="\t") + elif pts_f is not None: + pwlt = pwlTransform() + pwlt.estimate(src, dst) + + pts_df = pd.read_csv(pts_f, delimiter=delimiter) + pts = np.concatenate([np.array(pts_df['x']).reshape([-1, 1]), + np.array(pts_df['y']).reshape([-1, 1])], + axis=-1) + pts_pwlt = pwlt(pts) + + df = pd.DataFrame() + df['x'] = pts_pwlt[:, 0] + df['y'] = pts_pwlt[:, 1] + df.to_csv(out_f, index=False, sep="\t", float_format='%.1f') + else: A = np.zeros((src.size, 6)) A[0:src.shape[0], [0, 1]] = src @@ -47,14 +89,18 @@ if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Estimate affine transformation matrix based on landmark coordinates") - parser.add_argument("fn_pts1", help="Coordinates of SRC landmarks (tsv file)") - parser.add_argument("fn_pts2", help="Coordinates of DST landmarks (tsv file)") - parser.add_argument("fn_tmat", help="Path the output (transformation matrix)") + parser = argparse.ArgumentParser(description="estimates the affine transformation matrix or performs piecewiese affine transformation based on landmarks") + parser.add_argument("fn_lmkmov", help="Coordinates of moving landmarks (tsv file)") + parser.add_argument("fn_lmkfix", help="Coordinates of fixed landmarks (tsv file)") + parser.add_argument("fn_out", help="Path to the output") + parser.add_argument("--pwlt", dest="fn_ptsmov", help="Coordinates of points to be transformed (tsv file)") parser.add_argument("--res_th", dest="res_th", type=float, help="Maximum distance for a data point to be classified as an inlier") parser.add_argument("--max_ite", dest="max_ite", type=int, help="Maximum number of iterations for random sample selection") args = parser.parse_args() + fn_ptsmov = None + if args.fn_ptsmov: + fn_ptsmov = args.fn_ptsmov res_th = None if args.res_th: res_th = args.res_th @@ -62,4 +108,4 @@ if args.max_ite: max_ite = args.max_ite - landmark_registration(args.fn_pts1, args.fn_pts2, args.fn_tmat, res_th=res_th, max_ite=max_ite) + landmark_registration(args.fn_lmkmov, args.fn_lmkfix, args.fn_out, pts_f=fn_ptsmov, res_th=res_th, max_ite=max_ite)
--- a/landmark_registration.xml Sat Feb 26 17:14:05 2022 +0000 +++ b/landmark_registration.xml Mon Jul 18 18:41:19 2022 +0000 @@ -1,5 +1,5 @@ -<tool id="ip_landmark_registration" name="Landmark Registration" version="0.0.4" profile="20.05"> - <description>estimates the affine transformation matrix</description> +<tool id="ip_landmark_registration" name="Landmark Registration" version="0.0.5" profile="20.05"> + <description>estimates the affine transformation matrix or performs piecewise affine transformation</description> <requirements> <requirement type="package" version="0.18.1">scikit-image</requirement> <requirement type="package" version="1.6.2">scipy</requirement> @@ -9,58 +9,69 @@ <command detect_errors="aggressive"> <![CDATA[ python '$__tool_directory__/landmark_registration.py' - '$fn_pts1' - '$fn_pts2' - '$fn_tmat' - #if '$algo_option.algo' == 'ransac': - --res_th $algo_option.res_thr - --max_ite $algo_option.max_iter + '$fn_lmkmov' + '$fn_lmkfix' + '$fn_out' + #if $algo_option.algo == "pwat" + --pwlt '$algo_option.fn_ptsmov' + #elif $algo_option.algo == "ransac" + --res_th $algo_option.res_th + --max_ite $algo_option.max_ite #end if -]]></command> + ]]> + </command> <inputs> - <param name="fn_pts1" type="data" format="tabular" label="Coordinates of SRC landmarks (tsv file)" /> - <param name="fn_pts2" type="data" format="tabular" label="Coordinates of DST landmarks (tsv file)" /> + <param name="fn_lmkmov" type="data" format="tabular" label="Coordinates of moving landmarks (tsv file)" /> + <param name="fn_lmkfix" type="data" format="tabular" label="Coordinates of fixed landmarks (tsv file)" /> <conditional name="algo_option"> <param name="algo" type="select" label="Select the algorithm"> - <option value="ransac" selected="True">RANSAC</option> - <option value="ls">Least Squares</option> + <option value="ransac">Affine Transformation (based on RANSAC)</option> + <option value="ls">Affine Transformation (based on Least Squares)</option> + <option value="pwat" selected="True">Piecewise Affine Transformation</option> </param> <when value="ransac"> - <param name="res_thr" type="float" value="2.0" label="Maximum distance for a data point to be classified as an inlier." /> - <param name="max_iter" type="integer" value="100" label="Maximum number of iterations for random sample selection." /> + <param name="res_th" type="float" value="2.0" label="Maximum distance for a data point to be classified as an inlier." /> + <param name="max_ite" type="integer" value="100" label="Maximum number of iterations for random sample selection." /> </when> <when value="ls"></when> + <when value="pwat"> + <param name="fn_ptsmov" type="data" format="tabular" label="Coordinates of points to be transformed (tsv file)" /> + </when> </conditional> </inputs> <outputs> - <data format="tabular" name="fn_tmat" /> + <data format="tabular" name="fn_out" /> </outputs> <tests> <test> - <param name="fn_pts1" value="points_moving.tsv"/> - <param name="fn_pts2" value="points_fixed.tsv"/> - <conditional name="algo_option"> - <param name="algo" value="ls"/> - </conditional> - <output name="fn_tmat" value="tmat.tsv" ftype="tabular" compare="diff" lines_diff="6"/> + <param name="fn_lmkmov" value="points_moving.tsv"/> + <param name="fn_lmkfix" value="points_fixed.tsv"/> + <param name="algo" value="ls"/> + <output name="fn_out" value="tmat.tsv" ftype="tabular" compare="diff" lines_diff="6"/> </test> <test> - <param name="fn_pts1" value="points_moving.tsv"/> - <param name="fn_pts2" value="points_fixed.tsv"/> - <conditional name="algo_option"> - <param name="algo" value="ransac"/> - <param name="res_thr" value="2"/> - <param name="max_iter" value="100"/> - </conditional> - <output name="fn_tmat" value="tmat.tsv" ftype="tabular" compare="diff" lines_diff="6"/> + <param name="fn_lmkmov" value="points_moving.tsv"/> + <param name="fn_lmkfix" value="points_fixed.tsv"/> + <param name="algo" value="ransac"/> + <param name="res_th" value="2.0"/> + <param name="max_ite" value="100"/> + <output name="fn_out" value="tmat.tsv" ftype="tabular" compare="diff" lines_diff="6"/> + </test> + <test> + <param name="fn_lmkmov" value="lmk_mov.tsv"/> + <param name="fn_lmkfix" value="lmk_fix.tsv"/> + <param name="algo" value="pwat"/> + <param name="fn_ptsmov" value="points.tsv"/> + <output name="fn_out" value="points_pwlt.tsv" ftype="tabular"/> </test> </tests> <help> **What it does** - This tool estimates the transformation matrix between two sets of 2d points. + 1) Estimation of the affine transformation matrix between two sets of 2d points; + 2) Piecewise affine transformation of points based on landmark pairs. - About the format of landmark coordinates in the input TSV table: Columns with header "x" and "y" are for x- and y-coordinate, respectively. + About the format of landmark/point coordinates in the input TSV table: Columns with header "x" and "y" are for x- and y-coordinate, respectively. </help> <citations> <citation type="doi">10.1016/j.jbiotec.2017.07.019</citation>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/lmk_fix.tsv Mon Jul 18 18:41:19 2022 +0000 @@ -0,0 +1,7 @@ +x y +6 1710 +546 474 +909 150 +1443 51 +1983 225 +2352 678 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/lmk_mov.tsv Mon Jul 18 18:41:19 2022 +0000 @@ -0,0 +1,7 @@ +x y +51.253 1661.5 +292.57 536.03 +640.67 232.78 +1106.2 106.78 +1576 192.2 +1969 533.89 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/points.tsv Mon Jul 18 18:41:19 2022 +0000 @@ -0,0 +1,20 @@ +x y +563.79 386.54 +429.25 602.23 +448.47 681.24 +841.67 405.33 +1088.3 350.67 +767 674.67 +951 506.67 +1140.3 533.33 +1350 568 +1368 612 +1296 576 +1834 406 +1608 318 +1110 1194 +366 1770 +1322 1282 +1912 662 +867 322.67 +764.33 424 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/points_pwlt.tsv Mon Jul 18 18:41:19 2022 +0000 @@ -0,0 +1,20 @@ +x y +832.3 326.6 +676.7 565.3 +677.8 656.5 +1132.4 383.5 +1395.9 347.8 +1022.4 688.3 +1254.2 519.6 +1459.2 575.2 +1676.9 640.1 +1685.3 691.8 +1616.7 642.5 +2238.4 517.6 +1983.1 373.4 +1262.6 1314.6 +318.0 1870.8 +1469.0 1439.7 +2258.7 815.1 +1156.4 286.6 +1049.8 396.6