OSCR

Back-illumination Phase Imaging Enables Nanoscale Drift Stabilization in Non-transparent Biological Tissues

Code ↔ Paper

3 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 3 matches
  1. [1] § Results and discussion › Stabilization in fixed brain slices ↔ Transmission_microscopeControl/Autofocus_ui_v1.3.py, lines 612–691 · score 0.72 · cross correlation curve, numerical correction, xy drift, CCC, SIFT, fitted
  2. [2] § Methods › Autofocusing procedure ↔ Transmission_microscopeControl/Autofocus_ui_v1.3.py, lines 552–611 · score 0.61 · XY correction, Microscope control, GPU, 1.5 s, SIFT, autofocusing
  3. [3] § Methods › Oblique back-illumination optical setup ↔ LEDcontrol/LEDdisplay2.3_2.4.py, lines 35–66 · score 0.60 · Micro Manager, Hamamatsu, KURO, hardware, triggering, exposure

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 955 lines · 46 KB · no license · 2 matches

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Tue Apr 16 15:54:00 2024
  4. @author: hmanko
  5. """
  6. #!/usr/bin/env python3
  7. # -*- coding: utf-8 -*-
  8. """
  9. Created on Thu Jun 22 18:17:01 2023
  10. @author: hannamanko
  11. """
  12. """
  13. The gui created in order to control Nikon Ti microscope with Phasics camera. This version of GUI was created using QtDesigner
  14. (can be started using 'qt5-tools designer' from the command promt).
  15. The soft was developed to be started on windows system, if you are going to use it on any
  16. other system it will be required to change the way how the path for saving data is defined
  17. in all the functions.
  18. Ex: for windows before the file name separated by '\\' need to be written, as it was done in this code
  19. The lines where changes could be required are marked as ############ ***
  20. #### *** !!!
  21. """
  22. ### importing all the required libraries
  23. import pymmcore_plus
  24. import numpy as np
  25. import cv2
  26. import os.path
  27. from pymmcore_plus import CMMCorePlus
  28. import useq
  29. from useq import MDAEvent, MDASequence
  30. from pymmcore_plus.mda import MDAEngine
  31. import matplotlib.pyplot as plt
  32. from IPython import get_ipython
  33. from numpy import median
  34. import pymmcore
  35. import pandas as pd
  36. import numpy as np
  37. import napari
  38. import os.path
  39. import matplotlib
  40. #matplotlib.use("Qt5Agg")
  41. import matplotlib.pyplot as plt
  42. from tifffile import imread, imwrite
  43. from skimage import io
  44. import sys
  45. from matplotlib.widgets import Button
  46. import warnings
  47. from qtpy.QtWidgets import QApplication, QWidget, QLineEdit, QLabel,QPushButton, QProgressBar, QMessageBox, QCheckBox
  48. from qtpy.QtGui import QFont
  49. from qtpy import QtCore
  50. from matplotlib.widgets import RectangleSelector
  51. np.seterr(divide='ignore', invalid='ignore')
  52. from IPython import get_ipython
  53. #get_ipython().run_line_magic('matplotlib', 'inline')
  54. import glob
  55. import time
  56. from silx.image import sift
  57. import silx
  58. import math
  59. from numpy import where
  60. import datetime
  61. from math import sqrt
  62. import glob
  63. import os
  64. import keyboard
  65. from scipy.optimize import curve_fit
  66. import cv2
  67. from PyQt5 import QtWidgets, uic
  68. from pymmcore_plus import CMMCorePlus
  69. from qtpy.QtWidgets import QApplication, QGroupBox, QHBoxLayout, QBoxLayout, QWidget,QGridLayout
  70. from pymmcore_widgets import ExposureWidget
  71. get_ipython().run_line_magic('matplotlib', 'qt5')
  72. ############ ****************
  73. ######### *** !!! ***
  74. # Here I am addind the folder with required functions file and then importing *-everything from this file
  75. # if you want to specify the function that will be imported you need to write the function name intead of *
  76. sys.path.append("Z:\Hanna\CODE")
  77. from functions import *
  78. ############ ****************
  79. ######### *** !!! ***
  80. pathMM = "C:\Program Files\Micro-Manager-2.0_NB" ## path to Micromanager folder on the computer
  81. config = "Phasics_dis_coller_Ni.cfg" ## name of configuration file. Need to be created in MicroManager
  82. # before starting this soft, NikonTi and Phasics camera need to be in devices
  83. #pymmcore.CMMCore().getAPIVersionInfo()
  84. mmc = CMMCorePlus() ## initialisation of MicroManager core
  85. mmc.setDeviceAdapterSearchPaths([pathMM]) ## looking for device adapters
  86. mmc.loadSystemConfiguration(os.path.join(pathMM, config)) # Loading configuration
  87. ############ ****************
  88. ######### *** !!! ***
  89. ## As in our study we used QLSI module i.e. Phasics (Andor) camera, there is the requirement to turn off the sensor cooling
  90. print('The cooling of camera sensor is :', mmc.getProperty("Andor sCMOS Camera", "SensorCooling")) ##checking if the cooler is off
  91. mmc.waitForDevice('TIDiaLamp') ## The lamp of Nikon Ti can take time to turn on so we need to wait a bit
  92. mmc.setAutoShutter(False) ##
  93. ############ ****************
  94. ######### *** !!! ***
  95. lamp = str('TIDiaLamp')
  96. #mmc.getProperty(lamp, "ComputerControl")
  97. mmc.setProperty(lamp, "ComputerControl", "On") ### preparing the lamp of Nikon microscope
  98. mmc.setProperty(lamp, "Intensity", 4)
  99. mmc.setProperty(lamp, "State", 1)
  100. Zstage = mmc.getFocusDevice() # giving the name to the zdrive
  101. exposure = mmc.getExposure()
  102. pos0 = mmc.getPosition(Zstage) # getting current position
  103. mmc.setROI(500,500 ,1500, 1500) #for Phasics camera it is required to make the roi
  104. mmc.snapImage() # The camera gets the image to have it in the bufffer for further use
  105. #######
  106. ## In this part I define all the functios that will be used in the gui
  107. viewer = napari.Viewer() ## opening napari viewer
  108. exposure = 10 ## the deaful value of exposure time
  109. center1_x,center1_y,center2_x,center2_y = 1005, 320, 1170, 1003 # the positions of harmonics of the fourier transform of 1500*1500 image
  110. #textBrow.append("Initialization Done")
  111. global pathth
  112. def start_live(): ## function to start live\ show images in real time
  113. textBrow.append("Live is running, to stop/close the window press 'q'")
  114. while (True):
  115. mmc.snapImage()
  116. frame = mmc.getImage()
  117. gray = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
  118. gray = cv2.resize(gray, (700, 700)) ## to resize the window (otherwise can be bigger than screen)
  119. cv2.imshow('frame', gray)
  120. cv2.setWindowTitle("frame", "Pres q to quit")
  121. if cv2.waitKey(1) & 0xFF == ord('q'):
  122. break
  123. cv2.destroyAllWindows()
  124. def set_exposure(): ## The function to set new exposure time from input field in the gui
  125. expos = int(lineExp.text()) ## reading the value from the input field line
  126. mmc.setExposure(expos) ## seting exposure time
  127. global exposure
  128. exposure = mmc.getExposure() ## reading exposure from MicroManager to be sure thet it was set
  129. textBrow.append("Exposure time was set to : "+str(exposure))
  130. return exposure
  131. def set_lamp_int(): # the function to set lamp intensity to value entered into corresponding line in gui
  132. global ints # intensity value set to be global. Allows to access it from other functions
  133. ints = int(lineLamp.text()) # reading value from the input line
  134. mmc.setProperty(lamp, "Intensity", ints) # the intensity set to lamp
  135. textBrow.append("Nikon lamp intensity was set to "+str(ints))
  136. return ints
  137. def Lamp_on(): ## the function to turn On the microscope Lamp
  138. mmc.setProperty(lamp, "State", 1)
  139. def Lamp_off(): ## the function to turn Off microscope Lamp
  140. mmc.setProperty(lamp, "State", 0)
  141. def set_z_pos(): # the function to move z drive
  142. pos0 = mmc.getPosition(Zstage) # getting current position
  143. pos = np.float32(lineZpos.text()) # reading desired value of movement from gui line
  144. print("pos = ", pos)
  145. mmc.setPosition(Zstage, pos+pos0)
  146. mmc.waitForDevice(Zstage)
  147. textBrow.append("the position of z-drive is set to = "+str(mmc.getPosition(Zstage)))
  148. global R
  149. def reference_image():
  150. global reference
  151. start = time.time()
  152. textBrow.append("Starting refererence aquisition")
  153. progressBar.resetFormat() ## progress bar shows nothing at the begining
  154. try: ### To check if path to folder was defined
  155. pathth
  156. except NameError: # in case if path was not defined before it will be read from line in the gui
  157. pathth = linePath.text()
  158. if os.path.isdir(pathth) == False: ## if path do not exist the error message will pop up
  159. textBrow.append("Path does not exists, try again")
  160. return
  161. else:
  162. with open(pathth + '\\METADATA.txt', 'a') as file: ## opening the Metadata file, if file do not exists it will be created automaticaly
  163. file.write('Ref recorded at: %s\n Exposure: %s\n Lamp: %s\n' %(datetime.datetime.now(), exposure, ints))
  164. im =[]
  165. n_of_im = int(lineRef.text()) ## reading the number of images to acquire from corresponding input field
  166. c = 100/n_of_im
  167. mmc.startSequenceAcquisition(n_of_im, 0, True)
  168. i=0
  169. while mmc.isSequenceRunning():
  170. if mmc.getRemainingImageCount() != 0:
  171. image_and_MD_raw = mmc.popNextImageAndMD(fix = False)
  172. image_and_MD = np.asarray([image_and_MD_raw[0], image_and_MD_raw[1].json()], dtype=object)
  173. im.append(image_and_MD[0])
  174. progressBar.setValue(int(i*c))
  175. i=i+1
  176. ref = np.mean(np.asarray(im), axis=0)
  177. viewer.add_image(ref, name='Reference image')
  178. R = ref.shape[0] // 6
  179. #start = time.time()
  180. xm, ym = np.meshgrid(np.arange(ref.shape[1]), np.arange(ref.shape[0]))
  181. mask_x = np.sqrt((xm - center1_x)**2 + (ym - center1_y)**2) <= R
  182. mask_y = np.sqrt((xm - center2_x)**2 + (ym - center2_y)**2) <= R
  183. fourier_ref = fft.fftshift(fft.fft2(ref, norm="ortho")).astype(np.complex64)
  184. Ix_ref = fft.ifft2(fftpack.fftshift((fourier_ref) * mask_x))
  185. Iy_ref = fft.ifft2(fftpack.fftshift((fourier_ref) * mask_y))
  186. reference = np.stack((ref, mask_x, mask_y, Ix_ref, Iy_ref))
  187. np.save(file_name_check(pathth + '\\ref.npy'), reference.reshape(5*ref.shape[0], ref.shape[1]))
  188. textBrow.append('The obtained images were saved under the name ref.tif')
  189. #return image_ref
  190. textBrow.append('time:' +str(time.time()-start))
  191. with open(pathth + '\\METADATA.txt', 'a') as file:
  192. file.write('The number of images avaraged for reference: %s\n' %n_of_im)
  193. textBrow.append("Done")
  194. return
  195. def stack_acquisition(): # the function to perform the acqusition without autofocusing
  196. progressBar.resetFormat()
  197. try:
  198. pathth
  199. except NameError:
  200. pathth = linePath.text()
  201. if os.path.isdir(pathth) == False:
  202. textBrow.append("Path does not exists, try again")
  203. return
  204. else:
  205. im =[]
  206. stack = []
  207. nIm = int(line_acq.text())
  208. if line_nIm.text() =='':
  209. nImAv = 10
  210. else:
  211. nImAv = int(line_nIm.text())
  212. c = 100/(nIm*nImAv)
  213. mmc.startSequenceAcquisition(nIm*nImAv, 0, True)
  214. i=0
  215. while mmc.isSequenceRunning():
  216. if mmc.getRemainingImageCount() != 0:
  217. image_and_MD_raw = mmc.popNextImageAndMD(fix = False)
  218. image_and_MD = np.asarray([image_and_MD_raw[0], image_and_MD_raw[1].json()], dtype=object)
  219. im.append(image_and_MD[0])
  220. i=i+1
  221. progressBar.setValue(int(i*c))
  222. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  223. textBrow.append("Interrupted by user")
  224. break
  225. if keyboard.is_pressed('s'): # Check if 'q' is pressed
  226. textBrow.append("Interrupted by user, the data will be saved")
  227. images = np.asarray(im)
  228. Stack = np.asarray([np.mean(images[i:i+nImAv], axis=0) for i in range(0, len(images), nImAv)])
  229. textBrow.append("Saving the data...")
  230. save_path = file_name_check(pathth + '\\Stack.tif')
  231. _, tail = os.path.split(save_path)
  232. imwrite(save_path, Stack.astype(np.float16))
  233. textBrow.append("Done")
  234. break
  235. images = np.asarray(im)
  236. Stack = np.asarray([np.mean(images[i:i+nImAv], axis=0) for i in range(0, len(images), nImAv)])
  237. progressBar.setFormat("Saving")
  238. save_path = file_name_check(pathth + '\\Stack.tif')
  239. _, tail = os.path.split(save_path)
  240. imwrite(save_path, Stack.astype(np.float16))
  241. textBrow.append('The obtained images were saved under the name ' +srt(tail))
  242. textBrow.append("Done")
  243. #global zInt
  244. def zStack():
  245. global reference
  246. progressBar.resetFormat()
  247. start = time.time()
  248. try: ### To check if path to folder was defined
  249. pathth
  250. except NameError: # in case if path was not defined before the path will be read from line in the gui
  251. pathth = linePath.text()
  252. if os.path.isdir(pathth) == False: ## if path do not exist the error message will pop up
  253. textBrow.append("Path does not exists, try again")
  254. return
  255. else:
  256. if 'reference' not in globals():
  257. print('reading zGradients from disk')
  258. list_of_files = glob.glob(os.path.normpath(pathth+ '\\*'))
  259. refpath = os.path.normpath(max([file for file in list_of_files if 'ref' in file], key=os.path.getmtime))
  260. reference = np.load(refpath)
  261. reference = reference.reshape(5, int(reference.shape[0]/5), reference.shape[1])
  262. ref = reference[0].real
  263. Zstage = mmc.getFocusDevice()
  264. if line_start.text() =='':
  265. start_pos = -1.5
  266. else:
  267. start_pos = np.float32(line_start.text())
  268. if line_stop.text() =='':
  269. stop_pos = 1.5
  270. else:
  271. stop_pos = np.float32(line_stop.text())
  272. if line_step.text() =='':
  273. step = 0.05
  274. else:
  275. step = np.float32(line_step.text())
  276. pos0 = mmc.getPosition(Zstage)
  277. print("0 position : ", pos0)
  278. if line_nIm.text() =='':
  279. nIm = 10
  280. else:
  281. nIm = int(line_nIm.text())
  282. start_pos = start_pos+pos0
  283. stop_pos = stop_pos + pos0 #+ step
  284. print("start:", start_pos, "stop: ", stop_pos, "step :", step)
  285. mmc.snapImage()
  286. length = len(np.arange(start_pos, stop_pos, step))
  287. print(length)
  288. c = 100/length
  289. frame = 0
  290. posR = []
  291. stack=[]
  292. with open(pathth + '\\METADATA.txt', 'a') as file:
  293. file.write('zStack recorded at %s\n zStack \n start:%s\n end: %s\n step %s\n N of averaged images %s\n Exposure: %s\n Lamp: %s\n' %(datetime.datetime.now(), start_pos, stop_pos, step, nIm, exposure, ints))
  294. for pos in np.arange(start_pos, stop_pos, step):
  295. textBrow.append("pos = "+str(pos))
  296. mmc.setPosition(Zstage, pos)
  297. mmc.waitForDevice(Zstage)
  298. mmc.startSequenceAcquisition(nIm, 0, True)
  299. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  300. textBrow.append("Interrupted by user")
  301. break
  302. while mmc.isSequenceRunning():
  303. if mmc.getRemainingImageCount() != 0:
  304. image_and_MD_raw = mmc.popNextImageAndMD(fix = False)
  305. image_and_MD = np.asarray([image_and_MD_raw[0], image_and_MD_raw[1].json()], dtype=object)
  306. stack.append(image_and_MD[0])
  307. textBrow.append("pos read = "+str(mmc.getPosition(Zstage)))
  308. posR.append(mmc.getPosition(Zstage))
  309. frame = frame + 1
  310. progressBar.setValue(int(frame*c))
  311. textBrow.append('Saving, it took:'+str(time.time()-start))
  312. z_Stack = np.asarray([np.mean(stack[i:i+nIm], axis=0) for i in range(0, len(stack), nIm)])
  313. #viewer.add_image(z_Stack, name = 'z Stack')
  314. global zGrads, zInt
  315. zGrads = grad_diff(z_Stack, reference[1], reference[2],reference[3],reference[4])
  316. viewer.add_image(zGrads, name = 'gradients z Stack')
  317. mmc.setPosition(Zstage, pos0)
  318. np.save(file_name_check(pathth + '\\zStackRaw.npy'), z_Stack.astype(np.float16).reshape(z_Stack.shape[0]*z_Stack.shape[1], z_Stack.shape[2]))
  319. zInt = intensity_image(z_Stack, ref, choose_coord=False)
  320. np.savetxt(file_name_check(pathth + '\\z_posRead.txt'), posR)
  321. textBrow.append('The obtained images were saved')
  322. progressBar.setFormat("Done")
  323. mmc.setPosition(Zstage, pos0)
  324. #viewer.add_image(phase_image(z_Stack[int(len(z_Stack)/2)], ref, choose_coord=False), name = 'Phase z Stack')
  325. print('Done', 'pos now = ', pos0, 'it took: ', time.time()-start )
  326. return zGrads
  327. def start_live_grad(): ## function to start live\ show images in real time
  328. try:
  329. reference
  330. except NameError:
  331. try:
  332. ref = imread(pathth+'\\ref.tif' )
  333. except:
  334. msgBox = QMessageBox()
  335. msgBox.setIcon(QMessageBox.Information)
  336. msgBox.setText("There is no reference")
  337. msgBox.setStandardButtons(QMessageBox.Ok)
  338. msgBox.exec_()
  339. while (True):
  340. mmc.snapImage()
  341. frame = mmc.getImage()
  342. diff = grad_diff(frame, mask_x, mask_y,Ix_ref,Iy_ref )
  343. gray = cv2.cvtColor(diff, cv2.COLOR_GRAY2BGR)
  344. gray = cv2.resize(gray, (1000, 1000)) ## to resize the window (otherwise can be bigger than screen)
  345. cv2.imshow('frame', gray)
  346. cv2.setWindowTitle("frame", "Pres q to quit")
  347. mmc.sleep(exposure)
  348. if cv2.waitKey(1) & 0xFF == ord('q'):
  349. break
  350. cv2.destroyAllWindows()
  351. def check_max():
  352. mmc.snapImage()
  353. image = mmc.getImage()
  354. textBrow.append("The maaximum value on the image is "+str(image.max()))
  355. def test_z_stack():
  356. global reference
  357. progressBar.resetFormat()
  358. start = time.time()
  359. textBrow.append("Starting zStack acquisition")
  360. try: ### To check if path to folder was defined
  361. pathth
  362. except NameError: # in case if path was not defined before the path will be read from line in the gui
  363. pathth = linePath.text()
  364. if os.path.isdir(pathth) == False: ## if path do not exist the error message will pop up
  365. textBrow.append("Path does not exists, try again")
  366. return
  367. else:
  368. if 'reference' not in globals():
  369. textBrow.append('reading ref from disk')
  370. list_of_files = glob.glob(os.path.normpath(pathth+ '\\*'))
  371. refpath = os.path.normpath(max([file for file in list_of_files if 'ref' in file], key=os.path.getmtime))
  372. reference = np.load(refpath)
  373. reference = reference.reshape(5, int(reference.shape[0]/5), reference.shape[1])
  374. ref = reference[0].real
  375. Zstage = mmc.getFocusDevice()
  376. if line_start.text() =='': # if the value is not specified in GUI, the default one will be used
  377. start_pos = -1.5
  378. else:
  379. start_pos = np.float32(line_start.text())
  380. if line_stop.text() =='':
  381. stop_pos = 1.5
  382. else:
  383. stop_pos = np.float32(line_stop.text())
  384. if line_step.text() =='':
  385. step = 0.05
  386. else:
  387. step = np.float32(line_step.text())
  388. pos0 = mmc.getPosition(Zstage)
  389. textBrow.append("0 position : "+str(pos0))
  390. if line_nIm.text() =='':
  391. nIm = 8
  392. else:
  393. nIm = int(line_nIm.text())
  394. start_pos = start_pos+pos0
  395. stop_pos = stop_pos + pos0
  396. textBrow.append("start:"+str(start_pos)+"stop: "+str(stop_pos)+ "step :"+str(step))
  397. mmc.snapImage()
  398. length = len(np.arange(start_pos, stop_pos, step))
  399. textBrow.append(str(length)+"of zStack")
  400. c = 100/length
  401. frame = 0
  402. posR = []
  403. stack=[]
  404. with open(pathth + '\\METADATA.txt', 'a') as file:
  405. file.write('zStack recorded at %s\n zStack \n start:%s\n end: %s\n step %s\n N of averaged images %s\n Exposure: %s\n Lamp: %s\n' %(datetime.datetime.now(), start_pos, stop_pos, step, nIm, exposure, ints))
  406. pos_list = []
  407. pos=start_pos
  408. rpos = pos-pos0
  409. while rpos < stop_pos-pos0:
  410. pos_list.append(pos)
  411. if (rpos>-0.4) and (rpos <0.4):
  412. print('step = 0.05:' , pos)
  413. pos=pos+step
  414. elif (rpos<-0.4)or(rpos>0.4):
  415. print('step = 0.2', pos)
  416. pos=pos+0.2
  417. elif (rpos<-0.4)or(rpos>0.4):
  418. print('step = 0.2', pos)
  419. pos=pos+0.2
  420. rpos=pos-pos0
  421. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  422. textBrow.append("Interrupted by user")
  423. break
  424. textBrow.append("pos = "+str(pos))
  425. mmc.setPosition(Zstage, pos)
  426. mmc.waitForDevice(Zstage)
  427. mmc.startSequenceAcquisition(nIm, 0, True)
  428. while mmc.isSequenceRunning():
  429. if mmc.getRemainingImageCount() != 0:
  430. image_and_MD_raw = mmc.popNextImageAndMD(fix = False)
  431. image_and_MD = np.asarray([image_and_MD_raw[0], image_and_MD_raw[1].json()], dtype=object)
  432. stack.append(image_and_MD[0])
  433. textBrow.append("pos read = "+str(mmc.getPosition(Zstage)))
  434. posR.append(mmc.getPosition(Zstage))
  435. frame = frame + 1
  436. progressBar.setValue(int(frame*c))
  437. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  438. textBrow.append("Interrupted by user")
  439. break
  440. z_Stack = np.asarray([np.mean(stack[i:i+nIm], axis=0) for i in range(0, len(stack), nIm)])
  441. mmc.setPosition(Zstage, pos0)
  442. ##################################### To Rytov/Intensity part
  443. textBrow.append('acquired'+str(time.time()-start))
  444. #zInt = intensity_image(z_Stack, ref, choose_coord=False)
  445. global zGrads, zInt
  446. zGrads = grad_diff(z_Stack, reference[1], reference[2],reference[3],reference[4])
  447. viewer.add_image(zGrads, name = 'grqdients z Stack')
  448. textBrow.append('stacks done'+str( time.time()-start))
  449. textBrow.append("Saving the data ...")
  450. mmc.setPosition(Zstage, pos0)
  451. np.save(file_name_check(pathth + '\\zStackRaw.npy'), z_Stack.astype(np.float16).reshape(z_Stack.shape[0]*z_Stack.shape[1], z_Stack.shape[2]))
  452. zInt = intensity_image(z_Stack, ref, choose_coord=False)
  453. np.savetxt(file_name_check(pathth + '\\z_posRead.txt'), posR)
  454. textBrow.append('Done, pos now = '+str(pos0)+'time = '+str(time.time()-start))
  455. msgBox = QMessageBox()
  456. msgBox.setText('The obtained images were saved')
  457. msgBox.exec_()
  458. progressBar.setFormat("Done")
  459. mmc.setPosition(Zstage, pos0)
  460. viewer.add_image(phase_image(z_Stack[int(len(z_Stack)/2)], ref, choose_coord=False), name = 'Example of phase image from z Stack')
  461. def acquisition_calib_grad(): ## the function to perform autofocusing with gradient images
  462. progressBar.resetFormat() ##
  463. textBrow.append("Starting acquisition with autofocusing using Gradient images") #message to GUI window
  464. try: ### To check if path to folder was defined
  465. pathth
  466. except NameError: # in case if path was not defined before the path will be read from line in the gui
  467. pathth = linePath.text()
  468. if os.path.isdir(pathth) == False: ## if path do not exist the error message is shown
  469. textBrow.append("Path does not exists, try again") # message to GUI wimdow
  470. list_of_files = glob.glob(os.path.normpath(pathth+ '\\*')) # list of files in folder
  471. refpath = os.path.normpath(max([file for file in list_of_files if 'ref' in file], key=os.path.getmtime)) # looking for the last file with name containing 'ref'
  472. reference = np.load(refpath) # saving path to last ref file
  473. Reference = reference.reshape(5, int(reference.shape[0]/5), reference.shape[1]) # geting ref image frm ref file
  474. ref = Reference[0].real # .real because ref can be saved in complex format
  475. mask_x = Reference[1]
  476. mask_y = Reference[2]
  477. Ix_ref = Reference[3]
  478. Iy_ref = Reference[4]
  479. Gradpath = os.path.normpath(max([file for file in list_of_files if 'zStack' in file], key=os.path.getmtime)) # geting path to last gradients zStack
  480. _, tail = os.path.split(Gradpath)
  481. if 'zGrads' not in globals(): # checking if Gradients z Stack was saved in global values, if no read from disk
  482. textBrow.append('reading zGradients from disk')
  483. zImage = np.load(Gradpath)
  484. zImage = zImage.reshape(int(zImage.shape[0]/ref.shape[0]), ref.shape[0], ref.shape[1])
  485. zImage = grad_diff(zImage, Reference[1], Reference[2],Reference[3],Reference[4])
  486. else:
  487. zImage = zGrads
  488. textBrow.append('The start position'+str(mmc.getPosition(Zstage)))
  489. nIm = int(lineAcqCalibNbI.text()) # getting the numebr of images to acquire from GUI
  490. nImAv = 8 #int(line_nImAcq.text())
  491. if lineFitDegree.text() =='': # if degree was not specified it will be set to 12
  492. degree = 12# = 10
  493. else:
  494. degree = int(lineFitDegree.text()) # the values will be used if specified in GUI
  495. frequency = int(lineAcqCalibFr.text()) # getting frequency of refocusing from GUI
  496. Stack = np.zeros((nIm, int(mmc.getImage().shape[0]), int(mmc.getImage().shape[1]))) # empty array where images will be added
  497. posPath = os.path.normpath(max([file for file in list_of_files if '_posRead' in file], key=os.path.getmtime))
  498. poslist = np.loadtxt(posPath)
  499. cfr = 1
  500. drft = []
  501. posN=[]
  502. micPos=[]
  503. poslist = poslist-poslist.min()
  504. x = poslist-poslist[int(len(poslist)/2)]
  505. xx = np.arange(x.min(), x.max(), 0.001)
  506. frame = int(len(zImage)/2)
  507. sift_ocl = silx.image.sift.SiftPlan(template=zImage[frame], devicetype="GPU") # zImage[frame] will be used as template for xy correction
  508. keypoints = sift_ocl(zImage[frame]) #looking for keypoints on the image
  509. mp = sift.MatchPlan()
  510. # creating the figure where the calculated drift values will be displayed
  511. plt.ion()
  512. xg = np.linspace(0, nIm, nIm)
  513. yg = np.arange(-1.5, 1.5, 3/nIm)
  514. fig = plt.figure()
  515. ax = fig.add_subplot(111)
  516. line1, = ax.plot(xg, yg, 'b+:')
  517. plt.xlabel("Refocusing step")
  518. plt.ylabel("Drift, μm")
  519. plt.title("Updating plot...")
  520. yyg = np.zeros(nIm)
  521. yyg[:]= np.nan
  522. yygg = np.zeros(nIm)
  523. yygg[:]= np.nan
  524. k=0
  525. # creating the figure where the values read from z-drive will be displayed
  526. plt.ion()
  527. fig2 = plt.figure()
  528. ax2 = fig2.add_subplot(111)
  529. line2, = ax2.plot(x, np.linspace(0, 0.0005, len(zImage)), 'b+:')
  530. line3, = ax2.plot(x, np.linspace(0, 0.0005, len(zImage)), 'r')
  531. plt.xlabel("Refocusing step")
  532. plt.ylabel("CCC, μm")
  533. plt.title("Updating plot...")
  534. progressBar.setValue(0)
  535. c = 100/nIm
  536. for i in range(0, nIm): # starting the main loop of acquisition with autofocusing
  537. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  538. textBrow.append("Interrupted by user")
  539. break
  540. if keyboard.is_pressed('s'): # Check if 's' is pressed if yes the process is interupted while saving the data
  541. textBrow.append("Interrupted by user, the data will be saved")
  542. np.savetxt(file_name_check(pathth+'/detectedDrift_grad_interupted_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  543. progressBar.setFormat("Done, interupted")
  544. np.save(file_name_check(pathth + '\\Stack_autofocus_grad_interupted_z'+tail[-5]+'.npy'), Stack.astype(np.float16).reshape(Stack.shape[0]*Stack.shape[1], Stack.shape[2]))
  545. textBrow.append("Done")
  546. break
  547. mmc.snapImage() # getting the image from camera
  548. stack = np.zeros((nImAv, int(mmc.getImage().shape[0]), int(mmc.getImage().shape[1]))) # images will be stored to stack
  549. for n in range(0, nImAv): # getting 10 images to avarage
  550. mmc.snapImage()
  551. stack[n] = mmc.getImage()
  552. st = np.mean(stack, axis=0) # getting mean value of images
  553. Stack[i] = st # mean image stored in Stack
  554. ###############################
  555. if (i % frequency == 0) == True: # when the frequency matches the value specified in GUI do autofocusing
  556. if lineFitDegree.text() =='': # checking if degree of fit was changed in GUI
  557. degree = 12# = 10
  558. else:
  559. degree = int(lineFitDegree.text())
  560. corrcoef = []
  561. pos = mmc.getPosition(Zstage) # current position of z-drive
  562. start = time.time() # getting current time
  563. imm = grad_diff(Stack[i], mask_x, mask_y,Ix_ref,Iy_ref) # calculation of gradient image
  564. ### Shift correction
  565. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  566. textBrow.append("Interrupted by user")
  567. break
  568. try:
  569. im_keypoints = sift_ocl(imm.astype(np.float32)) # looking for keyposint on the new image
  570. match = mp(keypoints, im_keypoints) # looking for maching keyposint
  571. sa = silx.image.sift.LinearAlign(zImage[frame], devicetype="GPU") # xy-drift numerical correction
  572. im = sa.align(imm, shift_only=True)
  573. except: # if something went wrong the process is interupted and data is saved
  574. np.savetxt(file_name_check(pathth+'/detectedDrift_grad_err1_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  575. textBrow.append("Done, data saved after xy-drfit correction didn't work")
  576. imwrite(file_name_check(pathth + '\\Stack_autofocus_grad_err1_z'+tail[-5]+'.tif', Stack.astype(np.float16)))
  577. with open(pathth + '\\METADATA.txt', 'a') as file:
  578. file.write('Aqqusition with autofocus recorded FAIL xy correction at %s\n N of images %s \n frequency:%s\n Exposure: %s\n Lamp: %s\n degree: %s\n ' %(datetime.datetime.now(), nIm, frequency, exposure, ints, degree))
  579. textBrow.append('xy correction failed, data was saved')
  580. break
  581. ######################
  582. for f in range(0, len(zImage)): # loop to run through all images in zStack and calculate cross-correlation coeficients (CCC)
  583. try:
  584. corrcoef.append(ncc(im[200:1300, 200:1300], zImage[f,200:1300, 200:1300])) ##
  585. except: # if something went wrong interupt with saving data
  586. np.savetxt(file_name_check(pathth+'/detectedDrift_grad_err2_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  587. textBrow.append("Done, data saved after xy-drfit correction didn't work")
  588. imwrite(file_name_check(pathth + '\\Stack_autofocus_grad_err2_z'+tail[-5]+'.tif'), Stack.astype(np.float16))
  589. with open(pathth + '\\METADATA.txt', 'a') as file:
  590. file.write('Aqqusition with autofocus recorded FAIL correlation at %s\n N of images %s \n frequency:%s\n Exposure: %s\n Lamp: %s\n degree: %s\n ' %(datetime.datetime.now(), nIm, frequency, exposure, ints, degree))
  591. textBrow.append('correlation failed, data was saved')
  592. break
  593. y = np.array(corrcoef)
  594. model2 = np.poly1d(np.polyfit(x, y, degree)) # fitting the cross-correlation curve
  595. drft.append(xx[where(model2(xx) == model2(xx).max())]) # the calculated drift stored into 'drft' list
  596. i=i+1
  597. yyg[i] = drft[-1][0] # updayting the value on the figure
  598. line1.set_ydata(yyg)
  599. k = k+1
  600. fig.canvas.draw()
  601. fig.canvas.flush_events()
  602. ax2.set_ylim(y.min()-y.min()*0.1, y.max()+y.max()*0.1)
  603. line2.set_ydata(y)
  604. line3.set_ydata(model2(x))
  605. fig2.canvas.draw()
  606. fig2.canvas.flush_events()
  607. textBrow.append('newvalue'+str(drft[-1])) # message to GIU with the last value of drift calculated
  608. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  609. textBrow.append("Interrupted by user")
  610. break
  611. micPos.append(mmc.getPosition(Zstage)) # reading current position of z-drive and storing into list
  612. if keyboard.is_pressed('s'): # Check if 'q' is pressed
  613. textBrow.append("Interrupted by user, the data will be saved")
  614. np.savetxt(file_name_check(pathth+'/detectedDrift_grad_interupted_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  615. progressBar.setFormat("Done, interupted")
  616. np.save(file_name_check(pathth + '\\Stack_autofocus_grad_interupted_z'+tail[-5]+'.npy'), Stack.astype(np.float16).reshape(Stack.shape[0]*Stack.shape[1], Stack.shape[2]))
  617. break
  618. if (np.abs(drft[-1]) < 0.010): # if the drift was smaller then 10 nm corresction is not performed to avoid werd behavious of z-drive
  619. textBrow.append('drift was smaller then 10 nm no correction is done')
  620. continue
  621. mmc.setPosition(Zstage, pos-drft[-1][0]) # the new position (corrected one) is set to z-drive
  622. mmc.waitForDevice(Zstage) # to ensure that z-drive finisehd movement
  623. cfr = cfr+1
  624. textBrow.append("calibration, detected drift = "+str(drft[-1])+'the drift was = '+str(pos-drft[-1])+'microscope reply = '+str(mmc.getPosition(Zstage))+'it took '+str(time.time()-start)+'to refocus')
  625. progressBar.setValue(int(i*c))
  626. plt.figure() # after acquisition is finished the last cross-correlation curve and fit are displayed
  627. plt.plot(xx, model2(xx))
  628. plt.plot(x, y)
  629. plt.figure()
  630. plt.plot(micPos)
  631. plt.show()
  632. np.savetxt(file_name_check(pathth+'/detectedDrift_grad_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  633. textBrow.append("Done")
  634. np.save(file_name_check(pathth + '\\Stack_autofocus_grad_z'+tail[-5]+'.npy'), Stack.astype(np.float16).reshape(Stack.shape[0]*Stack.shape[1], Stack.shape[2]))
  635. with open(pathth + '\\METADATA.txt', 'a') as file:
  636. file.write('Aqqusition with autofocus recorded at %s\n N of images %s \n frequency:%s\n Exposure: %s\n Lamp: %s\n degree: %s\n' %(datetime.datetime.now(), nIm, frequency, exposure, ints, degree))
  637. def acquisition_calib_int():
  638. progressBar.resetFormat()
  639. textBrow.append("Starting acquisition with active autofocusing using Intensity images")
  640. try: ### To check if path to folder was defined
  641. pathth
  642. except NameError: # in case if path was not defined before the path will be read from line in the gui
  643. pathth = linePath.text()
  644. if os.path.isdir(pathth) == False: ## if path do not exist the error message will pop up
  645. textBrow.append("Path does not exists, try again")
  646. list_of_files = glob.glob(os.path.normpath(pathth+ '\\*'))
  647. if 'reference' not in globals():
  648. textBrow.append('reading reference from drive')
  649. refpath = os.path.normpath(max([file for file in list_of_files if 'ref' in file], key=os.path.getmtime))
  650. reference = np.load(refpath)
  651. reference = reference.reshape(5, int(reference.shape[0]/5), reference.shape[1])
  652. else:
  653. reference
  654. Reference = reference
  655. ref = Reference[0].real
  656. mask_x = Reference[1]
  657. mask_y = Reference[2]
  658. Ix_ref = Reference[3]
  659. Iy_ref = Reference[4]
  660. Gradpath = os.path.normpath(max([file for file in list_of_files if 'zStack' in file], key=os.path.getmtime))
  661. _, tail = os.path.split(Gradpath)
  662. if 'zInt' not in globals():
  663. textBrow.append('reading zGradients from disk')
  664. zImage = np.load(Gradpath)
  665. zImage = zImage.reshape(int(zImage.shape[0]/ref.shape[0]), ref.shape[0], ref.shape[1])
  666. zImage = intensity_image(zImage, ref, choose_coord=False)
  667. else:
  668. zImage = zInt
  669. textBrow.append('The start position'+str(mmc.getPosition(Zstage)))
  670. nIm = int(lineAcqCalibNbI.text())
  671. nImAv = 10
  672. if lineFitDegree.text() =='':
  673. degree = 12# = 10
  674. else:
  675. degree = int(lineFitDegree.text())
  676. frequency = int(lineAcqCalibFr.text())
  677. Stack = np.zeros((nIm, int(mmc.getImage().shape[0]), int(mmc.getImage().shape[1])))
  678. posPath = os.path.normpath(max([file for file in list_of_files if '_posRead' in file], key=os.path.getmtime))
  679. poslist = np.loadtxt(posPath)
  680. cfr = 1
  681. drft = []
  682. posN=[]
  683. micPos=[]
  684. poslist = poslist-poslist.min()
  685. x = poslist-poslist[int(len(poslist)/2)]
  686. xx = np.arange(x.min(), x.max(), 0.001)
  687. frame = int(len(zImage)/2)
  688. sift_ocl = silx.image.sift.SiftPlan(template=zImage[frame], devicetype="GPU")
  689. keypoints = sift_ocl(zImage[frame])
  690. mp = sift.MatchPlan()
  691. plt.ion()
  692. xg = np.linspace(0, nIm, nIm)
  693. yg = np.arange(-1.5, 1.5, 3/nIm)
  694. fig = plt.figure()
  695. ax = fig.add_subplot(111)
  696. line1, = ax.plot(xg, yg, 'b+:')
  697. plt.xlabel("Refocusing step")
  698. plt.ylabel("Drift, μm")
  699. plt.title("Updating plot...")
  700. yyg = np.zeros(nIm)
  701. yyg[:]= np.nan
  702. yygg = np.zeros(nIm)
  703. yygg[:]= np.nan
  704. k=0
  705. plt.ion()
  706. fig2 = plt.figure()
  707. ax2 = fig2.add_subplot(111)
  708. line2, = ax2.plot(x, np.linspace(0, 0.0005, len(zImage)), 'b+:')
  709. line3, = ax2.plot(x, np.linspace(0, 0.0005, len(zImage)), 'r')
  710. plt.xlabel("Refocusing step")
  711. plt.ylabel("CCC, μm")
  712. plt.title("Updating plot...")
  713. progressBar.setValue(0)
  714. c = 100/nIm
  715. for i in range(0, nIm):
  716. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  717. textBrow.append("Interrupted by user")
  718. break
  719. mmc.snapImage()
  720. stack = np.zeros((nImAv, int(mmc.getImage().shape[0]), int(mmc.getImage().shape[1])))
  721. for n in range(0, nImAv):
  722. mmc.snapImage()
  723. stack[n] = mmc.getImage()
  724. st = np.mean(stack, axis=0)
  725. Stack[i] = st
  726. ###############################
  727. if (i % frequency == 0) == True:
  728. ###############################
  729. if lineFitDegree.text() =='':
  730. degree = 12
  731. else:
  732. degree = int(lineFitDegree.text())
  733. corrcoef = []
  734. pos = mmc.getPosition(Zstage)
  735. start = time.time()
  736. imageInt = intensity_image(Stack[i], ref, choose_coord = False)
  737. ### Shift correction
  738. try:
  739. im_keypoints = sift_ocl(imageInt.astype(np.float32))
  740. match = mp(keypoints, im_keypoints)
  741. sa = silx.image.sift.LinearAlign(zImage[frame], devicetype="GPU")
  742. im = sa.align(imageInt, shift_only=True)
  743. except:
  744. np.savetxt(file_name_check(pathth+'/detectedDrift_int_err1_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  745. imwrite(file_name_check(pathth + '\\Stack_autofocus_int_err1_z'+tail[-5]+'.tif', Stack.astype(np.float16)))
  746. with open(pathth + '\\METADATA.txt', 'a') as file:
  747. file.write('Finished with xy drift correction error, aqusition with autofocus recorded at %s\n N of images %s \n frequency:%s\n Exposure: %s\n Lamp: %s\n degree: %s\n ' %(datetime.datetime.now(), nIm, frequency, exposure, ints, degree))
  748. textBrow.append('xy correction failed, data was saved')
  749. break
  750. ######################
  751. for f in range(0, len(zImage)):
  752. try:
  753. corrcoef.append(ncc(im[200:1300, 200:1300], zImage[f,200:1300, 200:1300]))
  754. except:
  755. np.savetxt(file_name_check(pathth+'/detectedDrift_grad_err2_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  756. textBrow.append("Done, data saved after xy-drfit correction didn't work")
  757. imwrite(file_name_check(pathth + '\\Stack_autofocus_grad_err2_z'+tail[-5]+'.tif'), Stack.astype(np.float16))
  758. with open(pathth + '\\METADATA.txt', 'a') as file:
  759. file.write('Aqqusition with autofocus recorded FAIL correlation at %s\n N of images %s \n frequency:%s\n Exposure: %s\n Lamp: %s\n degree: %s\n ' %(datetime.datetime.now(), nIm, frequency, exposure, ints, degree))
  760. textBrow.append('xy correction failed, data was saved')
  761. break
  762. y = np.array(corrcoef)
  763. model2 = np.poly1d(np.polyfit(x, y, degree))
  764. drft.append(xx[where(model2(xx) == model2(xx).max())])
  765. i=i+1
  766. yyg[i] = drft[-1][0]
  767. line1.set_ydata(yyg)
  768. k = k+1
  769. fig.canvas.draw()
  770. fig.canvas.flush_events()
  771. ax2.set_ylim(y.min()-y.min()*0.1, y.max()+y.max()*0.1)
  772. line2.set_ydata(y)
  773. line3.set_ydata(model2(x))
  774. fig2.canvas.draw()
  775. fig2.canvas.flush_events()
  776. if keyboard.is_pressed('q'): # Check if 'q' is pressed
  777. textBrow.append("Interrupted by user")
  778. break
  779. textBrow.append('newvalue'+str(drft[-1]))
  780. micPos.append(mmc.getPosition(Zstage))
  781. if keyboard.is_pressed('s'): # Check if 'q' is pressed
  782. textBrow.append("Interrupted by user, the data will be saved")
  783. np.savetxt(file_name_check(pathth+'/detectedDrift_int_interupted_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  784. progressBar.setFormat("Done, interupted")
  785. np.save(file_name_check(pathth + '\\Stack_autofocus_int_interupted_z'+tail[-5]+'.npy'), Stack.astype(np.float16).reshape(Stack.shape[0]*Stack.shape[1], Stack.shape[2]))
  786. break
  787. if (np.abs(drft[-1]) < 0.010):
  788. print('drift was smaller then 10 nm')
  789. continue
  790. mmc.setPosition(Zstage, pos-drft[-1][0])
  791. mmc.waitForDevice(Zstage)
  792. cfr = cfr+1
  793. textBrow.append("calibration, detected drift = "+str(drft[-1])+'the drift was = '+str(pos-drft[-1])+'microscope reply = '+str(mmc.getPosition(Zstage))+'it took '+str(time.time()-start)+'to refocus')
  794. progressBar.setValue(int(i*c))
  795. plt.figure()
  796. #plt.plot(xx, model2(xx))
  797. plt.plot(x, y)
  798. plt.figure()
  799. plt.plot(micPos)
  800. plt.show()
  801. np.savetxt(file_name_check(pathth+'/detectedDrift_int_z'+tail[-5]+'.txt'), pd.concat([pd.DataFrame(drft), pd.DataFrame(micPos)], axis=1))
  802. textBrow.append("Done")
  803. np.save(file_name_check(pathth + '\\Stack_autofocus_int_z'+tail[-5]+'.npy'), Stack.astype(np.float16).reshape(Stack.shape[0]*Stack.shape[1], Stack.shape[2]))
  804. with open(pathth + '\\METADATA.txt', 'a') as file:
  805. file.write('Aqqusition with autofocus recorded at %s\n N of images %s \n frequency:%s\n Exposure: %s\n Lamp: %s\n degree: %s\n ' %(datetime.datetime.now(), nIm, frequency, exposure, ints, degree))
  806. ################################################################################################
  807. ################################################################################################
  808. ######################## Main window created by QtDesigner ################################
  809. ################################################################################################
  810. class Ui(QtWidgets.QMainWindow):
  811. def __init__(self):
  812. super(Ui, self).__init__()
  813. ui = uic.loadUi('Z:/Hanna/CODE/Autofocus_fArtcl/Autofocus.ui', self)
  814. global lineRef,lineLamp,line_name,lineExp,line_start,line_stop,line_step,linePath,line_nImAcq, lineZpos,lineDegree ## The global names are defined in order
  815. global line_nIm,progressBar,line_acq,linePhase,lineRoi,lineCalib,labelRefIm,lineRefIm,lineAcqCalibNbI,lineAcqCalibFr,lineFitDegree # be able to use it outside the window function
  816. global checkBoxIntsave,textBrow
  817. lineFitDegree = ui.fitDegree
  818. lineRef = ui.lineRef
  819. lineLamp = ui.lineLamp
  820. line_nImAcq = ui.line_nImAcq
  821. #line_name = ui.line_name
  822. lineExp = ui.lineExp
  823. line_start = ui.line_start
  824. line_stop = ui.line_stop
  825. line_step = ui.line_step
  826. linePath = ui.line_path
  827. line_nIm = ui.line_nIm
  828. progressBar = ui.progressBar
  829. lineAcqCalibNbI = ui.lineAcqCalibNbI
  830. lineAcqCalibFr = ui.lineAcqCalibFr
  831. line_acq = ui.line_acq
  832. lineZpos = ui.lineZpos
  833. #checkBoxIntsave = ui.checkBoxIntsave
  834. #checkBoxRAWsave = ui.checkBoxRAWsave
  835. textBrow = ui.fuckingText
  836. #checkBoxIntsave.stateChanged.connect(checkbox_saveInt)
  837. #checkBoxRAWsave.stateChanged.connect(checkbox_saveRAW)
  838. buttonMaxV = ui.buttonMaxV
  839. buttonMaxV.clicked.connect(check_max)
  840. buttonRef = ui.buttonRef
  841. buttonRef.clicked.connect(reference_image)
  842. buttonExp = ui.buttonExp
  843. buttonExp.clicked.connect(set_exposure)
  844. buttonLampOn = ui.LampOn
  845. buttonLampOn.clicked.connect(Lamp_on)
  846. buttonLampOff = ui.LampOff
  847. buttonLampOff.clicked.connect(Lamp_off)
  848. buttonLamp = ui.buttonLamp
  849. buttonLamp.clicked.connect(set_lamp_int)
  850. buttonZpos = ui.buttonZpos
  851. buttonZpos.clicked.connect(set_z_pos)
  852. buttonZ = ui.buttonZ
  853. buttonZ.clicked.connect(zStack)
  854. buttonAcq = ui.buttonAcq
  855. buttonAcq.clicked.connect(stack_acquisition)
  856. buttonAcqCalib_int = ui.buttonAcqCalib_int
  857. buttonAcqCalib_int.clicked.connect(acquisition_calib_int)
  858. buttonAcqCalib_grads = ui.buttonAcqCalib_grads
  859. buttonAcqCalib_grads.clicked.connect(acquisition_calib_grad)
  860. ######## tests
  861. buttonZ_stepping = ui.buttonZ_stepping
  862. buttonZ_stepping.clicked.connect(test_z_stack)
  863. buttonLive = ui.startLive
  864. buttonLive.clicked.connect(start_live)
  865. self.show()
  866. app = QtWidgets.QApplication(sys.argv)
  867. window = Ui()
  868. window.show()
  869. app.exec_()
  870. ################################################################################################
  871. ################################################################################################

Autofocus_ui_v1.3.py at commit 64141b1, no license · at the source

Overview

Authors: Hanna Manko1,2, Marc Tondusson1,2, Adeline Boyreau1,2, Morgane Meras3, Stéphane Bancelin1,2, Laurent Groc3, Laurent Cognet1,2
ORCID iDs: Laurent Cognet
  1. Laboratoire Photonique Numérique et Nanosciences, Université de Bordeaux, 33400, Talence, France
  2. LP2N, Institut d’Optique Graduate School, CNRS UMR 5298, 33400, Talence, France
  3. Interdisciplinary Institute for Neuroscience, CNRS, Univ. Bordeaux, 33076, Bordeaux, France
Dates: published online 14 March 2026
Type: Preprint
License: CC BY-NC
Identifiers: DOI 10.64898/2026.03.12.711239 · OpenAlex W7135371821
Open access: green, a free copy (OpenAlex)
Status: code verified
Categories: histology / microscopy (modality)
Methods: Spectral & time-frequency, fMRI & imaging
Keywords: Microscope stabilization, deep tissue imaging, oblique back-illumination, phase contrast imaging, single-particle tracking, super-resolution microscopy
Topic: Digital Holography and Microscopy (Atomic and Molecular Physics, and Optics, Physics and Astronomy), according to OpenAlex
Funding: European Research Council (951294)
Citations: not cited yet (Europe PMC); 36 references in the paper

Abstract

High-resolution optical microscopy enables nanoscale investigation of molecular structures but is challenged by sample drift during long acquisitions, particularly in thick biological tissues where trans-illumination is unpractical. Precise stabilization at the nanoscale is critical for high-resolution imaging techniques like localization microscopy and single particle tracking. Here we introduce a method combining homogenized differential phase contrast imaging with cross-correlation-based analysis to achieve automated, precise 3D drift correction applicable under oblique back-illumination. We demonstrate its effectiveness in fixed and live organotypic brain slices, maintaining focus within tens of nanometers and enabling high-quality nanoscale mapping of extracellular structures based on single particle tracking. Furthermore, we illustrate its application to opaque liver tissues combined with near-infrared single particle tracking. Our label-free approach provides a versatile solution for stabilizing optical microscopes in thick non-transparent tissues, facilitating extended high-resolution imaging across increasingly complex biological samples.

Reproduced under the paper's license (CC BY-NC), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 3 matches between paragraphs and lines of code.

hmanko/hDPC_autofocus

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: 64141b18ee1b913536e088b1da777666fc3ceb28, 27 March 2026
Languages: Python (3)
Size: 8 files, 3 scripts
Software Heritage: not archived
Found in: “Data and Software Availability”
Holds: README, environment (requirements.txt)
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: Matplotlib (3 files), NumPy (3 files), tifffile (3 files), pandas (2 files), scikit-image (2 files), SciPy (2 files), CuPy (1 file), napari (1 file), OpenCV (1 file), Pillow (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
4 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 3 scripts, each with its path and the digest of its content;
  • 3 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data and Software Availability

Data underlying the results presented in this paper are not publicly available at this time but may be obtained from the authors upon reasonable request.

The custom python-based software and the user interface developed during this study together with user manual are freely available at https://github.com/hmanko/hDPC_autofocus.git.

Reproduced under the paper's license (CC BY-NC), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 30 September 2026: the first record

Recorded: type, journal, dates, 7 authors, 6 keywords, 1 funder, 32 references.

Cite

This paper

Manko, H., Tondusson, M., Boyreau, A., Meras, M., Bancelin, S., Groc, L., & Cognet, L. (2026). Back-illumination Phase Imaging Enables Nanoscale Drift Stabilization in Non-transparent Biological Tissues. bioRxiv (preprint). https://doi.org/10.64898/2026.03.12.711239

BibTeX

@article{manko2026back,
author = {Manko, Hanna and Tondusson, Marc and Boyreau, Adeline and Meras, Morgane and Bancelin, Stéphane and Groc, Laurent and Cognet, Laurent},
title = {{Back-illumination Phase Imaging Enables Nanoscale Drift Stabilization in Non-transparent Biological Tissues}},
journal = {bioRxiv (preprint)},
year = {2026},
month = mar,
publisher = {bioRxiv},
issn = {2692-8205},
doi = {10.64898/2026.03.12.711239},
url = {https://doi.org/10.64898/2026.03.12.711239}
}

RIS

TY - JOUR
AU - Manko, Hanna
AU - Tondusson, Marc
AU - Boyreau, Adeline
AU - Meras, Morgane
AU - Bancelin, Stéphane
AU - Groc, Laurent
AU - Cognet, Laurent
TI - Back-illumination Phase Imaging Enables Nanoscale Drift Stabilization in Non-transparent Biological Tissues
T2 - bioRxiv (preprint)
J2 - bioRxiv
PY - 2026
DA - 2026/03/14
SN - 2692-8205
PB - bioRxiv
DO - 10.64898/2026.03.12.711239
UR - https://doi.org/10.64898/2026.03.12.711239
ER -

CSL-JSON

{
"id": "10.64898/2026.03.12.711239",
"type": "article",
"title": "Back-illumination Phase Imaging Enables Nanoscale Drift Stabilization in Non-transparent Biological Tissues",
"container-title": "bioRxiv (preprint)",
"author": [
{
"family": "Manko",
"given": "Hanna"
},
{
"family": "Tondusson",
"given": "Marc"
},
{
"family": "Boyreau",
"given": "Adeline"
},
{
"family": "Meras",
"given": "Morgane"
},
{
"family": "Bancelin",
"given": "Stéphane"
},
{
"family": "Groc",
"given": "Laurent"
},
{
"family": "Cognet",
"given": "Laurent"
}
],
"container-title-short": "bioRxiv",
"DOI": "10.64898/2026.03.12.711239",
"ISSN": "2692-8205",
"publisher": "bioRxiv",
"URL": "https://doi.org/10.64898/2026.03.12.711239",
"issued": {
"date-parts": [
[
2026,
3,
14
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1038/s41467-026-73045-9 [code]
Aberration-aware 3D localization microscopy via self-supervised neural-physics learning.
Journal: Nature communications
In common: napari, tifffile, OpenCV, 6 other tools, histology / microscopy, 1 reference
[2] doi: [code]
Real-time closed-loop feedback system for mouse mesoscale cortical signal and movement control
Journal: eLife
In common: napari, tifffile, OpenCV, 6 other tools
[3] doi:10.1371/journal.pcbi.1014571 [code]
SynAPSeg: A novel dataset and image analysis framework for deep learning-based synapse detection and quantification.
Journal: PLoS computational biology
In common: napari, tifffile, OpenCV, 6 other tools
[4] doi:10.1038/s41586-026-10323-y [code]
Genetically encoded assembly recorder temporally resolves cellular history.
Journal: Nature
In common: napari, tifffile, OpenCV, 6 other tools
[5] doi:10.1038/s41467-026-76956-9 [code]
Innervated human cardiac muscle model reveals sympathetic drivers of KCNH2-associated arrhythmias.
Journal: Nature communications
In common: napari, tifffile, OpenCV, 5 other tools
[6] doi:10.1038/s41467-026-75352-7 [code]
Mechanosensory encoding of surface mechanics optimizes locomotion.
Journal: Nature communications
In common: napari, tifffile, OpenCV, 5 other tools
[7] doi:10.1038/s42003-026-10063-9 [code]
Conserved Kir channel mechanisms governing intrinsic excitability in human and rodent parvalbumin neurons.
Journal: Communications biology
In common: napari, tifffile, scikit-image, 5 other tools
[8] doi:10.1016/j.celrep.2026.117420 [code]
Neural population dynamics of direct electrical stimulation of neocortex.
Journal: Cell reports
In common: napari, OpenCV, scikit-image, 5 other tools
[9] doi:10.1038/s41598-026-57519-w [code]
Automated segmentation of neurons and spinal cord structures in immunofluorescence images using SpineDL.
Journal: Scientific reports
In common: tifffile, OpenCV, scikit-image, 5 other tools, histology / microscopy
[10] doi:10.1038/s41467-026-72709-w [code]
An epifluorescence microscope design for naturalistic behavior and cellular activity in freely moving Caenorhabditis elegans.
Journal: Nature communications
In common: tifffile, OpenCV, scikit-image, 5 other tools, histology / microscopy

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.