diff --git a/stpt_pipeline/main.py b/stpt_pipeline/main.py
index b5a97829a5b7216980ff8bc185588d62c2e973a6..e66401992d82690acddd7122cbcf158439543011 100644
--- a/stpt_pipeline/main.py
+++ b/stpt_pipeline/main.py
@@ -1,10 +1,209 @@
 import logging
+from os import listdir
 
+import numpy as np
 from dask import delayed  # noqa: F401
+from scipy.ndimage import geometric_transform
+
+from .chi_functions import find_overlap_conf, read_mosaicifile_stpt
+from .mosaic_functions import (find_delta, get_img_cube, get_img_list,
+                               get_mosaic_file)
+from .settings import Settings
+from .stpt_displacement import defringe, get_coords, magic_function
 
 log = logging.getLogger('owl.daemon.pipeline')
-log = logging.LoggerAdapter(log, {'component': 'DASK PIPELINE'})
 
 
-def main(*, datalen: int):
-    pass
+def main(*, root_dir: str, flat_file: str, output_dir: str):
+    """[summary]
+
+    Parameters
+    ----------
+    root_dir : str
+        [description]
+    flat_file : str
+        [description]
+    output_dir : str
+        [description]
+    """
+    # Read flat
+    if Settings.do_flat:
+        fl = np.load(flat_file)
+        channel = Settings.channel_to_use - 1
+        if Settings.defring:
+            fr_img = defringe(fl[:, :, channel])
+            nflat = (fl[:, :, channel] - fr_img) / np.median(fl[:, :, channel])
+        else:
+            nflat = (fl[:, :, channel]) / np.median(fl[:, :, channel])
+        nflat[nflat < 0.5] = 1.0
+    else:
+        nflat = 1.0
+
+    # This lists all the subdirectories. Once there is an
+    # standarized naming convention this will have to be edited,
+    # as at the moment looks for dir names with the '4t1' string
+    # on them, as all the experiments had this
+    dirs = []
+    for this_file in listdir(root_dir):
+        if this_file.find('4t1') > -1:
+            if this_file.find('.txt') > -1:
+                continue
+            dirs.append(root_dir + '/' + this_file + '/')
+    dirs.sort()
+
+    # Now we loop over all subirectories
+    for this_dir in dirs:
+        log.info('Directory %s', this_dir)
+        # read mosaic file, get delta in microns
+        mosaic_file = get_mosaic_file(this_dir)
+        dx, dy, lx, ly = read_mosaicifile_stpt(this_dir + mosaic_file)
+        delta_x, delta_y = find_delta(dx, dy)
+        # dx0,dy0 are just the coordinates of each image
+        # in columns/rows
+        dx0 = np.round((dx - dx.min()) / delta_x).astype(int)
+        dy0 = np.round((dy - dy.min()) / delta_y).astype(int)
+        # get image names and select the first optical slice
+        imgs, img_num, channel, optical_slice = get_img_list(this_dir, mosaic_size=len(dx))
+        optical_slice = optical_slice - optical_slice.min() + 1
+        # read image cube
+        img_cube = get_img_cube(
+            this_dir,
+            imgs,
+            img_num,
+            channel,
+            optical_slice,
+            channel_to_use=Settings.channel_to_use,
+            slice_to_use=optical_slice.min(),
+        )
+        #
+        # std_img is the per pixel std of the cube,
+        # shapes is the reference detector size
+        #
+        std_img = magic_function(np.std(img_cube, 0))
+        shapes = magic_function(img_cube[0, ...]).shape
+        #
+        print(
+            'Found {0:d} images, cube STD {1:.3f}'.format(
+                img_cube.shape[0], np.mean(std_img)
+            )
+        )
+        # Default confidence map, as the array is square but
+        # the geometrical transform to correct distortion
+        # leaves some pixels empty, so these are set to zero in
+        # this conf. map. As all images go through the same initial
+        # transformation, only on conf map is needed
+        general_conf = np.ones_like(magic_function(img_cube[0, ...]))
+        dist_conf = geometric_transform(
+            general_conf,
+            get_coords,
+            output_shape=(int(shapes[0]), shapes[1]),
+            extra_arguments=(Settings.cof_dist, shapes[0] * 0.5, shapes[0]),
+            extra_keywords={'direct': True},
+            mode='constant',
+            cval=0.0,
+            order=1,
+        )
+        #
+        # These are the matrixes where the displacements that come out
+        # of cross-correlation are stored. dx_mat[i,j] is the optimal
+        # displacement between image i and j in the x direction. If these
+        # images do not overlap, it is set to -9999
+        #
+        dx_mat = np.zeros((len(dx), len(dx))) - 9999
+        dy_mat = np.zeros((len(dx), len(dx))) - 9999
+        #
+        for i in range(len(dx0)):
+            # pick up if crash by reloading already calculated
+            # displacements
+            try:
+                dx_mat = np.load(this_dir + 'desp_dist_x.npy')
+                dy_mat = np.load(this_dir + 'desp_dist_y.npy')
+            except FileNotFoundError:
+                print('No saved displacements found')
+            #
+            # This is more or less the distance between images in detectors,
+            # so we only crossmatch images withn 1 detector size of the
+            # reference image
+            #
+            r = (dx0 - dx0[i]) ** 2 + (dy0 - dy0[i]) ** 2
+            r[i] = 100
+            i_t = np.where(r <= 1)[0]
+            #
+            for this_img in i_t:
+                if dx_mat[i, this_img] != -9999:
+                    # already done
+                    print('({0:2d},{1:2d}) already done'.format(i, this_img))
+                    continue
+                print('Finding shifts for ({0:2d},{1:2d})'.format(i, this_img))
+                #
+                # Find relative orientation. As the crossmatching code always assumes
+                # that the images are aligned along the X axis and the reference is to
+                # the left, we need to juggle things if that's not the case
+                #
+                ind_ref = i
+                ind_obj = this_img
+                if np.abs(dx0[i] - dx0[this_img]) > np.abs(dy0[i] - dy0[this_img]):
+                    ORIENTATION = 'X'
+                    # Relative position
+                    if dx0[i] > dx0[this_img]:
+                        ind_ref = this_img
+                        ind_obj = i
+                        continue
+                else:
+                    ORIENTATION = 'Y'
+                    # Relative position
+                    if dy0[i] > dy0[this_img]:
+                        ind_ref = this_img
+                        ind_obj = i
+                        continue
+                #
+                # Transformed images
+                #
+                new_ref = geometric_transform(
+                    magic_function(img_cube[ind_ref, ...]),
+                    get_coords,
+                    output_shape=(int(shapes[0]), shapes[1]),
+                    extra_arguments=(Settings.cof_dist, shapes[0] * 0.5, shapes[0]),
+                    extra_keywords={'direct': True},
+                    mode='constant',
+                    cval=0.0,
+                    order=1,
+                )
+                new_obj = geometric_transform(
+                    magic_function(img_cube[ind_obj, ...]),
+                    get_coords,
+                    output_shape=(int(shapes[0]), shapes[1]),
+                    extra_arguments=(Settings.cof_dist, shapes[0] * 0.5, shapes[0]),
+                    extra_keywords={'direct': True},
+                    mode='constant',
+                    cval=0.0,
+                    order=1,
+                )
+                # finding shift
+                dx, dy, mer = find_overlap_conf(
+                    new_ref,
+                    dist_conf,
+                    new_obj,
+                    dist_conf,
+                    ORIENTATION=ORIENTATION,
+                    produce_image=False,
+                    return_chi=True,
+                    DOUBLE_MEDIAN=False,
+                    IMG_STD=np.mean(std_img),
+                )
+                # undoing the index shifts
+                if ORIENTATION == 'Y':
+                    dx_mat[ind_ref, ind_obj] = dx
+                    dy_mat[ind_ref, ind_obj] = dy
+                    #
+                    dx_mat[ind_obj, ind_ref] = -dx
+                    dy_mat[ind_obj, ind_ref] = -dy
+                if ORIENTATION == 'X':
+                    dx_mat[ind_ref, ind_obj] = dy
+                    dy_mat[ind_ref, ind_obj] = -dx
+                    #
+                    dx_mat[ind_obj, ind_ref] = -dy
+                    dy_mat[ind_obj, ind_ref] = dx
+                # storing
+                np.save(this_dir + 'desp_dist_x', dx_mat)
+                np.save(this_dir + 'desp_dist_y', dy_mat)
diff --git a/stpt_pipeline/stpt_displacement.py b/stpt_pipeline/stpt_displacement.py
index f73beb4af5e995fa726bdf81213819077bb6a6b3..33462624531c7ec9973cecf4bfd98442295d2723 100644
--- a/stpt_pipeline/stpt_displacement.py
+++ b/stpt_pipeline/stpt_displacement.py
@@ -1,11 +1,7 @@
-from os import listdir
 
 import numpy as np
