diff --git a/Code/AdipoQuant.groovy b/Code/AdipoQuant.groovy index 68f384e..f532e01 100644 --- a/Code/AdipoQuant.groovy +++ b/Code/AdipoQuant.groovy @@ -78,7 +78,7 @@ mq_classes.each { the_class -> } } -getQuPath().getAvailablePathClasses().setAll(all_classes) +Platform.runLater{ getQuPath().getAvailablePathClasses().setAll(all_classes) } fireHierarchyUpdate() def ij = IJExtension.getImageJInstance() @@ -105,7 +105,7 @@ tissues.eachWithIndex{ tissue, i -> } fireHierarchyUpdate() -def imageName = getCurrentImageData().getServer().getShortServerName() +def imageName = getCurrentImageNameWithoutExtension() println("Processing complete for " + imageName ); //ij.quit() @@ -121,8 +121,11 @@ class AdipocyteDetector { IJ.run("Close All") // Returns the image as an ImageJ ImagePlus object with ROIs and the overlay - def image = GUIUtils.getImagePlus(tissue, this.downsample, true, true) - + def request = RegionRequest.createInstance( getCurrentServerPath(), this.downsample, tissue.getROI() ) + def pathImage = IJExtension.extractROIWithOverlay(getCurrentServer(), tissue, getCurrentHierarchy(), request, true, getCurrentViewer().getOverlayOptions()); + + def image = pathImage.getImage() + // Pick up pixel size def px_size = image.getCalibration().pixelWidth @@ -146,24 +149,17 @@ class AdipocyteDetector { IJ.run(hsb_image, "HSB Stack", "") hsb_image.show() - // Call Color Deconvolution and recover the images (must be done through GUI for now) - IJ.run(image, "Colour Deconvolution", "vectors=H&E hide") - - //Pickup the images for later processing - def col1 = WindowManager.getImage( image.getTitle()+"-(Colour_1)" ) - def col2 = WindowManager.getImage( image.getTitle()+"-(Colour_2)" ) - def col3 = WindowManager.getImage( image.getTitle()+"-(Colour_3)" ) - + // Call Color Deconvolution and recover the images ) + def cols = colorDeconvolution( image, "H&E" ) + // Creates the final image we are going to process from the hue and brightness image obtained def ic = new ImageCalculator() - def adip_raw_image = ic.run("Subtract create", col3, col1) + def adip_raw_image = ic.run("Subtract create", cols[2], cols[0]) adip_raw_image.show() image.close() - col1.close() - col2.close() - col3.close() + cols.each{ it.close() } def saturation = hsb_image.getStack().getProcessor(2) // Saturation is the second image saturation.multiply(8) @@ -181,8 +177,11 @@ class AdipocyteDetector { IJ.run( adip_mask, "Invert", "") // IB? IJ.run( adip_mask, "Watershed", "" ) adip_mask.show() + + IJ.run( adip_mask, "Options...", "iterations=50 count=5 pad do=Erode" ) + adip_mask.setRoi( all_edges ) //IJ.run(adip_mask, "Make Inverse", "") IJ.setRawThreshold(adip_mask, 0, 127, null) @@ -192,25 +191,29 @@ class AdipocyteDetector { def rm = RoiManager.getInstance() ?: new RoiManager() // Save as Detections in QuPath def adips = rm.getRoisAsArray() as List - rm.runCommand("Reset") + rm.reset() rm.close() + + def um = GeneralTools.micrometerSymbol() + def total_area = 0 // Measurement of adipocytes areas and displaying of the data in QuPath adips.eachWithIndex{ adip, idx -> - def qu_adip = ROIConverterIJ.convertToPathROI( adip, image.getCalibration(), this.downsample, 0,0,0) - def det = new PathDetectionObject(qu_adip, getPathClass("Adipocyte")) + def det = IJTools.convertToDetection( adip, this.downsample, image ) + det.setPathClass( getPathClass("Adipocyte") ) def area = adip.getStatistics().area det.getMeasurementList().putMeasurement( "Adipocyte Index", idx+1 ) - det.getMeasurementList().putMeasurement( "Area "+Utils.um+"^2", area * px_size * px_size ) + det.getMeasurementList().putMeasurement( "Area "+um+"^2", area * px_size * px_size ) - tissue.addPathObject(det) + tissue.addChildObject(det) total_area += area } - tissue.getMeasurementList().clear(); - tissue.getMeasurementList().putMeasurement( "Total Adipocyte Area "+Utils.um+"^2", total_area * px_size * px_size ) + tissue.getMeasurementList().clear() + tissue.getMeasurementList().putMeasurement( "Total Adipocyte Area "+um+"^2", total_area * px_size * px_size ) Interpreter.batchMode = false + fireHierarchyUpdate() } // Excludes the artifacts from the ROI we want to process @@ -219,20 +222,20 @@ class AdipocyteDetector { return tissue_roi } - if (artifacts.size > 0) { + if (artifacts.size() > 0) { def rm = RoiManager.getInstance() ?: new RoiManager() - rm.runCommand("Reset") + rm.reset() artifacts.each{ rm.addRoi(it) } def all_artifacts - if ( artifacts.size == 1 ) { + if ( artifacts.size() == 1 ) { all_artifacts = artifacts[0] } else { rm.setSelectedIndexes((0..rm.getCount()-1) as int[]) rm.runCommand(image, "OR") all_artifacts = image.getRoi() } - rm.runCommand("Reset") + rm.reset() // AND then XOR with tissue IJ.log(""+all_artifacts) rm.addRoi(all_artifacts) @@ -243,13 +246,32 @@ class AdipocyteDetector { rm.addRoi( overlap_artifacts ) rm.setSelectedIndexes([1,2] as int[]) rm.runCommand(image, "XOR") + rm.reset() rm.close() return image.getRoi() } } + + // Use Color Deconvolution Plugin in MarrowQuant + public ImagePlus[] colorDeconvolution ( ImagePlus image, String stain ) { + def cd = new Colour_Deconvolution() + def matList = cd.getStainList() + def mt = matList.get( stain ) + def stackList = mt.compute( false, true, image ) + // This returns an array of ImageStacks + + // Make into an ImagePlus + def imageStack = new ImageStack( stackList[0].getWidth(), stackList[0].getHeight() ) + + stackList.each { imageStack.addSlice( it.getProcessor( 1 ) ) } + + def deconvolved = stackList.collect{ new ImagePlus( image.getTitle()+"-"+stain, it ) } + + return deconvolved + } } -// Import BIOP library to do fun things -import ch.epfl.biop.qupath.utils.* + + import ij.IJ import sc.fiji.colourDeconvolution.* import ij.WindowManager @@ -258,18 +280,15 @@ import ij.ImagePlus import ij.process.ImageProcessor import ij.plugin.frame.RoiManager import qupath.lib.objects.PathDetectionObject -import qupath.imagej.objects.ROIConverterIJ import ij.macro.Interpreter -import ch.epfl.biop.qupath.utils.Utils +import ij.ImageStack import ij.gui.Roi import qupath.imagej.gui.IJExtension -import qupath.lib.gui.helpers.DisplayHelpers + import qupath.imagej.helpers.* -import qupath.lib.roi.PathObjectToolsAwt import qupath.lib.objects.PathAnnotationObject - \ No newline at end of file diff --git a/Code/AdipoQuant_Export_Results.groovy b/Code/Export_AdipoQuant_results.groovy similarity index 86% rename from Code/AdipoQuant_Export_Results.groovy rename to Code/Export_AdipoQuant_results.groovy index bf27e9c..ec2dc0c 100644 --- a/Code/AdipoQuant_Export_Results.groovy +++ b/Code/Export_AdipoQuant_results.groovy @@ -9,13 +9,14 @@ -import ch.epfl.biop.qupath.utils.* +import qupath.ext.biop.utils.Results selectDetections(); runPlugin('qupath.lib.plugins.objects.ShapeFeaturesPlugin', '{"area": false, "perimeter": true, "circularity": true, "useMicrons": true}'); -def um = Utils.um +def um = GeneralTools.micrometerSymbol() + def columns = ["Adipocyte Index", "Parent", "Area "+um+"^2"] def resultsfolder = buildFilePath(PROJECT_BASE_DIR, "results") @@ -25,6 +26,6 @@ def resultsfile = new File(resultsfolder, "adipocyte-measurements.txt") println(resultsfile.getAbsolutePath()) def detections = getDetectionObjects() -Utils.sendResultsToFile(columns, detections, resultsfile) +Results.sendResultsToFile(columns, detections, resultsfile) println("Completed") \ No newline at end of file diff --git a/Code/Export_MarrowQuant_Results_QuPath_0.4.3.groovy b/Code/Export_MarrowQuant_results.groovy similarity index 94% rename from Code/Export_MarrowQuant_Results_QuPath_0.4.3.groovy rename to Code/Export_MarrowQuant_results.groovy index f5cccef..c95f897 100644 --- a/Code/Export_MarrowQuant_Results_QuPath_0.4.3.groovy +++ b/Code/Export_MarrowQuant_results.groovy @@ -37,7 +37,7 @@ def outputPath = buildFilePath( PROJECT_BASE_DIR, 'results' ) mkdirs( outputPath ) // Give the results file a name -def fileName = 'MarrowQuant_Results.txt' +def fileName = 'MarrowQuant_Results_20230721_final.txt' // Write results in the desired directory to the desired filename def file = new File( outputPath, fileName ) @@ -54,12 +54,12 @@ def columns = [ "Image Name", "Tt.Ad.Ar_"+U+"^2", "It.Ar_"+U+"^2", "Ma.Ar_"+U+"^2", - "Other.Ar_"+U+"^2", + "Un.Ar_"+U+"^2", "Hm.Ar/(Hm.Ar+Tt.Ad.Ar)_%_Equation_1", "Hm.Ar/Ma.Ar_%_Equation_2", "Tt.Ad.Ar/Ma.Ar_%", "It.Ar/Ma.Ar_%", - "Other.Ar/Ma.Ar_%", + "Un.Ar/Ma.Ar_%", "Aj.Ad.N", "Ad_Min_Size", "Ad_Max_Size", diff --git a/Code/MarrowQuant_Mouse_QuPath_0.4.3.groovy b/Code/MarrowQuant.groovy similarity index 98% rename from Code/MarrowQuant_Mouse_QuPath_0.4.3.groovy rename to Code/MarrowQuant.groovy index 27b0658..eb7cc08 100644 --- a/Code/MarrowQuant_Mouse_QuPath_0.4.3.groovy +++ b/Code/MarrowQuant.groovy @@ -83,9 +83,9 @@ ij.quit() // end of script// -// MarrowQnat class starts below +// MarrowQuat class starts below @ToString(includeNames=true) -class MarrowQuant { +class MarrowQuant1 { def downsample = 4 def adipMin = 5 @@ -120,7 +120,7 @@ class MarrowQuant { def boneMaskImage def hematoMaskImage - final private static Logger logger = LoggerFactory.getLogger( MarrowQuant.class ) + final private static Logger logger = LoggerFactory.getLogger( MarrowQuant1.class ) public void run() { def all_annotations = getAnnotationObjects() @@ -144,7 +144,14 @@ class MarrowQuant { //tissueAnnotation.getChildObjects().find{ it.getPathClass() == getPathClass("BG") } def tissue_artifacts = tissueAnnotation.getChildObjects().findAll{ it.getPathClass() == getPathClass("Artifact") } - def mergedArtifactsAnnotation = PathUtils.merge( tissue_artifacts ) + // Merge artifacts for later use + def hasMerged = mergeAnnotations( tissue_artifacts ) + def mergedArtifactsAnnotation + if( hasMerged ) { + mergedArtifactsAnnotation = getSelectedObject() + } else { + mergedArtifactsAnnotation = tissue_artifacts[0] + } this.image = getImagePlus( tissueAnnotation, downsample) @@ -515,6 +522,7 @@ class MarrowQuant { } measurements.putMeasurement( "Aj.Ad.N", rois.size() ) measurements.putMeasurement("Ad.MA.Ar_Nby_"+U+"^2", rois.size()/ round( ( area_hemato + area_adips + area_imv ) * px_size * px_size ,0 ) ) + rm.reset() rm.close() } @@ -670,7 +678,7 @@ class MarrowQuant { } // The lines below allow us to user the Builder Pattern withourh having to declare it in the MarrowQuant class -@Builder(builderStrategy = ExternalStrategy, forClass = MarrowQuant, prefix = 'assign', buildMethodName = 'create') +@Builder(builderStrategy = ExternalStrategy, forClass = MarrowQuant1, prefix = 'assign', buildMethodName = 'create') class MQBuilder { MQBuilder() { downsample = 4 diff --git a/Code/Remove_Overview_And_Label_Images.groovy b/Code/Remove_Overview_And_Label_Images.groovy index d28c8e9..45affb6 100644 --- a/Code/Remove_Overview_And_Label_Images.groovy +++ b/Code/Remove_Overview_And_Label_Images.groovy @@ -7,21 +7,10 @@ * but otherwise everything kept the same. */ -import qupath.lib.gui.QuPathGUI -import qupath.lib.gui.panels.ProjectBrowser -import qupath.lib.images.ImageData -import qupath.lib.images.servers.ImageServerProvider -import qupath.lib.io.PathIO -import qupath.lib.projects.Project -import qupath.lib.projects.ProjectIO - -import java.awt.image.BufferedImage - // Get the running QuPath instance -def qupath = QuPathGUI.getInstance() - +def qupath = getQuPath() // Get the current project -def project = qupath.getProject() +def project = getProject() if (project == null) { println("No project open!") return @@ -36,11 +25,6 @@ for (def entry in project.getImageList()) { } sleep(1000) -getQuPath().refreshProject() -ProjectIO.writeProject(project) -fireHierarchyUpdate() - -// Write the new project itself -//ProjectIO.writeProject(projectNew) +qupath.refreshProject() -print("Done! Project written to ") \ No newline at end of file +fireHierarchyUpdate() \ No newline at end of file diff --git a/Setup/Extensions/Colour_Deconvolution-3.0.2.jar b/Setup/Extensions/Colour_Deconvolution-3.0.2.jar deleted file mode 100644 index d3609d1..0000000 Binary files a/Setup/Extensions/Colour_Deconvolution-3.0.2.jar and /dev/null differ diff --git a/Setup/Extensions/colourdeconvolution.txt b/Setup/Extensions/colourdeconvolution.txt deleted file mode 100644 index 56bab8a..0000000 --- a/Setup/Extensions/colourdeconvolution.txt +++ /dev/null @@ -1,17 +0,0 @@ -#Stain_Name,R0,G0,B0,R1,G1,B1,R2,G2,B2 -H&E,0.644211000,0.716556000,0.266844000,0.09278900,0.95411100,0.28311100,0.00000000,0.00000000,0.0000000 -H&E 2,0.490157340,0.768970850,0.410401730,0.04615336,0.84206840,0.53739250,0.00000000,0.00000000,0.0000000 -H DAB,0.650000000,0.704000000,0.286000000,0.26800000,0.57000000,0.77600000,0.00000000,0.00000000,0.0000000 -Feulgen Light Green,0.464209200,0.830083350,0.308271870,0.94705542,0.25373821,0.19650764,0.00000000,0.00000000,0.0000000 -Giemsa,0.834750233,0.513556283,0.196330403,0.09278900,0.95411100,0.28311100,0.00000000,0.00000000,0.0000000 -FastRed FastBlue DAB,0.213939210,0.851126690,0.477940220,0.74890292,0.60624161,0.26731082,0.26800000,0.57000000,0.7760000 -Methyl Green DAB,0.980000000,0.144316000,0.133146000,0.26800000,0.57000000,0.77600000,0.00000000,0.00000000,0.0000000 -H&E DAB,0.650000000,0.704000000,0.286000000,0.07200000,0.99000000,0.10500000,0.26800000,0.57000000,0.7760000 -H AEC,0.650000000,0.704000000,0.286000000,0.27430000,0.67960000,0.68030000,0.00000000,0.00000000,0.0000000 -Azan-Mallory,0.853033000,0.508733000,0.112656000,0.09289875,0.86620080,0.49098468,0.10732849,0.36765403,0.9237484 -Masson Trichrome,0.799510700,0.591352100,0.105286670,0.09997159,0.73738605,0.66803260,0.00000000,0.00000000,0.0000000 -Alcian blue & H,0.874622000,0.457711000,0.158256000,0.55255600,0.75440000,0.35374400,0.00000000,0.00000000,0.0000000 -H PAS,0.644211000,0.716556000,0.266844000,0.17541100,0.97217800,0.15458900,0.00000000,0.00000000,0.0000000 -Brilliant_Blue,0.314655480,0.660239500,0.681964640,0.38357300,0.52711410,0.75830240,0.74335430,0.51731443,0.4240403 -RGB,0.000000000,1.000000000,1.000000000,1.00000000,0.00000000,1.00000000,1.00000000,1.00000000,0.0000000 -CMY,1.000000000,0.000000000,0.000000000,0.00000000,1.00000000,0.00000000,0.00000000,0.00000000,1.0000000 \ No newline at end of file diff --git a/Setup/Extensions/qupath-extension-biop-1.1.0.jar b/Setup/Extensions/qupath-extension-biop-1.1.0.jar deleted file mode 100644 index fc3db7f..0000000 Binary files a/Setup/Extensions/qupath-extension-biop-1.1.0.jar and /dev/null differ diff --git a/Setup/ij-plugins/BIOP_SimpleColorBalance.bsh b/Setup/ij-plugins/BIOP_SimpleColorBalance.bsh deleted file mode 100644 index 5fc691f..0000000 --- a/Setup/ij-plugins/BIOP_SimpleColorBalance.bsh +++ /dev/null @@ -1,73 +0,0 @@ -import ij.*; -import ij.process.*; -import ij.measure.Measurements; -import ij.gui.Roi; -// White Balance based on ROI - -// Get Current Image -ImagePlus imp = IJ.getImage(); - -// Make sure it is RGB -if (imp.getType() != ImagePlus.COLOR_RGB) { - return; -} -//get ROI or make one if not available -Roi theRoi = imp.getRoi(); -if (theRoi == null) { - IJ.log("No ROI, making a square at (0,0) of width 65 px"); - theRoi = new Roi(0, 0, 65,65, imp); -} -//Remove ROI before duplication -imp.killRoi(); - - -ImagePlus imp2 = imp.duplicate(); -imp2.setTitle("Color Balanced "+imp.getTitle()); - -// Make a 3 slice stack -ImageConverter ic = new ImageConverter(imp2); -ic.convertToRGBStack(); -imp2.setRoi(theRoi); -statOptions = Measurements.MEAN+Measurements.MEDIAN; - -// Calculate mean/median of each color -imp2.setPosition(1); //R -ImageStatistics isR = imp2.getStatistics(statOptions); -imp2.setPosition(2); //G -ImageStatistics isG = imp2.getStatistics(statOptions); -imp2.setPosition(3); //B -ImageStatistics isB = imp2.getStatistics(statOptions); - -//IJ.log("R:"+isR.mean+", G:"+isG.mean+", B:"+isB.mean); - -double[] rgb = {isR.mean,isG.mean,isB.mean}; - -// find largest value. -double maxVal = 0; -int idx = -1; -double scale; -for(i=0; i<3;i++) { - if (rgb[i] > maxVal) { - idx = i; - maxVal = rgb[i]; - scale = 255/maxVal; - } -} - -// Remove ROI again to make sure we apply the multiplication to the whole image -imp2.killRoi(); - -for (i=0; i<3; i++) { - imp2.setPosition(i+1); - ip = imp2.getProcessor(); - val = maxVal/rgb[i]*scale; - IJ.log(""+val+", "+rgb[i]+", "+maxVal); - ip.multiply(maxVal/rgb[i]*scale); //Scaling the other channels to the largest one. -} - -// Convert it back -ImageConverter ic = new ImageConverter(imp2); -ic.convertRGBStackToRGB(); - -//Show the image -imp2.show(); \ No newline at end of file diff --git a/Setup/ij-plugins/Colour_Deconvolution-3.0.2.jar b/Setup/ij-plugins/Colour_Deconvolution-3.0.2.jar deleted file mode 100644 index d3609d1..0000000 Binary files a/Setup/ij-plugins/Colour_Deconvolution-3.0.2.jar and /dev/null differ diff --git a/Setup/ij-plugins/colourdeconvolution.txt b/Setup/ij-plugins/colourdeconvolution.txt deleted file mode 100644 index 56bab8a..0000000 --- a/Setup/ij-plugins/colourdeconvolution.txt +++ /dev/null @@ -1,17 +0,0 @@ -#Stain_Name,R0,G0,B0,R1,G1,B1,R2,G2,B2 -H&E,0.644211000,0.716556000,0.266844000,0.09278900,0.95411100,0.28311100,0.00000000,0.00000000,0.0000000 -H&E 2,0.490157340,0.768970850,0.410401730,0.04615336,0.84206840,0.53739250,0.00000000,0.00000000,0.0000000 -H DAB,0.650000000,0.704000000,0.286000000,0.26800000,0.57000000,0.77600000,0.00000000,0.00000000,0.0000000 -Feulgen Light Green,0.464209200,0.830083350,0.308271870,0.94705542,0.25373821,0.19650764,0.00000000,0.00000000,0.0000000 -Giemsa,0.834750233,0.513556283,0.196330403,0.09278900,0.95411100,0.28311100,0.00000000,0.00000000,0.0000000 -FastRed FastBlue DAB,0.213939210,0.851126690,0.477940220,0.74890292,0.60624161,0.26731082,0.26800000,0.57000000,0.7760000 -Methyl Green DAB,0.980000000,0.144316000,0.133146000,0.26800000,0.57000000,0.77600000,0.00000000,0.00000000,0.0000000 -H&E DAB,0.650000000,0.704000000,0.286000000,0.07200000,0.99000000,0.10500000,0.26800000,0.57000000,0.7760000 -H AEC,0.650000000,0.704000000,0.286000000,0.27430000,0.67960000,0.68030000,0.00000000,0.00000000,0.0000000 -Azan-Mallory,0.853033000,0.508733000,0.112656000,0.09289875,0.86620080,0.49098468,0.10732849,0.36765403,0.9237484 -Masson Trichrome,0.799510700,0.591352100,0.105286670,0.09997159,0.73738605,0.66803260,0.00000000,0.00000000,0.0000000 -Alcian blue & H,0.874622000,0.457711000,0.158256000,0.55255600,0.75440000,0.35374400,0.00000000,0.00000000,0.0000000 -H PAS,0.644211000,0.716556000,0.266844000,0.17541100,0.97217800,0.15458900,0.00000000,0.00000000,0.0000000 -Brilliant_Blue,0.314655480,0.660239500,0.681964640,0.38357300,0.52711410,0.75830240,0.74335430,0.51731443,0.4240403 -RGB,0.000000000,1.000000000,1.000000000,1.00000000,0.00000000,1.00000000,1.00000000,1.00000000,0.0000000 -CMY,1.000000000,0.000000000,0.000000000,0.00000000,1.00000000,0.00000000,0.00000000,0.00000000,1.0000000 \ No newline at end of file diff --git a/Setup/ij-plugins/jars/BeanShell.jar b/Setup/ij-plugins/jars/BeanShell.jar deleted file mode 100644 index b3bb0a2..0000000 Binary files a/Setup/ij-plugins/jars/BeanShell.jar and /dev/null differ diff --git a/Setup/ij-plugins/jars/Biovoxxel_Plugins-2.1.5.jar b/Setup/ij-plugins/jars/Biovoxxel_Plugins-2.1.5.jar deleted file mode 100644 index 464cf42..0000000 Binary files a/Setup/ij-plugins/jars/Biovoxxel_Plugins-2.1.5.jar and /dev/null differ