WingScanner


In [ ]:
# hide all code by default via JavaScript

from IPython.display import HTML

HTML('''<script>
code_show=true; 
function code_toggle() {
 if (code_show){
 $('div.input').hide();
 } else {
 $('div.input').show();
 }
 code_show = !code_show
} 
$( document ).ready(code_toggle);
</script>
The raw code for this Jupyter notebook is by default hidden for easier reading.
To toggle on/off the raw code, click <a href="javascript:code_toggle()">here</a>.''')

In [ ]:
#########################
# defs and imports
#########################

import logging
import os
import shutil
import json
import threading
import traceback

import numpy as np
from numpy.linalg import inv

from nis_util import *
from simple_detection import *

from skimage.transform import AffineTransform
from skimage.io import imread
from xmlrpc.client import ServerProxy

from annotation import manually_correct_rois
from automation import WidgetProgressIndicator

In [ ]:
###################
# set up the environment, nis, and image saving path
###################

import resources

# Wrapper for default values
class WingScannerSettings:
    def __init__(self):
        # value is (description, value)
        self.path_to_nis = ('Path to NIS .exe', 'C:\\Program Files\\NIS-Elements\\nis_ar.exe')
        self.save_base_path = ('Local Temp Folder', 'C:\\Users\\Nikon\\Documents\\automation_temp')
        self.save_server_path_local = ('Destination Folder on Server (Network Share)', 'Y:\\results')
        self.save_server_path_remote = ('Destination Folder on Server (On Server)', '/data/wing-scanner/results')

        # location of the calibration files
        self.calib_left = ('Calibration File (left)', resources.left_calib)
        self.calib_mid = ('Calibration File (mid)', resources.mid_calib)
        self.calib_right = ('Calibration File (right)', resources.right_calib)

        # detail images z settings
        self.z_drive= ('Z device for detail stacks', 'NIDAQ Piezo Z')
        self.z_range = ('Z range (um)', 50)
        self.z_step= ('Z steps (um)', 2)


# plot size
%matplotlib inline
plt.rcParams['figure.figsize'] = [10,10]

In [ ]:
#################
# do the scans
#################

style = {'description_width': 'initial'}

from ipywidgets import Layout, HBox, VBox, Box, Checkbox, Text, BoundedFloatText, Button, FloatProgress, Label, Dropdown, Tab, Layout
from IPython.display import display

import automation
from copy import copy