-from scipy.ndimage import geometric_transform
 
-from chi_functions import find_overlap_conf, read_mosaicifile_stpt
-from mosaic_functions import (find_delta, get_img_cube, get_img_list,
-                              get_mosaic_file)
+from .settings import Settings
 
 
 # these two functions are only used to filter and defringe the flat
@@ -108,38 +104,7 @@ def get_coords(coords, cof, center_x, max_x, direct=True):
         )
 
 
-#
-##################################################################################
-#
-# x/y_min and max are the lower/upper boundaries of the useful section of the
-# detector.
-#
-# Norm val is a normalization value for the stored values, ideally the gain
-#
-# do_flat activates flat correction prior to crossmatching. defringe does that to
-# the flat before dividing by it, but it is time consuming and not very
-# useful at the moment
-#
-# cof_dist are the coefficients of the optical distortion, as measured from
-# the images themselves.
-#
-x_min = 2
-x_max = 2080
-y_min = 80
-y_max = 1990
-norm_val = 10000.0
-do_flat = True
-defring = False
-channel_to_use = 4
-cof_dist = np.array([3.93716645e-05, -7.37696218e-02, 2.52457306e01]) / 2.0
-#
-# this is the directory where all the subdirectories (one per physical slice)
-# are stored. Ideally this should be passed as an argument
-#
-root_dir = '../20190201_tumour_opticalsections_extraoverlap/'
-
-
-def magic_function(x):
+def magic_function(x, nflat=1):  # TODO: Call this some other name
     """[summary]
 
     This function transform the raw images into the ones used
@@ -149,198 +114,16 @@ def magic_function(x):
     ----------
     x : [type]
         [description]
+    nflat : [type]
+        [description]
 
     Returns
     -------
     [type]
         [description]
     """
