diff --git a/src/main/groovy/qupath/ext/qp_scope/QP_scope.groovy b/src/main/groovy/qupath/ext/qp_scope/QP_scope.groovy index 53bcadb..28a178e 100644 --- a/src/main/groovy/qupath/ext/qp_scope/QP_scope.groovy +++ b/src/main/groovy/qupath/ext/qp_scope/QP_scope.groovy @@ -61,7 +61,8 @@ class QP_scope implements QuPathExtension { def qpScope1 = new MenuItem("Start qp_scope") // TODO: tooltip qpScope1.setOnAction(e -> { - // TODO: check preferences for all necessary entries + // TODO: check preferences for all necessary entries, and check for micromanager running+version + // search java app with a subprocesses for MicroManager +version number QP_scope_GUI.createGUI1() }) diff --git a/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy b/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy index 144a00c..3d122f9 100644 --- a/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy +++ b/src/main/groovy/qupath/ext/qp_scope/functions/QP_scope_GUI.groovy @@ -39,7 +39,7 @@ class QP_scope_GUI { // New text fields for Python environment, script path, and sample label static TextField virtualEnvField = new TextField(preferences.environment) - static TextField pythonScriptField = new TextField(preferences.installation) + static TextField pythonScriptField = new TextField(preferences.pycromanager) static TextField projectsFolderField = new TextField(preferences.projects) static TextField sampleLabelField = new TextField("First_Test") // New field for sample label // GUI3 @@ -83,6 +83,8 @@ class QP_scope_GUI { boolean dataCheck = true def annotations = QP.getAnnotationObjects() // Check if using annotations + + //TODO REPLACE ALL OF THIS WITH TILING if (useAnnotationsCheckBox.isSelected()) { // Check if annotations are present diff --git a/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy b/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy index 8aa2527..441ec27 100644 --- a/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy +++ b/src/main/groovy/qupath/ext/qp_scope/utilities/utilityFunctions.groovy @@ -147,24 +147,18 @@ class utilityFunctions { Process process = command.execute(); logger.info("Executing command: " + command); logger.info("This should get stage coordinates back") - // Construct the command - BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - String line; - String value1 - String value2 - while ((line = reader.readLine()) != null) { - // Process the line to retrieve value1 and value2 - // For example, if they are printed in a single line separated by space - String[] values = line.split(" "); - value1 = values[0]; - value2 = values[1]; - // Do something with the values + List result = handleProcessOutput(process) + if (result != null) { + logger.info("Received coordinates: ${result[0]}, ${result[1]}") + return result + } else { + logger.error("Error occurred or no valid output received from the script.") + return null } - return [value1, value2] } else if (arguments.size() == 2) { // Change the script to 'moveStageToCoordinates.py' File scriptFile = new File(pythonScriptPath); - pythonScriptPath = new File(scriptFile.getParent(), "moveStageToCoordinates.py").getCanonicalPath(); + pythonScriptPath = new File(scriptFile.parent, "moveStageToCoordinates.py").canonicalPath } String args = arguments != null ? arguments.collect { "\"$it\"" }.join(' ') : ""; @@ -176,18 +170,52 @@ class utilityFunctions { // Execute the command Process process = command.execute(); - process.waitFor(); + // Redirect the output and error streams to the logger + process.consumeProcessOutput(new StringWriter(), new StringWriter()) - // Read and log standard output - process.inputStream.eachLine { line -> logger.info(line) }; + // Wait for the process to complete + process.waitFor() - // Read and log standard error - process.errorStream.eachLine { line -> logger.error(line) }; + // Log the output and error (or use it as needed) + logger.info(process.text) // This logs the standard output + logger.error(process.err.text) // This logs the standard error return null } catch (Exception e) { e.printStackTrace(); } } + static List handleProcessOutput(Process process) { + BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream())); + BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); + + String line; + List outputLines = [] + List errorLines = [] + String value1 = null + String value2 = null + + while ((line = outputReader.readLine()) != null) { + outputLines.add(line) + // Assuming coordinates are on the first line + if (outputLines.size() == 1) { + String[] values = line.split(" "); + value1 = values[0]; + value2 = values[1]; + } + } + + while ((line = errorReader.readLine()) != null) { + errorLines.add(line) + } + + // Check for errors or invalid output + if (!errorLines.isEmpty() || value1 == null || value2 == null) { + return null; + } + + return [value1, value2]; + } + // static void runPythonCommand(String anacondaEnvPath, String pythonScriptPath, List arguments) { // try { // def logger = LoggerFactory.getLogger(QuPathGUI.class) @@ -221,10 +249,10 @@ class utilityFunctions { //If preferences are null or missing, throw an error and close //Open to discussion whether scan types should be included here or typed every time, or some other option //TODO fix the installation to be a folder with an expected .py file target? Or keep as .py file target? - return [installation : "C:\\ImageAnalysis\\QPExtensionTest\\qp_scope\\src\\main\\pythonScripts/4x_bf_scan_pycromanager.py", + return [ pycromanager : "C:\\ImageAnalysis\\QPExtensionTest\\qp_scope\\src\\main\\pythonScripts/4x_bf_scan_pycromanager.py", environment : "C:\\Anaconda\\envs\\paquo", - projects : "C:\\ImageAnalysis\\slides", - tissueDetection: "C:\\ImageAnalysis\\QPExtensionTest\\qp_scope\\src\\main\\groovyScripts/DetectTissue.groovy", + projects : "C:\\ImageAnalysis\\QPExtensionTest\\data\\slides", + tissueDetection: "DetectTissue.groovy", firstScanType : "4x_bf", secondScanType : "20x_bf", tileHandling : "Zip"] //Zip Delete or anything else is ignored @@ -505,6 +533,10 @@ class utilityFunctions { //Convert the QuPath pixel based coordinates for a location into the MicroManager micron based stage coordinates static List QPtoMicroscopeCoordinates(List qpCoordinates, Double imagePixelSize, Object transformation) { //TODO figure out conversion + def xUpperLeft = qpCoordinates[0]*imagePixelSize + def yUpperLeft = qpCoordinates[1]*imagePixelSize + + def mmCoordinates = qpCoordinates return mmCoordinates } diff --git a/src/main/pythonScripts/4x_bf_scan_pycromanager.py b/src/main/pythonScripts/4x_bf_scan_pycromanager.py index f2dc72d..26d062f 100644 --- a/src/main/pythonScripts/4x_bf_scan_pycromanager.py +++ b/src/main/pythonScripts/4x_bf_scan_pycromanager.py @@ -3,59 +3,53 @@ import shutil import glob -# Function to log messages -def log_message(message): - with open('D:/log.txt', 'a') as log_file: - print(message, file=log_file, flush=True) - def copy_tif_files(projectsFolderPath, sampleLabel, imageType): if "4x" in imageType: - TILES_LOCATION = 'C:/ImageAnalysis/Brightfield demo/Tiles/BurnTest2-4x-bf' + TILES_LOCATION = 'C:/ImageAnalysis/QPExtensionTest/data/sample_tiles/some_4x_data' else: - TILES_LOCATION = 'C:/ImageAnalysis/Brightfield demo/Tiles/PDAC.3.A_Unstained-20x--C-7' + TILES_LOCATION = 'C:/ImageAnalysis/QPExtensionTest/data/sample_tiles/some_20x_data' - log_message(f"Copying .tif files from {TILES_LOCATION} to {projectsFolderPath}/{sampleLabel}") + print(f"Copying .tif files from {TILES_LOCATION} to {projectsFolderPath}/{sampleLabel}") dest_dir = os.path.join(projectsFolderPath, sampleLabel, imageType) - log_message(f"Destination directory: {dest_dir}") + print(f"Destination directory: {dest_dir}") if not os.path.exists(dest_dir): - log_message("Destination directory does not exist, creating it.") + print("Destination directory does not exist, creating it.") os.makedirs(dest_dir) tif_files = [] for extension in ['*.tif', '*.tiff', '*.txt']: tif_files.extend(glob.glob(os.path.join(TILES_LOCATION, extension))) - log_message(f"Number of .tif files found: {len(tif_files)}") + print(f"Number of .tif files found: {len(tif_files)}") if not tif_files: - log_message(f"No .tif files found in {TILES_LOCATION}") + print(f"No .tif files found in {TILES_LOCATION}") return False for file in tif_files: try: - log_message(file) + print(file) shutil.copy(file, dest_dir) except Exception as e: print(f"Error copying file {file}: {e}") - return True -log_message("Python script started.") +print("Python script started.") projectsFolderPath = sys.argv[2] -log_message(f"Projects Folder Path: {projectsFolderPath}") +print(f"Projects Folder Path: {projectsFolderPath}") sampleLabel = sys.argv[3] -log_message(f"Sample Label: {sampleLabel}") +print(f"Sample Label: {sampleLabel}") imageType = sys.argv[4] -log_message(f"Image Type: {imageType}") +print(f"Image Type: {imageType}") success = copy_tif_files(projectsFolderPath, sampleLabel, imageType) if not success: - log_message("File copying did not complete successfully.") + print("File copying did not complete successfully.") else: - log_message("File copying completed successfully.") + print("File copying completed successfully.") # import os @@ -63,78 +57,57 @@ def copy_tif_files(projectsFolderPath, sampleLabel, imageType): # import shutil # import glob -# # Redirecting print statements to a log file -# sys.stdout = open('logpython.txt', 'w') -# print(os.getcwd()) +# # Function to log messages +# def log_message(message): +# with open('D:/log.txt', 'a') as log_file: +# print(message, file=log_file, flush=True) + # def copy_tif_files(projectsFolderPath, sampleLabel, imageType): # if "4x" in imageType: -# TILES_LOCATION = 'C:/ImageAnalysis/Brightfield demo/Tiles/BurnTest2-4x-bf' # Replace with the absolute path +# TILES_LOCATION = 'C:/ImageAnalysis/QPExtensionTest/data/sample_tiles/some_4x_data' # else: -# TILES_LOCATION = 'C:/ImageAnalysis/Brightfield demo/Tiles/PDAC_MetroHealth_N352L42-20x--null' - +# TILES_LOCATION = 'C:/ImageAnalysis/QPExtensionTest/data/sample_tiles/some_20x_data' -# print(f"Copying .tif files from {TILES_LOCATION} to {projectsFolderPath}/{sampleLabel}") +# log_message(f"Copying .tif files from {TILES_LOCATION} to {projectsFolderPath}/{sampleLabel}") -# dest_dir = os.path.join(projectsFolderPath, sampleLabel, f"{imageType}{sampleLabel}") -# print(f"Destination directory: {dest_dir}") +# dest_dir = os.path.join(projectsFolderPath, sampleLabel, imageType) +# log_message(f"Destination directory: {dest_dir}") # if not os.path.exists(dest_dir): -# print("Destination directory does not exist, creating it.") +# log_message("Destination directory does not exist, creating it.") # os.makedirs(dest_dir) -# # Find all .tif files # tif_files = [] # for extension in ['*.tif', '*.tiff', '*.txt']: # tif_files.extend(glob.glob(os.path.join(TILES_LOCATION, extension))) -# print(f"Number of .tif files found: {len(tif_files)}") -# #print(f"Files: {tif_files}") -# # Check if any.tif files were found +# log_message(f"Number of .tif files found: {len(tif_files)}") # if not tif_files: -# print(f"No .tif files found in {TILES_LOCATION}") +# log_message(f"No .tif files found in {TILES_LOCATION}") # return False -# #Copy each .tif file -# #shutil.copy(tif_files[0], dest_dir) -# # print(f"Copying last file: {tif_files[-1]}") -# # shutil.copy(tif_files[-1], dest_dir) - -# # for file in tif_files[:42]: -# # print(f"Copying file: {file}") -# # shutil.copy(file, dest_dir) # for file in tif_files: # try: -# print(f"Copying file: {file}") +# log_message(file) # shutil.copy(file, dest_dir) # except Exception as e: # print(f"Error copying file {file}: {e}") -# # print("Copy operation completed.") # return True - -# # if len(sys.argv) != 9: -# # print("Incorrect arguments for function: python script.py ") -# # print(len(sys.argv)) -# # return -# print("Python script started.") +# log_message("Python script started.") # projectsFolderPath = sys.argv[2] -# print(f"Projects Folder Path: {projectsFolderPath}") +# log_message(f"Projects Folder Path: {projectsFolderPath}") # sampleLabel = sys.argv[3] -# print(f"Sample Label: {sampleLabel}") +# log_message(f"Sample Label: {sampleLabel}") # imageType = sys.argv[4] -# print(f"Image Type: {imageType}") -# # x1, y1, x2, y2 are received but not used in this script. They can be used if needed. - -# #jsonFileLocation = sys.arv[9] -# #WOULD NEED FUNCTION HERE TO TRANSLATE COORDINATES TO STAGE COORDINATES +# log_message(f"Image Type: {imageType}") # success = copy_tif_files(projectsFolderPath, sampleLabel, imageType) # if not success: -# print("File copying did not complete successfully.") +# log_message("File copying did not complete successfully.") # else: -# print("File copying completed successfully.") +# log_message("File copying completed successfully.") + -# # Close the log file -# sys.stdout.close() \ No newline at end of file diff --git a/src/main/pythonScripts/getStageCoordinates.py b/src/main/pythonScripts/getStageCoordinates.py index 730368b..2ea3169 100644 --- a/src/main/pythonScripts/getStageCoordinates.py +++ b/src/main/pythonScripts/getStageCoordinates.py @@ -1,17 +1,10 @@ import sys -# Function to log messages -def log_message(message): - with open('D:/log.txt', 'a') as log_file: - print(message, file=log_file, flush=True) - -log_message("Python script started.") - -# Check if the first command-line argument is None -if len(sys.argv) >= 2: - first_argument = sys.argv[1] - if first_argument is None: - log_message("The first argument is None.") +# Check if any command-line arguments were provided +if len(sys.argv) == 1: + # No arguments were passed, print default coordinates + print('12345', '54321') else: - log_message("No arguments were provided.") -print('12345', '54321') \ No newline at end of file + # Arguments were passed, print an error message to standard error + print("Error: Unexpected arguments received.", file=sys.stderr) + sys.exit(1) # Optionally exit with a non-zero status to indicate an error diff --git a/src/main/pythonScripts/mat_file_converter.py b/src/main/pythonScripts/mat_file_converter.py deleted file mode 100644 index 26701de..0000000 --- a/src/main/pythonScripts/mat_file_converter.py +++ /dev/null @@ -1,11 +0,0 @@ -import scipy.io -import numpy as np -import cv2 -from skimage import io -matfile = scipy.io.loadmat('sequencenew.mat') -image_data = matfile['sequencenew'] - -data = np.transpose(image_data, (2, 0, 1)) -print(data.dtype) -io.imsave('Stack.tif' ,data) - diff --git a/src/main/pythonScripts/moveStageToCoordinates.py b/src/main/pythonScripts/moveStageToCoordinates.py index 5f1d524..9379caa 100644 --- a/src/main/pythonScripts/moveStageToCoordinates.py +++ b/src/main/pythonScripts/moveStageToCoordinates.py @@ -1,20 +1,15 @@ import sys -# Function to log messages -def log_message(message): - with open('D:/log.txt', 'a') as log_file: - print(message, file=log_file, flush=True) - -log_message("Python script started.") - # Check if there are exactly two command-line arguments if len(sys.argv) == 3: try: # Parse the two arguments as doubles (X and Y) X = float(sys.argv[1]) Y = float(sys.argv[2]) - log_message(f"X: {X}, Y: {Y}") + print(f"X: {X}, Y: {Y}") except ValueError: - log_message("Invalid arguments. Both X and Y must be doubles.") + print("Invalid arguments. Both X and Y must be doubles.", file=sys.stderr) + sys.exit(1) else: - log_message("Usage: python script.py ") + print("Expected two arguments, X and Y as doubles", file=sys.stderr) + sys.exit(1) diff --git a/src/main/pythonScripts/py_dummydoc.py b/src/main/pythonScripts/py_dummydoc.py deleted file mode 100644 index 7df6819..0000000 --- a/src/main/pythonScripts/py_dummydoc.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import sys - -def find_next_filename(): - counter = 1 - filename = f"dummy{counter}.txt" - while os.path.exists(filename): - counter += 1 - filename = f"dummy{counter}.txt" - print(filename) - return filename - -def create_file(filename, args): - with open(filename, 'w') as file: - file.write("Arguments passed:\n") - for arg in args: - file.write(f"{arg}\n") - -# Find the next available filename -next_filename = find_next_filename() - -# Get command line arguments (excluding the script name) -arguments = sys.argv[1:] - -# Create the file and write the arguments to it -create_file(next_filename, arguments) -print("Anything goes here")