logging.basicConfig(format='%(asctime)s - %(levelname)s in %(funcName)s: %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)


settings = WingScannerSettings()

# this will fail on systems without nis -> use dummy values
try:
    pos = get_position(settings.path_to_nis[1])
    color = is_color_camera(settings.path_to_nis[1])
    ocs = get_optical_confs(settings.path_to_nis[1])
except FileNotFoundError as e:
    pos = (0, 0, 0, 0)
    color = False
    ocs = ['oc_1', 'oc_2']
    
if color:
    settings.calib_left = ('Calibration File (left)', resources.left_color_calib)
    settings.calib_mid = ('Calibration File (mid)', resources.mid_color_calib)
    settings.calib_right = ('Calibration File (right)', resources.right_color_calib)

# Tab 1: basic settings
selection_oc_ov = Dropdown(
    options=ocs,
    value=ocs[0],
    disabled=False,
    description='Overview OC:',
    style=style
)
selection_oc_det_dia = Dropdown(
    options=ocs,
    value=ocs[0],
    disabled=False,
    description='detailed DIA OC:',
    style=style
)
selection_oc_det_fluo_vb = Box(
    [Checkbox(description='',indent=False),
     Dropdown(
         options=ocs,
         value=ocs[0],
         description='Detail fluo OC :',
         disabled=False,
         style=style )])

manual_annot_check = Checkbox(description='Manually correct detections?')
detection_first_check = Checkbox(description='Do all overviews/detections first')
hbox_ocs_mendatory = VBox([selection_oc_ov, selection_oc_det_dia])
hbox_ocs_optionnal = VBox([selection_oc_det_fluo_vb, manual_annot_check, detection_first_check])
sub_folder = Text(description='subfolder name:', style=style)

left = HBox([Checkbox(description='left slide'), Text(description='prefix:'),
             Checkbox(description='manual focus position', value=True), BoundedFloatText(description='z', value=float(pos[2]), min=0, max=5000, step=10)])

mid = HBox([Checkbox(description='mid slide'), Text(description='prefix:'),
             Checkbox(description='manual focus position', value=True), BoundedFloatText(description='z', value=float(pos[2]), min=0, max=5000, step=10)])

right = HBox([Checkbox(description='right slide'), Text(description='sample name:'),
             Checkbox(description='manual focus position', value=True), BoundedFloatText(description='z', value=float(pos[2]), min=0, max=5000, step=10)])

status_main = HBox([FloatProgress(), Label()])
status_detail = HBox([FloatProgress(), Label()])


go = Button(description='GO')

tab1 = VBox([ hbox_ocs_mendatory, hbox_ocs_optionnal, sub_folder, left, mid, right, status_main, status_detail, go])

settings_textboxes = [Text(description=v[0], value=str(v[1]), layout=Layout(width='80%'), style=style) for _,v in vars(settings).items()]

tab2 = VBox([
    Label('Expert settings, only change if you know what you are doing')
] + settings_textboxes )

tabs = Tab(children=[tab1, tab2])
tabs.set_title(0, 'Wing Scanner')
tabs.set_title(1, 'Expert Settings')

display(tabs)


status = WidgetProgressIndicator(status_detail.children[0], status_detail.children[1])

def onclick_go(btn):
   
    btn.disabled = True
    
    # update settings object
    for i, k in enumerate(settings.__dict__):
        settings.__dict__[k] = (settings_textboxes[i].description, settings_textboxes[i].value)
        
     # NB: we change the calibration if we use the color cam
    # TODO: respect user choice for custom calibration
    try:
        set_optical_configuration(settings.path_to_nis[1], selection_oc_ov.value)
        color = is_color_camera(settings.path_to_nis[1])
        if color:
            settings.calib_left = ('Calibration File (left)', resources.left_color_calib)
            settings.calib_mid = ('Calibration File (mid)', resources.mid_color_calib)
            settings.calib_right = ('Calibration File (right)', resources.right_color_calib)
        else:
            settings.calib_left = ('Calibration File (left)', resources.left_calib)
            settings.calib_mid = ('Calibration File (mid)', resources.mid_calib)
            settings.calib_right = ('Calibration File (right)', resources.right_calib)
    except Exception as e:
        pass
    
    save_path_local = settings.save_server_path_local[1]
    save_path_remote = settings.save_server_path_remote[1]
    if sub_folder.value:
        save_path_local = os.path.join(save_path_local, sub_folder.value)
        save_path_remote = (os.path.join(save_path_remote, sub_folder.value)).replace(os.sep, '/')
    logger.info('Saving files to (local drive) %s '%(save_path_local))
    logger.info('Saving files to (server) %s '%(save_path_remote))
    
    oc_overview = selection_oc_ov.value
    ocs_detail = [selection_oc_det_dia.value]
    if selection_oc_det_fluo_vb.children[0].value:
        logger.info('Imaging also a second channel')
        ocs_detail.append(selection_oc_det_fluo_vb.children[1].value)
    
    slide_left = left.children[1].value if left.children[0].value else None 
    slide_mid = mid.children[1].value if mid.children[0].value else None
    slide_right = right.children[1].value if right.children[0].value else None

    z_left = float(left.children[3].value) if left.children[2].value else None 
    z_mid = float(mid.children[3].value) if mid.children[2].value else None
    z_right = float(right.children[3].value) if right.children[2].value else None

    status_main.children[0].value = 0
    status_main.children[1].value = 'scanning left'
    
    
    
    # TODO: set meaningful default in automation
    config = automation.CommonParameters()
    config.path_to_nis = settings.path_to_nis[1]
    config.prefix = 'experiment'
    config.progress_indicator = status
    config.save_base_path = settings.save_base_path[1]
    config.server_path_local = save_path_local
    config.server_path_remote = save_path_remote
    
    ov_param = automation.OverviewParameters()
    ov_param.export_as_tiff = True
    ov_param.field_def_file = None
    ov_param.manual_z = z_left
    ov_param.oc_overview = oc_overview
    ov_param.return_overview_img = True
    
    det_param = automation.DetectionParameters()
    # TODO: add to settings
    #det_param.detector_adress
    det_param.do_manual_annotation = manual_annot_check.value
    #det_param.object_filter = {}
    det_param.plot_detection = True
    
    detail_param = automation.DetailParameters()
    detail_param.auto_focus_detail = True
    detail_param.channel_for_autofocus = 0
    detail_param.channel_for_stitch = 0
    detail_param.dry_run_details = False
    detail_param.ocs_detail = ocs_detail
    detail_param.projection_params = True
    #detail_param.stitcher_adress
    detail_param.tiff_export_details = True
    detail_param.z_drive = settings.z_drive[1]
    detail_param.z_range = int(settings.z_range[1])
    detail_param.z_step = int(settings.z_step[1])
    
    # TODO: add callback to set 
    
    configs = []
    ov_params = []
    det_params = []
    detail_params = []
    
    do_scan_left  = slide_left != None
    if do_scan_left:
        logger.info('Scanning left scan.')
        
        config_l = copy(config)
        config_l.prefix = slide_left
        ov_param_l = copy(ov_param)
        ov_param_l.field_def_file = settings.calib_left[1]
        
        configs.append(config_l)
        ov_params.append(ov_param_l)
        det_params.append(det_param)
        detail_params.append(detail_param)
        
        '''
        do_scan(settings.calib_left[1], oc_overview, ocs_detail, settings.path_to_nis[1], settings.save_base_path[1],
                slide_left, save_path_local, save_path_remote,
                manual_z_overview=z_left, z_drive=settings.z_drive[1],
                z_range=int(settings.z_range[1]), z_step=int(settings.z_step[1]), progress_indicator=status,
                manual_annotation_check = manual_annot_check.value )
        '''
    else:
        logger.info('Skipping left slide.')

    # mid slide
    
    status_main.children[0].value = 33
    status_main.children[1].value = 'scanning mid'
    
    do_scan_mid  = slide_mid != None
    if do_scan_mid:
        logger.info('Scanning mid scan.')
        
        config_m = copy(config)
        config_m.prefix = slide_mid
        ov_param_m = copy(ov_param)
        ov_param_m.field_def_file = settings.calib_mid[1]
        
        configs.append(config_m)
        ov_params.append(ov_param_m)
        det_params.append(det_param)
        detail_params.append(detail_param)
        
        '''
        do_scan(settings.calib_mid[1], oc_overview, ocs_detail, settings.path_to_nis[1], settings.save_base_path[1],
                slide_mid, save_path_local, save_path_remote,
                manual_z_overview=z_mid, z_drive=settings.z_drive[1],
                z_range=int(settings.z_range[1]), z_step=int(settings.z_step[1]), progress_indicator=status,
               manual_annotation_check = manual_annot_check.value)
        '''
    else:
        logger.info('Skipping middle slide.')

    status_main.children[0].value = 66
    status_main.children[1].value = 'scanning right'
    
    # right slide
    do_scan_right  = slide_right != None
    if do_scan_right:
        logger.info('Scanning right scan.')
        
        config_r = copy(config)
        config_r.prefix = slide_right
        ov_param_r = copy(ov_param)
        ov_param_r.field_def_file = settings.calib_right[1]
        
        configs.append(config_r)
        ov_params.append(ov_param_r)
        det_params.append(det_param)
        detail_params.append(detail_param)
        
        '''
        do_scan(settings.calib_right[1], oc_overview, ocs_detail, settings.path_to_nis[1], settings.save_base_path[1],
                slide_right, save_path_local, save_path_remote,
                manual_z_overview=z_right, z_drive=settings.z_drive[1],
                z_range=int(settings.z_range[1]), z_step=int(settings.z_step[1]), progress_indicator=status,
               manual_annotation_check = manual_annot_check.value)
        '''
    else:
        logger.info('Skipping right slide.')
    
    status_main.children[0].value = 100
    status_main.children[1].value = 'Done'
    
    
    if not detection_first_check.value:
        automation.do_scan(configs, ov_params, det_params, detail_params)
    else:
        automation.do_scan_detection_first(configs, ov_params, det_params, detail_params)
    
    btn.disabled = False
    
go.on_click(onclick_go)

User Guide

  1. Select the optical configurations to use for overview, detail (transmitted light) and detail (fluorescence)
  2. Tick which slides are present (image .. slide)
  3. Give sample names to the slides you are imaging NOTE: These have to be unique, if a sample of the same name already exists, we will not scan the slide
  4. Press GO

If you want to manually focus on a slide, tick manual focus and enter the z-focus position (in microns)