-    return np.flipud(x / nflat)[x_min:x_max, y_min:y_max] / norm_val
-
-
-# Read flat
-#
-if do_flat:
-    fl = np.load('flat2.npy')
-    if defringe:
-        fr_img = defringe(fl[:, :, channel_to_use - 1])
-        nflat = (fl[:, :, channel_to_use - 1] - fr_img) / np.median(
-            fl[:, :, channel_to_use - 1]
-        )
-    else:
-        nflat = (fl[:, :, channel_to_use - 1]) / np.median(fl[:, :, channel_to_use - 1])
-    nflat[nflat < 0.5] = 1.0
-else:
-    nflat = 1.0
-#
-# This lists all the subdirectories. Once there is an
-# standarized naming convention this will have to be edited,
-# as at the moment looks for dir names with the '4t1' string
-# on them, as all the experiments had this
-#
-dirs = []
-for this_file in listdir(root_dir):
-    if this_file.find('4t1') > -1:
-        if this_file.find('.txt') > -1:
-            continue
-        dirs.append(root_dir + '/' + this_file + '/')
-dirs.sort()
-#
-# Now we loop over all subirectories
-#
-for this_dir in dirs:
-    #
-    print(this_dir)
-    # read mosaic file, get delta in microns
-    mosaic_file = get_mosaic_file(this_dir)
-    dx, dy, lx, ly = read_mosaicifile_stpt(this_dir + mosaic_file)
-    delta_x, delta_y = find_delta(dx, dy)
-    # dx0,dy0 are just the coordinates of each image
-    # in columns/rows
-    dx0 = np.round((dx - dx.min()) / delta_x).astype(int)
-    dy0 = np.round((dy - dy.min()) / delta_y).astype(int)
-    # get image names and select the first optical slice
-    imgs, img_num, channel, optical_slice = get_img_list(this_dir, mosaic_size=len(dx))
-    optical_slice = optical_slice - optical_slice.min() + 1
-    # read image cube
-    img_cube = get_img_cube(
-        this_dir,
-        imgs,
-        img_num,
-        channel,
-        optical_slice,
-        channel_to_use=channel_to_use,
-        slice_to_use=optical_slice.min(),
-    )
-    #
-    # std_img is the per pixel std of the cube,
-    # shapes is the reference detector  size
-    #
-    std_img = magic_function(np.std(img_cube, 0))
-    shapes = magic_function(img_cube[0, ...]).shape
-    #
-    print(
-        'Found {0:d} images, cube STD {1:.3f}'.format(
-            img_cube.shape[0], np.mean(std_img)
-        )
-    )
-    # Default confidence map, as the array is square but
-    # the geometrical transform to correct distortion
-    # leaves some pixels empty, so these are set to zero in
-    # this conf. map. As all images go through the same initial
-    # transformation, only on conf map is needed
-    general_conf = np.ones_like(magic_function(img_cube[0, ...]))
-    dist_conf = geometric_transform(
-        general_conf,
-        get_coords,
-        output_shape=(int(shapes[0]), shapes[1]),
-        extra_arguments=(cof_dist, shapes[0] * 0.5, shapes[0]),
-        extra_keywords={'direct': True},
-        mode='constant',
-        cval=0.0,
-        order=1,
-    )
-    #
-    # These are the matrixes where the displacements that come out
-    # of cross-correlation are stored. dx_mat[i,j] is the optimal
-    # displacement between image i and j in the x direction. If these
-    # images do not overlap, it is set to -9999
-    #
-    dx_mat = np.zeros((len(dx), len(dx))) - 9999
-    dy_mat = np.zeros((len(dx), len(dx))) - 9999
-    #
-    for i in range(len(dx0)):
-        # pick up if crash by reloading already calculated
-        # displacements
-        try:
-            dx_mat = np.load(this_dir + 'desp_dist_x.npy')
-            dy_mat = np.load(this_dir + 'desp_dist_y.npy')
-        except FileNotFoundError:
-            print('No saved displacements found')
-        #
-        # This is more or less the distance between images in detectors,
-        # so we only crossmatch images withn 1 detector size of the
-        # reference image
-        #
-        r = (dx0 - dx0[i]) ** 2 + (dy0 - dy0[i]) ** 2
-        r[i] = 100
-        i_t = np.where(r <= 1)[0]
-        #
-        for this_img in i_t:
-            if dx_mat[i, this_img] != -9999:
-                # already done
-                print('({0:2d},{1:2d}) already done'.format(i, this_img))
-                continue
-            print('Finding shifts for ({0:2d},{1:2d})'.format(i, this_img))
-            #
-            # Find relative orientation. As the crossmatching code always assumes
-            # that the images are aligned along the X axis and the reference is to
-            # the left, we need to juggle things if that's not the case
-            #
-            ind_ref = i
-            ind_obj = this_img
-            if np.abs(dx0[i] - dx0[this_img]) > np.abs(dy0[i] - dy0[this_img]):
-                ORIENTATION = 'X'
-                # Relative position
-                if dx0[i] > dx0[this_img]:
-                    ind_ref = this_img
-                    ind_obj = i
-                    continue
-            else:
-                ORIENTATION = 'Y'
-                # Relative position
-                if dy0[i] > dy0[this_img]:
-                    ind_ref = this_img
-                    ind_obj = i
-                    continue
-            #
-            # Transformed images
-            #
-            new_ref = geometric_transform(
-                magic_function(img_cube[ind_ref, ...]),
-                get_coords,
-                output_shape=(int(shapes[0]), shapes[1]),
-                extra_arguments=(cof_dist, shapes[0] * 0.5, shapes[0]),
-                extra_keywords={'direct': True},
-                mode='constant',
-                cval=0.0,
-                order=1,
-            )
-            new_obj = geometric_transform(
-                magic_function(img_cube[ind_obj, ...]),
-                get_coords,
-                output_shape=(int(shapes[0]), shapes[1]),
-                extra_arguments=(cof_dist, shapes[0] * 0.5, shapes[0]),
-                extra_keywords={'direct': True},
-                mode='constant',
-                cval=0.0,
-                order=1,
-            )
-            # finding shift
-            dx, dy, mer = find_overlap_conf(
-                new_ref,
-                dist_conf,
-                new_obj,
-                dist_conf,
-                ORIENTATION=ORIENTATION,
-                produce_image=False,
-                return_chi=True,
-                DOUBLE_MEDIAN=False,
-                IMG_STD=np.mean(std_img),
-            )
-            # undoing the index shifts
-            if ORIENTATION == 'Y':
-                dx_mat[ind_ref, ind_obj] = dx
-                dy_mat[ind_ref, ind_obj] = dy
-                #
-                dx_mat[ind_obj, ind_ref] = -dx
-                dy_mat[ind_obj, ind_ref] = -dy
-            if ORIENTATION == 'X':
-                dx_mat[ind_ref, ind_obj] = dy
-                dy_mat[ind_ref, ind_obj] = -dx
-                #
-                dx_mat[ind_obj, ind_ref] = -dy
-                dy_mat[ind_obj, ind_ref] = dx
-            # storing
-            np.save(this_dir + 'desp_dist_x', dx_mat)
-            np.save(this_dir + 'desp_dist_y', dy_mat)
+    x_min, x_max = Settings.x_min, Settings.x_max
+    y_min, y_max = Settings.y_min, Settings.y_max
+    norm_val = Settings.norm_val
+    res = np.flipud(x / nflat)[x_min:x_max, y_min:y_max] / norm_val
+    return res