Pixel -> Stage calibration for overviews


In [1]:
import os
import logging
import json

from nis_util import do_large_image_scan, set_optical_configuration, get_position

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

set paths


In [13]:
path_to_nis = 'C:\\Program Files\\NIS-Elements\\nis_ar.exe'
save_base_path = 'C:\\Users\\Nikon\\Documents\\David\\overview_calibrations'
calibration_name = 'right_color_251019.json'

if not os.path.exists(save_base_path):
    os.makedirs(save_base_path)
    
if os.path.exists(os.path.join(save_base_path, calibration_name)):
    logger.warning('output file already exists, will be overwritten')

do a dummy overview scan

please enter the coordinates of the field you wish to calibrate as (left, right, top, bottom) and the optical configuration you are using for overviews.

Running the cell will do a dummy overview and leave the resulting image open in NIS.

! The z-position will be recorded to the calibration file, so please focus on a slide !


In [14]:
calibration_fov = (-26500,
  -50000,
  -21053,
  18177)
calibration_oc = 'DIA4x'
left, right, top, bottom = calibration_fov

set_optical_configuration(path_to_nis, calibration_oc)
do_large_image_scan(path_to_nis, '', left, right, top, bottom, close=False)
pos = get_position(path_to_nis)

corresponding points

Now, please collect 3 pairs of pixel (x,y)-coordinates and stage (um) coordinates. To do so, hover over the image, the pixel coordinates will be displayed on the bottom of the image window. If you right-click, the corresponding stage coordinates will be shown under Move this point to center.

if you use binning, please multiply the pixel coordinates with the binning factor


In [15]:
coords1px = (2071*3, 2273*3)
coords1st = (-29777, -17306)

coords2px = (11437*3, 6683*3)
coords2st = (-49516, -7747)

coords3px = (2873*3, 10802*3)
coords3st = (-30954, 1180)

save the calibration

execute the following to save the calibration as a JSON-file.


In [16]:
res = {}
res['bbox'] = calibration_fov
res['coords_px'] = [coords1px, coords2px, coords3px]
res['coords_st'] = [coords1st, coords2st, coords3st]
res['zpos'] = pos[2]

with open(os.path.join(save_base_path, calibration_name), 'w') as fd:
    json.dump(res, fd, indent=1)
    print('saved calibration: \n\n{}'.format(json.dumps(res, indent=1)))


saved calibration: 

{
 "bbox": [
  -26500,
  -50000,
  -21053,
  18177
 ],
 "coords_px": [
  [
   6990,
   6819
  ],
  [
   34311,
   20049
  ],
  [
   8619,
   32406
  ]
 ],
 "coords_st": [
  [
   -29777,
   -17306
  ],
  [
   -49516,
   -7747
  ],
  [
   -30954,
   1180
  ]
 ],
 "zpos": 2647.46
}

test the transformation

below, you can test the transformation by entering new pixel coordinates and checking if the output corresponds to the stage coordinates shown in NIS.


In [17]:
import numpy as np
from skimage.transform import AffineTransform

test_coords = (10116*3, 15814*3)

coords_px = np.array([coords1px, coords2px, coords3px], dtype=np.float)
coords_st = np.array([coords1st, coords2st, coords3st], dtype=np.float)

at = AffineTransform()
at.estimate(coords_px, coords_st)
at(np.array(test_coords)).ravel()


Out[17]:
array([-46652.87970798,  12043.65437229])

In [7]:
from resources import left_color_calib
import numpy as np
from skimage.transform import AffineTransform

test_coords = (11159*3, 19913*3)
field_def_file = left_color_calib

with open(field_def_file, 'r') as fd:
    field_calib = json.load(fd)

coords_px = np.array(field_calib['coords_px'], dtype=np.float)
coords_st = np.array(field_calib['coords_st'], dtype=np.float)
at = AffineTransform()
at.estimate(coords_px, coords_st)
at.params, at(np.array(test_coords)).ravel()


Out[7]:
(array([[ -7.22466570e-01,  -3.50383624e-06,   5.51037221e+04],
        [ -3.19971041e-06,   7.22455959e-01,  -2.19046340e+04],
        [  0.00000000e+00,   0.00000000e+00,   1.00000000e+00]]),
 array([ 30917.49940791,  21254.05542249]))