#pragma TextEncoding = "UTF-8" #pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma rtFunctionErrors=1 //************************************************************************************************************************* //************************************ SUMMARY **************************************************************************** // Image Explorer // Ben Murphy-Baum, 2023 // Image Explorer is a data visualization tool for 3D image stacks. // It is capable of loading complex image stacks generated by ScanImage microscopy software. // Although only ScanImage tif files can be loaded, the visualization tools will work on any 3D wave. // For non-ScanImage 3D waves, load them into a folder structure like this: // root:Scans:ParentFolder:ChildFolder:ScanWaves // ParentFolder might represent a days experiments, while ChildFolder might represent a single trial. // ScanImage .tif files can be loaded as normal tiffs for single channel, single scanfield, single frame per slice image stacks. // Anything else requires de-interleaving the data in multiple ways. // There are undoubtedly some scan configurations that have not been tested for loading. This package currently supports: // Time-varying frame scans containing: // Multiple channels // Multiple scanfields (ROIs) // Multiple z positions (e.g. using fast-z functionality from an electrically tunable lens (ETL) or piezoelectric actuator lens). // Z-stacks with multiple frames per z position // Each scanfield and channel will result in its own image wave. // So a two channel scan (e.g. red and green) with 2 scanfields will produce 4 image waves in the destination folder. // Z stacks are distinguishable because their z positions are recorded sequentially instead or near-simultaneously, // as they would be when using an ETL/piezo to get time-varying data from multiple z planes at the same time. // Z-stacks will produce a single image wave. // Time-varying scans with multiple z planes will split each z plane into a different output image wave. // So, if I have two channels, and two scanfields that are present in two z planes using an ETL, the loader will // produce 8 output image waves, one for each z plane per scanfield per channel. // Meta-data about the scan configuration and parameters is saved as a ScanInfo string in the destination folder. //************************************************************************************************************************* //********************************** HOW TO USE *************************************************************************** // Image Explorer can be opened from the 'Analysis' menu. // Once open, load in your scans. You might need to click 'Refresh' to update the explorer. // Select from 'Scan Groups' and 'Scanfields' to select which scans you want to view. // Click 'Display' to open the viewer and explore your data. Multiple scans can be displayed at the same time. // CONTROLS: //TOP ROW // Play : Begins playback of each frame in the image stack // << : Slow down playback speed // >> : Speed up playbac speed // Step : Step through the image stack one frame at a time // Auto : Auto-scale the image in X and Y // Max Proj : Displays a max projection of the image stack. Clicking Play from here will go back to the normal single frame display. // Live : Opens a 'Live ROI' display. Mousing over the image displays the time-varying fluorescence data (Z) // averaged over the indicated region. The size of the ROI is controlled in microns as a SetVariable control. // -Cumulative scaling : Scales the graph using the smallest and largest values encountered so far during Live ROI. // -Unchecking this auto-scales the data. //BOTTOM ROW // Sliders : Control the black and white points of the image display. // S : Performs an 'auto-stretch' on the image (automatically adjusts black and white points to optimal values). // -1 : Inverts the image. // ROIs : Opens a side panel for creating ROIs using different methods. //Crosshair : Overlays crosshairs on the image. // White is the center of the display window. // Green is (0,0) on the actual image coordinates // L.A. : Lock aspect ratio. Selecting this will lock the aspect ratio to be the actual image aspect based on its X/Y scaling. // Square : Displays the current contents of the image viewer into a new image graph. // ROIs: // Select New Group or any existing ROI group to put any newly created ROI in. // Marquee : Select an area of the image and click + to add the ROI. // Click : Automatically creates an ROI of the defined size at the location of a mouse click. This is my preferred method by far. // Draw : After clicking 'Start', click and drag around the image to create arbitrary ROI shapes. // This is slightly finicky, make sure the ROI name is not already taken. // In Image Explorer, check the 'Show ROI Masks' box to overlay masks on top of any displayed ROIs in the image. // These masks can be adjusted to only include areas of fluorescence and not dark pixels (e.g. dendrites). // To adjust a mask use the scroll wheel up and down to adjust the threshold during ROI creation. If adjusting after creation, // you have to go back in to the ROI panel and select the 'Click' option. After clicking 'Start', you can use the scroll wheel on any // ROI to adjust the mask threshold, regardless of how it was created. StrConstant IE = "root:Packages:NeuroToolsPlus:ScanImage" StrConstant IE_LIGHT_FONT = "Calibri Light" Menu "Analysis" "Image Explorer...",/Q,IE_OpenImageExplorer() End Function/S IE_BrowseScanImage() //Opens a browser for the user to select .tif files to load //Returns list of selected paths to the .tif files Variable refnum String extension = ".tif" //Browse the folder String message = "Select one or more ScanImage .tif files" String fileFilters = "ScanImage Files (*.tif,*.tiff):.tif,.tiff;" fileFilters += "All Files:.*;" Open/D/R/F=fileFilters/MULT=1/M=message refnum //Convert to semi-colon separated list of files paths S_filename = ReplaceString("\r",S_filename,";") //Loads the images as waves IE_LoadScanImage(S_filename) return S_filename End Function/DF IE_CreateDestinationFolder(filePath) String filePath //INPUT: full path to the .tif file //Make the data folder to hold the scan waves filePath = ReplaceString("/",filePath,":") //This is the full path of the folder to be created in Igor that will hold the scan wave String folder = "root:Scans:" + ParseFilePath(0,filePath,":",1,1) If(!DataFolderExists("root:Scans")) NewDataFolder root:Scans EndIf //Remove any whitespaces folder = ReplaceString(" ",folder,"") If(!DataFolderExists(folder)) NewDataFolder $folder EndIf //add the scan name folder on and make the folder folder += ":" + RemoveEnding(ParseFilePath(0,filePath,":",1,0),".tif") folder = ReplaceString(" ",folder,"_") If(!DataFolderExists(folder)) NewDataFolder $folder EndIf SetDataFolder $folder return $folder End Function/WAVE IE_GetHeader(fileRef,length,offset) Variable fileRef,length,offset //INPUT: valid file reference to a .tif file // length of the header, from FRAME_DATA_LENGTH tag // offset of the header //Returns the ScanImage Big Tiff HEADER from the open file reference FStatus fileRef String path = S_path + S_fileName Variable i = 0 //Set position to start of HEADER FSetPos fileRef,offset //Read in the binary data into the correctly sized string for the number of bytes in the header String/G root:str = "" SVAR str = root:str str = PadString(str,length,0) FBinRead/B=3/F=3 fileRef,str String param = IE_GetParamStr() Make/O/N=(ItemsInList(param,";"),2)/T/FREE header For(i=0;i 1) //Z stack (probably) with multiple frames per slice Make/N=(xPixels,yPixels,numZs,framesPerSlice)/O/W $ROIname/Wave=scanROI Else If(numROIs > 1 || numZs == 1) //Not a Zstack (not necessarily true, but probably true for our purposes) //Standard for multi ROI multi-plane imaging //Old method, create wave before filling it. // Make/N=(xPixels,yPixels,(numFrames / numZs))/O/W $ROIname/Wave=scanROI //Just make this so the WaveDim call below works, not optimal but much faster than making the wave prior to duplication below. //Should clean this up to avoid the wave creation step entirely. Make/N=(1,1,1)/O/W $ROIname/Wave=scanROI Else //Z stack, single frame per slice, potentially multiple volumes taken (numTimeFrames) Make/N=(xPixels,yPixels,numZs,numTimeFrames)/O/W $ROIname/Wave=scanROI EndIf EndIf imageList += GetWavesDataFolder(scanROI,2) + ";" //These are built in scan mirror offsets used to center the image. By removing these, the scaling of the image reflects the actual stage position, //which is a lot more useful for our analysis. Variable XOffset = str2num(IE_GetSIParam("scanAngleShiftFast",header)) Variable YOffset = str2num(IE_GetSIParam("scanAngleShiftSlow",header)) Variable XCenter = str2num(theROI[1]) - XOffset Variable YCenter = str2num(theROI[2]) - YOffset //Get the z plane of the scan ROI, and it's frame offset String Zstr = theROI[5] Z = str2num(Zstr) //Put the frames into the output waves offsetZ = WhichListItem(Zstr,zs,";") If(offsetZ == -1) offsetZ = 0 EndIf offsetY = (Z == prevZ) ? Ypixels : 0 Variable k //First step of de-interleaving the data for the z positions and frames per slice //'theImage' contains all of the data, and we're pulling it out selectively into individual image waves //depending on the scan configuration. If(framesPerSlice == 1) If(WaveDims(scanROI) == 4) Multithread scanROI[][][][] = theImage[p][offsetY + q][offsetZ + r * numZs] Else If(offsetY == 0 && numROIs == 1) Duplicate/O theImage,scanROI //much faster than indexed wave assignment Else //Using duplication followed by matrix op is much faster than the below multithreaded wave assignment Variable endY = offsetY + yPixels - 1 //Duplicate, including all of the Z pixels, which are interleaved still for multiple scanfield ROIs Duplicate/FREE/RMD=[][offsetY,offsetY + yPixels-1][] theImage,temp Variable endZ = DimSize(temp,2)-1 //De-interleave the data MatrixOP/O scanROI = temp[][][offsetZ,endZ,numZs] //Old, slower method // Multithread scanROI[][][] = theImage[p][offsetY + q][offsetZ + r * numZs] EndIf EndIf Else //Multiple frames per slice. //In the tiff file, frames per slice are in the 3rd dimension, we want them in the 4th dimension in our final waves For(k=0;k 1) Duplicate/O scanROI,$(scanName + "_" + ch) Wave scanChannel = $(scanName + "_" + ch) Redimension/N=(-1,-1,DimSize(scanROI,2) / numChannels) scanChannel scanChannel = scanROI[p][q][c + r * numChannels] Else Duplicate/O scanROI,$(scanName + "_" + ch) EndIf Wave scanChannel = $(scanName + "_" + ch) //Set the scale for the final image. SetScale/I x,objResolution * (XCenter - (str2num(theROI[3]) / 2)),objResolution * (XCenter + (str2num(theROI[3]) / 2)),"m",scanChannel //Reverse scaling from what I originally had, so now the image is oriented the same as in MATLAB when the data is taken // SetScale/I y,objResolution * (theROI[1] - (theROI[3] / 2)),objResolution * (theROI[1] + (theROI[3] / 2)),"m",scanROI SetScale/I y,objResolution * (YCenter - (str2num(theROI[4]) / 2)),objResolution * (YCenter + (str2num(theROI[4]) / 2)),"m",scanChannel SetScale/P z,0,str2num(theROI[12]),"s",scanChannel EndFor KillWaves/Z scanROI prevZ = Z offsetY += yPixels EndFor Variable size = str2num(StringByKey("SIZEINBYTES",WaveInfo(theImage,0))) / (1e6) KillWaves/Z theImage print "Loaded " + file + ":", StopMSTimer(ref) / (1e6),"s (" + num2str(size) + " MB)" EndFor End //Colon separated string of all the parameter fields in the header Function/S IE_GetParamStr() String param = "" param += "SI.acqState;" param += "SI.acqsPerLoop;" param += "SI.loopAcqInterval;" param += "SI.objectiveResolution;" param += "SI.hBeams.powers;" param += "SI.hChannels.channelsActive;" param += "SI.hFastZ.enable;" param += "SI.hFastZ.waveformType;" param += "SI.hRoiManager.linePeriod;" param += "SI.hRoiManager.linesPerFrame;" param += "SI.hRoiManager.mroiEnable;" param += "SI.hRoiManager.pixelsPerLine;" param += "SI.hRoiManager.scanAngleShiftFast;" param += "SI.hRoiManager.scanAngleShiftSlow;" param += "SI.hRoiManager.scanFramePeriod;" param += "SI.hRoiManager.scanFrameRate;" param += "SI.hRoiManager.scanRotation;" param += "SI.hRoiManager.scanType;" param += "SI.hRoiManager.scanVolumeRate;" param += "SI.hRoiManager.scanZoomFactor;" param += "SI.hScan2D.bidirectional;" param += "SI.hScan2D.fillFractionSpatial;" param += "SI.hScan2D.fillFractionTemporal;" param += "SI.hScan2D.fovCornerPoints;" param += "SI.hScan2D.scanPixelTimeMaxMinRatio;" param += "SI.hScan2D.scanPixelTimeMean;" param += "SI.hStackManager.actualNumSlices;" param += "SI.hStackManager.actualNumVolumes;" param += "SI.hStackManager.actualStackZStepSize;" param += "SI.hStackManager.arbitraryZs;" param += "SI.hStackManager.enable;" param += "SI.hStackManager.framesPerSlice;" param += "SI.hStackManager.numFramesPerVolume;" param += "SI.hStackManager.numSlices;" param += "SI.hStackManager.numVolumes;" param += "SI.hStackManager.stackDefinition;" param += "SI.hStackManager.stackFastWaveformType;" param += "SI.hStackManager.stackMode;" param += "SI.hStackManager.stackZEndPos;" param += "SI.hStackManager.stackZStartPos;" param += "SI.hStackManager.stackZStepSize;" param += "SI.hStackManager.zs;" param += "SI.hStackManager.zsRelative;" return param End Function/S IE_GetSIParamStr() String param = "" param += "SI.LINE_FORMAT_VERSION;" param += "SI.TIFF_FORMAT_VERSION;" param += "SI.VERSION_COMMIT;" param += "SI.VERSION_MAJOR;" param += "SI.VERSION_MINOR;" param += "SI.acqState;" param += "SI.acqsPerLoop;" param += "SI.extTrigEnable;" param += "SI.imagingSystem;" param += "SI.loopAcqInterval;" param += "SI.objectiveResolution;" param += "SI.hStackManager.framesPerSlice;" param += "SI.hStackManager.numSlices;" param += "SI.hStackManager.shutterCloseMinZStepSize;" param += "SI.hStackManager.slowStackWithFastZ;" param += "SI.hStackManager.stackReturnHome;" param += "SI.hStackManager.stackSlicesDone;" param += "SI.hStackManager.stackStartCentered;" param += "SI.hStackManager.stackZEndPos;" param += "SI.hStackManager.stackZStartPos;" param += "SI.hStackManager.stackZStepSize;" param += "SI.hStackManager.stageDependentZs;" param += "SI.hStackManager.stepSizeLock;" param += "SI.hStackManager.zPowerReference;" param += "SI.hStackManager.zs;" param += "SI.hUserFunctions.userFunctionsCfg;" param += "SI.hUserFunctions.userFunctionsUsr;" param += "SI.hWSConnector.communicationTimeout;" param += "SI.hWSConnector.enable;" param += "SI.hWaveformManager.optimizedScanners;" param += "SI.hScan2D.beamClockDelay;" param += "SI.hScan2D.beamClockExtend;" param += "SI.hScan2D.bidirectional;" param += "SI.hScan2D.channelOffsets;" param += "SI.hScan2D.channels;" param += "SI.hScan2D.channelsAdcResolution;" param += "SI.hScan2D.channelsAutoReadOffsets;" param += "SI.hScan2D.channelsAvailable;" param += "SI.hScan2D.channelsDataType;" param += "SI.hScan2D.channelsFilter;" param += "SI.hScan2D.channelSInputRanges;" param += "SI.hScan2D.channelsSubtractOffsets;" param += "SI.hScan2D.fillFractionSpatial;" param += "SI.hScan2D.fillFractionTemporal;" param += "SI.hScan2D.flybackTimePerFrame;" param += "SI.hScan2D.flytoTimePerScanfield;" param += "SI.hScan2D.fovCornerPoints;" param += "SI.hScan2D.hasResonantMirror;" param += "SI.hScan2D.hasXGalvo;" param += "SI.hScan2D.keepResonantScannerOn;" param += "SI.hScan2D.linePhase;" param += "SI.hScan2D.linePhaseMode;" param += "SI.hScan2D.logAverageFactor;" param += "SI.hScan2D.logFramesPerFile;" param += "SI.hScan2D.logFramesPerFileLock;" param += "SI.hScan2D.logOverwriteWarn;" param += "SI.hScan2D.mask;" param += "SI.hScan2D.maskDisableAveraging;" param += "SI.hScan2D.maxSampleRate;" param += "SI.hScan2D.name;" param += "SI.hScan2D.nominalFovCornerPoints;" param += "SI.hScan2D.pixelBinFactor;" param += "SI.hScan2D.sampleRate;" param += "SI.hScan2D.scanMode;" param += "SI.hScan2D.scanPixelTimeMaxMinRatio;" param += "SI.hScan2D.scanPixelTimeMean;" param += "SI.hScan2D.scannerFrequency;" param += "SI.hScan2D.scannerToRefTransform;" param += "SI.hScan2D.scannerType;" param += "SI.hScan2D.settleTimeFraction;" param += "SI.hScan2D.SImulated;" param += "SI.hScan2D.stripingEnable;" param += "SI.hScan2D.trigAcqEdge;" param += "SI.hScan2D.trigAcqInTerm;" param += "SI.hScan2D.trigNextEdge;" param += "SI.hScan2D.trigNextInTerm;" param += "SI.hScan2D.trigNextStopEnable;" param += "SI.hScan2D.trigStopEdge;" param += "SI.hScan2D.trigStopInTerm;" param += "SI.hScan2D.uniformSampling;" param += "SI.hScan2D.useNonlinearResonantFov2VoltsCurve;" param += "SI.hRoiManager.forceSquarePixelation;" param += "SI.hRoiManager.forceSquarePixels;" param += "SI.hRoiManager.imagingFovDeg;" param += "SI.hRoiManager.imagingFovUm;" param += "SI.hRoiManager.linePeriod;" param += "SI.hRoiManager.linesPerFrame;" param += "SI.hRoiManager.mroiEnable;" param += "SI.hRoiManager.pixelsPerLine;" param += "SI.hRoiManager.scanAngleMultiplierFast;" param += "SI.hRoiManager.scanAngleMultiplierSlow;" param += "SI.hRoiManager.scanAngleShiftFast;" param += "SI.hRoiManager.scanAngleShiftSlow;" param += "SI.hRoiManager.scanFramePeriod;" param += "SI.hRoiManager.scanFrameRate;" param += "SI.hRoiManager.scanRotation;" param += "SI.hRoiManager.scanType;" param += "SI.hRoiManager.scanVolumeRate;" param += "SI.hRoiManager.scanZoomFactor;" param += "SI.hPmts.autoPower;" param += "SI.hPmts.bandwidths;" param += "SI.hPmts.gains;" param += "SI.hPmts.names;" param += "SI.hPmts.offsets;" param += "SI.hPmts.powersOn;" param += "SI.hPmts.tripped;" param += "SI.hPhotostim.allowMultipleOutputs;" param += "SI.hPhotostim.autoTriggerPeriod;" param += "SI.hPhotostim.compensateMotionEnabled;" param += "SI.hPhotostim.completedSequences;" param += "SI.hPhotostim.laserActiveSIgnalAdvance;" param += "SI.hPhotostim.lastMotion;" param += "SI.hPhotostim.logging;" param += "SI.hPhotostim.monitoring;" param += "SI.hPhotostim.monitoringSampleRate;" param += "SI.hPhotostim.nextStimulus;" param += "SI.hPhotostim.numOutputs;" param += "SI.hPhotostim.numSequences;" param += "SI.hPhotostim.sequencePoSItion;" param += "SI.hPhotostim.sequenceSelectedStimuli;" param += "SI.hPhotostim.status;" param += "SI.hPhotostim.stimImmediately;" param += "SI.hPhotostim.stimSelectionAsSIgnment;" param += "SI.hPhotostim.stimSelectionDevice;" param += "SI.hPhotostim.stimSelectionTerms;" param += "SI.hPhotostim.stimSelectionTriggerTerm;" param += "SI.hPhotostim.stimTriggerTerm;" param += "SI.hPhotostim.stimulusMode;" param += "SI.hPhotostim.syncTriggerTerm;" param += "SI.hPhotostim.zMode;" param += "SI.hMotors.azimuth;" param += "SI.hMotors.backlashCompensation;" param += "SI.hMotors.dimNonblockingMoveInProgress;" param += "SI.hMotors.elevation;" param += "SI.hMotors.motorFastMotionThreshold;" param += "SI.hMotors.motorPoSItion;" param += "SI.hMotors.motorPoSItionTarget;" param += "SI.hMotors.motorStepLimit;" param += "SI.hMotors.motorToRefTransform;" param += "SI.hMotors.motorToRefTransformAbsolute;" param += "SI.hMotors.motorToRefTransformValid;" param += "SI.hMotors.nonblockingMoveInProgress;" param += "SI.hMotors.scanimageToMotorTF;" param += "SI.hMotors.userDefinedPoSItions;" param += "SI.hMotionManager.correctionBoundsXY;" param += "SI.hMotionManager.correctionBoundsZ;" param += "SI.hMotionManager.correctionDeviceXY;" param += "SI.hMotionManager.correctionDeviceZ;" param += "SI.hMotionManager.correctionEnableXY;" param += "SI.hMotionManager.correctionEnableZ;" param += "SI.hMotionManager.correctorClassName;" param += "SI.hMotionManager.enable;" param += "SI.hMotionManager.estimatorClassName;" param += "SI.hMotionManager.motionHistoryLength;" param += "SI.hMotionManager.motionMarkersXY;" param += "SI.hMotionManager.resetCorrectionAfterAcq;" param += "SI.hMotionManager.zStackAlignmentFcn;" param += "SI.hIntegrationRoiManager.enable;" param += "SI.hIntegrationRoiManager.enableDisplay;" param += "SI.hIntegrationRoiManager.integrationHistoryLength;" param += "SI.hIntegrationRoiManager.postProcessFcn;" param += "SI.hFastZ.actuatorLag;" param += "SI.hFastZ.discardFlybackFrames;" param += "SI.hFastZ.enable;" param += "SI.hFastZ.enableFieldCurveCorr;" param += "SI.hFastZ.flybackTime;" param += "SI.hFastZ.hasFastZ;" param += "SI.hFastZ.nonblockingMoveInProgress;" param += "SI.hFastZ.numDiscardFlybackFrames;" param += "SI.hFastZ.numFramesPerVolume;" param += "SI.hFastZ.numVolumes;" param += "SI.hFastZ.poSItionAbsolute;" param += "SI.hFastZ.poSItionAbsoluteRaw;" param += "SI.hFastZ.poSItionTarget;" param += "SI.hFastZ.poSItionTargetRaw;" param += "SI.hFastZ.useArbitraryZs;" param += "SI.hFastZ.userZs;" param += "SI.hFastZ.volumePeriodAdjustment;" param += "SI.hFastZ.waveformType;" param += "SI.hDisplay.autoScaleSaturationFraction;" param += "SI.hDisplay.channelsMergeEnable;" param += "SI.hDisplay.channelsMergeFocusOnly;" param += "SI.hDisplay.displayRollingAverageFactor;" param += "SI.hDisplay.displayRollingAverageFactorLock;" param += "SI.hDisplay.enableScanfieldDisplays;" param += "SI.hDisplay.lineScanHistoryLength;" param += "SI.hDisplay.renderer;" param += "SI.hDisplay.scanfieldDisplayColumns;" param += "SI.hDisplay.scanfieldDisplayRows;" param += "SI.hDisplay.scanfieldDisplayTilingMode;" param += "SI.hDisplay.selectedZs;" param += "SI.hDisplay.showScanfieldDisplayNames;" param += "SI.hDisplay.volumeDisplayStyle;" param += "SI.hDisplay.scanfieldDisplays.enable;" param += "SI.hDisplay.scanfieldDisplays.name;" param += "SI.hDisplay.scanfieldDisplays.channel;" param += "SI.hDisplay.scanfieldDisplays.roi;" param += "SI.hDisplay.scanfieldDisplays.z;" param += "SI.hCycleManager.cycleIterIdxTotal;" param += "SI.hCycleManager.cyclesCompleted;" param += "SI.hCycleManager.enabled;" param += "SI.hCycleManager.itersCompleted;" param += "SI.hCycleManager.totalCycles;" param += "SI.hChannels.channelAdcResolution;" param += "SI.hChannels.channelDisplay;" param += "SI.hChannels.channelInputRange;" param += "SI.hChannels.channelLUT;" param += "SI.hChannels.channelMergeColor;" param += "SI.hChannels.channelName;" param += "SI.hChannels.channelOffset;" param += "SI.hChannels.channelSave;" param += "SI.hChannels.channelSubtractOffset;" param += "SI.hChannels.channelType;" param += "SI.hChannels.channelsActive;" param += "SI.hChannels.channelsAvailable;" param += "SI.hChannels.loggingEnable;" param += "SI.hConfigurationSaver.cfgFilename;" param += "SI.hConfigurationSaver.usrFilename;" param += "SI.hBeams.beamCalibratedStatus;" param += "SI.hBeams.directMode;" param += "SI.hBeams.enablePowerBox;" param += "SI.hBeams.flybackBlanking;" param += "SI.hBeams.interlaceDecimation;" param += "SI.hBeams.interlaceOffset;" param += "SI.hBeams.lengthConstants;" param += "SI.hBeams.powerLimits;" param += "SI.hBeams.powers;" param += "SI.hBeams.pzAdjust;" param += "SI.hBeams.pzCustom;" param += "SI.hBeams.stackEndPower;" param += "SI.hBeams.stackStartPower;" param += "SI.hBeams.stackUseStartPower;" param += "SI.hBeams.stackUserOverrideLz;" param += "SI.hBeams.powers;" param += "SI.hBeams.powerBoxEndFrame;" param += "SI.hBeams.powerBoxStartFrame;" param += "SI.hBeams.powerBoxes.name;" param += "SI.hBeams.powerBoxes.oddLines;" param += "SI.hBeams.powerBoxes.evenLines;" param += "SI.hBeams.powerBoxes.rect;" return param End //Returns integer 1 or 0 for true or false input string Static Function bool2int(String bool) If(!cmpstr(bool,"true")) return 1 ElseIf(!cmpstr(bool,"false")) return 0 Else //bad input return -1 EndIf End Function/S IE_GetSIParam(param,header) String param Wave/T header String value = "" value = header[tableMatch(param,header)][1] return value End Function IE_GetROIVar(param,header) String param Wave/T header //ROI data wave Variable index = FindDimLabel(header,0,param) If(index == -2) return index EndIf return str2num(header[index]) End Function/S IE_GetROIString(param,header) String param Wave/T header //ROI data wave Variable index = FindDimLabel(header,0,param) If(index == -2) return "" EndIf return header[index] End Function/WAVE IE_GetROIData(roiStr,file,header) String roiStr,file Wave/T/Z header //Extracts the position,rotation, z plane, etc. data for all ROIs, puts into ROI output wave Variable imagingROIpos,photoStimROIpos,integrationROIpos imagingROIpos = strsearch(roiStr,"imagingRoiGroup",0) photoStimROIpos = strsearch(roiStr,"photostimRoiGroups",0) integrationROIpos = strsearch(roiStr,"integrationRoiGroup",0) JSONXOP_Parse roiStr Variable jsonID = V_Value //Type of JSON object (array or object, depending on if there are >1 ROI) JSONXOP_GetType jsonID, "RoiGroups/imagingRoiGroup/rois" //How many ROIs are we extracting? If(V_Value) JSONXOP_GetArraySize jsonID,"RoiGroups/imagingRoiGroup/rois" Variable numROI = V_Value String roiPath = "RoiGroups/imagingRoiGroup/rois/" Else numROI = 1 roiPath = "RoiGroups/imagingRoiGroup/rois" EndIf Variable i,j,k,count = 0 //Wave reference wave that will hold the ROI data waves Make/FREE/WAVE/N=(0) roiWaveRefs For(i=0;i 1) String roiFullPath = roiPath + num2str(i) Else roiFullPath = roiPath EndIf JSONXOP_GetKeys jsonID,roiFullPath,keys //check for more than one scanfield in the ROI JSONXOP_GetType jsonID,roiFullPath + "/scanfields" If(V_Value) JSONXOP_GetArraySize jsonID,roiFullPath + "/scanfields" Variable numScanFields = V_Value Else numScanFields = 1 EndIf For(j=0;j 1) //take name from the scanfields if the ROI has multiple defined JSONXOP_GetValue/T jsonID,roiFullPath + "/scanfields/" + num2str(j) + "/name" String name = S_Value Else JSONXOP_GetValue/T jsonID,roiFullPath + "/name" name = S_Value EndIf //Will hold the ROI data If(strlen(name)) String roiName = "ROI_" + name roiName = ReplaceString(" ",roiName,"") Else roiName = "ROI_" + num2str(count) EndIf If(stringmatch(name,"Default*")) roiName = "ROI_" + num2str(count) EndIf KillWaves/Z $(":" + roiName) Make/O/N=20/T $(":" + roiName)/Wave=ROI ROI[0] = name If(numScanFields > 1) String suffix = "/" + num2str(j) Else suffix = "" EndIf JSONXOP_GetKeys jsonID,roiFullPath + "/scanfields" + suffix,scanKeys //Get Z plane of each Scanfield in the ROI JSONXOP_GetValue/V jsonID,roiFullPath + "/zs" + suffix ROI[5] = num2str(V_Value) JSONXOP_GetValue/V jsonID,roiFullPath + "/discretePlaneMode" ROI[17] = num2str(V_Value) //Single plane ROIs, or volumetric ROIs For(k=0;k DimSize(tableWave,0) - 1) return "" EndIf If(endp < DimSize(tableWave,0) - 1) return "" EndIf For(j=0;j DimSize(tableWave,0) - 1) return -1 EndIf If(endp < DimSize(tableWave,0) - 1) return -1 EndIf If(!ParamIsDefault(whichCol)) If(startFrom) //Backwards For(i=endp;i>startp-1;i-=1) If(stringmatch(tableWave[i][whichCol][0],str)) return i EndIf EndFor Else //Forwards For(i=startp;istartp-1;i-=1) If(stringmatch(tableWave[i][j][0],str)) If(returnCol) return j Else return i EndIf EndIf EndFor Else //Forwards For(i=startp;i 0) ROIGroupSelWave = 0 ROIGroupSelWave[0] = 1 String group = ROIGroupListWave[0] Else group = "" EndIf Variable/G NTSI:ROI_Engaged NVAR ROI_Engaged = NTSI:ROI_Engaged ROI_Engaged = 0 Variable/G NTSI:drawROI_Engaged NVAR drawROI_Engaged = NTSI:drawROI_Engaged drawROI_Engaged = 0 Variable/G NTSI:mouseStartX,NTSI:mouseStartY Make/O/N=0 NTSI:drawROIX,NTSI:drawROIY Make/O/WAVE/N=2 NTSI:clickedROIRef Variable/G NTSI:Nudge_Engaged NVAR Nudge_Engaged = NTSI:Nudge_Engaged Nudge_Engaged = 0 Variable/G NTSI:ROI_Width NVAR ROI_Width = NTSI:ROI_Width ROI_Width = 10 Variable/G NTSI:ROI_Height NVAR ROI_Height = NTSI:ROI_Height ROI_Height = 10 Variable/G NTSI:ROI_PctThreshold NVAR ROI_PctThreshold = NTSI:ROI_PctThreshold ROI_PctThreshold = 50 //ROIs within the selected group Wave/T listWave = IE_GetROIs(group) Redimension/N=(DimSize(listWave,0),-1,-1) ROIListWave,ROISelWave ROIListWave = listWave //Mouse drag variable Variable/G NTSI:mouseDrag NVAR mouseDrag = NTSI:mouseDrag mouseDrag = 0 String/G NTSI:SIDisplay_ImagePaths SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths SIDisplay_ImagePaths = "" //Create custom color table wave for ROI masks Make/O/N=(10,4) NTSI:ROI_ColorTable Wave color = NTSI:ROI_ColorTable //Set all to cyan transparency 25% initially color[0][] = 0 color[1,*][0] = 0 color[1,*][1] = 43690 color[1,*][2] = 65535 color[1,*][3] = 16384 If(!DataFolderExists("root:Packages:NeuroToolsPlus:CustomColors")) NewDataFolder root:Packages:NeuroToolsPlus:CustomColors EndIf String whichColor = "Geo" //more pleasant color contrast than Rainbow or Spectrum Wave/Z colorTab = root:Packages:NeuroToolsPlus:CustomColors:$whichColor If(!WaveExists(colorTab)) SetDataFolder root:Packages:NeuroToolsPlus:CustomColors ColorTab2Wave $whichColor Duplicate/O root:Packages:NeuroToolsPlus:CustomColors:M_colors,root:Packages:NeuroToolsPlus:CustomColors:$whichColor Wave colorTab = root:Packages:NeuroToolsPlus:CustomColors:$whichColor KillWaves/Z root:Packages:NeuroToolsPlus:CustomColors:M_colors EndIf //Records double click events Variable/G NTSI:doubleClick NVAR doubleClick = NTSI:doubleClick doubleClick = 0 //Saves the name of an edited ROI Group temporarily String/G NTSI:oldROIGroupName SVAR oldROIGroupName = NTSI:oldROIGroupName oldROIGroupName = "" // //list and selection waves for loading SI files // Wave/T ScanLoadListWave = NTSI:ScanLoadListWave // // If(!WaveExists(ScanLoadListWave)) // Make/O/T/N=(0,2) NTSI:ScanLoadListWave /Wave = ScanLoadListWave // Make/O/N=(0) NTSI:ScanLoadSelWave /Wave = ScanLoadSelWave // Else // Wave ScanLoadSelWave = NTSI:ScanLoadSelWave // Redimension/N=(DimSize(ScanLoadListWave,0)) ScanLoadSelWave // EndIf // // String/G NTSI:ScanLoadPath // SVAR ScanLoadPath = NTSI:ScanLoadPath // ScanLoadPath = "" //Scan monitor path string String/G NTSI:SIDisplay_ImageNameList = "" String/G NTSI:measure //Outer folder - Scan File, which may contain multiple scans of ROIs and Zs //Selection shows the Scan ROIs within that scan group. Z level will be shown as text somewhere else. //The scan folder - this is the parent folder for a set of groups, and is the subfolder that the group of tiff files are actually kept in. //Mine are typically the experiment date (i.e. R4_200326), so multiple days of experiments can be organized in a single Igor pxp. Make/O/T/N=(0,1,3) NTSI:ScanFolderListWave /Wave = ScanFolderListWave Make/O/N=(0) NTSI:ScanFolderSelWave /Wave = ScanFolderSelWave //The scan group Make/O/T/N=(0,1,3) NTSI:ScanGroupListWave /Wave = ScanGroupListWave Make/O/N=(0) NTSI:ScanGroupSelWave /Wave = ScanGroupSelWave //The scans themselves Make/O/T/N=(0,1,3) NTSI:ScanFieldListWave /Wave = ScanFieldListWave Make/O/N=(0) NTSI:ScanFieldSelWave /Wave = ScanFieldSelWave //Get the scan group list wave Wave/T listWave = IE_GetScanFolders() Redimension/N=(DimSize(listWave,0),-1,-1) ScanFolderListWave,ScanFolderSelWave ScanFolderListWave = listWave If(DimSize(ScanFolderListWave,0) > 0) Wave/T listWave = IE_GetScanGroups(folder=ScanFolderListWave[0][0][0]) Redimension/N=(DimSize(listWave,0),-1,-1) ScanGroupListWave,ScanGroupSelWave ScanGroupListWave = listWave EndIf //initialize to the first scan folder If(DimSize(ScanGroupListWave,0) > 0) ScanGroupSelWave[0][0][0] = 1 Wave/T listWave = IE_GetScanFields(ScanFolderListWave[0][0][0],group=ScanGroupListWave[0][0][0]) EndIf If(DimSize(ScanFieldListWave,0) > 0) ScanFieldSelWave[0][0][0] = 1 EndIf //Scan Field match string String/G NTSI:scanFieldMatchStr SVAR scanFieldMatchStr = NTSI:scanFieldMatchStr scanFieldMatchStr = "" //Scan Registration variables, etc. If(!DataFolderExists("root:Packages:NeuroToolsPlus:ScanImage:Registration")) NewDataFolder root:Packages:NeuroToolsPlus:ScanImage:Registration EndIf DFREF NTSR = root:Packages:NeuroToolsPlus:ScanImage:Registration String/G NTSR:roiXlist String/G NTSR:roiYlist Variable/G NTSR:hidden End Function IE_OpenImageExplorer() //Create the ScanImage Browsing panel GetWindow/Z IE wsize If(!V_flag) DoWindow/F IE return 0 Else GetMouse NewPanel/N=IE/K=1/W=(V_left-460,V_top + 25,V_left,V_top + 270) as "Image Browser" EndIF DFREF NTSI = $IE If(!DataFolderRefStatus(NTSI)) IE_CreatePackage() EndIf DFREF NTSI = $IE Wave/T ScanFolderListWave = NTSI:ScanFolderListWave Wave ScanFolderSelWave = NTSI:ScanFolderSelWave //The scan group Wave/T ScanGroupListWave = NTSI:ScanGroupListWave Wave ScanGroupSelWave = NTSI:ScanGroupSelWave //The scans themselves Wave/T ScanFieldListWave = NTSI:ScanFieldListWave Wave ScanFieldSelWave = NTSI:ScanFieldSelWave //ROIs Wave/T ROIListWave = NTSI:ROIListWave Wave ROISelWave = NTSI:ROISelWave //Scan Field match string String/G NTSI:scanFieldMatchStr SVAR scanFieldMatchStr = NTSI:scanFieldMatchStr scanFieldMatchStr = "" //list and selection waves for the ROI Group list box If(!WaveExists(NTSI:ROIGroupListWave)) Make/O/T/N=0 NTSI:ROIGroupListWave /Wave = ROIGroupListWave Make/O/N=0 NTSI:ROIGroupSelWave /Wave = ROIGroupSelWave Else Wave/T ROIGroupListWave = NTSI:ROIGroupListWave Wave ROIGroupSelWave = NTSI:ROIGroupSelWave EndIf ListBox scanFolders win=IE,pos={5,40},size={85,200},title="",listWave=ScanFolderListWave,selWave=ScanFolderSelWave,mode=2,proc=IE_ListBoxProc,disable=0 ListBox scanGroups win=IE,pos={95,40},size={85,200},title="",listWave=ScanGroupListWave,selWave=ScanGroupSelWave,mode=9,proc=IE_ListBoxProc,disable=0 ListBox scanFields win=IE,pos={185,40},size={140,180},title="",listWave=ScanFieldListWave,selWave=ScanFieldSelWave,mode=9,proc=IE_ListBoxProc,disable=0 ListBox roiGroups win=IE,pos={330,40},size={60,180},title="",listWave=ROIGroupListWave,selWave=ROIGroupSelWave,mode=9,proc=IE_ListBoxProc,disable=0 ListBox rois win=IE,pos={395,40},size={60,180},title="",listWave=ROIListWave,selWave=ROISelWave,mode=9,proc=IE_ListBoxProc,disable=0 SetVariable scanFieldMatch win=IE,pos={185,226},size={140,20},title=" ",value=scanFieldMatchStr,proc=IE_VarProc,disable=0 CheckBox selectAllScanFields win=IE,pos={200,23},font=$IE_LIGHT_FONT,fsize=12,size={20,20},title="Scan Fields",value=0,proc=IE_CheckBoxProc,disable=0 CheckBox selectAllScanGroups win=IE,pos={96,23},font=$IE_LIGHT_FONT,fsize=12,size={20,20},title="Scan Groups",value=0,proc=IE_CheckBoxProc,disable=0 PopUpMenu targetImage win=IE,pos={330,224},size={120,20},bodywidth=120,font=$IE_LIGHT_FONT,title="",mode=1,value=#"root:Packages:NeuroToolsPlus:ScanImage:availableImages",proc=IE_PopProc SetDrawEnv/W=IE fname=$IE_LIGHT_FONT,fsize=12,xcoord=abs,ycoord=abs DrawText/W=IE 34,39,"Cells" SetDrawEnv/W=IE fname=$IE_LIGHT_FONT,fsize=12,xcoord=abs,ycoord=abs DrawText/W=IE 353,39,"ROI Groupings" Button displayScanField win=IE,pos={4,1},size={60,20},title="Display",font=$IE_LIGHT_FONT,proc=IE_ButtonProc,disable=0 Button updateImageBrowser win=IE,pos={70,1},size={70,20},title="Refresh",font=$IE_LIGHT_FONT,proc=IE_ButtonProc,disable=0 Button getNewScans win=IE,pos={145,1},size={100,20},title="Load Scans",font=$IE_LIGHT_FONT,proc=IE_ButtonProc,disable=0 Checkbox displayROIMasks win=IE,pos={310,3},size={0,20},value=0,title="Show ROI Masks",font=$IE_LIGHT_FONT,fsize=12,proc=IE_CheckBoxProc,disable=0 //set resize hook on the Image Browser for vertical sizing only SetWindow IE hook(resizeHook) = IE_ResizeHook //Start a mouse hook for hovering over the in-between spaces between list boxes for resizing purposes SetWindow IE hook(ImageBrowserMouseHook) = IE_ImageBrowserMouseHook End Function IE_ImageBrowserMouseHook(s) STRUCT WMWinHookStruct &s DFREF NTSI = $IE //Are we currently resizing a column? NVAR columnDrag = NTSI:columnDrag //Holds the current hook positions for resizing the Image Browser Wave resizeListBoxPositions = NTSI:resizeListBoxPositions String ctrlNames = "scanFolders;scanGroups;scanFields;roiGroups;rois;" Variable hookResult = 0 switch(s.eventCode) case 0: //Activate break case 1: //Deactivate break case 4: //Mouse Moved Variable xPos = s.mouseLoc.h Variable i //Resizing list box If(columnDrag > 0) Variable r = ScreenResolution / 72 GetWindow IE wsize Variable height = s.winRect.bottom Variable vSize = height - 45 Variable vPos = height - 19 For(i=0;i 1) ListBox $theCtrl win=IE,size={V_width + xExpand,vSize-19},pos = {V_left,V_top} Else ListBox $theCtrl win=IE,size={V_width + xExpand,vSize},pos = {V_left,V_top} EndIf Else ListBox $theCtrl win=IE,pos = {V_left + xExpand,V_top} EndIf resizeListBoxPositions[i] = V_right + xExpand EndFor //Shift checkboxes and text DrawAction/W=IE delete If(columnDrag < 2) ControlInfo/W=IE selectAllScanGroups CheckBox selectAllScanGroups win=IE,pos = {V_left + xExpand,V_top} ControlInfo/W=IE selectAllScanFields CheckBox selectAllScanFields win=IE,pos = {V_left + xExpand,V_top} ElseIf(columnDrag < 3) ControlInfo/W=IE selectAllScanFields CheckBox selectAllScanFields win=IE,pos = {V_left + xExpand,V_top} EndIf //Set the drawn text labels SetDrawEnv/W=IE fname=$IE_LIGHT_FONT,fsize=12,xcoord=abs,ycoord=abs DrawText/W=IE 34,39,"Cells" ControlInfo/W=IE roiGroups SetDrawEnv/W=IE fname=$IE_LIGHT_FONT,fsize=12,xcoord=abs,ycoord=abs DrawText/W=IE V_right - 37,39,"ROI Groupings" ControlInfo/W=IE scanFieldMatch If(columnDrag == 3) SetVariable scanFieldMatch win=IE,pos = {V_left,V_top},size={V_width + xExpand,vSize} ControlInfo/W=IE targetImage PopUpMenu targetImage win=IE,pos={V_left + xExpand,vPos-3} ElseIf(columnDrag < 3) SetVariable scanFieldMatch win=IE,pos={V_left + xExpand,vPos} ControlInfo/W=IE targetImage PopUpMenu targetImage win=IE,pos={V_left + xExpand,vPos-3} ElseIf(columnDrag < 4) ControlInfo/W=IE targetImage PopUpMenu targetImage win=IE,pos={V_left + xExpand,vPos-3},size={V_width + xExpand,vSize} EndIf //Resize the panel as well GetWindow IE wsize height = s.winRect.bottom Variable top = V_top Variable left = V_left Variable right = V_right MoveWindow/W=IE left,top,right + xExpand/r,top + height/r Else //Hovering For(i=0;i<5;i+=1) If(xPos > resizeListBoxPositions[i] && xPos < resizeListBoxPositions[i] + 5) //Change the cursor to the left right drag icon s.doSetCursor = 1 s.cursorCode = 5 //hand cursor break EndIf EndFor EndIf break case 3: //mouse down xPos = s.mouseLoc.h For(i=0;i<5;i+=1) If(xPos > resizeListBoxPositions[i] && xPos < resizeListBoxPositions[i] + 5) //which resize column was clicked? columnDrag = i + 1 EndIf EndFor break case 5: //mouse up columnDrag = 0 endswitch return hookResult End Function IE_SliderProc(sa) : SliderControl STRUCT WMSliderAction &sa DFREF NTSI = $IE switch( sa.eventCode ) case -3: // Control received keyboard focus case -2: // Control lost keyboard focus case -1: // Control being killed break default: If( sa.eventCode & 1 ) // value set Variable curval = sa.curval / 100 //resets all the scaling on the displayed images NVAR numImages = NTSI:numImages NVAR imagePlane = NTSI:imagePlane Variable i For(i=0;i= minX && xLoc <= maxX && yLoc >= minY && yLoc <= maxY) WhichROI = RemoveEnding(NameOfWave(ROIWaveY),"_y") break Else WhichROI = "" EndIf EndFor IE_PrintHoverROI(WhichROI) If(!cmpstr(ROITypeStr,"Marquee")) return 0 EndIf //Skip dynamic ROI if we're dragging the frame around If(!mouseDrag) target = "IEDisplay#image" + num2str(sw) + "#graph" + num2str(sw) If(drawROI_Engaged) //Horizontal index of image Variable hPixel = AxisValFromPixel(target,"top",s.mouseLoc.h) //Vertical index of image Variable vPixel = AxisValFromPixel(target,"left",s.mouseLoc.v) //Add the pixel scale value into the draw ROI waves Variable dim = DimSize(drawROIX,0) Redimension/N=(dim + 1) drawROIX,drawROIY drawROIX[dim] = hPixel drawROIY[dim] = vPixel String traces = TraceNameList(target,";",0) If(WhichListItem("drawROIY",traces,";") == -1) AppendToGraph/W=$target/L/T drawROIY vs drawROIX EndIf ElseIf(isDynamicROI) NVAR size = NTSI:dynamicROI_Size SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths SVAR dynamicROI_Image = NTSI:dynamicROI_Image //If the image being hovered over isn't already on the dynamic ROI plot String theImagePath = StringFromList(sw,SIDisplay_ImagePaths,";") If(cmpstr(dynamicROI_Image,theImagePath)) IE_StartDynamicROI($theImagePath) EndIf dynamicROI_Image = StringFromList(sw,SIDisplay_ImagePaths,";") Wave theImage = $dynamicROI_Image If(!WaveExists(theImage)) return 1 EndIf Variable rows,cols rows = DimSize(theImage,0) cols = DimSize(theImage,1) //Horizontal index of image hPixel = AxisValFromPixel(target,"top",s.mouseLoc.h) //Vertical index of image vPixel = AxisValFromPixel(target,"left",s.mouseLoc.v) //Kill the indicator box DrawAction/L=Overlay/W=$target getgroup=dynamicROIIndicator,delete //Ensure valid index Variable hPixelTest = ScaleToIndex(theImage,hPixel,0) Variable vPixelTest = ScaleToIndex(theImage,vPixel,1) If(hPixelTest > rows - 1 || vPixelTest > cols - 1 || hPixelTest < 0 || vPixelTest < 0) return 1 EndIf Wave dROI = NTSI:dynamicROI Wave block = NTSI:block Variable left = hPixel - 0.5 * (size *1e-6) Variable right = hPixel + 0.5 * (size *1e-6) Variable bottom = vPixel - 0.5 * (size *1e-6) Variable top = vPixel + 0.5 * (size *1e-6) Variable xEndPix = xEnd(theImage) Variable yEndPix = yEnd(theImage) left = (left < DimOffset(theImage,0)) ? DimOffset(theImage,0) : left right = (right > xEndPix) ? xEndPix : right bottom = (bottom < DimOffset(theImage,1)) ? DimOffset(theImage,1) : bottom top = (top > yEndPix) ? yEndPix : top // SetDrawLayer/W=$target Overlay SetDrawEnv/W=$target gname=dynamicROIIndicator,gstart SetDrawEnv/W=$target linethick=1,linefgc=(0,43690,65535),xcoord=top,ycoord=left,fillpat=0 DrawRect/W=$target left,top,right,bottom SetDrawEnv/W=$target gstop Variable leftPix = ScaleToIndex(theImage,left,0) Variable rightPix = ScaleToIndex(theImage,right,0) Variable topPix = ScaleToIndex(theImage,top,1) Variable bottomPix = ScaleToIndex(theImage,bottom,1) try //Significantly faster than indexed wave assignment by about 12x Duplicate/R=(left,right)(top,bottom)/O theImage,block;AbortOnRTE catch Variable error = GetRTError(1) return 1 endtry MatrixOP/FREE meanLayers = sum(block) MatrixOP/O dROI = transposeVol(meanLayers,3) Redimension/S/N=(-1,0) dROI dROI /= (DimSize(block,0) * DimSize(block,1)) NVAR maxVal = NTSI:dynamicROI_MaxVal NVAR minVal = NTSI:dynamicROI_MinVal Variable dROI_min = WaveMin(dROI) Variable dROI_max = WaveMax(dROI) //Accumulates min and max scaling such that the scale is the widest scale encountered during mouse movement If(scaleCumulative) If(dROI_max > maxVal) maxVal = dROI_max SetAxis/W=dynamicROI left,minVal,maxVal EndIf If(dROI_min < minVal) minVal = dROI_min SetAxis/W=dynamicROI left,minVal,maxVal EndIf Else //always autoscales to the data limits maxVal = 0 SetAxis/Z/W=dynamicROI left,dROI_min,dROI_max EndIf // //Get the ROI number we are hovering over // String list = ImageNameList("IEDisplay#image" + num2str(sw) + "#graph" + num2str(sw),";") // String ROIname = StringFromList(1,list,";") // // If(strlen(ROIname)) // Wave roiMask = NTSR:$(ROIname + "Num") // Variable roiNumber = roiMask[hPixel][vPixel] // print roiNumber // EndIf EndIf If(strlen(target)) //Draw ROI square IE_DrawROISquare(target,AxisValFromPixel(target,"top",s.mouseLoc.h),AxisValFromPixel(target,"left",s.mouseLoc.v)) EndIf return 1 Else //Drag the image around NVAR mouseStartX = NTSI:mouseStartX NVAR mouseStartY = NTSI:mouseStartY s.doSetCursor = 1 s.cursorCode = 13 //hand cursor graphRef = "IEDisplay#image" + num2str(sw) + "#graph" + num2str(sw) //Are there ROI masks laid on top of the //difference in pixels from last step to now Variable diffX = AxisValFromPixel(graphRef,"top",s.mouseLoc.h) - AxisValFromPixel(graphRef,"top",mouseStartX) Variable diffY = AxisValFromPixel(graphRef,"left",s.mouseLoc.v) - AxisValFromPixel(graphRef,"left",mouseStartY) //If nudge ROI is engaged, we may have clicked an ROI, in which case this is the wave reference If(WaveExists(clickedROIRef)) Wave/Z xROI = clickedROIRef[0] Wave/Z yROI = clickedROIRef[1] EndIf If(WaveExists(xROI) && WaveExists(yROI)) Variable doNudge = 1 EndIf If(!doNudge) //shift the axis of the entire image GetAxis/W=$graphRef/Q top SetAxis/W=$graphRef top,V_min - diffX,V_max - diffX Variable xMin = V_min - diffX Variable xMax = V_max - diffX GetAxis/W=$graphRef/Q left SetAxis/W=$graphRef left,V_min - diffY,V_max - diffY Variable yMin = V_min - diffY Variable yMax = V_max - diffY Variable scaleLength = round(0.1 * abs(xMax - xMin) * 10^6) * 10^-6 //should get rounded microns number at 10% total width Variable leftPos = xMin + 0.5 * scaleLength //5% from left side of the image Variable rightPos = leftPos + scaleLength //Adjust a scale bar position SetDrawLayer/W=$graphRef UserFront DrawAction/W=$graphRef/L=UserFront getgroup=$("ScaleBar_" + num2str(sw)),delete SetDrawEnv/W=$graphRef gname=$("ScaleBar_" + num2str(sw)),gstart SetDrawEnv/W=$graphRef linefgc=(0xffff,0xffff,0xffff),textrgb=(0xffff,0xffff,0xffff),linethick=2,textxjust=0,xcoord=top,ycoord=abs DrawLine/W=$graphRef leftPos,30,rightPos,30 SetDrawEnv/W=$graphRef textxjust=1,textrgb=(0xffff,0xffff,0xffff),linethick=2,xcoord=top,ycoord=abs DrawText/W=$graphRef 0.5 * (rightPos + leftPos),25,num2str(scaleLength * 10^6) + " µm" SetDrawEnv/W=$graphRef gstop ElseIf(Nudge_Engaged && doNudge) //Move the ROI position according to mouse movement xROI += diffX yROI += diffY EndIf //reset the start points mouseStartX = s.mouseLoc.h mouseStartY = s.mouseLoc.v hookResult = 1 EndIf return hookResult break case 5: //mouse up If(!cmpstr(ROITypeStr,"Marquee")) return 0 EndIf Variable/G NTSI:mouseDrag NVAR mouseDrag = NTSI:mouseDrag NVAR mouseStartX = NTSI:mouseStartX NVAR mouseStartY = NTSI:mouseStartY //Reset the clicked ROI reference if it exists If(WaveExists(clickedROIRef)) clickedROIRef = $"" EndIf //Get target image for drawing ControlInfo/W=IE targetImage target = S_Value If(!cmpstr(target,"IEDisplay")) sw = WhichSubWindow() If(sw == -1) //in case of window focus error or something sw = 0 EndIf target = "IEDisplay#image" + num2str(sw) + "#graph" + num2str(sw) EndIf mouseDrag = 0 drawROI_Engaged = 0 //Create a new ROI if it's engaged If(ROI_Engaged) ControlInfo/W=IEDisplay#ROIPanel roiType roiType = S_Value //What is the width and height? ControlInfo/W=IEDisplay#ROIPanel roiWidth Variable width = V_Value ControlInfo/W=IEDisplay#ROIPanel roiHeight Variable height = V_Value ControlInfo/W=IEDisplay#ROIPanel roiName String baseName = S_Value ControlInfo/W=IEDisplay#ROIPanel roiGroupSelect String group = S_Value strswitch(roiType) case "Click": IE_CreateROIFromClick(mouseStartX,mouseStartY,width,height,target,group,baseName) //set mouse cursor to crosshairs s.doSetCursor = 1 s.cursorCode = 3 break case "Grid": break default: break endswitch Else s.doSetCursor = 1 s.cursorCode = 3 //hand cursor EndIf break case 22: //mouse scroll //If we're creating an ROI, don't perform hook function //Instead, allow for ROI thresholding for masking out the dendrite SVAR imageList = NTSI:SIDisplay_ImageNameList SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths NVAR displayROIMasks = NTSI:displayROIMasks GetMouse/W=IEDisplay Variable mouseX = V_left,mouseY = V_top If(ROI_Engaged) If(displayROIMasks) sw = whichSubWindow() If(sw == -1) return hookResult EndIf //Graph the mouse is hovering over graphRef = "IEDisplay#image" + num2str(sw) + "#graph" + num2str(sw) //Image the mouse is hovering over String imagePath = StringFromList(sw,SIDisplay_ImagePaths,";") Wave image = $imagePath If(!WaveExists(image)) break EndIf Wave/Z maxImage = $(GetWavesDataFolder(image,2) + "_max") If(!WaveExists(maxImage)) IE_GetMaxProj(imagePath,noReplace=1) Wave/Z maxImage = $(GetWavesDataFolder(image,2) + "_max") EndIf xLoc = AxisValFromPixel(graphRef,"Top",mouseX) yLoc = AxisValFromPixel(graphRef,"Left",mouseY) ROITraceList = TraceNameList(graphRef,";",1) //ROI the mouse is hovering over For(i=0;i= ROIWaveX[0] && xLoc <= ROIWaveX[2] && yLoc >= ROIWaveY[0] && yLoc <= ROIWaveY[1]) //adjust the threshold of the hovered ROI threshold += delta * s.wheeldy //Check for threshold going too high or below zero threshold = (threshold > maxROIVal) ? maxROIVal : threshold threshold = (threshold < 0) ? 0 : threshold //re-calculate the ROI mask String ROIMaskPath = RemoveEnding(GetWavesDataFolder(ROIWaveY,2),"y") + "Mask" Wave/Z ROIMask = $ROIMaskPath If(!WaveExists(ROIMask)) break EndIf //Check validity of the ROI points, are they outside the image? LeftPt = (LeftPt > DimSize(ROIMask,0) - 1) ? DimSize(ROIMask,0) - 1 : LeftPt LeftPt = (LeftPt < 0) ? 0 : LeftPt RightPt = (RightPt > DimSize(ROIMask,0) - 1) ? DimSize(ROIMask,0) - 1 : RightPt RightPt = (RightPt < 0) ? 0 : RightPt TopPt = (TopPt > DimSize(ROIMask,1) - 1) ? DimSize(ROIMask,1) - 1 : TopPt TopPt = (TopPt < 0) ? 0 : TopPt BottomPt = (BottomPt > DimSize(ROIMask,1) - 1) ? DimSize(ROIMask,1) - 1 : BottomPt BottomPt = (BottomPt < 0) ? 0 : BottomPt ROIMask = 0 ROIMask[LeftPt,RightPt][TopPt,BottomPt] = (maxImageROI[p - LeftPt][q-TopPt] >= threshold) ? 1 : 0 EndIf EndFor EndIf //Make sure to break here, to avoid actually zooming the image during ROI creation break EndIf sw = whichSubWindow() If(sw == -1) return hookResult EndIf graphRef = "IEDisplay#image" + num2str(sw) + "#graph" + num2str(sw) String imageName = StringFromList(sw,imageList,";") //Get center point of the graph GetWindow $graphRef wsize //reduce by 1% per scroll event Variable newMax,newMin GetAxis/W=$graphRef/Q left delta = (V_max - V_min) * 0.06 If(s.wheeldy > 0) newMin = V_min + delta newMax = V_max - delta ElseIf(s.wheeldy < 0) newMin = V_min - delta newMax = V_max + delta Else return hookResult EndIf SetAxis/W=$graphRef left,newMin,newMax yMin = newMin yMax = newMax GetAxis/W=$graphRef/Q top delta = (V_max - V_min) * 0.06 If(s.wheeldy > 0) newMin = V_min + delta newMax = V_max - delta ElseIf(s.wheeldy < 0) newMin = V_min - delta newMax = V_max + delta Else return 1 EndIf SetAxis/W=$graphRef top,newMin,newMax xMin = newMin xMax = newMax scaleLength = round(0.1 * abs(xMax - xMin) * 10^6) * 10^-6 //should get rounded microns number at 10% total width leftPos = xMin + 0.5 * scaleLength //5% from left side of the image rightPos = leftPos + scaleLength //Adjust a scale bar position SetDrawLayer/W=$graphRef UserFront DrawAction/W=$graphRef/L=UserFront getgroup=$("ScaleBar_" + num2str(sw)),delete SetDrawEnv/W=$graphRef gname=$("ScaleBar_" + num2str(sw)),gstart SetDrawEnv/W=$graphRef linefgc=(0xffff,0xffff,0xffff),textrgb=(0xffff,0xffff,0xffff),linethick=2,textxjust=0,xcoord=top,ycoord=abs DrawLine/W=$graphRef leftPos,30,rightPos,30 SetDrawEnv/W=$graphRef textxjust=1,textrgb=(0xffff,0xffff,0xffff),linethick=2,xcoord=top,ycoord=abs DrawText/W=$graphRef 0.5 * (rightPos + leftPos),25,num2str(scaleLength * 10^6) + " µm" SetDrawEnv/W=$graphRef gstop return 1 break endswitch End //returns the string of the subwindow that the mouse is over static Function whichSubWindow() GetMouse/W=IEDisplay Variable mouseX,mouseY mouseX = V_left;mouseY = V_top DFREF NTSI = $IE NVAR numImages = NTSI:numImages Variable i For(i=0;i V_left && mouseX < V_right && mouseY > V_top && mouseY < V_bottom) return i//"IEDisplay#" + subPanel + "#" + graph EndIf EndFor return -1 End //Kills wave even if it is a part of a graph or window static Function ReallyKillWaves(w) Wave w If(!WaveExists(w)) return 0 EndIf string name=nameofwave(w) string graphs=WinList("*",";","WIN:1") // A list of all graphs //NeuroToolsPlus Viewer needs to be checked graphs += "NTP#Nav#Viewer" variable i,j for(i=0;i 0) imageList += listWave[i][0][1] + ";" EndIf EndFor return imageList End //Takes string list, and creates a text wave with its contents static Function/WAVE StringListToTextWave(strList,separator) String strList,separator Variable size,i If(!strlen(strList)) Make/FREE/N=0/T textWave return textWave EndIf size = ItemsInList(strList,separator) Make/FREE/T/N=(size) textWave For(i=0;i DimSize(theImage,2)) plane = 0 EndIf String panel = "image" + num2str(i) String graph = "graph" + num2str(i) name = StringFromList(i,imageList,";") ModifyImage/Z/W=IEDisplay#$("image" + num2str(i))#$("graph" + num2str(i)) $name plane=plane EndFor DrawAction/W=IEDisplay#control getgroup=frameCountText, delete GetWindow/Z IEDisplay wsize SetDrawEnv/W=IEDisplay#control textxjust=0,gstart,gname=frameCountText DrawText/W=IEDisplay#control 150,40,"Frame: " + num2str(plane) + ", " + num2str(plane * DimDelta(theImage,2)) + "s" SetDrawEnv/W=IEDisplay#control gstop return 0 End //Background task for playing the image frames Function IE_PlayFramesBackroundTask(s) STRUCT WMBackgroundStruct &s DFREF NTSI = $IE NVAR plane = NTSI:imagePlane NVAR deltaPlane = NTSI:deltaPlane plane += deltaPlane NVAR numImages = NTSI:numImages SVAR imagePaths = NTSI:SIDisplay_ImagePaths SVAR imageList = NTSI:SIDisplay_ImageNameList DoWindow IEDisplay If(!V_Flag) IE_StopFramePlay() return 0 EndIf Variable i For(i=0;i DimSize(theImage,2)) plane = 0 EndIf String panel = "image" + num2str(i) String graph = "graph" + num2str(i) name = StringFromList(i,imageList,";") ModifyImage/Z/W=IEDisplay#$("image" + num2str(i))#$("graph" + num2str(i)) $name plane=plane EndFor DrawAction/W=IEDisplay#control getgroup=frameCountText,delete GetWindow/Z IEDisplay wsize SetDrawEnv/W=IEDisplay#control textxjust=0,gstart,gname=frameCountText DrawText/W=IEDisplay#control 150,40,"Frame: " + num2str(plane) + ", " + num2str(plane * DimDelta(theImage,2)) + "s" SetDrawEnv/W=IEDisplay#control gstop return 0 End //Removes the wave from the SIDisplay window Function IE_RemoveFromSIDisplay(w) Wave/Z w If(!WaveExists(w)) return 0 EndIf DFREF NTSI = root:Packages:NeuroToolsPlus:ScanImage NVAR numImages = NTSI:numImages numImages = IE_GetNumImages("SIDisplay","image") Variable i For(i=0;i 0) ROIGroupSelWave[0] = 1 EndIf String groupList = IE_SelectedROIGroup() Wave/T roiList = IE_GetROIs(groupList) Redimension/N=(DimSize(roiList,0),-1,-1) ROIListWave,ROISelWave ROIListWave = roiList //Set selection to the first ROI after refreshing If(DimSize(ROISelWave,0) > 0) ROISelWave = 0 ROISelWave[0] = 1 EndIf EndIf //Refresh the scan folders, if any have been added or deleted Wave/T listWave = IE_GetScanFolders() Redimension/N=(DimSize(listWave,0),-1,-1) ScanFolderListWave,ScanFolderSelWave ScanFolderListWave = listWave ControlInfo/W=IE scanFolders Variable folderSelect = V_Value //If there are no scan folders, reset everything If(DimSize(ScanFolderListWave,0) == 0) Redimension/N=(0,-1,-1) ScanFolderListWave,ScanFolderSelWave,ScanGroupListWave,ScanGroupSelWave,ScanFieldListWave,ScanFieldSelWave return 0 EndIf String folder = IE_SelectedScanFolder() Wave/T groups = IE_GetScanGroups(folder=ScanFolderListWave[folderSelect][0][0]) Redimension/N=(DimSize(groups,0),-1,-1) ScanGroupListWave,ScanGroupSelWave ScanGroupListWave = groups //If there are no scan folders, reset everything If(DimSize(ScanGroupListWave,0) == 0) Redimension/N=(0,-1,-1) ScanGroupListWave,ScanGroupSelWave,ScanFieldListWave,ScanFieldSelWave return 0 EndIf String selGroups = IE_SelectedScanGroups() Wave/T fields = IE_GetScanFields(ScanFolderListWave[folderSelect][0][0],group=selGroups) //Matches the scan fields according to the match string SVAR scanFieldMatchStr = NTSI:scanFieldMatchStr If(strlen(scanFieldMatchStr)) IE_matchScanFields(scanFieldMatchStr) EndIf End //Handles the variable inputs on the SI display panel Function IE_VarProc(sva) : SetVariableControl STRUCT WMSetVariableAction &sva DFREF NTSI = $IE switch( sva.eventCode ) case 1: // mouse up case 2: // Enter key case 3: // Live update Variable dval = sva.dval String sval = sva.sval NVAR numImages = NTSI:numImages NVAR imagePlane = NTSI:imagePlane SVAR imagePaths = NTSI:SIDisplay_ImagePaths SVAR imageList = NTSI:SIDisplay_ImageNameList Variable i strswitch(sva.ctrlName) case "dynamicROISize": SVAR dynamicROI_Image = NTSI:dynamicROI_Image If(!strlen(dynamicROI_Image)) return 0 EndIf Wave/Z theImage = $dynamicROI_Image NVAR isDynamicROI = NTSI:isDynamicROI If(isDynamicROI) If(!WaveExists(theImage)) isDynamicROI = 0 return 1 EndIf IE_StartDynamicROI(theImage) EndIf break case "scanFieldMatch": //refreshes the list boxes in case of any deleted or loaded scans IE_UpdateImageBrowserLists(skipROIList = 1) //Matches the scan fields according to the match string IE_MatchScanFields(sval) break case "selectROI": //turns the indicated ROI yellow and the rest cyan. String list = ImageNameList("IEDisplay#image0#graph0",";") String roiName = StringFromList(1,list,";") If(!strlen(roiName)) break EndIf If(dval == 0) break EndIf Wave color = NTSI:ROI_ColorTable //Set all to cyan transparency 25% initially color[0][] = 0 color[1,*][0] = 0 color[1,*][1] = 43690 color[1,*][2] = 65535 color[1,*][3] = 16384 //Set specific ROI to yellow color[dval][0] = 52425 color[dval][1] = 52425 color[dval][2] = 0 break endswitch break case -1: // control being killed break endswitch return 0 End //Handles list box selections in the ScanImage package Function IE_ButtonProc(ba) : ButtonControl STRUCT WMButtonAction &ba DFREF NTSI = root:Packages:NeuroToolsPlus:ScanImage NVAR ROI_Width = NTSI:ROI_Width NVAR ROI_Height = NTSI:ROI_Height NVAR ROI_PctThreshold = NTSI:ROI_PctThreshold NVAR ROI_Engaged = NTSI:ROI_Engaged NVAR Nudge_Engaged = NTSI:Nudge_Engaged NVAR drawROI_Engaged = NTSI:drawROI_Engaged Variable hookResult = 0 switch( ba.eventCode ) case 2: // mouse up // click code here strswitch(ba.ctrlName) case "displayScanfield": //first ensure that the mouse drag monitor is set to 0 NVAR mouseDrag = NTSI:mouseDrag mouseDrag = 0 //displays the selected scanfield in a new panel String imageList = IE_GetSelectedImages() IE_DisplayScanField(imageList) break case "updateImageBrowser": //refreshes the list boxes in case of any deleted or loaded scans IE_UpdateImageBrowserLists() break case "getNewScans": IE_BrowseScanImage() //enters main function to browse scans to load IE_UpdateImageBrowserLists() break case "autoScale": //resets all the scaling on the displayed images NVAR numImages = NTSI:numImages Variable i For(i=0;i DimSize(roiMask,0) - 1) ? DimSize(roiMask,0) - 1 : leftPt leftPt = (leftPt < 0) ? 0 : leftPt rightPt = (rightPt > DimSize(roiMask,0) - 1) ? DimSize(roiMask,0) - 1 : rightPt rightPt = (rightPt < 0) ? 0 : rightPt topPt = (topPt > DimSize(roiMask,1) - 1) ? DimSize(roiMask,1) - 1 : topPt topPt = (topPt < 0) ? 0 : topPt bottomPt = (bottomPt > DimSize(roiMask,1) - 1) ? DimSize(roiMask,1) - 1 : bottomPt bottomPt = (bottomPt < 0) ? 0 : bottomPt roiMask[leftPt,rightPt][topPt,bottomPt] = 1 NVAR numImages = NTSI:numImages If(!cmpstr(target,"IEDisplay")) For(i=0;i 0) ScanGroupSelWave[0] = 1 EndIf //Update the scan fields list box String folder = IE_SelectedScanFolder() String groups = IE_SelectedScanGroups() IE_GetScanFields(folder,group=groups) ControlInfo/W=SI selectAllScanFields Variable selectAll = V_Value If(selectAll) ScanFieldSelWave = 1 EndIf break case "selectAllScanFields": Wave ScanFieldSelWave = NTSI:ScanFieldSelWave ScanFieldSelWave = checked break case "CumulativeScale": NVAR scaleCumulative = NTSI:scaleCumulative scaleCumulative = checked break case "displayROIMasks": NVAR displayROIMasks = NTSI:displayROIMasks If(!NVAR_Exists(displayROIMasks)) Variable/G NTSI:displayROIMasks NVAR displayROIMasks = NTSI:displayROIMasks EndIf displayROIMasks = checked //Number of images currently displayed NVAR numImages = NTSI:numImages //Full paths to the displayed images SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths Variable i,j //Append or remove the ROI Masks from the SIDisplay window For(i=0;i 0) ROIListWave = ROIFolder + ROIListWave[p] Variable i For(i=0;i 0) //Graph window String graphStr = "IEDisplay#image" + num2str(i) + "#graph" + num2str(i) //This will be the reference image with which to create the ROI mask Wave image = $StringFromList(0,SIDisplay_ImagePaths,";") //If there is no ROI mask, create one For(i=0;i 0) ROISelWave = 1 EndIf roiList = IE_SelectedROIs() groupList = IE_SelectedROIs(groups=1) IE_appendROIsToImage(groupList,roiList) //Sets this variable to block the very next call to WMListBoxAction, which is Cell Selection doubleClick = 1 break endswitch break case 4: // cell selection case 5: // cell selection plus shift key strswitch(lba.ctrlName) case "scanFolders": String folder = IE_SelectedScanFolder() Wave/T scanGroups = IE_GetScanGroups(folder=folder) //update the scan field list box according to the scan group selection Redimension/N=(DimSize(scanGroups,0),-1,-1) ScanGroupListWave,ScanGroupSelWave ScanGroupListWave = scanGroups String groups = IE_SelectedScanGroups() Wave/T scanFields = IE_GetScanFields(folder,group=groups) //update the scan field list box according to the scan group selection Redimension/N=(DimSize(scanFields,0),-1,-1) ScanFieldListWave,ScanFieldSelWave ScanFieldListWave = scanFields break case "scanGroups": ControlInfo/W=IE selectAllScanGroups Variable selectAll = V_Value If(row > DimSize(listWave,0) - 1) return 0 ElseIf(selectAll) ScanGroupSelWave = 1 EndIf folder = IE_SelectedScanFolder() groups = IE_SelectedScanGroups() IE_GetScanFields(folder,group=groups) ControlInfo/W=IE selectAllScanFields selectAll = V_Value If(selectAll) ScanFieldSelWave = 1 EndIf break case "scanFields": ControlInfo/W=IE selectAllScanFields selectAll = V_Value If(selectAll) ScanFieldSelWave = 1 return 0 EndIf break case "roiGroups": //Updates the ROI list box for the selected ROI groups If(lba.eventMod == 19) //shift held during right click //Rename/Goto/Delete ROI contextual menu PopupContextualMenu/C=(lba.mouseLoc.h, lba.mouseLoc.v) "Delete;" If(V_flag) DoAlert/T="Delete ROI Group" 1,"Are you sure you want to delete the ROI group?" If(V_flag == 1) For(i=0;i 0) roiGroup = ROIGroupListWave[i] ROIFolder = "root:Packages:NeuroToolsPlus:ScanImage:ROIs:" + roiGroup + ":" //All the ROIs in the selected ROI group Wave/T ROIListWave = IE_GetROIs(roiGroup) If(DimSize(ROIListWave,0) > 0) //Make this a full path list wave for the ROIs ROIListWave = ROIFolder + ROIListWave[p] //Remove any of the ROIs from the SIDisplay or other graphs, then kill them Variable j For(j=0;j 0) ROISelWave = 0 ROISelWave[0] = 1 Else //remove any ROI displays from the selected image IE_AppendROIsToImage("","") EndIf hookResult = 1 break case "rois": If(lba.eventMod == 19) //shift held during right click //Rename/Goto/Delete ROI contextual menu PopupContextualMenu/C=(lba.mouseLoc.h, lba.mouseLoc.v)/N "roiRightClickMenu" //"Rename;GoTo;Move To;Delete;" If(V_flag) IE_HandleSelectionRightClick(S_Selection,ROIListWave,ROISelWave) EndIf ElseIf(lba.eventMod == 0) //Keyboard selection roiList = IE_SelectedROIs() groupList = IE_SelectedROIs(groups=1) IE_AppendROIsToImage(groupList,roiList) hookResult = 1 EndIf break endswitch SVAR scanFieldMatchStr = NTSI:scanFieldMatchStr IE_MatchScanFields(scanFieldMatchStr) break case 6: // begin edit SVAR oldROIGroupName = NTSI:oldROIGroupName //this will work for both groups and rois strswitch(lba.ctrlName) case "roiGroups": oldROIGroupName = ROIGroupListWave[row] break case "rois": oldROIGroupName = ROIListWave[row] break endswitch break case 7: // finish edit SVAR oldROIGroupName = NTSI:oldROIGroupName strswitch(lba.ctrlName) case "roiGroups": String newName = ROIGroupListWave[row][0][0] //Can't overwrite itself If(!cmpstr(newName,oldROIGroupName)) ROIGroupSelWave[row] = 1 return 0 EndIf roiGroup = ROIGroupListWave[row][0][1] ROIGroupSelWave[row] = 1 RenameDataFolder root:Packages:NeuroToolsPlus:ScanImage:ROIs:$oldROIGroupName,$ROIGroupListWave[row] If(DataFolderExists("root:Analysis:'" + oldROIGroupName + "'")) RenameDataFolder root:Analysis:$oldROIGroupName,$ROIGroupListWave[row] EndIf break case "rois": newName = ROIListWave[row][0][0] //Can't overwrite itself If(!cmpstr(newName,oldROIGroupName)) ROISelWave[row] = 1 return 0 EndIf roiGroup = ROIListWave[row][0][1] DFREF NTR = root:Packages:NeuroToolsPlus:ScanImage:ROIs:$roiGroup Wave origROIx = NTR:$(oldROIGroupName + "_x") Wave origROIy = NTR:$(oldROIGroupName + "_y") Duplicate/O origROIx, NTR:$(newName + "_x") Duplicate/O origROIy, NTR:$(newName + "_y") IE_RemoveFromSIDisplay(origROIy) ReallyKillWaves(origROIy) ReallyKillWaves(origROIx) ROISelWave[row] = 1 break endswitch IE_updateImageBrowserLists() IE_refreshROIGroupList() break case 13: // checkbox clicked (Igor 6.2 or later) break endswitch return hookResult End //returns names of the selected ROIs in the Image Browser Function/S IE_SelectedROIs([groups]) Variable groups //1 to return the group assignment list groups = (ParamIsDefault(groups)) ? 0 : 1 String roiList = "" Wave selWave = root:Packages:NeuroToolsPlus:ScanImage:ROISelWave Wave/T listWave = root:Packages:NeuroToolsPlus:ScanImage:ROIListWave Variable i For(i=0;i 0) If(groups) roiList += listWave[i][0][1] + ";" Else roiList += listWave[i][0][0] + ";" EndIf EndIf EndFor return roiList End //Returns the currently selected scan folder Function/S IE_SelectedScanFolder() Wave/T listWave = root:Packages:NeuroToolsPlus:ScanImage:ScanFolderListWave ControlInfo/W=IE scanFolders If(DimSize(listWave,0) == 0) return "" EndIf If(V_Value > DimSize(listWave,0) - 1) V_Value = 0 EndIf return listWave[V_Value][0][0] End //Returns the currently selected scan groups Function/S IE_SelectedScanGroups() Wave/T listWave = root:Packages:NeuroToolsPlus:ScanImage:ScanGroupListWave Wave selWave = root:Packages:NeuroToolsPlus:ScanImage:ScanGroupSelWave Variable i String groups = "" For(i=0;i 0) groups += listWave[i][0][0] + ";" EndIf EndFor groups = RemoveEnding(groups,";") //extra semi-colon on the end return groups End //returns names of the selected ROI Group in the Image Browser Function/S IE_SelectedROIGroup() String groupList = "" Wave selWave = root:Packages:NeuroToolsPlus:ScanImage:ROIGroupSelWave Wave/T listWave = root:Packages:NeuroToolsPlus:ScanImage:ROIGroupListWave Variable i For(i=0;i 0) groupList += listWave[i] + ";" EndIf EndFor return groupList End //Returns the currently selected scan fields Function/S IE_SelectedScanFields([fullpath]) Variable fullpath //returns full path to the scans, not just the names If(ParamIsDefault(fullpath)) fullpath = 0 Else fullpath = 1 EndIf Wave/T listWave = root:Packages:NeuroToolsPlus:ScanImage:ScanFieldListWave Wave selWave = root:Packages:NeuroToolsPlus:ScanImage:ScanFieldSelWave Variable i String fields = "" For(i=0;i 0) If(fullpath) fields += listWave[i][0][1] + ";" Else fields += listWave[i][0][0] + ";" EndIf EndIf EndFor fields = RemoveEnding(fields,";") //extra semi-colon on the end return fields End //Returns a text wave with all available scan folders (immediate subfolders within the root:Scans: directory) Function/Wave IE_GetScanFolders() DFREF NTS = root:Scans If(!DataFolderRefStatus(NTS)) Make/FREE/N=0/T listWave return listWave EndIf String folders = StringByKey("FOLDERS",DataFolderDir(1,NTS),":",";") Wave/T listWave = StringListToTextWave(folders,",") Sort listWave,listWave return listWave End //Returns a text wave with all available scan groups within the selected or indicated scan folder Function/Wave IE_GetScanGroups([folder]) String folder DFREF NTSI = $IE Wave/T ScanFolderListWave = NTSI:ScanFolderListWave DFREF saveDF = GetDataFolderDFR() If(ParamIsDefault(folder)) folder = TextWaveToStringList(ScanFolderListWave,";") EndIf If(!strlen(folder)) return $"" EndIf DFREF NTS = $("root:Scans:" + folder) String folders = StringByKey("FOLDERS",DataFolderDir(1,NTS),":",";") Variable i For(i=ItemsInList(folders,",")-1;i>-1;i-=1) //go backwards SetDataFolder NTS:$StringFromList(i,folders,",") String scanList = WaveList("*",";","DIMS:3") scanList += WaveList("*",";","DIMS:4") If(ItemsInList(scanList,";") == 0) folders = RemoveListItem(i,folders,",") EndIf EndFor Wave/T listWave = StringListToTextWave(folders,",") Sort listWave,listWave SetDataFolder saveDF return listWave End //Returns a text wave with all available scans that are within each scan group Function/Wave IE_GetScanFields(folder[,group]) String folder,group DFREF saveDF = $GetDataFolder(1) DFREF NTSI = $IE Wave/T ScanGroupListWave = NTSI:ScanGroupListWave Wave/T ScanFieldListWave = NTSI:ScanFieldListWave Wave ScanFieldSelWave = NTSI:ScanFieldSelWave If(ParamIsDefault(group)) group = TextWaveToStringList(ScanGroupListWave,";") EndIf If(!strlen(group)) Make/FREE/N=0/T listWave return listWave EndIf String baseFolder = "root:Scans:" Variable i,j String list = "" String fullList = "" String path = "" For(i=0;i 0) ScanFieldListWave[][][0] = listWave ScanFieldListWave[][][1] = pathWave[p] + ":" + listWave[p] EndIf return listWave End //Returns a string list of matched items from the listWave or listString Function/S IE_MatchScanFields(matchStr) String matchStr DFREF NTSI = $IE If(!strlen(matchStr)) matchStr = "*" EndIf //List and seletion waves in the SI panel Wave/T fieldList = NTSI:ScanFieldListWave Wave/T fieldSel = NTSI:ScanFieldSelWave String nameList = "",fullPathList = "" nameList = TextWaveToStringList(fieldList,";",layer=0) fullPathList = TextWaveToStringList(fieldList,";",layer=1) //Are there any OR statements in the match string? Variable i,j,numORs = ItemsInList(matchStr,"||") //Set empty temporary list String tempList = "" String indexList = "" //Match each OR element in the match string separately For(j=0;j-1;i-=1) //go backwards Variable inList = WhichListItem(num2str(i),indexList,";") If(inList == -1) DeletePoints/M=0 i,1,fieldList EndIf EndFor Redimension/N=(DimSize(fieldList,0)) fieldSel Redimension/N=(DimSize(fieldList,0),1,2) fieldList End //Opens the scanfield display and displays the selected image stack Function IE_DisplayScanField(imageList[,add]) String imageList Variable add DFREF NTSI = $IE //Reset the mouse drag indicator to prevent image from moving with mouse... //...immediately without a click Variable/G NTSI:mouseDrag NVAR mouseDrag = NTSI:mouseDrag mouseDrag = 0 NVAR numImages = NTSI:numImages NVAR isInverted = NTSI:isInverted isInverted = 0 //Make the master panel or resize it if it exists already GetWindow/Z IEDisplay wsize //Kill original panel KillWindow/Z IEDisplay If(ParamIsDefault(add)) add = 0 numImages = ItemsInList(imageList) Else numImages += ItemsInList(imageList) EndIf Variable i,j,totalY = 0,maxX = 0 String yDimList = "",xDimList = "" //Check that images all exist and get x/y dimension size For(i=ItemsInList(imageList,";")-1;i>-1;i-=1) //step backwards Wave theImage = $StringFromList(i,imageList,";") If(!WaveExists(theImage)) imageList = RemoveListItem(i,imageList,";") Else xDimList += num2str(DimSize(theImage,0) * DimDelta(theImage,0)) + ";" yDimList += num2str(DimSize(theImage,1) * DimDelta(theImage,1)) + ";" totalY += DimSize(theImage,1) * DimDelta(theImage,1) //maximum x dimension If(DimSize(theImage,0) * DimDelta(theImage,0) > maxX) maxX = DimSize(theImage,0) * DimDelta(theImage,0) Variable maxXScan = i EndIf EndIf EndFor //reverse the list for correct order xDimList = SortList(xDimList, ";", 16) yDimList = SortList(yDimList, ";", 16) //No valid images If(ItemsInList(imageList,";") == 0) return 0 EndIf Variable xPixels,yPixels,frames,xSize,ySize,xDim,yDim,sizeRatio,numCols,baseWidth baseWidth = 405 //sizing of the panel numCols = ceil(numImages / 3) If(numCols > 1) Variable numRows = 3 xSize = baseWidth * numCols ySize = ceil((xSize/numCols) * numRows) Else numRows = numImages xsize = baseWidth If(numRows < 3) ySize = ceil(xSize * numImages) Else baseWidth *= 0.9 ySize = ceil(xSize * numImages) EndIf EndIf Variable segmentY = floor(ySize/numImages) Variable fractionY,fractionX //put the new image panel next to the Image Browser window Variable r = ScreenResolution / 72 GetWindow/Z SI wsize Variable leftOffset = V_right * r + 10 //Make a new SI Display panel NewPanel/K=1/W=(leftOffset,0,leftOffset + xSize,ySize)/N=IEDisplay as "Scanfield Display" ModifyPanel/W=IEDisplay frameStyle=0 //Make the image part of the panel DefineGuide/W=IEDisplay imageDivide = {FT,50} //Make the control bar part of the panel NewPanel/HOST=IEDisplay/N=control/FG=(FL,FT,FR,imageDivide) ModifyPanel/W=IEDisplay#control frameStyle=0 //Define bottom guides for each image in a column For(i=0;i 1) ? 1 : fractionY //ensure less than 1 DefineGuide/W=IEDisplay $("imageBottom" + num2str(i)) = {imageDivide,fractionY,FB} EndFor //Define right guides for each image in a row For(i=0;i 1) ? 1 : fractionX //ensure less than 1 DefineGuide/W=IEDisplay $("imageRight" + num2str(i)) = {FL,fractionX,FR} EndFor //will save the image name list to an SVAR String/G NTSI:SIDisplay_ImageNameList SVAR SIDisplay_ImageNameList = NTSI:SIDisplay_ImageNameList SIDisplay_ImageNameList = "" //full paths of the waves in the SI display panel String/G NTSI:SIDisplay_ImagePaths SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths SIDisplay_ImagePaths = imageList Variable count = 0 For(i=0;i>",disable=0,proc=IE_HandlePlayFrames Button stepFrame win=IEDisplay#control,pos={115,0},size={40,20},font=$IE_LIGHT_FONT,title="Step",disable=0,proc=IE_HandlePlayFrames Button autoScale win=IEDisplay#control,pos={160,0},size={40,20},font=$IE_LIGHT_FONT,title="Auto",disable=0,proc=IE_ButtonProc Button maxProj win=IEDisplay#control,pos={205,0},size={60,20},font=$IE_LIGHT_FONT,title="Max Proj",disable=0,proc=IE_ButtonProc Button liveROIs win=IEDisplay#control,pos={270,25},size={40,20},font=$IE_LIGHT_FONT,title="ROIs",disable=0,proc=IE_ButtonProc Button dynamicROI win=IEDisplay#control,pos={270,0},size={40,20},font=$IE_LIGHT_FONT,title="Live",disable=0,proc=IE_ButtonProc Button crossHairs win=IEDisplay#control,pos={315,25},size={27,20},font=$IE_LIGHT_FONT,fsize=20,title="⊕",disable=0,proc=IE_ButtonProc Button lockAspectRatio win=IEDisplay#control,pos={345,25},size={27,20},font=$IE_LIGHT_FONT,fsize=10,title="L.A.",disable=0,proc=IE_ButtonProc Button extractImageDisplay win=IEDisplay#control,pos={375,25},size={27,20},font=$IE_LIGHT_FONT,fsize=24,title="◻︎",disable=0,proc=IE_ButtonProc If(strlen(FunctionInfo("NeuronTracer"))) String PictPathStr = SpecialDirPath("Igor Pro User Files",0,0,0) + "User Procedures:NeuroTools+:Functions:ScanImage:" NewPath/O/Z/Q PictPath,PictPathStr LoadPICT/P=PictPath/O/Q "NeuronTracerPict.png",NeuronTracerPict Button NeuronTracer win=IEDisplay#control,pos={360,0},size={40,20},title="\\$PICT$name=NeuronTracerPict$/PICT$",proc=IE_ButtonProc EndIf NVAR size = NTSI:dynamicROI_Size SetVariable dynamicROISize win=IEDisplay#control,pos={315,3},size={40,20},fsize=10,font=$IE_LIGHT_FONT,title=" ",value=size,disable=0,proc=IE_VarProc String/G NTSI:availableImages SVAR availableImages = NTSI:availableImages availableImages = WinList("*",";","WIN:1") Variable numGraphs = ItemsInList(availableImages,";") For(i=numGraphs-1;i>-1;i-=1) //go backwards String images = ImageNameList(StringFromlist(i,availableImages,";"),";") If(!strlen(images)) availableImages = RemoveListItem(i,availableImages,";") EndIf EndFor availableImages = "IEDisplay;" + availableImages //Create custom color table wave for ROI masks Make/O/N=(10,4) NTSI:ROI_ColorTable Wave color = NTSI:ROI_ColorTable //Set all to cyan transparency 25% initially color[0][] = 0 color[1,*][0] = 0 color[1,*][1] = 43690 color[1,*][2] = 65535 color[1,*][3] = 16384 Slider darkValueSlider win=IEDisplay#control,pos={5,25},size={75,20},vert=0,side=0,limits={0,100,1},value=0,proc=IE_SliderProc Slider brightValueSlider win=IEDisplay#control,pos={5,35},size={75,20},vert=0,side=0,limits={0,100,1},value=100,proc=IE_SliderProc Button scale94pct win=IEDisplay#control,pos={90,25},size={20,20},title="S",proc=IE_ButtonProc Button invert win=IEDisplay#control,pos={120,25},size={20,20},font=$IE_LIGHT_FONT,title="-1",disable=0,proc=IE_ButtonProc //Bring panel to the front DoWindow/F IEDisplay //Ensure that the image selection drop down list is filled with something. PopUpMenu targetImage win=IE,mode=1 //Set the resize hook to allow for aspect ratio lock functionality SetWindow IEDisplay hook(ImageResizeHook) = IE_ImageResizeHook NVAR lockAspect = NTSI:lockAspect If(lockAspect) Button lockAspectRatio win=IEDisplay#control,fcolor=(0x0000,0xa000,0x0000) GetWindow/Z IEDisplay wsize MoveWindow/W=IEDisplay V_left,V_top,V_right+1,V_bottom GetWindow/Z IEDisplay wsize MoveWindow/W=IEDisplay V_left,V_top,V_right-1,V_bottom Else Button lockAspectRatio win=IEDisplay#control,fcolor=(0,0,0) EndIf End //Returns the X range of a wave static Function xRange(w) Wave w return abs((rightx(w) - DimDelta(w,0)) - leftx(w)) End //Returns the X range of a wave static Function yRange(w) Wave w return (DimSize(w,1)-1) * DimDelta(w,1) End //Returns the last X point in a wave static Function xEnd(w) Wave w return rightx(w) - DimDelta(w,0) End //Returns the last Y point in a wave static Function yEnd(w) Wave w return (DimSize(w,1) - 1) * DimDelta(w,1) + DimOffset(w,1) End //handles resize events on the SI Display Function IE_ImageResizeHook(s) STRUCT WMWinHookStruct &s DFREF NTSI = $IE //paths to the currently displayed images SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths NVAR numImages = NTSI:numImages NVAR lockAspect = NTSI:lockAspect Variable hookResult = 0 switch(s.eventCode) case 0: //Activate break case 1: //Deactivate break case 6: //Resize Variable r = ScreenResolution / 72 If(lockAspect) //current sizing info for the window GetWindow/Z IEDisplay wsize //get the aspect ratio of the image. Only can be done with single image for now Wave theImage = $StringFromList(0,SIDisplay_ImagePaths,";") Variable aspect = abs(yRange(theImage) / xRange(theImage)) Variable numCols = ceil(numImages / 3) If(numCols > 1) Variable numRows = 3 Else numRows = numImages EndIf //Use the x size as the base size for controlling the aspect of the image. //Image paneling starts 50 pixels from the top of the window. Variable newHeight = round(((V_right - V_left)/numCols) * aspect * numRows) + 50 MoveWindow/W=IEDisplay V_left,V_top,V_right,V_top + newHeight EndIf break endswitch return hookResult End //handles resize events on the Image Browser Function IE_ResizeHook(s) STRUCT WMWinHookStruct &s DFREF NTSI = $IE Wave resizeListBoxPositions = NTSI:resizeListBoxPositions //Are we currently resizing a column? NVAR columnDrag = NTSI:columnDrag Variable hookResult = 0 switch(s.eventCode) case 0: //Activate break case 1: //Deactivate break case 6: //Resize Variable r = ScreenResolution / 72 //prevents horizontal resize, allows vertical resize. 460 is the set width of the panel GetWindow IE wsize Variable height = s.winRect.bottom height = (height < 125) ? 125 : height Variable width = s.winRect.right width = (width < 460) ? 460 : width If(width == 460 && columnDrag) break EndIf //MoveWindow/W=SI V_left,V_top,V_left + 460/r,V_top + height/r MoveWindow/W=IE V_left,V_top,V_left + width/r,V_top + height/r Variable vSize = height - 45 Variable vPos = height - 19 //Get the right edge of the ROI box to know how much width we need to expand to ControlInfo/W=IE rois Variable xExpand = width - (V_right + 5) //This distance is evenly divided by the 5 list boxes Variable controlExpand = floor(xExpand / 5) //Remainder Gets assigned to the Scan Fields list box Variable remainder = mod(controlExpand,5) //Set the vertical size of the list boxes ControlInfo/W=IE scanFolders resizeListBoxPositions[0] = V_right + controlExpand ListBox scanFolders win=IE,size={V_width + controlExpand,vSize},pos = {5,V_top} ControlInfo/W=IE scanGroups resizeListBoxPositions[1] = V_right + controlExpand ListBox scanGroups win=IE,size={V_width + controlExpand,vSize},pos = {V_left + controlExpand,V_top} ControlInfo/W=IE scanFields resizeListBoxPositions[2] = V_right + controlExpand ListBox scanFields win=IE,size={V_width + controlExpand,vSize-19},pos = {V_left + 2 * controlExpand,V_top} ControlInfo/W=IE roiGroups resizeListBoxPositions[3] = V_right + controlExpand ListBox roiGroups win=IE,size={V_width + controlExpand,vSize-19},pos = {V_left + 3 * controlExpand,V_top} ControlInfo/W=IE rois resizeListBoxPositions[4] = V_right + controlExpand + remainder ListBox rois win=IE,size={V_width + controlExpand + remainder,vSize-19},pos = {V_left + 4 * controlExpand,V_top} ControlInfo/W=IE scanFieldMatch SetVariable scanFieldMatch win=IE,pos={V_left + 2 * controlExpand,vPos},size = {V_width + controlExpand,20} ControlInfo/W=IE targetImage PopUpMenu targetImage win=IE,pos={V_left + 3 * controlExpand + remainder,vPos-3} //Shift the checkboxes ControlInfo/W=IE selectAllScanGroups CheckBox selectAllScanGroups win=IE,pos = {V_left + controlExpand,V_top} ControlInfo/W=IE selectAllScanFields CheckBox selectAllScanFields win=IE,pos = {V_left + controlExpand * 2,V_top} //Set the drawn text labels DrawAction/W=IE delete SetDrawEnv/W=IE fname=$IE_LIGHT_FONT,fsize=12,xcoord=abs,ycoord=abs DrawText/W=IE 34,39,"Cells" ControlInfo/W=IE roiGroups SetDrawEnv/W=IE fname=$IE_LIGHT_FONT,fsize=12,xcoord=abs,ycoord=abs DrawText/W=IE V_right - 37,39,"ROI Groupings" break endswitch return hookResult End //this allows us to kill all of our other hook functions as we kill the display window Function IE_KillWindowHook(s) STRUCT WMWinHookStruct &s Variable hookResult = 0 switch(s.eventCode) case 0: //Activate break case 1: //Deactivate break case 2: //killing window DFREF NTSI = $IE NVAR numImages = NTSI:numImages NVAR isMaxProj = NTSI:isMaxProj Variable i IE_StopFramePlay() //remove all the window hooks For(i=0;i DimSize(ROIMask,0) - 1) ? DimSize(ROIMask,0) - 1 : LeftPt LeftPt = (LeftPt < 0) ? 0 : LeftPt RightPt = (RightPt > DimSize(ROIMask,0) - 1) ? DimSize(ROIMask,0) - 1 : RightPt RightPt = (RightPt < 0) ? 0 : RightPt TopPt = (TopPt > DimSize(ROIMask,1) - 1) ? DimSize(ROIMask,1) - 1 : TopPt TopPt = (TopPt < 0) ? 0 : TopPt BottomPt = (BottomPt > DimSize(ROIMask,1) - 1) ? DimSize(ROIMask,1) - 1 : BottomPt BottomPt = (BottomPt < 0) ? 0 : BottomPt //Create the threshold variable Variable/G Folder:$(ROIName + "_Threshold") NVAR threshold = Folder:$(ROIName + "_Threshold") threshold = 0 //Mask the ROI within the coordinates ROIMask[LeftPt,RightPt][TopPt,BottomPt] = 1 //Thresholding of the mask ROIMask[LeftPt,RightPt][TopPt,BottomPt] = (BaseImage[p][q] >= threshold) ? 1 : 0 SetDataFolder saveDF return ROIMask End Function IE_AppendROIMask(graphStr,mask) String graphStr Wave mask If(!WaveExists(mask)) return 0 EndIf //Append the mask to the display and color it AppendImage/W=$graphStr/L/T mask String imageList = ImageNameList(graphStr,";") imageList = ListMatch(imageList,"*Mask",";") Variable nMasks = ItemsInList(imageList,";") Wave color = root:Packages:NeuroToolsPlus:CustomColors:Geo Duplicate/FREE color,colorRotate Rotate -round(0.25 * DimSize(color,0)),colorRotate Variable delta = round(DimSize(colorRotate,0) / 15) Variable row = (nMasks - 1) * delta Variable modRow = mod(row,DimSize(colorRotate,0) - 1) Variable R = colorRotate[modRow][0] Variable G = colorRotate[modRow][1] Variable B = colorRotate[modRow][2] ModifyImage/W=$graphStr $NameOfWave(mask) explicit=1,eval={0,0,0,0,0},eval={1,R,G,B,32768},eval={255,-1,-1,-1} End //Append the ROIs in the list to the top image plot Function IE_AppendROIsToImage(groupList,roiList) String groupList,roiList //If groupList or roiList are empty strings, just removes all ROIs DFREF NTSI = root:Packages:NeuroToolsPlus:ScanImage NVAR numImages = NTSI:numImages numImages = IE_GetNumImages("IEDisplay","image") //Get name of selected graph window in the drop down menu ControlInfo/W=IE targetImage String graphName = S_Value //ROI color table wave Wave color = NTSI:ROI_ColorTable Variable i,j //Check it's IEDisplay or another image plot If(!cmpstr("IEDisplay",graphName)) DoWindow IEDisplay If(V_flag == 0) return 0 EndIf //in case of errors in image number If(numImages == 0) numImages = 1 EndIf For(i=0;i-1;j-=1) //step backwards RemoveFromGraph/W=IEDisplay#$subpanel#$graph/Z $StringFromList(j,tracelist,";") EndFor //First remove all ROI image masks to clear the image graph tracelist = ImageNameList("IEDisplay#" + subpanel + "#" + graph,";") For(j=ItemsInList(tracelist,";")-1;j>0;j-=1) //step backwards RemoveImage/Z/W=IEDisplay#$subpanel#$graph $StringFromList(j,tracelist,";") EndFor For(j=0;j-1;j-=1) //step backwards RemoveFromGraph/W=$graphName/Z $StringFromList(j,tracelist,";") EndFor Variable isSoma,numROIs String axisFlags="",info = "",hAxisName="",vAxisName="" numROIs = ItemsInList(roiList,";") For(i=0;i IndexToScale(image,DimSize(image,0)-1,0)) return 0 ElseIf(yCenter < DimOffset(image,1) || yCenter > IndexToScale(image,DimSize(image,1)-1,1)) return 0 EndIf If(!strlen(baseName)) baseName = "ROI" EndIf Wave/WAVE roiRefs = IE_CreateROI(left,top,right,bottom,group=group,baseName=baseName,autoname=1) AppendToGraph/W=$target/T=$xAxis/L=$yAxis roiRefs[1] vs roiRefs[0] DFREF NTSI = $IE NVAR displayROIMasks = NTSI:displayROIMasks If(!NVAR_Exists(displayROIMasks)) Variable/G NTSI:displayROIMasks NVAR displayROIMasks = NTSI:displayROIMasks ControlInfo/W=SI displayROIMasks displayROIMasks = V_Value EndIf Variable LeftPt,RightPt,TopPt,BottomPt,LeftScale,RightScale,TopScale,BottomScale //Make the mask ROI image wave and the threshold variables for dendrite masking String ROIFolder = GetWavesDataFolder(roiRefs[0],0) String indexStr = RemoveEnding(ParseFilePath(0,NameOfWave(roiRefs[0]),"_",1,1),"_") String ROIName = baseName + "_" + indexStr //Create the ROI Mask Wave/Z ROIMask = IE_CreateROIMask(image,ROIFolder,ROIName,left,right,top,bottom) If(displayROIMasks && WaveExists(ROIMask)) IE_AppendROIMask(target,ROIMask) EndIf //Update lists IE_UpdateImageBrowserLists() IE_RefreshROIGroupList() End //Creates a new ROI using marquee coordinates, returns a wave reference wave with the X and Y coordinate waves Function/WAVE IE_CreateROI(left,top,right,bottom,[group,baseName,autoName]) Variable left,top,right,bottom String baseName,group Variable autoName If(ParamIsDefault(autoName)) autoName = 0 EndIf If(ParamIsDefault(group)) group = "**NEW**" EndIf If(!DataFolderExists("root:Packages:NeuroToolsPlus:ScanImage:ROIs")) NewDataFolder root:Packages:NeuroToolsPlus:ScanImage:ROIs EndIf String roiFolder = "root:Packages:NeuroToolsPlus:ScanImage:ROIs:" DFREF saveDF = GetDataFolderDFR() //Make a new ROI group if selected If(!cmpstr(group,"**NEW**")) SetDataFolder $roiFolder group = UniqueName("Group",11,0) NewDataFolder $(roiFolder + group) EndIf //If automatic naming is indicated or we're creating a new group If(autoName) DFREF NTR = $(roiFolder + group) //Make numerically named ROIs SetDataFolder NTR Variable index = 0 Do If(!WaveExists($(roiFolder + group + ":" + baseName + "_" + num2str(index) + "_x")) && !WaveExists($(roiFolder + group + ":" + baseName + num2str(index) + "_y"))) baseName += "_" + num2str(index) break EndIf index += 1 If(index == 1000) Abort "Couldn't find an available ROI name" EndIf While(1) Else DFREF NTR = $(roiFolder + group) If(!DataFolderRefStatus(NTR)) //If the ROI group doesn't actually exist for some reason, create one with that name NewDataFolder $(roiFolder + group) DFREF NTR = $(roiFolder + group) EndIf //Make ROI coordinates X and Y waves ControlInfo/W=IEDisplay#ROIPanel ROIname baseName = S_Value If(!strlen(S_Value)) Abort "Must enter a name for the ROI" return $"" EndIf EndIf If(WaveExists($(roiFolder + group + ":" + basename + "_x")) || WaveExists($(roiFolder + group + ":" + basename + "_y"))) DoAlert/T="Overwrite ROI?" 1,"ROI already exists. Overwrite?" If(V_flag == 2) //clicked no return $"" EndIf EndIf Make/O/N=5 NTR:$(baseName + "_x") /Wave = roiX Make/O/N=5 NTR:$(baseName + "_y") /Wave = roiY //Fill the ROI wave with the coordinates to form a rectangle roiX[0] = left //top left roiY[0] = top //top left roiX[1] = left //bottom left roiY[1] = bottom //bottom left roiX[2] = right //bottom right roiY[2] = bottom //bottom right roiX[3] = right //top right roiY[3] = top //top right roiX[4] = left //top left roiY[4] = top //top left Make/FREE/WAVE roiRefs roiRefs[0] = roiX roiRefs[1] = roiY SetDataFolder saveDF //Set the ROI Group Selector to the current group, in case ***NEW** group was created. //This will allow you to click-create ROIs in a NEW group without having to choose the group that //was just created. DFREF NTSI = $IE IE_UpdateImageBrowserLists() IE_RefreshROIGroupList() SVAR ROIGroupList = NTSI:GroupList index = WhichListItem(group,ROIGroupList,";") If(index != -1) PopUpMenu roiGroupSelect,win=IEDisplay#ROIPanel,mode=index+1 ControlUpdate/A EndIf return roiRefs End //Creates an ROI according to the drawn shape on the image Function IE_CreateDrawnROI(drawROIX,drawROIY,target,group,baseName) Wave drawROIX,drawROIY String target,group,baseName If(!DataFolderExists("root:Packages:NeuroToolsPlus:ScanImage:ROIs")) NewDataFolder root:Packages:NeuroToolsPlus:ScanImage:ROIs EndIf String roiFolder = "root:Packages:NeuroToolsPlus:ScanImage:ROIs:" DFREF saveDF = GetDataFolderDFR() //Make a new ROI group if selected If(!cmpstr(group,"**NEW**")) SetDataFolder $roiFolder group = UniqueName("Group",11,0) NewDataFolder $(roiFolder + group) EndIf DFREF NTR = $(roiFolder + group) //If the ROI group doesn't actually exist for some reason, create one with that name If(!DataFolderRefStatus(NTR)) NewDataFolder $(roiFolder + group) DFREF NTR = $(roiFolder + group) EndIf //If no ROI name base was given If(!strlen(baseName)) baseName = "ROI" EndIf If(WaveExists($(roiFolder + group + ":" + basename + "_x")) || WaveExists($(roiFolder + group + ":" + basename + "_y"))) DoAlert/T="Overwrite ROI?" 1,"ROI already exists. Overwrite?" If(V_flag == 2) //clicked no return 0 EndIf EndIf //Make the X and Y ROI waves Make/O/N=(DimSize(drawROIX,0)) NTR:$(baseName + "_x") /Wave = roiX Make/O/N=(DimSize(drawROIY,0)) NTR:$(baseName + "_y") /Wave = roiY roiX = drawROIX roiY = drawROIY //Replace the temporary draw ROI waves with the new ROI waves IE_AppendROIsToImage(group,baseName) SetDataFolder saveDF //Set the ROI Group Selector to the current group, in case ***NEW** group was created. //This will allow you to click-create ROIs in a NEW group without having to choose the group that //was just created. DFREF NTSI = $IE IE_UpdateImageBrowserLists() IE_RefreshROIGroupList() SVAR ROIGroupList = NTSI:GroupList Variable index = WhichListItem(group,ROIGroupList,";") If(index != -1) PopUpMenu roiGroupSelect,win=IEDisplay#ROIPanel,mode=index+1 ControlUpdate/A EndIf End //Returns a mask wave for the input scan Function/WAVE IE_GetDendriticMask(theWave,[threshold]) Wave theWave Variable threshold Variable rows,cols,frames,i,j rows = DimSize(theWave,0) cols = DimSize(theWave,1) frames = DimSize(theWave,2) //For 2D images, max projections, etc. If(DimSize(theWave,2) == 0) Duplicate/O theWave,:tempWave Wave tempWave = :tempWave ImageStats/Q theWave //Min/max of the image Variable minVal = V_min Variable maxVal = V_max If(ParamIsDefault(threshold)) threshold = minVal + (maxVal - minVal) * 0.03//1.25 is a mask threshold and can be changed EndIf Multithread tempWave = (theWave < threshold) ? 0 : 1 Note/K tempWave,"Threshold=" + num2str(threshold) return tempWave Else //Get max projection image MatrixOP/S/O maxProj = sumBeams(theWave) Redimension/S maxProj EndIf Multithread maxProj /= DimSize(theWave,2) Make/FREE/N=(DimSize(theWave,0),DimSize(theWave,1)) varMap varMap = 0 For(i=0;i rows-2 || j-2 < 0 || j+2 > cols-2) continue Else //Get data block surrounding point block = varMap[i-2 + p][j-2 + q] //Check for isolated point If(sum(block) < 3*varMap[i][j]) varMap[i][j] = 0 EndIf EndIf block = 0 EndFor EndFor //2D median filter 3x3 MatrixFilter/N=3 median varMap //Create mask wave String maskName = NameOfWave(theWave) + "_mask" If(strlen(maskName) > 31) maskName = "Scan_mask" EndIf Make/O/N=(rows,cols) theMask MultiThread theMask = (varMap == 0) ? 0 : 1 //Scaling SetScale/P x,DimOffset(theWave,0),DimDelta(theWave,0),theMask SetScale/P y,DimOffset(theWave,1),DimDelta(theWave,1),theMask return theMask End //Create an ROI grid across an image Function IE_CreateROIGrid(w,h,threshold,target,group,baseName) Variable w,h,threshold String target,group,baseName DFREF NTSI = $IE //Get the image wave (time-varying scan, not max projection) SVAR SIDisplay_ImagePaths = NTSI:SIDisplay_ImagePaths Wave image = $StringFromList(0,SIDisplay_ImagePaths,";") If(!WaveExists(image)) return 0 EndIf String roiFolder = "root:Packages:NeuroToolsPlus:ScanImage:ROIs:" //Make a new ROI group if selected If(!cmpstr(group,"**NEW**")) SetDataFolder $roiFolder group = UniqueName("Group",11,0) NewDataFolder $(roiFolder + group) EndIf //First get a variance map of the image, in order to create a dendritic mask Wave mask = IE_GetDendriticMask(image) Redimension/B/U mask CopyScales/P image,mask threshold /= 100 //Fill the entire image with ROIs in square grid first, then prune them away Variable row=0,col=0,strideX=(w*1e-6)/DimDelta(mask,0),strideY=(h*1e-6)/DimDelta(mask,1),index=0 Do col = 0 If(row + strideX - 1 > DimSize(mask,0)-1) break EndIf Do If(col + strideY - 1 > DimSize(mask,1)-1) break EndIf Make/N=5/FREE roiX,roiY //X ROI coordinates roiX[0] = IndexToScale(mask,row,0) roiX[1] = IndexToScale(mask,row,0) roiX[2] = IndexToScale(mask,row+strideX-1,0) roiX[3] = IndexToScale(mask,row+strideX-1,0) roiX[4] = IndexToScale(mask,row,0) //Y ROI coordinates roiY[0] = IndexToScale(mask,col,1) roiY[1] = IndexToScale(mask,col+strideY-1,1) roiY[2] = IndexToScale(mask,col+strideY-1,1) roiY[3] = IndexToScale(mask,col,1) roiY[4] = IndexToScale(mask,col,1) //Create mask for the ROI and compare it with the image mask to see if there is enough fluorescence to merit an ROI. Variable xSeed = IndexToScale(mask,row+3,0) Variable ySeed = IndexToScale(mask,col+3,1) ImageBoundaryToMask width=DimSize(mask,0),height=DimSize(mask,1),xwave=roiX,ywave=roiY,scalingwave=mask,seedX=xSeed,seedY=ySeed Wave ROIMask = M_ROIMask MatrixOP/FREE bit = bitAND(mask,ROIMask) //thresholding If(sum(bit) < threshold * (w * h)) KillWaves/Z roiX,roiY col += strideY continue EndIf If(!strlen(baseName)) baseName = "ROI" EndIf //Make new waves Make/N=5/O $(roiFolder + group + ":" + baseName + "_" + num2str(index) + "_y")/Wave=yROI Make/N=5/O $(roiFolder + group + ":" + baseName + "_" + num2str(index) + "_x")/Wave=xROI //put into the wave reference waves xROI = roiX yROI = roiY col += strideY index += 1 While(1) row += strideX While(1) End //Determines the number of subwindows in the window Function IE_GetNumImages(windowNameStr,baseNameStr) String windowNameStr,baseNameStr Variable i i = 0 Do String fullWinName = windowNameStr + "#" + baseNameStr + num2str(i) GetWindow/Z $fullWinName wsize //keyword doesn't matter, but need to reserve V_flag for existence or not i += 1 While(!V_flag) return i - 1 End Function/WAVE IE_GetMaxProj(imageList[,noReplace]) String imageList Variable noReplace If(ParamIsDefault(noReplace)) noReplace = 0 EndIf DFREF NTSI = $IE NVAR isMaxProj = NTSI:isMaxProj NVAR isInverted = NTSI:isInverted Variable i For(i=0;i 1) ImageHistogram/I/P=(imagePlane) theImage Else ImageHistogram/I theImage EndIf EndIf Wave hist = W_ImageHist Integrate hist/D=cumHist Variable minLevel=cumHist[0] Variable maxLevel=cumHist[dimsize(cumHist,0)-1] Variable range=maxLevel-minLevel FindLevel/Q cumHist, minLevel + range*pct Variable lowerThreshold=V_levelX FindLevel/Q cumHist,minLevel+range*(1-pct) Variable upperThreshold=V_levelX Variable sliderLeft,sliderRight ModifyImage/W=IEDisplay#$subpanel#$graph $NameOfWave(theImage) ctab= {lowerThreshold,upperThreshold,Grays,isInverted} //Set the slider positions ImageStats/Q theImage range = V_max - V_min sliderLeft = round(100 * (lowerThreshold - V_min)/range) sliderRight = round(100 * (upperThreshold - V_min)/range) If(isInverted) Slider darkValueSlider win=IEDisplay#control,value=sliderRight Slider brightValueSlider win=IEDisplay#control,value=sliderLeft Else Slider darkValueSlider win=IEDisplay#control,value=sliderLeft Slider brightValueSlider win=IEDisplay#control,value=sliderRight EndIf EndFor // KillWaves hist,cumHist End //Dynamic ROI Function IE_StartDynamicROI(theImage) Wave theImage DFREF NTSI = $IE NVAR scaleCumulative = NTSI:scaleCumulative //Make a new display window GetWindow/Z dynamicROI wsize Variable winExists = V_flag KillWindow/Z dynamicROI If(!winExists) //window exists Display/N=dynamicROI/W=(V_left,V_top,V_right,V_bottom)/K=2 as "Dynamic ROI" Else //window doesn't exists GetWindow/Z IEDisplay wsize If(V_top < 0) V_top = 0 EndIf Display/N=dynamicROI/W=(V_right,V_top,V_right+300,V_top+200)/K=2 as "Dynamic ROI" EndIf ControlBar/T/W=dynamicROI 20 Checkbox CumulativeScale,win=dynamicROI,pos={5,0},size={100,20},side=1,title="Cumulative Scaling ",value=scaleCumulative,proc=IE_CheckBoxProc Variable frames = DimSize(theImage,2) Variable delta = DimDelta(theImage,2) Variable offset = DimOffset(theImage,2) Make/O/N=(frames) NTSI:dynamicROI/Wave=dROI SetScale/P x,offset,delta,"s",dROI //Size in microns NVAR size = NTSI:dynamicROI_Size Variable xSize = round((size * 1e-6) / DimDelta(theImage,0)) Variable ySize = round((size * 1e-6) / DimDelta(theImage,1)) Make/O/N=(xSize,ySize,frames) NTSI:block Variable/G NTSI:isDynamicROI NVAR isDynamicROI = NTSI:isDynamicROI isDynamicROI = 1 Variable/G NTSI:dynamicROI_MaxVal NVAR maxVal = NTSI:dynamicROI_MaxVal Variable/G NTSI:dynamicROI_MinVal NVAR minVal = NTSI:dynamicROI_MinVal maxVal = -5000 minVal = 5000 String/G NTSI:dynamicROI_Image SVAR dynamicROI_Image = NTSI:dynamicROI_Image dynamicROI_Image = GetWavesDataFolder(theImage,2) AppendToGraph/W=dynamicROI dROI SetAxis/W=dynamicROI left,0,maxVal End //Gets the middle point of an ROI defined by an x wave and a y wave //Returns the X/Y coordiate waves as a wave reference wave Function/Wave IE_GetCenter([group]) String group Variable i If(ParamIsDefault(group)) //Selected ROIs and their group assignments String roiList = IE_SelectedROIs() String roiGroupList = IE_SelectedROIs(groups=1) Else Wave/T roiListWave = IE_GetROIs(group) roiList = TextWaveToStringList(roiListWave,";") roiGroupList = "" For(i=0;i 0) roiNameList += ROIListWave[i][0][0] + ";" roiGroupList += ROIListWave[i][0][1] + ";" selectedRowList += num2str(i) + ";" EndIf EndFor Variable numROIs = ItemsInList(roiNameList,";") For(i=0;i