colorassign_manual.m"/**
* Script to Pass QuPath to colorassign_manual.m,
* QuPath detection objects.
*
* This requires the MATLAB Engine, available with MATLAB R2016b or later,
* and setup as described at https://github.com/qupath/qupath/wiki/Working-with-MATLAB
*
* @author Jason DeFuria
*/
import qupath.lib.classifiers.PathClassificationLabellingHelper
import qupath.lib.common.ColorTools
import qupath.lib.objects.classes.PathClass
import qupath.lib.objects.classes.PathClassFactory
import qupath.lib.scripting.QP
import qupath.extension.matlab.QuPathMATLABExtension
import com.mathworks.matlab.types.Struct
import qupath.lib.images.tools.BufferedImageTools
import qupath.lib.objects.PathObject
import qupath.lib.objects.PathTileObject
import qupath.lib.regions.RegionRequest
import qupath.lib.roi.PolygonROI
import qupath.lib.scripting.QP
import qupath.extension.matlab.QuPathMATLABExtension
import java.awt.image.BufferedImage
// Import the helper class
QuPathMATLAB = this.class.classLoader.parseClass(QuPathMATLABExtension.getQuPathMATLABScript())
// Get the MATLAB engine
QuPathMATLAB.getEngine(this)
try {
def imageData = QP.getCurrentImageData()
double downsample = 8
BufferedImage img;
def roi = QP.getSelectedROI()
if (roi != null) {
img = imageData.getServer().readBufferedImage(RegionRequest.createInstance(imageData.getServerPath(), downsample, roi))
} else
img = imageData.getServer().getBufferedThumbnail(1000, -1, 0)
// Put RGB version of QuPath image & calibration data into MATLAB workspace
if (roi == null) {
double downsampleH = (double)imageData.getServer().getHeight()/(double)img.getHeight()
double downsampleW = (double)imageData.getServer().getWidth()/(double)img.getWidth()
double downsampleActual = Math.max(downsampleH, downsampleW)
QuPathMATLAB.putQuPathImageStruct("img", img, null, 0, 0, downsampleActual, true)
}
else {
def imgMask = BufferedImageTools.createROIMask(img.getWidth(), img.getHeight(), roi, roi.getBoundsX(), roi.getBoundsY(), downsample)
QuPathMATLAB.putQuPathImageStruct("img", img, imgMask, roi.getBoundsX(), roi.getBoundsY(), downsample, true)
}
// Take Image and Move Into MATLAB Color Assign Manual function
QuPathMATLAB.eval("image = imread(img);")
QuPathMATLAB.eval("colorassign_manual(image)")
// Print a message so we know we reached the end
print("Image loaded in MATLAB")
} catch (Exception e) {
println("Error running script: " + e.getMessage())
} finally {
QuPathMATLAB.close()
}INFO: Error using <a href="matlab:matlab.internal.language.introspective.errorDocCallback('imread>parse_inputs', '/Applications/MATLAB_R2018a.app/toolbox/matlab/imagesci/imread.p', 450)" style="font-weight:bold">imread>parse_inputs</a> (<a href="matlab: opentoline('/Applications/MATLAB_R2018a.app/toolbox/matlab/imagesci/imread.p',450,0)">line 450</a>)
The file name or URL argument must be a character vector.
Error in <a href="matlab:matlab.internal.language.introspective.errorDocCallback('imread', '/Applications/MATLAB_R2018a.app/toolbox/matlab/imagesci/imread.p', 322)" style="font-weight:bold">imread</a> (<a href="matlab: opentoline('/Applications/MATLAB_R2018a.app/toolbox/matlab/imagesci/imread.p',322,0)">line 322</a>)
[filename, fmt_s, extraArgs, was_cached_fmt_used] = parse_inputs(cached_fmt, varargin{:});
INFO: Exception running statement: image = imread(img);
INFO: Caused by com.mathworks.mvm.exec.MvmRuntimeException: The file name or URL argument must be a character vector.
INFO: Error running script: image = imread(img);QuPathMATLAB.eval("image = imread(img);")
expects the path to an image, but in fact you should at that point have a struct that includes the pixels already. You could try something like this:
QuPathMATLAB.eval("image = img.im;")
/**
* Script to Pass QuPath to Color Normalization in Workflow. Must use RGB image at input, but can be of any fileformat that QuPath Supports
* QuPath detection objects.
*
* This requires the MATLAB Engine, available with MATLAB R2016b or later,
* and setup as described at https://github.com/qupath/qupath/wiki/Working-with-MATLAB
*
* NOTE: You will also need the Parallel Computing Toolbox installed for MATLAB, or if you do not have it, comment out the lines in the MATLAB scripts. (AKA- change ('UseParallel',true) to ('UseParallel',false))
* @author Jason DeFuria
*/
import qupath.lib.classifiers.PathClassificationLabellingHelper
import qupath.lib.common.ColorTools
import qupath.lib.objects.classes.PathClass
import qupath.lib.objects.classes.PathClassFactory
import qupath.lib.scripting.QP
import qupath.extension.matlab.QuPathMATLABExtension
import com.mathworks.matlab.types.Struct
import qupath.lib.images.tools.BufferedImageTools
import qupath.lib.objects.PathObject
import qupath.lib.objects.PathTileObject
import qupath.lib.regions.RegionRequest
import qupath.lib.roi.PolygonROI
import qupath.lib.scripting.QP
import qupath.extension.matlab.QuPathMATLABExtension
import java.awt.image.BufferedImage
// Import the helper class
QuPathMATLAB = this.class.classLoader.parseClass(QuPathMATLABExtension.getQuPathMATLABScript())
// Get the MATLAB engine
QuPathMATLAB.getEngine(this)
try {
def imageData = QP.getCurrentImageData()
double downsample = 1
BufferedImage img;
def roi = QP.getSelectedROI()
if (roi != null) {
img = imageData.getServer().readBufferedImage(RegionRequest.createInstance(imageData.getServerPath(), downsample, roi))
} else
img = imageData.getServer().getBufferedThumbnail(1000, -1, -1)
// Put RGB version of QuPath image & calibration data into MATLAB workspace
if (roi == null) {
double downsampleH = (double)imageData.getServer().getHeight()/(double)img.getHeight()
double downsampleW = (double)imageData.getServer().getWidth()/(double)img.getWidth()
double downsampleActual = Math.max(downsampleH, downsampleW)
QuPathMATLAB.putQuPathImageStruct("img", img, null, 0, 0, downsampleActual, true)
}
else {
def imgMask = BufferedImageTools.createROIMask(img.getWidth(), img.getHeight(), roi, roi.getBoundsX(), roi.getBoundsY(), downsample)
QuPathMATLAB.putQuPathImageStruct("img", img, imgMask, roi.getBoundsX(), roi.getBoundsY(), downsample, true)
}
// Take Image and Move Into MATLAB Color Assign Manual function. Function should load GUI, and you must select at least 1 value each for Nuclei, Stroma, Lumen, and Cytoplasm.
QuPathMATLAB.eval("loadedimage = img.im;")
QuPathMATLAB.eval("[idx, lumen, nuclei, stroma, cytoplasm] = colorassign_manual(loadedimage)")
// Print a message so we know we reached the end of the first function
print("Color Assign Manual Complete")
// Take Image and outputted Lumen, Nuclei, Stroma, and Cytoplasm variables and Move Into MATLAB Train Classifier function.
QuPathMATLAB.eval("classifier = train_classifier(loadedimage, idx, lumen, nuclei, stroma, cytoplasm)")
// Print a message so we know we reached the end of the second function
print("Train Classifier Function Complete")
// Take Image and Move Into MATLAB Color Classifier
QuPathMATLAB.eval("classified = color_classify(loadedimage, classifier)")
// Print a message so we know we reached the end of the third function
print("Color Classifier Function Complete")
// Take Image and Move Into MATLAB Color Normalize
QuPathMATLAB.eval("load('target.mat')")
QuPathMATLAB.eval("rgb = color_normalize(loadedimage, target, classified)")
// Print a message so we know we reached the end of the fourth function
print("Color Normalize Function Complete")
// Take Color Normalized image and Save Output
QuPathMATLAB.eval("imwrite(rgb,'Normalized_Image.tif')")
// Print a message so we know we know the image was saved to the Present Working Directory in MATLAB
print("Image Saved to MATLAB PWD")
// Print a message so we know we reached the end
print("Complete Color Classify and Normalize Process Complete")path = buildFilePath(PROJECT_BASE_DIR, 'matlab')
mkdirs(path)QuPathMATLAB.eval("colorassign_manual(image)")QuPathMATLAB.eval("colorassign_manual(image);")class WholeSlideImageOverlay extends AbstractImageDataOverlay {
private boolean initialized = false
private QuPathViewer viewer
private ImageServer<BufferedImage> server
private AffineTransform transform
private boolean bindToObjectDisplay
public WholeSlideImageOverlay(final QuPathViewer viewer, final String path, boolean bindToObjectDisplay) {
super(viewer.getOverlayOptions(), viewer.getImageData())
this.viewer = viewer
this.server = ImageServerProvider.buildServer(path, BufferedImage.class)
this.initialized = true
this.bindToObjectDisplay = bindToObjectDisplay
}def path = viewer.getServerPath()def path = "/Users/jason/Documents/MATLAB/Normalized_Image723.tif" // Apply transform... handy if using the same image, just to check *something* happens
g2d.translate(1000, 1000)