2015-06-04 3 views
1

Я написал сценарий imageJ для цветного изображения и слияния ряда черно-белых изображений. Сценарий сохраняет как немигаемые цветные изображения, так и объединенные цветные изображения. Все работает красиво, когда я работаю в режиме отладки и просматриваю скрипт. Однако, когда я запускаю его по-настоящему, он иногда сохраняет пару оригинальных черных и белых вместо результирующего цветного изображения. Все объединенные изображения выглядят нормально.Strange File Save Behavior with ImageJ

Почему все работает нормально в режиме отладки, но не работает при регулярном использовании?

Ниже мой код:

// Choose the directory with the images 
dir = getDirectory("Choose a Directory "); 

// Get a list of everything in the directory 
list = getFileList(dir); 

// Determine if a composite directory exists. If not create one. 
if (File.exists(dir+"/composite") == 0) { 
    File.makeDirectory(dir+"/composite") 
} 

// Determine if a colored directory exists. If not create one. 
if (File.exists(dir+"/colored") == 0) { 
    File.makeDirectory(dir+"/colored") 
} 

// Close all files currently open to be safe 
run("Close All"); 

// Setup options 
setOption("display labels", true); 
setBatchMode(false); 

// Counter 1 keeps track of if you're on the first or second image of the tumor/vessel pair 
count = 1; 
// Counter 2 keeps track of the number of pairs in the folder 
count2 = 1; 
// Default Radio Button State 
RadioButtonDefault = "Vessel"; 
// Set Default SatLevel for Contrast Adjustment 
// The contrast adjustment does a histogram equalization. The Sat Level is a percentage of pixels that are allowed to saturate. A larger number means more pixels can saturate making the image appear brighter. 
satLevelDefault = 2.0; 

// For each image in the list 
for (i=0; i<list.length; i++) { 
    // As long as the name doesn't end with/or .jpg 
    if (endsWith(list[i], ".tif")) { 
     // Define the full path to the filename 
     fn = list[i]; 
     path = dir+list[i]; 
     // Open the file  
      open(path); 
     // Create a dialog box but don't show it yet 
     Dialog.create("Image Type"); 
     Dialog.addRadioButtonGroup("Type:", newArray("Vessel", "Tumor"), 1, 2, RadioButtonDefault) 
     Dialog.addNumber("Image Brightness Adjustment", satLevelDefault, 2, 4, "(applied only to vessel images)") 
     // If it's the first image of the pair ... 
     if (count == 1) { 
      // Show the dialog box 
      Dialog.show(); 
      // Get the result and put it into a new variable and change the Default Radio Button State for the next time through 
      if (Dialog.getRadioButton=="Vessel") { 
       imgType = "Vessel"; 
       RadioButtonDefault = "Tumor"; 
      } else { 
       imgType = "Tumor"; 
       RadioButtonDefault = "Vessel"; 
      } 
     // If it's the second image of the pair 
     } else { 
      // And the first image was a vessel assume the next image is a tumor 
      if (imgType=="Vessel") { 
       imgType="Tumor"; 
      // otherwise assume the next image is a vessel 
      } else { 
       imgType="Vessel"; 
      } 
     } 
     // Check to see the result of the dialog box input 
     // If vessel do this 
     if (imgType=="Vessel") { 
      // Make image Red 
      run("Red"); 
      // Adjust Brightness 
      run("Enhance Contrast...", "saturated="+Dialog.getNumber+" normalize"); 
      // Strip the .tif off the existing filename to use for the new filename 
      fnNewVessel = replace(fn,"\\.tif",""); 
      // Save as jpg 
      saveAs("Jpeg", dir+"/colored/"+ fnNewVessel+"_colored"); 
      // Get the title of the image for the merge 
      vesselTitle = getTitle(); 
     // Othersie do this ... 
     } else { 
      // Make green 
      run("Green"); 
      // Strip the .tif off the existing filename to use for the new filename 
      fnNewTumor = replace(fn,"\\.tif",""); 
      // Save as jpg 
      saveAs("Jpeg", dir+"/colored/"+ fnNewTumor+"_colored"); 
      // Get the title of the image for the merge 
      tumorTitle = getTitle(); 
     } 
    // If it's the second in the pair ... 
    if (count == 2) { 
     // Merge the two images 
     run("Merge Channels...", "c1="+vesselTitle+" c2="+tumorTitle+" create"); 
     // Save as Jpg 
     saveAs("Jpeg", dir+"/composite/composite_"+count2); 
     // Reset the number within the pair counter 
     count = count-1; 
     // Increment the number of pairs counter 
     count2 = count2+1; 
    // Otherwise 
    } else { 
    // Increment the number within the pair counter 
    count += 1; 
    } 
    } 
} 

ответ

0

Не знаю, почему я должен был бы сделать это, но добавление wait(100) непосредственно перед saveAs(), кажется, сделать трюк

+0

Это связано с [условиями гонки] (http://stackoverflow.com/questions/34510/what-is-a-race-condition) с запуском 'Merge Channels'. Он должен работать на своем потоке, поэтому иногда он заканчивается до 'saveAs', а иногда и нет. Когда вы переходите через код, вы всегда даете ему время, чтобы завершить, чтобы вы никогда не видели, что состояние гонки появляется. – hinerm

+0

'wait (100)' не гарантируется, что он всегда будет работать (если вызов «Объединить каналы» занимает менее 100 мс, вы можете снова поразить это состояние гонки). В верхней части моей головы легче всего было бы опросить 'IJ.macroRunning()'. Итак, после вашего 'run (« Объединить каналы ... »..)' line, put 'while (IJ.macroRunning()) {/ * Дождаться завершения макроса * /}'. Полагаю, это должно быть безопаснее. – hinerm

+0

@hinerm спасибо. Если вы хотите сделать это своим собственным ответом, я удалю шахту о выжидании (100). Последний вопрос: какой синтаксис ждет завершения макроса? Будет ли это просто «ждать (запустить (« Объединить каналы ... »))?? – agf1997

0

лучшая практика в этом случае будет опрос IJ.macroRunning(). Этот метод возвращает true, если выполняется макрос. Я предложил бы использовать вспомогательные методы, которые могут в конечном итоге тайм-аут, как:

/** Run with default timeout of 30 seconds */ 
public boolean waitForMacro() { 
    return waitForMacro(30000); 
} 

/** 
* @return True if no macro was running. False if a macro runs for longer than 
*   the specified timeOut value. 
*/ 
public boolean waitForMacro(final long timeOut) { 
    final long time = System.currentTimeMillis(); 

    while (IJ.macroRunning()) { 
     // Time out after 30 seconds. 
     if (System.currentTimeMillis() - time > timeOut) return false; 
    } 

    return true; 
} 

Затем вызовите один из этих вспомогательных методов всякий раз, когда вы используете run(), open() или newImage().

Другое направление, которое может потребовать больше работы, но обеспечивает более надежное решение, использует ImageJ2. Затем вы можете запускать вещи с помощью ThreadService, который возвращает вам Java Future, который затем может гарантировать выполнение выполнения.