Data_analysis_with_IDL.doc 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Thu May 31 17:34:29 2018
  4. @author: Giovanni Galizia
  5. """
  6. import pandas as pd
  7. import scipy as sp
  8. from scipy import ndimage
  9. import numpy as np
  10. import matplotlib.pyplot as plt
  11. import os
  12. from view.python_core.p1_class.filters import apply_filter
  13. from view.python_core.paths import get_existing_raw_data_filename
  14. from view.python_core.io import read_tif_2Dor3D
  15. import tifffile
  16. import pathlib as pl
  17. import logging
  18. def load_pst(filename):
  19. """
  20. read tillvision based .pst files as uint16.
  21. """
  22. # filename can have an extension (e.g. .pst), or not
  23. # reading stack size from inf
  24. #inf_path = os.path.splitext(filename)[0] + '.inf'
  25. #this does not work for /data/030725bR.pst\\dbb10F, remove extension by hand,
  26. #assuming it is exactly 3 elements
  27. if filename[-4] == '.':
  28. filename = filename[:-4] #reomove extension
  29. meta = {}
  30. with open(filename+'.inf','r') as fh:
  31. # fh.next()
  32. for line in fh.readlines():
  33. try:
  34. k,v = line.strip().split('=')
  35. meta[k] = v
  36. except:
  37. pass
  38. # reading stack from pst
  39. shape = sp.int32((meta['Width'],meta['Height'],meta['Frames']))
  40. expected_units = np.prod(shape)
  41. assert pl.Path(f"{filename}.pst").stat().st_size >= 2 * expected_units, \
  42. f"Expected atleast {2 * expected_units} bytes in {filename}.pst. Found {pl.Path(filename).stat().st_size}"
  43. raw = sp.fromfile(filename+'.pst', dtype='int16', count=expected_units)
  44. data = sp.reshape(raw,shape,order='F')
  45. # was swapping x, y axes; commented out to retain original order
  46. # data = data.swapaxes(0,1)
  47. # data is upside down as compared to what we see in TillVision
  48. data = np.flip(data, axis=1)
  49. data = data.astype('uint16')
  50. return data
  51. def read_lsm(path):
  52. """ takes a path to a lsm file, reads the file with the tifffile lib and
  53. returns a np array
  54. """
  55. data = tifffile.imread(path)
  56. Data_cut = data[0,0,:,:,:] # empirical ...
  57. Data_cut_rot = sp.swapaxes(Data_cut,0,2)
  58. Data_cut_rot_flip = sp.flip(Data_cut_rot, axis=1)
  59. return Data_cut_rot_flip
  60. def loadTILL(flag, p1):
  61. filename = get_existing_raw_data_filename(flags=flag, p1_metadata=p1, extension=".pst")
  62. #if not exist try FID format version oct18
  63. # if still not exist try FID format old
  64. print('ViewLoadData.loadTILL. Loading data :',filename)
  65. # write data directly into p1 structure: p1.Raw1
  66. p1["raw1"] = load_pst(filename.rstrip(".pst"))
  67. # saving the complete filename of raw data for reference
  68. p1["full_raw_data_path"] = filename
  69. # use shrinkfactor to shrink
  70. if (flag["LE_ShrinkFaktor"] not in [0,1]): #both 0 and 1 mean 'no shrink'
  71. shrink = 1/flag["LE_ShrinkFaktor"] # flag of 2 means half the size in each dimension
  72. import scipy.ndimage as scind
  73. # the command used in IDL for shrink was REBIN
  74. #raw1(*,*,i,1) = rebin(image(0:p1.format_x*shrinkFactor-1, 0:p1.format_y*shrinkFactor-1) ,p1.format_x, p1.format_y) ;
  75. # the following shrinks in x and y, not in t, with polinomial order 1.
  76. # "nearest" is for treatment at the borders
  77. p1.raw1 = scind.zoom(p1.raw1,(shrink,shrink,1), order=1, mode='nearest')
  78. # put shape into p structure
  79. datasize = p1.raw1.shape
  80. p1.format_x = datasize[0]
  81. p1.format_y = datasize[1]
  82. p1.frames = datasize[2]
  83. # IDL: MedianCorrection, oneOdour, fix(flag(csm_median)); mean filter added in pyVIEW
  84. # apply median filter first, then mean filter, depending on flags
  85. p1.raw1 = apply_filter(matrix_in=p1.raw1, view_flags=flag, filter_type="median")
  86. p1.raw1 = apply_filter(matrix_in=p1.raw1, view_flags=flag, filter_type="mean")
  87. # calculate foto
  88. p1.foto1 = p1.raw1[:,:,1:6].mean(axis = 2) #average of frames 1:6 p1.raw1[:,:,1:6]
  89. # IDL: foto1(i,j) = mean(raw1(i,j,1:5,0))
  90. #
  91. # calculate darkfoto: deprecated
  92. #
  93. if (flag["LE_AskForAir"] != 0):
  94. print('ViewLoadData.loadTILL. Loading Air not implemented yet')
  95. # use gettillloginfo to get the info for p1.control
  96. # load that measurement p_air["raw1"] = load_pst(filename)
  97. # check that shape is equal
  98. #
  99. return p1 #p1 contains all data for this measurement
  100. def loadFURA(flag, p1):
  101. # loads FURA measurements
  102. # here I deviate from IDL. I just call loadTILL two times (in IDL, that code was effectively duplicated)
  103. # but I play around with the p1 structure.
  104. p2 = p1.copy() # use p2 for the second wavelength.
  105. p2.dbb1 = p2.dbb2 # BUT loadTILL does not know, so swap the dbb info
  106. # load wavelength 1
  107. p1 = loadTILL(flag, p1)
  108. # load wavelength 2
  109. p2 = loadTILL(flag, p2)
  110. # copy data of wavelength 2 into 1, since they belong together
  111. p1["raw2"] = p2.raw1
  112. p1["foto2"] = p2.foto1
  113. if (flag["LE_AskForAir"] != 0):
  114. print('ViewLoadData.loadFURA. Loading Air not implemented yet')
  115. # in fact, it was never implemented in IDL either
  116. return p1 #p1 contains all data for this measurement
  117. def loadZeiss(flag, p1):
  118. filename = get_existing_raw_data_filename(flags=flag, p1_metadata=p1, extension=".lsm")
  119. print('ViewLoadData.loadZeiss: Loading data :',filename)
  120. #;load zeiss data set
  121. print('loadZeiss: loading Zeiss dataset ', filename)
  122. dataIn = read_lsm(filename)
  123. #;define data sets for IDL-View
  124. p1.raw1 = dataIn #;for old empty air format
  125. # saving the complete filename of raw data for reference
  126. p1["full_raw_data_path"] = filename
  127. datasize = p1.raw1.shape
  128. p1.format_x = datasize[0]
  129. p1.format_y = datasize[1]
  130. p1.frames = datasize[2]
  131. #;median correction
  132. p1.raw1 = MedianCorrection(p1.raw1, flag)
  133. # ;define foto as the mean of the first six frames
  134. p1.foto1 = p1.raw1[:, :, 1:6].mean(axis=2)
  135. print('loadZeiss: data loaded')
  136. return p1 #loadZeiss
  137. def load_VIEW_tif(flag, p1):
  138. filename = get_existing_raw_data_filename(flags=flag, p1_metadata=p1, extension=".tif")
  139. logging.getLogger("VIEW").info(f"Loading VIEW-tif from: {filename}")
  140. try:
  141. p1.raw1 = read_tif_2Dor3D(filename)
  142. except Exception as e:
  143. raise IOError(f"Error reading {filename}")
  144. # saving the complete filename of raw data for reference
  145. p1["full_raw_data_path"] = filename
  146. datasize = p1.raw1.shape
  147. assert len(datasize) == 3, \
  148. f"{filename} cannot be loaded as a VIEW-tif as it has {len(datasize)} dimensions (3 expected)"
  149. p1.format_x = datasize[0]
  150. p1.format_y = datasize[1]
  151. p1.frames = datasize[2]
  152. # ;median correction
  153. p1.raw1 = MedianCorrection(p1.raw1, flag)
  154. # ;define foto as the mean of the first six frames
  155. p1.foto1 = p1.raw1[:, :, 1:6].mean(axis=2)
  156. return p1
  157. def create_raw_data667(p1_metadata, peaksignal):
  158. '''
  159. 'this is the backup copy of the old create_raw_data666, that contained only square glomeruli
  160. '''
  161. print('ViewLoadData/LoadRaw667: generating test data with many fixed settings!')
  162. stimonset = p1_metadata.stimulus_on
  163. stimoffset = p1_metadata.stimulus_end
  164. ### for playing around start after #:
  165. # peaksignal, stimonset, stimoffset = 10, 25, 35 # - is in command line now
  166. # local flags
  167. lightlevel = 1000 # baseline value of each pixel.
  168. # at the setup, you would set exposure time and light level accordingly
  169. randomseed = 0 # set to None for irreproducible random numbers
  170. # add chipnoise
  171. darknoise = True
  172. darknoise_mean = 100 # mean of background values in the chip
  173. darknoise_amplitude = 20 # max amplitude of background chip noise
  174. # I assume chip noise to be random over time
  175. #
  176. xSize, ySize, tSize = 172, 130, 80 # 120, 99, 80
  177. rampwidth = 10 # width of the ramp, left 3x, right 2x
  178. stepsize = 13 # must be a divisor of ySze
  179. # glomerular locations are (make sure to exclude rampwidth)
  180. glo1 = (50, 70, 50, 70) # x,x - y,y
  181. glo2 = (60, 80, 60, 80) # x,x - y,y
  182. glo3 = (65, 75, 45, 55)
  183. glo4 = (70, 90, 30, 50)
  184. glo5 = (50, 65, 30, 45)
  185. glo6 = (70, 90, 50, 70) # off response
  186. glo7 = (50, 70, 90, 110) # biphasic response
  187. glo8 = (75, 95, 90, 110) # negative response
  188. shotnoise = True # add photon noise
  189. # add bad pixels on the CCD chip, i.e. pixels with value 0
  190. badpixels = True
  191. badpixels_clip = 0.98 # 0.9 for 10% bad pixels
  192. #
  193. # add global bleaching
  194. bleach = True
  195. bleach_percent = 10 # percentage bleaching
  196. bleach_tau = tSize / 5 # assume decay to 37% of percentage over this length
  197. # add lamp noise
  198. lampnoise = 0.1 # value in percent. 0 for no noise. Value is PEAK noise
  199. # add scattered light
  200. scatterlight = 0 # 2 # unit is gaussian pixels; 0 for no scattered light
  201. # change code, do exclude lateral step image
  202. # TODO
  203. # - add light scatter (smooth): modify
  204. # - add movement
  205. #
  206. def applytimecourse(matrix, glo_location, oneline):
  207. '''
  208. applies oneline as a factor (length: tSize)
  209. to square window (glomerulus) defined with upperleft, lowerright
  210. glo_location is (x_left,x_right,y_down, y_up)
  211. (y_down < y_up; but safety net included)
  212. '''
  213. x1 = np.min((glo_location[0], glo_location[1]))
  214. x2 = np.max((glo_location[0], glo_location[1]))
  215. y1 = np.min((glo_location[2], glo_location[2]))
  216. y2 = np.max((glo_location[3], glo_location[3]))
  217. matrix[x1:x2, y1:y2, :] = matrix[x1:x2, y1:y2, :] * oneline.reshape(1, 1, tSize)
  218. return matrix
  219. # set random numbers
  220. np.random.seed(randomseed)
  221. # create still image
  222. # with average light level as visible to the experimenter
  223. # therefore subtract darknoise_mean from lightlevel
  224. stillimage = np.full((xSize, ySize), (lightlevel - darknoise_mean))
  225. # create a ramp from 0 to 2*lightlevel
  226. oneline = np.linspace(0, 2 * lightlevel, ySize).reshape(1, ySize)
  227. stillimage[0:rampwidth, :] = oneline # first band, going up
  228. stillimage[rampwidth:2 * rampwidth, :] = np.flip(oneline) # first band, going up
  229. # create a ramp in the center, in order to avoid border effects
  230. oneline = np.linspace(0, 2 * lightlevel, ySize // 2).reshape(1, ySize // 2)
  231. stillimage[2 * rampwidth:np.int(2.5 * rampwidth),
  232. ySize // 4:ySize // 4 + ySize // 2] = oneline # first band, going up
  233. stillimage[np.int(2.5 * rampwidth):3 * rampwidth, ySize // 4:ySize // 4 + ySize // 2] = np.flip(
  234. oneline) # first band, going up
  235. # create a bit of a photo:.
  236. # background is darker
  237. stillimage[3 * rampwidth:xSize - rampwidth, 0:ySize] = (lightlevel - darknoise_mean) * 0.7
  238. # large area (antennal lobe) is average
  239. stillimage[40:95, 15:110] = (lightlevel - darknoise_mean)
  240. # some glomeruli are brighter, to unequal extent
  241. thisglo = glo1
  242. stillimage[thisglo[0]:thisglo[1], thisglo[2]:thisglo[3]] = (lightlevel - darknoise_mean) * 1.3
  243. thisglo = glo2
  244. stillimage[thisglo[0]:thisglo[1], thisglo[2]:thisglo[3]] = (lightlevel - darknoise_mean) * 1.5
  245. thisglo = glo3
  246. stillimage[thisglo[0]:thisglo[1], thisglo[2]:thisglo[3]] = (lightlevel - darknoise_mean) * 1.1
  247. thisglo = glo4
  248. stillimage[thisglo[0]:thisglo[1], thisglo[2]:thisglo[3]] = (lightlevel - darknoise_mean) * 1.8
  249. thisglo = glo5
  250. stillimage[thisglo[0]:thisglo[1], thisglo[2]:thisglo[3]] = (lightlevel - darknoise_mean) * 1.3
  251. thisglo = glo6
  252. stillimage[thisglo[0]:thisglo[1], thisglo[2]:thisglo[3]] = (lightlevel - darknoise_mean) * 1.3
  253. if badpixels:
  254. # bad pixels are fixed in space - therefore create in an image
  255. noise = np.random.rand(xSize, ySize) > badpixels_clip # values in [0-1]
  256. stillimage[noise] = 0
  257. # assumes that from now on everything is multiplicative, not additive
  258. # check result
  259. # plt.imshow(stillimage[:,:].T, origin='lower')
  260. # broadcast still image to time domain
  261. # movie memory structure
  262. raw666 = np.zeros((xSize, ySize, tSize))
  263. stillimage = stillimage.reshape(xSize, ySize, 1)
  264. raw666 = raw666 + stillimage # use broadcasting
  265. # now go into the time domain:
  266. # add bleaching
  267. if bleach:
  268. fullframe = (0, xSize, 0, ySize) # apply bleaching to full frame
  269. oneline = np.arange(tSize)
  270. oneline = (1 - bleach_percent / 200) + (bleach_percent / 100) * np.exp(-oneline / bleach_tau)
  271. raw666 = applytimecourse(raw666, fullframe, oneline)
  272. # plt.plot(oneline)
  273. if lampnoise: # if lampnoise == 0, it is like false.
  274. fullframe = (0, xSize, 0, ySize) # apply bleaching to full frame
  275. oneline = 1 + (lampnoise / 100) * np.random.rand(tSize)
  276. raw666 = applytimecourse(raw666, fullframe, oneline)
  277. # plt.plot(oneline)
  278. # add glomeruli
  279. ###sawtooth
  280. oneline = np.zeros(tSize)
  281. oneline[stimonset:stimoffset] = np.linspace(0, peaksignal / 100, stimoffset - stimonset)
  282. oneline[stimoffset:] = np.linspace(peaksignal / 100, 0, tSize - stimoffset)
  283. oneline = oneline + 1 # baseline factor is 1
  284. raw666 = applytimecourse(raw666, glo1, oneline)
  285. raw666 = applytimecourse(raw666, glo2, oneline)
  286. ###realistic:
  287. tau1 = stimoffset - stimonset
  288. tau2 = 2 * tau1
  289. c = 1
  290. oneline = np.ones(tSize)
  291. response = np.arange(tSize - stimonset)
  292. response = (-1) * np.exp(-response / tau1) + c * np.exp(-response / tau2)
  293. response = ((peaksignal / 100) / np.max(response)) * response # scale to peaksignal
  294. oneline[stimonset:] = oneline[stimonset:] + response
  295. raw666 = applytimecourse(raw666, glo3, oneline)
  296. raw666 = applytimecourse(raw666, glo4, oneline)
  297. raw666 = applytimecourse(raw666, glo5, oneline)
  298. # late response
  299. oneline = np.ones(tSize)
  300. oneline[stimoffset:] = oneline[stimoffset:] + response[:(tSize - stimoffset)]
  301. raw666 = applytimecourse(raw666, glo6, oneline)
  302. # biphasic response
  303. oneline = np.ones(tSize)
  304. oneline[stimonset:] = oneline[stimonset:] + response
  305. oneline[stimoffset:] = oneline[stimoffset:] - 2 * response[:(tSize - stimoffset)]
  306. raw666 = applytimecourse(raw666, glo7, oneline)
  307. # negative response, builds on factors defined in realistic
  308. oneline = np.ones(tSize)
  309. oneline[stimonset:] = oneline[stimonset:] - response
  310. raw666 = applytimecourse(raw666, glo8, oneline)
  311. # plt.plot(oneline)
  312. # add scattered light, as gaussian filter
  313. if scatterlight:
  314. raw666[3 * rampwidth:xSize - 2 * rampwidth, :, :] = sp.ndimage.gaussian_filter(
  315. raw666[3 * rampwidth:xSize - 2 * rampwidth, :, :], sigma=[scatterlight, scatterlight, 0])
  316. if shotnoise: # add noise, random and proportional to square root of signal
  317. # photons are poisson distributed
  318. # noisier = lambda p : np.random.poisson(p)
  319. # raw666 = noisier(raw666)
  320. raw666 = np.random.poisson(raw666) # one line solution! Python is so cool...
  321. if darknoise:
  322. # add chip noise.
  323. # This comes at the end, because it is not influenced by light
  324. noise = np.random.rand(xSize, ySize, tSize) # values in [0-1]
  325. noise = noise * darknoise_amplitude + darknoise_mean - darknoise_amplitude / 2
  326. raw666 = raw666 + noise
  327. # now, AFTER the noise, get a ramp of totally clean signals for calibration
  328. # create a step function with stepsize steps, also to 2*lightlevel
  329. # this area has no signals in time - only differrent background, no noise
  330. stepfunction = np.repeat(np.arange(stepsize), ySize / stepsize)
  331. stepfunction = stepfunction * (2 * lightlevel / np.max(stepfunction))
  332. # shift by darknoise_mean to avoid having values of 0, which cause trouble when dividing in CalcSig
  333. stepfunction = stepfunction + darknoise_mean
  334. stepfunction = stepfunction.reshape(1, ySize, 1)
  335. raw666[-rampwidth:, :, :] = stepfunction # set to uniform background level
  336. # create a step function with stepsize steps
  337. stepfunction = np.repeat(np.arange(stepsize), ySize / stepsize) - stepsize // 2 # negative and positive signals
  338. # calibrate to peaksignal max both ways
  339. stepfunction = ((peaksignal / 100) / np.max(stepfunction)) * stepfunction
  340. # values are given in percent
  341. stepfunction = (stepfunction + 1) * lightlevel
  342. raw666[-2 * rampwidth:-rampwidth, :, :] = lightlevel # set to uniform background level
  343. stepfunction = stepfunction.reshape(1, ySize, 1)
  344. raw666[-2 * rampwidth:-rampwidth, :, stimonset:stimoffset] = stepfunction
  345. # plt.plot(raw666[-2*rampwidth,:,10])
  346. # plt.plot(raw666[-2*rampwidth,:,25])
  347. # plt.show()
  348. ##
  349. # camera is 12 bit, therefore clip to 4095, and integer
  350. raw666 = np.clip(raw666.astype(int), 0, 4095)
  351. # plt.imshow(raw666[:,:,30].T, origin='lower')
  352. # plt.show()
  353. # plt.plot(raw666[100,10,:])
  354. # plt.plot(raw666[100,60,:])
  355. # plt.plot(raw666[100,80,:])
  356. # plt.plot(raw666[80,60,:])
  357. # plt.plot(raw666[60,60,:])
  358. # plt.show()
  359. return raw666 # end of create_raw_data667
  360. def create_raw_data666(p1_metadata, peaksignal):
  361. '''
  362. Giovanni, October 2020, based on previous 666 for square glomeruli, which is now called 667
  363. Add: glomeruli with round shapes, because CaImAn detects round shapes
  364. Add: movement (for now just lateral movements)
  365. Add: frames out of focus (simulated with smoothing)
  366. Add: unequal bleaching (created by adding non-bleaching base fluorescence)
  367. -> variable noBleach_lightlevel
  368. move bad pixels to the end (after artificial movement)
  369. Parameters
  370. ----------
  371. p1_metadata : TYPE
  372. contains all parameters, used are stimulus_on and stimulus_end
  373. peaksignal : TYPE real
  374. like odor concentration, i.e. how strong the response in the fictive glomeruli.
  375. Returns
  376. -------
  377. matrix : TYPE
  378. corresponds to p1.raw, to be copied there by caller
  379. '''
  380. print('ViewLoadData/LoadRaw666: generating test data with many fixed settings!')
  381. addRightBand = False
  382. #right band has fixed value squares, no noise, no change over time.
  383. addLeftBand = False
  384. # lateral band left is a continuus up and down, including noise
  385. stimulus_pulse_start_end_frames = p1_metadata["pulsed_stimuli_handler"].get_pulse_start_end_frames()
  386. stimonset = stimulus_pulse_start_end_frames[0][0]
  387. stimoffset = stimulus_pulse_start_end_frames[0][1]
  388. ### for playing around start after #:
  389. #####
  390. #peaksignal, stimonset, stimoffset = 10, 25, 35 # - is in command line now
  391. # local flags
  392. lightlevel = 1000 # baseline value of each pixel.
  393. # at the setup, you would set exposure time and light level accordingly
  394. noBleach_lightlevel = 500 # add this base lavel after fictive bleaching,
  395. # the effect is that bleaching cannot be completely corrected by our standard procedure,
  396. # because it will not have the same parameters in the deltaF/F data across all glomeruli.
  397. randomseed = 0 # set to None for irreproducible random numbers
  398. # add chipnoise
  399. darknoise = True
  400. darknoise_mean = 100 # mean of background values in the chip
  401. darknoise_amplitude = 20 # max amplitude of background chip noise
  402. # subtract the constant parts from the light level,
  403. # because in the experiment we set the light to the sum of them all
  404. brain_lightlevel = lightlevel - darknoise_mean - noBleach_lightlevel#
  405. # I assume chip noise to be random over time
  406. #
  407. xSize, ySize, tSize = 172, 130, 80 # 120, 99, 80
  408. rampwidth = 10 # width of the ramp, 3 left, 2 right, i.e.
  409. # usable range therefore is, in x, 30-152, center is 92
  410. stepsize = 13 # must be a divisor of ySze
  411. # glomerular locations for square glomeruli are (make sure to exclude rampwidth)
  412. # coordinates are x from left to right
  413. # y from bottom to top
  414. glo1 = (50, 70, 90, 110) # x,x - y,y
  415. # glo2 = (60, 80, 60, 80) # x,x - y,y
  416. # glo3 = (65, 75, 45, 55)
  417. # glo4 = (70, 90, 30, 50)
  418. # glo5 = (50, 65, 30, 45)
  419. # glo6 = (70, 90, 50, 70) # off response
  420. # glo7 = (50, 70, 90, 110) # biphasic response
  421. # glo8 = (75, 95, 90, 110) # negative response
  422. # glomerular locations for circle glomeruli, syntax centerX, centerY, radius
  423. # x from left to right, y from bottom to top
  424. circle1left = (50, 65, 20)
  425. circle2 = (60, 85, 15)
  426. circle3 = (70, 97, 10)
  427. circle4top = (92, 105, 18)
  428. circle5 = (110, 85, 12)
  429. circle6right= (120, 65, 15)
  430. circle7 = (110, 45, 10)
  431. circle8bottom=(92, 25, 19)
  432. circle9 = (70, 32, 10)
  433. circle0 = (60, 50, 16)
  434. circleCenter= (90, 65, 15)
  435. shotnoise = True # add photon noise
  436. # add bad pixels on the CCD chip, i.e. pixels with value 0
  437. badpixels = True
  438. badpixels_clip = 0.98 # 0.9 for 10% bad pixels
  439. #
  440. # add global bleaching
  441. bleach = True
  442. bleach_percent = 10 # percentage bleaching
  443. bleach_tau = tSize / 5 # assume decay to 37% of percentage over this length
  444. # add lamp noise
  445. lampnoise = 0.1 # value in percent. 0 for no noise. Value is PEAK noise
  446. # add scattered light
  447. scatterlight = 2 # 2 # unit is gaussian pixels; 0 for no scattered light
  448. # smoothBackground
  449. smoothBackground = 5
  450. # smoooth some frames, to mimit out of focus movement
  451. smoothOutOfFocus = 5
  452. smoothOutOfFocus_frames = [4,5,34,35,36,37,50,51,52,53,53,55,70,71,72]
  453. # add movement
  454. AddMovement = True
  455. AddMovementSize = 3 # in pixels, x and y direction, gaussian distribution
  456. # change code, do exclude lateral step image
  457. # TODO
  458. # - add light scatter (smooth): modify
  459. # - add movement
  460. #
  461. def applytimecourse_square_glo(matrix, square_glo, oneline):
  462. '''
  463. applies oneline as a factor (length: tSize)
  464. to square window (glomerulus) defined with upperleft, lowerright
  465. glo_location is (x_left,x_right,y_down, y_up)
  466. (y_down < y_up; but safety net included)
  467. '''
  468. x1 = np.min((square_glo[0], square_glo[1]))
  469. x2 = np.max((square_glo[0], square_glo[1]))
  470. y1 = np.min((square_glo[2], square_glo[2]))
  471. y2 = np.max((square_glo[3], square_glo[3]))
  472. matrix[x1:x2, y1:y2, :] = matrix[x1:x2, y1:y2, :] * oneline.reshape(1, 1, tSize)
  473. return matrix
  474. # functions to create circular regions, and apply time courses to them
  475. # def create_circular_mask(h, w, center=None, radius=None):
  476. # # from
  477. # # https://stackoverflow.com/questions/44865023/how-can-i-create-a-circular-mask-for-a-numpy-array
  478. # if center is None: # use the middle of the image
  479. # center = (int(w/2), int(h/2))
  480. # if radius is None: # use the smallest distance between the center and image walls
  481. # radius = min(center[0], center[1], w-center[0], h-center[1])
  482. # Y, X = np.ogrid[:h, :w]
  483. # dist_from_center = np.sqrt((X - center[0])**2 + (Y-center[1])**2)
  484. # mask = dist_from_center <= radius
  485. # return mask
  486. def create_circular_mask(x, y, glomerulus):
  487. # glomerulus is (x, y, radius)
  488. # x from left to right, y from bottom to top
  489. Y, X = np.ogrid[:x, :y]
  490. # why x/y are inverted in the glomerulus coordinates (rows/columns instead of x/y) evades me
  491. dist_from_center = np.sqrt((X - glomerulus[1])**2 + (Y-glomerulus[0])**2)
  492. mask = dist_from_center <= glomerulus[2]
  493. return mask # this is a boolean 2D array.
  494. def applytimecourse_mask(matrix, mask, oneline):
  495. '''
  496. applies oneline as a factor (length: tSize)
  497. to a boolean glomerulus (2D) in mask
  498. '''
  499. #uses broadcasting to apply 2D mask
  500. matrix[mask,] = matrix[mask,] * oneline.reshape(1, 1, tSize)
  501. return matrix
  502. def applytimecourse_glomerulus(matrix, glomerulus, oneline):
  503. mask = create_circular_mask(matrix.shape[0], matrix.shape[1], glomerulus)
  504. matrix = applytimecourse_mask(matrix, mask, oneline)
  505. return matrix
  506. # set random numbers
  507. np.random.seed(randomseed)
  508. # create still image
  509. # with average light level as visible to the experimenter
  510. # therefore subtract darknoise_mean from lightlevel (has been done avoe)
  511. stillimage = np.full((xSize, ySize), brain_lightlevel, dtype='float64')
  512. # create a bit of a photo:.
  513. # background is darker
  514. stillimage[:, :] = brain_lightlevel * 0.7
  515. # large circle in the middle (antennal lobe) is average
  516. circlesize = min(xSize//2, ySize//2)
  517. position = (xSize//2, ySize//2, circlesize)
  518. stillimage[create_circular_mask(xSize, ySize, position)] = brain_lightlevel
  519. # two concentric circles inside, brighter
  520. position = (xSize//2, ySize//2, circlesize//1.5)
  521. stillimage[create_circular_mask(xSize, ySize, position)] = brain_lightlevel * 1.5
  522. position = (xSize//2, ySize//2, circlesize//2)
  523. stillimage[create_circular_mask(xSize, ySize, position)] = brain_lightlevel * 2
  524. # some glomeruli have different brightness, to unequal extent
  525. stillimage[create_circular_mask(xSize, ySize, circle1left)] *= 1.7
  526. stillimage[create_circular_mask(xSize, ySize, circle2)] *= 0.9
  527. stillimage[create_circular_mask(xSize, ySize, circle3)] *= 2.0
  528. stillimage[create_circular_mask(xSize, ySize, circle4top)] *= 0.7
  529. stillimage[create_circular_mask(xSize, ySize, circle5)] *= 1.4
  530. stillimage[create_circular_mask(xSize, ySize, circle6right)] *= 0.9
  531. stillimage[create_circular_mask(xSize, ySize, circle7)] *= 1.5
  532. stillimage[create_circular_mask(xSize, ySize, circle8bottom)] *= 0.7
  533. stillimage[create_circular_mask(xSize, ySize, circle9)] *= 1.9
  534. stillimage[create_circular_mask(xSize, ySize, circle0)] *= 0.8
  535. stillimage[create_circular_mask(xSize, ySize, circleCenter)] *= 2.0
  536. # smoooth image, sigma is smoothBackground
  537. stillimage = sp.ndimage.gaussian_filter(stillimage, smoothBackground, mode='nearest')
  538. if addLeftBand:
  539. # left side, overwriting everything here: create four ramps
  540. # create a ramp from 0 to 2*lightlevel
  541. oneline = np.linspace(0, 2 * lightlevel, ySize).reshape(1, ySize)
  542. stillimage[0:rampwidth, :] = oneline # first band, going up
  543. stillimage[rampwidth:2 * rampwidth, :] = np.flip(oneline) # second band, going down
  544. # create a ramp in the center, in order to avoid border effects
  545. oneline = np.linspace(0, 2 * lightlevel, ySize // 2).reshape(1, ySize // 2)
  546. stillimage[2 * rampwidth:np.int(2.5 * rampwidth),
  547. ySize // 4 : ySize // 4 + ySize // 2] = oneline # third half band, going up
  548. stillimage[np.int(2.5 * rampwidth):3 * rampwidth,
  549. ySize // 4:ySize // 4 + ySize // 2] = np.flip(oneline) # fourth half band, going down
  550. # check result while debugging
  551. # plt.imshow(stillimage[:,:].T, origin='lower')
  552. # broadcast still image to time domain
  553. # movie memory structure
  554. raw666 = np.zeros((xSize, ySize, tSize))
  555. stillimage = stillimage.reshape(xSize, ySize, 1)
  556. raw666 += stillimage # use broadcasting
  557. # now go into the time domain:
  558. # add bleaching
  559. if bleach:
  560. fullframe = (0, xSize, 0, ySize) # apply bleaching to full frame
  561. oneline = np.arange(tSize)
  562. oneline = (1 - bleach_percent / 200) + (bleach_percent / 100) * np.exp(-oneline / bleach_tau)
  563. # calculate deltaF/f first - avoid values of 0, therefore add 10
  564. stillimage += 10
  565. raw666 += 10
  566. raw666 /= stillimage
  567. raw666 = applytimecourse_square_glo(raw666, fullframe, oneline)
  568. # calculate back to "original" data
  569. raw666 *= stillimage
  570. raw666 += np.min(raw666) # avoid negative values
  571. # plt.plot(oneline)
  572. if lampnoise: # if lampnoise == 0, it is like false.
  573. fullframe = (0, xSize, 0, ySize) # apply lampnoise to full frame
  574. oneline = 1 + (lampnoise / 100) * np.random.rand(tSize)
  575. raw666 = applytimecourse_square_glo(raw666, fullframe, oneline)
  576. # plt.plot(oneline)
  577. # add glomeruli, using different time courses
  578. ###sawtooth
  579. oneline = np.zeros(tSize)
  580. oneline[stimonset:stimoffset] = np.linspace(0, peaksignal / 100, stimoffset - stimonset)
  581. oneline[stimoffset:] = np.linspace(peaksignal / 100, 0, tSize - stimoffset)
  582. oneline = oneline + 1 # baseline factor is 1
  583. #raw666 = applytimecourse_square_glo(raw666, glo1, oneline)
  584. # raw666 = applytimecourse_square_glo(raw666, glo2, oneline)
  585. raw666 = applytimecourse_glomerulus(raw666, circle1left, oneline)
  586. ###realistic:
  587. tau1 = stimoffset - stimonset
  588. tau2 = 2 * tau1
  589. c = 1
  590. oneline = np.ones(tSize)
  591. response = np.arange(tSize - stimonset)
  592. response = (-1) * np.exp(-response / tau1) + c * np.exp(-response / tau2)
  593. response = ((peaksignal / 100) / np.max(response)) * response # scale to peaksignal
  594. oneline[stimonset:] += response
  595. # raw666 = applytimecourse_square_glo(raw666, glo3, oneline)
  596. # raw666 = applytimecourse_square_glo(raw666, glo4, oneline)
  597. # raw666 = applytimecourse_square_glo(raw666, glo5, oneline)
  598. # apply to circle glomerulus
  599. raw666 = applytimecourse_glomerulus(raw666, circle2, oneline)
  600. oneline = (oneline -1)*1.5 +1
  601. raw666 = applytimecourse_glomerulus(raw666, circle3, oneline)
  602. # late response
  603. oneline = np.ones(tSize)
  604. oneline[stimoffset:] = oneline[stimoffset:] + response[:(tSize - stimoffset)]
  605. # raw666 = applytimecourse_square_glo(raw666, glo6, oneline)
  606. # apply to circle glomerulus
  607. raw666 = applytimecourse_glomerulus(raw666, circle4top, oneline)
  608. oneline = (oneline -1)*1.5 +1
  609. raw666 = applytimecourse_glomerulus(raw666, circle5, oneline)
  610. # slightly delayed
  611. oneline = np.ones(tSize)
  612. oneline[stimonset+5:] += response[:-5]
  613. raw666 = applytimecourse_glomerulus(raw666, circleCenter, oneline)
  614. # biphasic response
  615. oneline = np.ones(tSize)
  616. oneline[stimonset:] = oneline[stimonset:] + response
  617. oneline[stimoffset:] = oneline[stimoffset:] - 2 * response[:(tSize - stimoffset)]
  618. # raw666 = applytimecourse_square_glo(raw666, glo7, oneline)
  619. # apply to circle glomerulus
  620. raw666 = applytimecourse_glomerulus(raw666, circle6right, oneline)
  621. oneline = (oneline -1)*1.5 +1
  622. raw666 = applytimecourse_glomerulus(raw666, circle7, oneline)
  623. oneline = (oneline -1)*0.6 +1
  624. raw666 = applytimecourse_glomerulus(raw666, circle0, oneline)
  625. # negative response, builds on factors defined in realistic
  626. oneline = np.ones(tSize)
  627. oneline[stimonset:] = oneline[stimonset:] - response
  628. # raw666 = applytimecourse_square_glo(raw666, glo8, oneline)
  629. # apply to circle glomerulus
  630. raw666 = applytimecourse_glomerulus(raw666, circle8bottom, oneline)
  631. oneline = (oneline -1)*1.5 +1
  632. raw666 = applytimecourse_glomerulus(raw666, circle9, oneline)
  633. # plt.plot(oneline)
  634. # add scattered light, as gaussian filter
  635. if scatterlight:
  636. raw666[3*rampwidth:xSize - 2*rampwidth, :, :] = sp.ndimage.gaussian_filter(
  637. raw666[3 * rampwidth:xSize - 2 * rampwidth, :, :], sigma=[scatterlight, scatterlight, 0])
  638. if shotnoise: # add noise, random and proportional to square root of signal
  639. # photons are poisson distributed
  640. # noisier = lambda p : np.random.poisson(p)
  641. # raw666 = noisier(raw666)
  642. raw666 = np.random.poisson(raw666) # one line solution! Python is so cool...
  643. ##movement. I want movement that is subpixel, therefore each frame is rescaled 10fold.
  644. # using for-loop to save memory space
  645. if AddMovement:
  646. # create random movement array in x and y. AddMovementSize
  647. # movement is slow, therefore random numbers first on array a tenth of the size
  648. # then blown up by 10, and limited to tSize elements
  649. x_movement = np.random.rand(tSize//10 + 1)*AddMovementSize
  650. x_movement = ndimage.zoom(x_movement, 10)[:tSize]
  651. y_movement = np.random.rand(tSize//10 + 1)*AddMovementSize
  652. y_movement = ndimage.zoom(y_movement, 10)[:tSize]
  653. # shift image by image
  654. for i in range(tSize):
  655. raw666[3*rampwidth:xSize - 2*rampwidth,:,i] = ndimage.shift(
  656. raw666[3*rampwidth:xSize - 2*rampwidth,:,i], (x_movement[i], y_movement[i]),
  657. mode='nearest')
  658. if darknoise:
  659. # add chip noise.
  660. # This comes at the end, because it is not influenced by light
  661. noise = np.random.rand(xSize, ySize, tSize) # values in [0-1]
  662. noise = noise * darknoise_amplitude + darknoise_mean - darknoise_amplitude / 2
  663. raw666 = raw666 + noise
  664. # add background fluorescence level that is not affected by any of the above manipulations
  665. # simulating fluorescence that is not from the reporter
  666. # and that is not affected by bleaching
  667. raw666 += noBleach_lightlevel
  668. # now add movement. Smooth to mimic vertical movement
  669. # smoooth some frames, to mimit out of focus movement
  670. # smoothOutOfFocus = 5
  671. # smoothOutOfFocus_frames = [4,5,34,35,36,37,50,51,52,53,53,55,70,71,72]
  672. if smoothOutOfFocus: #only if not 0
  673. # syntax as for scatterlight
  674. raw666[3 * rampwidth:xSize - 2 * rampwidth, :, smoothOutOfFocus_frames] = sp.ndimage.gaussian_filter(
  675. raw666[3 * rampwidth:xSize - 2 * rampwidth, :, smoothOutOfFocus_frames], sigma=[scatterlight, scatterlight, 0])
  676. if badpixels: ##move to after movement creation
  677. # bad pixels are fixed in space - therefore equal for third dimension
  678. noise = np.random.rand(xSize, ySize) > badpixels_clip # values in [0-1]
  679. raw666[noise,:] = 0
  680. # now, AFTER the noise, get a ramp of totally clean signals for calibration
  681. if addRightBand:
  682. # create a step function with stepsize steps, also to 2*lightlevel
  683. # this area has no signals in time - only differrent background, no noise
  684. stepfunction = np.repeat(np.arange(stepsize), ySize / stepsize)
  685. stepfunction = stepfunction * (2 * lightlevel / np.max(stepfunction))
  686. # shift by darknoise_mean to avoid having values of 0, which cause trouble when dividing in CalcSig
  687. stepfunction = stepfunction + darknoise_mean
  688. stepfunction = stepfunction.reshape(1, ySize, 1)
  689. raw666[-rampwidth:, :, :] = stepfunction # set to uniform background level
  690. # create a step function with stepsize steps
  691. stepfunction = np.repeat(np.arange(stepsize), ySize / stepsize) - stepsize // 2 # negative and positive signals
  692. # calibrate to peaksignal max both ways
  693. stepfunction = ((peaksignal / 100) / np.max(stepfunction)) * stepfunction
  694. # values are given in percent
  695. stepfunction = (stepfunction + 1) * lightlevel
  696. raw666[-2 * rampwidth:-rampwidth, :, :] = lightlevel # set to uniform background level
  697. stepfunction = stepfunction.reshape(1, ySize, 1)
  698. raw666[-2 * rampwidth:-rampwidth, :, stimonset:stimoffset] = stepfunction
  699. # plt.plot(raw666[-2*rampwidth,:,10])
  700. # plt.plot(raw666[-2*rampwidth,:,25])
  701. # plt.show()
  702. ##
  703. # camera is 12 bit, therefore clip to 4095, and integer
  704. raw666 = np.clip(raw666.astype(int), 0, 4095)
  705. # plt.imshow(raw666[:,:,30].T, origin='lower')
  706. # plt.show()
  707. # plt.plot(raw666[100,10,:])
  708. # plt.plot(raw666[100,60,:])
  709. # plt.plot(raw666[100,80,:])
  710. # plt.plot(raw666[80,60,:])
  711. # plt.plot(raw666[60,60,:])
  712. # plt.show()
  713. return raw666
  714. def MovementCorrection(MatrixIN, flag):
  715. #;input: a 3-dim-matrix MatrixIN
  716. #;output: another matrix, with each frame shifted in x and y so that the movements are corrected
  717. #;this output has been removed - program should crash when called in old mode
  718. #;output: shiftArray contains how much each frame was shifted
  719. #;options
  720. def old_RollIt(frames, shiftArray, neighbourSearch, MatrixIN, matrixOUT, correlation, maxShiftX, maxShiftY):
  721. # uses shiftArray, matrix etc.
  722. # does not work yet (26.7.2018)
  723. bestXshift = shiftArray[0,frames]
  724. bestYshift = shiftArray[1,frames]
  725. # ;take values from previous shift
  726. for sx in range( (-1)*neighbourSearch, neighbourSearch+1):
  727. for sy in range( (-1)*neighbourSearch, neighbourSearch+1):
  728. shift1x = shiftArray[0,frames] + sx
  729. shift1y = shiftArray[1,frames] + sy
  730. if (shift1x > maxShiftX) : shift1x = maxShiftX
  731. if (shift1y > maxShiftY) : shift1y = maxShiftY
  732. if (shift1x < -maxShiftX): shift1x = -maxShiftX
  733. if (shift1y < -maxShiftY): shift1y = -maxShiftY
  734. result = np.corrcoef(MatrixIN[ (maxShiftX+shift1x):(maxShiftX+smallMsizeX+shift1x),
  735. (maxShiftY+shift1y):(maxShiftY+smallMsizeY+shift1y),
  736. frames].flatten(),
  737. MatrixIN[ (maxShiftX):(maxShiftX+smallMsizeX),
  738. (maxShiftY):(maxShiftY+smallMsizeY),
  739. compareFrame].flatten())
  740. # result = correlate(matrixIN(maxShiftX+shift1x:(maxShiftX+smallMsizeX+shift1x-1),maxShiftY+shift1y:(maxShiftY+smallMsizeY+shift1Y-1),frames), $
  741. # matrixIN(maxShiftX:(maxShiftX+smallMsizeX-1),MaxShiftY:(MaxShiftY+smallMsizeY-1),compareFrame) )
  742. #
  743. if (result[1][0] > correlation): # THEN begin ; found a better shift
  744. bestXshift = shift1x
  745. bestYshift = shift1y
  746. correlation= result[1][0]
  747. if (bestXshift > maxShiftX): print('*****Movementcorrection: shiftX exceeds positive limit!')
  748. if (bestXshift < -maxShiftX): print('*****Movementcorrection: shiftX exceeds negative limit!')
  749. if (bestYshift > maxShiftY): print('*****Movementcorrection: shiftY exceeds positive limit!')
  750. if (bestYshift < -maxShiftY): print('*****Movementcorrection: shiftY exceeds negative limit!')
  751. shiftArray[0,frames] = bestXshift
  752. shiftArray[1,frames] = bestYshift
  753. shiftArray[2,frames] = int(correlation*10)
  754. # the IDL program shifted by the negative amount??
  755. matrixOUT[:,:,frames] = np.roll(matrixOUT[:,:,frames], bestXshift, axis=0)
  756. matrixOUT[:,:,frames] = np.roll(matrixOUT[:,:,frames], bestYshift, axis=1)
  757. return (shiftArray, matrixOUT, correlation) #Rollit within MovementCorrection
  758. def RollIt(frames, compareFrame, neighbourSearch, MatrixIN, MatrixOUT, shiftArray):
  759. #simplified version - shifts always from central 0 position
  760. #this solution is slow, because all shifts are evaluated every time
  761. # in IDL (old_RollIt), neighbour search meant that only few additional shifts were tested each time
  762. # shift matrix by all pixel values up to neighbourSearch
  763. correlation = 0
  764. for sx in range( (-1)*neighbourSearch, neighbourSearch+1):
  765. for sy in range( (-1)*neighbourSearch, neighbourSearch+1):
  766. # for each shift, calculate correlation
  767. shiftMatrix = np.roll( MatrixIN[:,:,frames], sx, axis=0)
  768. shiftMatrix = np.roll(shiftMatrix, sy, axis=1)
  769. #calculate correlation, avoiding the border region
  770. result = np.corrcoef(shiftMatrix[ (neighbourSearch):(-neighbourSearch),
  771. (neighbourSearch):(-neighbourSearch)].flatten(),
  772. MatrixIN[ (neighbourSearch):(-neighbourSearch),
  773. (neighbourSearch):(-neighbourSearch),
  774. compareFrame].flatten())
  775. if (result[1][0] > correlation): # THEN begin ; found a better shift
  776. bestXshift = sx
  777. bestYshift = sy
  778. correlation= result[1][0]
  779. shiftArray[0,frames] = bestXshift
  780. shiftArray[1,frames] = bestYshift
  781. shiftArray[2,frames] = int(correlation*10)
  782. # the IDL program shifted by the negative amount??
  783. MatrixOUT[:,:,frames] = np.roll( MatrixIN[:,:,frames], bestXshift, axis=0)
  784. MatrixOUT[:,:,frames] = np.roll(MatrixOUT[:,:,frames], bestYshift, axis=1)
  785. return (shiftArray, MatrixOUT) #Rollit within MovementCorrection
  786. # local settings for MovementCorrection
  787. maxShift = 0.10 #;proportion of maximal shift allowed
  788. compareFrame = 5 #;which frame to take as standard view (i.e. not moved)
  789. plotShift = True #; plot the shift result
  790. logFile = True #;
  791. # logFileName = flag.STG_OdorReportPath +flag.STG_ReportTag +'_Shift.log'
  792. # ; if set to 0 then all possible movements are checked
  793. (sizeX, sizeY, sizeZ) = MatrixIN.shape
  794. neighbourSearch = min([int(sizeX * maxShift),int(sizeY * maxShift)])
  795. #;define ShiftArray which contains all shift information
  796. shiftArray = np.zeros((3, sizeZ), dtype=int) #;dim0:shiftX,dim1:shiftY, dim3:corr*100
  797. #;define outputmatrix
  798. MatrixOUT = MatrixIN.copy()
  799. # ;up from compareframe
  800. for frames in range(compareFrame+1, sizeZ):
  801. (shiftArray, MatrixOUT) = RollIt(frames, compareFrame, neighbourSearch, MatrixIN, MatrixOUT, shiftArray)
  802. # ;down from compareframe
  803. for frames in range(compareFrame-1, -1, -1):
  804. (shiftArray, MatrixOUT) = RollIt(frames, compareFrame, neighbourSearch, MatrixIN, MatrixOUT, shiftArray)
  805. #
  806. #;suboptimal approach: go through all possibel shifts
  807. # implemented differently from IDL now, by increasing neighbourSearch to very high values
  808. ######## done movement correction
  809. if plotShift:
  810. # evenly sampled time at 200ms intervals
  811. t = np.arange(0., sizeZ, 1) #maybe replace 1 with framerate, to have time
  812. # use p1.frequency or the like
  813. # red dashes, blue squares and green triangles
  814. plt.plot(t, shiftArray[0,:], 'r--', t, shiftArray[1,:], 'b--', t, shiftArray[2,:], 'g^')
  815. plt.show()
  816. # window, 0
  817. # ;loadCT, 39
  818. # range = max([maxshiftX,maxshiftY])
  819. # plot, shiftArray(0,*), yrange=[(-1)*range,range],color=140
  820. # oplot, shiftarray(1,*), color=254
  821. # oplot, shiftarray(2,*), color=255
  822. if logFile:
  823. print('ViewLoadData.MovementCorrection: logFile not implemented - still to do')
  824. #no need for log file, shifts are written in other program
  825. # openW, 10, logFileName, /APPEND
  826. # printF, 10, string(9b)+string(9b)+'Followes report shift for measurement ',p1.ex_name,'*',p1.experiment
  827. # for i=0,sizeZ-1 do begin #
  828. # printF, 10, strtrim(string(shiftArray(0,i)),2),+string(9b)+strtrim(string(shiftArray(1,i)),2) #
  829. # endFOR
  830. # printF, 10, string(9b)+string(9b)+'****************end of************** ',p1.ex_name
  831. # close, 10
  832. return (MatrixOUT, shiftArray) #MovementCorrection
  833. def ReadWriteMovementValues(flagWrite, MovementList, p1, flag):
  834. #;reads or writes movement values for within one measurement
  835. #;uses standard file name conventions
  836. #;write or read data? readFlag now boolean
  837. readFlag = (flagWrite == 'read')
  838. #any other string means: write.
  839. #filename for the list
  840. MoveFile = os.path.join(flag["STG_OdorInfoPath"],flag["STG_ReportTag"])+'.moveList'
  841. #what is the current measurement??
  842. #???inputlabel = fix(inputOdorFile)
  843. #debug MoveFile
  844. #MoveFile = 'C:/Users/Giovanni Galizia/Documents/Production/2017_Alja_PostOdor/Filme_data/data/ORN_Glomeruli/al_100312_e.moveList'
  845. if readFlag:
  846. # ;read the file
  847. if os.path.isfile(MoveFile):
  848. print('ReadWriteMovementValues: open info file for reading movement:', MoveFile)
  849. # format of movelist:
  850. # first column is the name of the measurement. For each measurement there are six rows.
  851. # first three rows relate to odor 0, second three rows to odor 1. Take odor 1 here.
  852. # the second column is the row label: 0 for x movement, 1 for y movement, 2 for "quality", i.e. 0,1,2 ... repeat this...
  853. # the third column is the odor flag, generally 0,0,0,1,1,1, ...repeat this...
  854. # HERE: take row 4 for x movement, and row 5 for y movement, IGNORE the rest for now.
  855. # movelist is tab-separated
  856. moveList_df = pd.read_csv(MoveFile, sep='\t', header=None)
  857. # which is the measurement I am interested in?
  858. measuNum = p1.messungszahl
  859. # I only want the rows that have measuNum in the first column
  860. moveList_df = moveList_df.loc[moveList_df.iloc[:,0] == measuNum]
  861. # remove the first two columns, and keep only fourth and fifth row
  862. #moveList_df = moveList_df.iloc[3:5,3:] #take rows 3-5, i.e. second three rows
  863. moveList_df = moveList_df.iloc[-3:,3:p1.metadata.frames+3] #take last three rows,
  864. # and only as many columns as frames starting at 3
  865. #;definition of movement list in the master is:
  866. #;movementList = intarr(3,p1.frames,p1.odors+1); x/y/quality, frames, data(odor/wavelength)
  867. # because in IDL there were, generally, two odors, the first fictive, the second not
  868. # in most moveLists there will be 6 lines, with identical values in the first 3 and secont 3
  869. # or with 0 in the first 3 lines.
  870. # therefore, here in Phython I take the LAST 3 lines
  871. # this way, in the future, I can write 3 lines only.
  872. # will go wrong if several odors are used (e.g. separate movementlist in Fura? CHECK)
  873. MovementList = moveList_df.values # report matrix only
  874. else: #write file
  875. print('ReadWriteMovementValues: open info file for writing ', MoveFile)
  876. # add the first three columns to movementList matrix
  877. # first column: p1.messungszahl
  878. # second column 0,1,2 (for x/y/quality)
  879. # third column 0 (for odor - not used in Python, yet)
  880. out_info = np.array([[p1.messungszahl,0,0],[p1.messungszahl,1,0],[p1.messungszahl,2,0]])
  881. out_move = pd.DataFrame(np.append(out_info, MovementList, axis=1)) #also convert to dataframe
  882. if os.path.isfile(MoveFile): #file exists
  883. print('ReadWriteMovementValues: appending to old file')
  884. # load previous data
  885. old_move = pd.read_csv(MoveFile, sep='\t', header=None)
  886. out_move = pd.concat([old_move,out_move]) #add this one to the existing list
  887. # now write the new movementList to file.
  888. # use dataframe format for my lazyness - np.savetxt would be leaner
  889. # do not add header line (also IDL did not do that any more)
  890. out_move.to_csv(MoveFile, sep='\t', header=False, index=False)
  891. #movementList is just the shiftArray, movementList_w has the first three columns added
  892. return MovementList #
  893. #end; ReadWriteMovementValues
  894. def MovementCorrectionMaster(p1, flag):
  895. #
  896. #;old movement correction (giovanni, beware, does not work for all datasets)
  897. #;or new movement correction (mathias, yet to be tested as of April 1st, 2003), with flag setting above 10
  898. #
  899. #; recalculate movement (flag set to 1), or recalculate and save the shifts (flag set to 2), or use saved shifts (flag set to 3)
  900. MovementFlag = flag.CSM_Movement
  901. ShrinkFactor = flag.LE_ShrinkFaktor #
  902. # movement values are stored WITHOUT shrink factor
  903. MathiasCorrection = (MovementFlag > 10)
  904. if MathiasCorrection: MovementFlag = MovementFlag - 10
  905. #;either recalculate movement (flag set to 1), or recalculate and save the shifts (flag set to 2), or use saved shifts (flag set to 3)
  906. if (MovementFlag == 1): print('ViewLoadData.MovementCorrectionMaster: on the spot')
  907. if (MovementFlag == 2): print('ViewLoadData.MovementCorrectionMaster: on the spot, saving values')
  908. if (MovementFlag == 3): print('ViewLoadData.MovementCorrectionMaster: using saved values')
  909. #IF (movementFlag eq 4) THEN print, 'MovementCorrectionMaster: using saved values, being equal for both sets (master/slave)'
  910. #IF (movementFlag eq 5) THEN print, 'Extracting Shifts from Movement List - ignoring movements'
  911. #
  912. #;check movement on monitor?
  913. # MonitorMovement = 1 # ;(movementFlag eq 2)
  914. #
  915. #;define movement value array
  916. # odors = 1 # or copy p1.odors, if that exists
  917. # MovementList = np.zeros((3, p1.frames, odors), dtype=int) # I take 2 odors for backwards compatibility
  918. # MovementList = np.zeros(3, p1.frames, 1, dtype=int) # I take 2 odors for backwards compatibility
  919. # the two odors are: 0 for control (empty) or fura1, 1 for measurement or fura2
  920. #intarr(3,p1.frames,p1.odors+1); x/y/quality, frames, data(odor/wavelength)
  921. MovementList = np.zeros((3, p1.metadata.frames), dtype=int) # I would take 2 odors for backwards compatibility
  922. ####################
  923. # Problem here: odors is abolished in this Python setting, but for FURA I don't have a solution yet
  924. # the thing is: I cannot do a movement correction separately for the two wavelengths, without alignem them,
  925. # because they might move astray.
  926. # For new data, movement correction should use new tools anyway.
  927. #
  928. #
  929. # ;go through raw data, do movement correction, for each 'odorset' separatedly (e.g. also for the two wavelengths in FURA)
  930. if MovementFlag in [1,2]:
  931. # IF ((MovementFlag ge 1) AND (MovementFlag le 2)) THEN begin
  932. # for i=0, p1.odors-1 do begin
  933. # IF (total(raw1[*,*,*,i]) gt 0) THEN begin
  934. if MathiasCorrection:
  935. print('MovementCorrectionMaster - MathiasCorrection still to do')
  936. # MovementCorrectionMathias()
  937. # ;MovementCorrectionMathias, raw1[*,*,*,i], movementList[*,*,i] ;in ImageALMathias
  938. # movementList[0:1,*,i] = MovementCorrectionMathias(raw1[*,*,*,i]) ;eine Funktion??
  939. # ;MovementCorrectionMathias gibt nur x/y, nicht qualität 'raus
  940. else:
  941. #MovementCorrection, raw1[*,*,*,i], movementList[*,*,i] # MatrixIN, shiftArray, flag
  942. print('MovementCorrectionMaster: now calling MovementCorrection - be patient!')
  943. (MatrixOUT, MovementList) = MovementCorrection(p1.raw1, flag)
  944. print('MovementCorrectionMaster: now done with MovementCorrection.')
  945. if MovementFlag in [2]:
  946. MovementList = ReadWriteMovementValues('write', MovementList, p1, flag)
  947. if MovementFlag in [3]:
  948. # ;load movementList for flag set to 3
  949. # IF ((MovementFlag ge 3) AND (MovementFlag le 4)) THEN begin
  950. # ReadWriteMovementValues, 'read', movementList
  951. # print, 'Reading movement information - values are corrected for shrinkraktor! (MovementCorrectionMaster)'
  952. # IF (ShrinkFactor ge 2) then begin
  953. # movementList[0,*,*] = fix(movementList[0,*,*] / shrinkfactor)
  954. # movementList[1,*,*] = fix(movementList[1,*,*] / shrinkfactor)
  955. # endIF
  956. # endIF
  957. MovementList = ReadWriteMovementValues('read', MovementList, p1, flag)
  958. if ShrinkFactor > 1:
  959. MovementList[0:2,:] = (MovementList[0:2,:] / ShrinkFactor).astype(int)
  960. # now apply to data
  961. MatrixOUT = p1.raw1.copy
  962. MatrixOUT[:,:,frames] = np.roll(MatrixOUT[:,:,frames], bestXshift, axis=0)
  963. MatrixOUT[:,:,frames] = np.roll(MatrixOUT[:,:,frames], bestYshift, axis=1)
  964. if MovementFlag in [4,5]:
  965. print('MovementCorrectionMaster: flag 4,5 not implemented yet in phython')
  966. # ;write info from one odor into the other one
  967. # IF (MovementFlag eq 4) THEN begin
  968. # ;which one is the odor that has information?
  969. # IF total(movementList[*,*,0]) eq 0 then begin
  970. # ;0 is the empty odor
  971. # movementList[*,*,0] = movementList[*,*,1]
  972. # endIF else begin
  973. # ;1 is the empty odor
  974. # movementList[*,*,1] = movementList[*,*,0]
  975. # endELSE
  976. # endIF
  977. # IF (movementFlag eq 5) THEN begin
  978. # ReadWriteMovementValues, 'read', movementList
  979. # ;no movement correction, but extract shifts
  980. # referenceImage = fix(flag[LE_StartBackground])
  981. # referenceOdorBuffer = 1
  982. # p1.shiftX = movementList[0,referenceImage,referenceOdorBuffer]
  983. # p1.shiftY = movementList[1,referenceImage,referenceOdorBuffer]
  984. # monitorMovement = 0 ; no need to see the movement on screen
  985. # print, 'Movement correction OFF, shifts taken from moveList frame ',referenceimage,'; and odorBuffer ',referenceOdorBuffer
  986. # ENDIF else begin
  987. # ;apply movementList to raw data
  988. # for i=0, p1.odors do begin
  989. # for j=0, p1.frames-1 do begin
  990. # raw1[*,*,j,i] = shift(raw1[*,*,j,i],movementList[0,j,i],movementList[1,j,i])
  991. # endFor
  992. # endFOR
  993. # endELSE ;movementFlag 5
  994. #
  995. # ;check movement with screen output for flag set to 2
  996. # ;show corrected data
  997. # IF monitorMovement then begin
  998. # ;part1: plot shifts and quality
  999. # window, 2*p1.odors, xsize=250, ysize=250
  1000. # loadCT, 39
  1001. # ;schleife über odors und x/y/qualität
  1002. # rangeTop = max(MovementList(0:1,*,*))
  1003. # rangeBot = min(MovementList(0:1,*,*))
  1004. # plot, movementList[2,*,0], yrange=[rangeBot-1,rangeTop+1],color=255
  1005. # oplot, movementList[1,*,0], color=254
  1006. # oplot, movementList[0,*,0], color=140
  1007. #
  1008. # ;part 2, plot x/y intersection over time
  1009. # for i=0, p1.odors-1 do begin
  1010. # IF (total(raw1[*,*,*,i]) gt 0) THEN begin
  1011. # showMovement, raw1[*,*,*,i], i+p1.odors ;opens one window for each 'odor'
  1012. # endIF
  1013. # endFOR
  1014. # endIF
  1015. #
  1016. #
  1017. #
  1018. #now overwrite p1.raw1
  1019. p1.raw1 = MatrixOUT
  1020. #end; MovementCorrectionMaster
  1021. return p1 # end movementcorrectionmaster
  1022. # def loadDataMaster(flag, p1):
  1023. # # ;correct flag setting
  1024. # #IF (fix(flag[LE_ShrinkFaktor]) eq 0) THEN flag[LE_ShrinkFaktor]=1
  1025. # if flag["LE_ShrinkFaktor"] == 0:
  1026. # print("ViewLoadData.loaddatamaster: flag.le_shrinkfactor == 0, add correction ")
  1027. # #;that has become necessary for pixel display and coordinate calculation
  1028. # #;in the loading routines 0 and 1 were already equivalent
  1029. # #;Giovanni, FEb.05
  1030. # setup = flag["LE_loadExp"]
  1031. # #;flag to clip dark pixels to a minimum value, Gio Sept 2015
  1032. # #;default value 0, i.e. no clipping.
  1033. # # ClipPixels = flag.le_ClipPixels
  1034. # #
  1035. # # ;load experiment
  1036. #
  1037. # # try to read dbb1 value as the absolute path of a VIEW-tiff. If there are any expected exceptions, abort.
  1038. # try:
  1039. # p1 = load_VIEW_tif(flag, p1)
  1040. # setup = 30
  1041. # except FileNotFoundError as fnfe:
  1042. # pass
  1043. # except AssertionError as ae:
  1044. # if str(ae).startswith("Error reading"):
  1045. # pass
  1046. # except IOError as ioe:
  1047. # if str(ioe).endswith("(3 expected)"):
  1048. # pass
  1049. #
  1050. # if (setup == 0):
  1051. # print("ViewLoadData.loaddatamaster: setup is 0, old Berlin system - load not implemented in python yet")
  1052. # # inFile = flag[stg_DataPath]+inputMark
  1053. # # loadexp, InFile, raw1, foto1, dark1, p1
  1054. # # parts = str_sep(inputMark, dirsign) ; separate parts of path+name
  1055. # # info = size(parts) ; get info on variable PARTS, info(1) holds size of array
  1056. # # experiment = parts(info(1)-1) ; name is at last position of array PARTS
  1057. # # p1.experiment = experiment
  1058. # # endIF
  1059. #
  1060. # elif (setup == 3):
  1061. # p1 = loadTILL(flag, p1)
  1062. # # IF setup eq 3 THEN begin
  1063. # # IF fix(flag[VIEW_No4Darray]) THEN begin
  1064. # # loadTILL_3Dim, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1065. # # endIF else begin
  1066. # # loadTILL, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1067. # # endELSE
  1068. # # endIF
  1069. # elif (setup == 4):
  1070. # p1 = loadFURA(flag, p1)
  1071. # # IF setup eq 4 THEN loadFURA, inputMark, measu2, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1072. # # ;setup 4 is compatible with VIEW_no4Darray
  1073. # #
  1074. # # IF setup eq 5 THEN loadFURA_and_CaGr, inputMark, measu2, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1075. # #
  1076. # # IF setup eq 6 THEN loadZseries, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1077. # #
  1078. # # IF setup eq 7 THEN begin
  1079. # # loadTILL, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1080. # # shuffleMultipleLayers, 3 ; 3 for three layers, recorded in one film, to be splitted as if 3 odors
  1081. # # endIF
  1082. # #
  1083. # # ;load till photonics setup, with split image of two wavelength,
  1084. # # ;treat as FURA data
  1085. # # IF setup eq 8 THEN loadMicroImager, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1086. # #
  1087. # #
  1088. # # IF setup eq 13 THEN loadTILLbyte, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1089. # #
  1090. # # IF setup eq 14 THEN loadIDLraw, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1091. # #
  1092. # #
  1093. # # IF setup eq 17 THEN begin
  1094. # # print, 'loading using setup type 17'
  1095. # # loadTILL3Layer, inputMark, measu2, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1096. # # ;loads measurements done on threelayers in 3 separate dbb files, and glues them side by side
  1097. # # ; Inga, Aug. 2014, Konstanz
  1098. # # endIF
  1099. # #
  1100. # # ;setup 9 loads single wavelength data, using the DBB-file specified in the measu2 column of the .lst file (TILL data)
  1101. # # ;usefult to load only the slave, or only the 380nm measurements in FURA data
  1102. # # IF setup eq 9 THEN loadTILL, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 2
  1103. # #
  1104. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1105. # # IF setup eq 15 THEN loadOlympusR, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1106. # #
  1107. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1108. # # IF setup eq 20 THEN loadZeiss, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1109. # elif (setup == 20):
  1110. # p1 = loadZeiss(flag, p1)
  1111. # #
  1112. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1113. # # ;21 reads a .tif file (the .lst may contain any extension, that is ignored and replaced by .tif
  1114. # # IF setup eq 21 THEN Load3DTiff, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1115. # # ;22 reads a _affine.tif
  1116. # # IF setup eq 22 THEN Load3DTiff, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1117. # # ;23 reads a _full.tif
  1118. # # IF setup eq 23 THEN Load3DTiff, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1119. # #
  1120. # #
  1121. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1122. # # IF setup eq 26 THEN load_3DArray_Raw, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1123. # #
  1124. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1125. # # IF setup eq 30 THEN load_redshirtimaging, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst', 1
  1126. # #
  1127. # #
  1128. # # ;load format from Olympus Imaging system, Andy March 2010
  1129. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1130. # # IF setup eq 40 THEN loadOlympusR, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1131. # # ;inputmark can be the file name, or the line tag number in the .lst file .
  1132. # # IF setup eq 41 THEN loadOlympusR_ratio, inputMark, flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.lst'
  1133. # elif setup == 30: # internal tif format
  1134. # pass # should have been read above
  1135. # elif (setup == 665): #generate test data, use odor concentration as max value
  1136. # p1 = LoadRaw666(flag, p1, peaksignal = -10)
  1137. # #generate test data, peaksignal -10
  1138. # elif (setup == 666):
  1139. # p1 = LoadRaw666(flag, p1, peaksignal = p1.odor_nr)
  1140. # # this allows to use the column odor concentration in a list file to generate different signal sizes
  1141. # elif (setup == 667): #generate test data
  1142. # p1 = LoadRaw666(flag, p1, peaksignal = 10)
  1143. # #generate test data, peaksignal 10
  1144. # else:
  1145. #
  1146. # print("ViewLoadData.loaddatamaster: setup load not implemented in python yet")
  1147. # raise NotImplementedError
  1148. # #
  1149. # #;SlaveCorrection ##NOT IMPLEMENTED IN PYTHON - from old mirror system
  1150. # #;if the image of the slave is shifted/rotated/distorted, correct it
  1151. # #IF ((setup eq 4) OR (setup eq 8)) THEN begin
  1152. # # ;the correction parameters are in file ....slaveMod
  1153. # # ;in the directory with the .inf files
  1154. # # ;a file 'all.slaveMod' is active for ALL files in that /listen directory
  1155. # # ;a file 'animal.slaveMod' overwrites 'all.slaveMod' should both be present
  1156. # # modifyFile1 = flag[stg_OdorInfoPath]+flag[stg_ReportTag]+'.slaveMod'
  1157. # # modifyFile2 = flag[stg_OdorInfoPath]+'all'+'.slaveMod'
  1158. # # existFile1 = existFile(modifyFile1)
  1159. # # existFile2 = existFile(modifyFile2)
  1160. # # IF (existFile1 OR existFile2) THEN begin ;modify if there is the necessary information
  1161. # # ;read that information
  1162. # # IF existFile1 THEN modifyFile = modifyFile1 ELSE modifyFile = modifyFile2
  1163. # # openR, unit, modifyFile, /GET_LUN
  1164. # # line = ''
  1165. # # readF, unit, line
  1166. # # readF, unit, line ;the second line contains the modify information
  1167. # # free_lun, unit ;close the file
  1168. # # print, 'LoadDataMaster: Modifying SLAVE according to information in file: ',modifyFile
  1169. # # print, 'Modify parameters are: ', line
  1170. # # ;line is: shiftX shiftY mod rotAng magni rotCentX rotCentY
  1171. # # shiftArray = str_sep(line, string(9b))
  1172. # # ;the slave to be modified is the dataset raw(*,*,*,1)
  1173. # # ;first the shift, then the rotation
  1174. # # for i=0, p1.frames-1 do begin
  1175. # # b = float(reform(raw1(*,*,i,1))) ; take that frame, remove spurious dimensions
  1176. # # b = shift(b,shiftArray(0),shiftArray(1))
  1177. # # ;modify this slice - after shift
  1178. # # b = rot(b, shiftArray(3),shiftArray(4)/100.0,shiftArray(5),shiftArray(6), /interp, /pivot)
  1179. # # ;Result = ROT( A, Angle, [Mag, X0, Y0] [, /INTERP] [, CUBIC=value{-1 to 0}] [, MISSING=value] [, /PIVOT] )
  1180. # # ;rotate around point x0/y0 by Angle clockwise, Magnify by Mag
  1181. # # raw1(*,*,i,1) = fix(b)
  1182. # # endFor
  1183. # # endIF
  1184. # #endIF
  1185. # #
  1186. # #;movementCorrection
  1187. # #;the settings in movementCorrection affect the shift correction - therefore, movement correction preceeds shift correction
  1188. # if (flag["CSM_Movement"] > 0):
  1189. # p1 = MovementCorrectionMaster(p1, flag)
  1190. # #endIF ; movementCorrection
  1191. # #
  1192. # #
  1193. # #;shift correction: if flag is 0: no shift here, but coordinates are shifted
  1194. # #; if flag is 1: shift here , coordinates are not shifted
  1195. # #; if flag is 2: shift entry in p1.shift is ignored altogether (e.g. when movement correction contains shift information)
  1196. # #$ DataShift not translated yet
  1197. # #IF (fix(flag[CSM_DataShift]) eq 1) THEN begin
  1198. # # print, 'LoadDataMaster: shift Data by ',p1.shiftX, p1.shiftY
  1199. # # ;correct shifts
  1200. # # p1.shiftX = (-1)*p1.shiftX / fix(flag[LE_ShrinkFaktor])
  1201. # # p1.shiftY = (-1)*p1.shiftY / fix(flag[LE_ShrinkFaktor])
  1202. # # ;shift the data instead of shifting the masks
  1203. # # raw1 = shift(raw1,p1.shiftX,p1.shiftY,0,0)
  1204. # # ;put the shifts to 0, to avoid that the masks will be shifted
  1205. # # p1.shiftX = 0
  1206. # # p1.shiftY = 0
  1207. # #endIF
  1208. # #IF (fix(flag[CSM_DataShift]) eq 2) THEN begin
  1209. # # print, 'LoadDataMaster: shift information ignored'
  1210. # # ;put the shifts to 0, to avoid that the masks will be shifted
  1211. # # p1.shiftX = 0
  1212. # # p1.shiftY = 0
  1213. # #endIF
  1214. # #
  1215. # #
  1216. # #
  1217. # #IF (fix(flag[VIEW_No4Darray]) eq 1) THEN begin
  1218. # # IF ((setup eq 4) OR (setup eq 3) OR (setup eq 8)) THEN begin
  1219. # # ;for these options specific care has been taken
  1220. # # end else begin
  1221. # # ;remove the odor buffer 0
  1222. # # ;watchout with FURA data
  1223. # # raw1 = raw1(*,*,*,1:p1.odors)
  1224. # # p1.odors = p1.odors-1
  1225. # # odor = (odor - 1)>0
  1226. # # IF (fix(flag[LE_UseFirstBuffer]) ge 1) THEN flag[LE_UseFirstBuffer] = flag[LE_UseFirstBuffer] - 1
  1227. # # print, '*****************LoadDataMaster: deleted odor buffer 1, only 0. '
  1228. # # endELSE
  1229. # #endIF
  1230. # #
  1231. # ## skip NOT IMPLEMENTED in python (yet?)
  1232. # #;skip frames if requested
  1233. # #SF_upFront = fix(flag(CSM_SkipFrmUpFront))
  1234. # #SF_atBack = fix(flag(CSM_SkipFrmAtBack))
  1235. # #SkipFrames = (SF_upFront ne 0) OR (SF_atBack ne 0)
  1236. # #IF SkipFrames THEN begin
  1237. # # ;if the numbers are negative, they are relative to Stimulus ONSET, otherwise to FIRST FRAME,
  1238. # # IF SF_upFront lt 0 THEN begin
  1239. # # SK_firstFrame = p1.stimulus_on + SF_upFront
  1240. # # endIF else begin
  1241. # # SK_firstFrame = SF_upFront
  1242. # # endELSE
  1243. # # ;if the numbers are negative, they are relative to Stimulus ONSET, otherwise to FIRST FRAME,
  1244. # # IF SF_atBack lt 0 THEN begin
  1245. # # SK_lastFrame = p1.stimulus_on - SF_atBack
  1246. # # endIF else begin
  1247. # # SK_lastFrame = SF_atBack
  1248. # # endELSE
  1249. # # IF (SF_atBack eq 0) THEN begin
  1250. # # SK_lastFrame = p1.frames -1
  1251. # # endIF
  1252. # # ;error messages
  1253. # # IF (SK_firstFrame lt 0) then begin
  1254. # # print, 'skipping frames with wrong parameters in LoadDataMaster.pro: SK_firstFrame = ',SK_firstframe
  1255. # # stop
  1256. # # endIF
  1257. # # IF (SK_lastFrame ge p1.frames) then begin
  1258. # # print, 'skipping frames with wrong parameters in LoadDataMaster.pro: SK_lastFrame = ',SK_lastFrame
  1259. # # stop
  1260. # # endIF
  1261. # # SK_Frames = SK_lastFrame - SK_firstFrame + 1
  1262. # # IF SK_Frames lt 1 THEN begin
  1263. # # print, 'skipping frames with wrong parameters in LoadDataMaster.pro: SK_Frames = ',SK_Frames
  1264. # # stop
  1265. # # endIF
  1266. # # ;now cut the excess frames
  1267. # # raw1 = raw1(*,*,SK_firstFrame:SK_lastFrame,*)
  1268. # # print, 'Frames skipped. Kept frames from ',SK_firstFrame,' to ',SK_lastFrame
  1269. # # ;correct parameters
  1270. # # p1.frames = SK_Frames
  1271. # # p1.stimulus_on = P1.stimulus_on - SK_firstFrame
  1272. # # p1.stimulus_end = p1.stimulus_end - SK_firstFrame
  1273. # # p1.stimulus_del = p1.stimulus_del - SK_firstFrame*p1.trial_ticks
  1274. # # p1.stim2ON = p1.stim2ON - SK_firstFrame
  1275. # # p1.stim2OFF = p1.stim2OFF - SK_firstFrame
  1276. # # p1.stim2_del = p1.stim2_del - SK_firstFrame*p1.trial_ticks
  1277. # #endIF ;SkipFrames
  1278. # #
  1279. # #IF ClipPixels gt 0 THEN begin
  1280. # # print, 'LoadDataMaster: Clip data to ', ClipPixels
  1281. # # raw1 = raw1 > ClipPixels
  1282. # #endIF
  1283. # #
  1284. # #IF ClipPixels lt 0 THEN begin
  1285. # # ;clips pixels to the positive value, and creates a mask file that can be used for overviews
  1286. # # ;example of how to run: set to -300, all pixels <300 will be set to 300, and a mask for the remaining pixels is saved
  1287. # # ;for faster performance, the second time the flag can be set to 300, because the mask file already exists
  1288. # # ClipPixels = (-1)*ClipPixels
  1289. # # print, 'LoadDataMaster: Clip data to ', ClipPixels
  1290. # # raw1 = raw1 > ClipPixels
  1291. # # ;create mask
  1292. # # IF (fix(flag[VIEW_No4Darray]) eq 1) THEN dataPlace = 0 ELSE dataPlace = 1
  1293. # # copyData = reform(raw1(*,*,*,dataPlace)) ;take the measurement
  1294. # # copyData = copyData gt ClipPixels ;gives 1 for all pixels gt clip
  1295. # # ;because we are not working on single frames, average for the time course
  1296. # # copyData = total(copyData, 3);sums across frames, now floating point
  1297. # # copyData = copyData / p1.frames;
  1298. # # copyData = copyData gt 0.5 ; take all pixels where for at least half of the frames
  1299. # # ; the value was larger than ClipPixels
  1300. # # maskFrame = byte(copyData) ;convert to byte
  1301. # # ;no save this mask to file
  1302. # # ;file name taken from singleOverview.pro
  1303. # # areaFileName = flag[stg_OdorMaskPath]+flag[stg_ReportTag]+'.Area'
  1304. # # print, 'LoadDataMaster.pro: saving area file to ',areaFileName
  1305. # # save, filename=areaFileName, maskFrame
  1306. # # copyData = 0B ; empty memory space
  1307. # # maskFrame = 0B
  1308. # #endIF ; ClipPixels lt 0
  1309. # #
  1310. # #
  1311. # data_sampling_period = pd.Timedelta(f"{p1.trial_ticks}ms")
  1312. # p1.pulsed_stimuli_handler.initialize_stimulus_offset(flag["mv_correctStimulusOnset"], data_sampling_period)
  1313. #
  1314. # print('ViewLoadData.LoadDataMaster: Data loaded, setup type ',setup)
  1315. # return # no return any more. p1