I'm writing an ImageJ macro to iterate through a folder of .lsm confocal microscope images, make a Z Project from each, combine the two channels into red and green, and save as an RGB image. The code works fine for one directory, but now it's throwing an error that has something to do with the filename from getFileList.
Here's the relevant part of the code:
dir1 = getDirectory("Choose Source Directory ");
format = getFormat();
dir2 = getDirectory("Choose Destination Directory ");
list = getFileList(dir1);
setBatchMode(true);
for (i = 0; i < list.length; i++) {
showProgress(i+1, list.length);
open(dir1+list[i]);
run("Z Project...", "projection=[Max Intensity]");
run("Split Channels");
run("Merge Channels...", "c1=C1-MAX_" + list[i] + " c2=C2-MAX_" + list[i]);
saveAs(format, dir2 + list[i]);
close();
}
It's necessary that "C1-MAX_" is appended to the input string because those prefixes are added to the image name during the calls to Z Project and Split Channels.
For reference, the name of the files look like Negative 1 5x.lsm, Negative 2 5x.lsm, Positive 1 5x.lsm, etc. Based on these filenames, I expect ImageJ to call the Merge Channels command with the strings "C1-MAX_Negative 1 5x.lsm" and "C2-MAX_Negative 1 5x.lsm".
Instead, I get the error message "C1-MAX_Negative" is not a valid choice for "C1 (red):"
I don't understand why ImageJ is trying to call Merge Channels with the string "C1-MAX_Negative" and not "C1-MAX_Negative 1 5x.lsm". Why isn't list[i] returning what I think it should?
It is probably because of the space in the filename. Try putting the name in square brackets like that:
run("Merge Channels...", "c1=[C1-MAX_" + list[i] + "] c2=[C2-MAX_" + list[i] + "]");
Related
for my Thesis I must count cells on pictures stained with Immunofluorescence and I am writing a macro in ImageJ to do it for me.
For this I coloursplit the picture, analyse particles in the red channel (my Antibody´s colour) and then I want to take the coordinates of analysed particles and only count them if at the same coordinates in the blue channel there is also a staining (DAPI - just a general cell staining).
This way I assure that there is as little dirt counted as possible.
The problem is that when I get the coordinates from the results table and use them to makePoint(x,y) the coordinates are "distorted" - usually the correct coordinates but plus 4ish, though never in exactly the same, which is why i can´t simply distract a number from the coordinates
Below I first write down the critical lines of code, then the whole code.
Thank you very much in advance
run("Analyze Particles...", " circularity=r1-r2 display clear in_situ");
roiManager("deselect");
z=nResults;
for (j=0; j<z; j++) { //loops through the Results table and adds to "counter" if a match is found
selectImage(channelsplit[2]); //selects blue window
setThreshold(d,l);
run("Threshold...");
setOption("BlackBackground", true);
run("Convert to Mask", "method=Default background=Default black");
run("Coordinates...", "left=0 right=19373 top=0 bottom=13600"); //I tried to set the boundaries of the pictures equally, but it didnt work
makePoint(getResult("X", j)), (getResult("Y", j));
print ("X" + j + ": " + getResult("X",j)); //this and the following line are not to be in the program, once it works
print ("Y" + j + ": " + getResult("Y",j));
run ("Measure");
if (getResult("Mean", nResults-1)>100) {
counter++;
}
} //for j
print (i + ": " + counter);
setBatchMode(true);
if (isOpen("ROI Manager")) {
r=roiManager("count");
} else {
setBatchMode(false);
exit("You need a ROI Manager open with the ROIs of all the pictures to be measured");
}
Dialog.create ("Variables")
Dialog.addCheckbox ("red", true);
Dialog.addCheckbox ("green", false);
Dialog.addCheckbox ("blue", false);
Dialog.addCheckbox ("watershed", true);
Dialog.addNumber ("Thresholddark:", 110);
Dialog.addNumber ("Thresholdlight:", 255);
Dialog.addNumber ("greenThresholddark:", 110);
Dialog.addNumber ("greenThresholdlight:", 253);
Dialog.addNumber ("pmin:", 15);
Dialog.addNumber ("pmax:", 100);
Dialog.addNumber ("roundness1:", 0.5);
Dialog.addNumber ("roundness2:", 1.0);
Dialog.addMessage("batch - select 'true' for your macro to run faster, but you will not see what it does until finished\nstack - selecht this box if you use unstacked pictures and want them stacked, deselect if you use a readied stack or a single picture\nred - select this box if you want to count red coloured cells \ngreen - select this box if you want to count green coloured cells \nblue - select this box if you want to count blue coloured cells\nall variables are the same for the colours you count. It may be better to adjust variables for each colour and count seperately\nwatershed - select this box only if you have overlapping cells in your image\nThresholdlight - particles lighter than this won't be measured/counted \nThresholddark - particles darker than this won't be measured/counted \nThresholdlight and Thresholddark can be between 0 and 255 \ntry thresholding manually at least once manually to get best results \npmin - particles with a size smaller than this won't be counted \npmax - particles with a size greater than this won't be counted")
Dialog.show ();
cr=Dialog.getCheckbox();
cg=Dialog.getCheckbox();
cb=Dialog.getCheckbox();
w=Dialog.getCheckbox();
d=Dialog.getNumber();
l=Dialog.getNumber();
dg=Dialog.getNumber();
lg=Dialog.getNumber();
pmin=Dialog.getNumber();
pmax=Dialog.getNumber();
r1=Dialog.getNumber();
r2=Dialog.getNumber();
dir = getDirectory("Choose a Directory "); //choose the folder with all the pictures to be measured
listFiles(dir); //I found this in a listFiles recursively Demo and changed it to open my pictures
function listFiles(dir) {
list = getFileList(dir);
for (o=0; o<list.length; o++) { //loops through the file list, opening then analysing then closing one after another
if (endsWith(list[o], "/")) {
listFiles(""+dir+list[i]);
} else {
open(dir + list[o]);
//the previous opens all pictures in a given folder in a way i do not understand
//I only use this function because I could not use the variable list.length outside of it for unknown reasons
//following is my cellcount program to be executed for each picture
//then the picture will be closed before the new one is opened
run("Split Channels");
channelsplit = getList("image.titles");
if (cr==1) {
a=0;
}
if (cg==1) {
a=1;
}
selectImage(channelsplit[a]); //selects red or green window, depending on input in the Dialog
setThreshold(d,l);
run("Threshold...");
setOption("BlackBackground", true);
run("Convert to Mask", "method=Default background=Default black");
run("Coordinates...", "left=0 right=19373 top=0 bottom=13600");
for (i=2*o; i<=((2*o)+1); i++) { //loops through two ROIs of the ROIManager
counter=0;
selectImage(channelsplit[a]);
roiManager("deselect");
roiManager("select", i);
if (w==1) {
run("Watershed", "slice");
}
run("Analyze Particles...", " circularity=r1-r2 display clear in_situ");
roiManager("deselect");
z=nResults;
for (j=0; j<z; j++) { //loops through the Results table and adds to "counter" if a match is found
selectImage(channelsplit[2]); //selects blue window
setThreshold(d,l);
run("Threshold...");
setOption("BlackBackground", true);
run("Convert to Mask", "method=Default background=Default black");
run("Coordinates...", "left=0 right=19373 top=0 bottom=13600"); //I tried to set the boundaries of the pictures equally, but it didnt work
makePoint(getResult("X", j)), (getResult("Y", j));
print ("X" + j + ": " + getResult("X",j)); //this and the following line are not to be in the program, once it works
print ("Y" + j + ": " + getResult("Y",j));
run ("Measure");
if (getResult("Mean", nResults-1)>100) {
counter++;
}
} //for j
print (i + ": " + counter);
close("Results"); //closes Results to get the variables in order for the next window
// IJ.renameResults("res" + i);
} //for i
close("*"); //closes all image windows to save RAM
} //else
} //for o
} //function
setBatchMode(false);
I have a small problem with imagej:
I have .tif files in a folder, which consist of three different files (blue channel, green channel, red channel).
I would like to convert them to separate pictures, then to only keep the green one
I want to do this with a macro, but i can't get it to work.
I can open the .tif, then convert it to separate images (Image-0001, Image-0002 and Image-0003). But then i want to rename them to blueImage, greenImage and redImage.
Googling got me to this, but this one saves the images as separate files and it gives an error.
macro split_color{
dir1 = getDirectory("InputDir");
list = getFileList(dir1);
dir2 = getDirectory("OutpurDir");
for (i=0; i<list.length; i++) {
open(dir1+list[i]);
title1=File.nameWithoutExtension;
for (j=1; j<=3; j++){
run("Stack to Images")
" slices="+j);
run("8-bit");
if (j==1) c = "blue";
else if(j==2) c = "green";
else c = "red";
saveAs("tif", dir2+title1+"-"+c+".tif");
wait(100);
close();
}
close();
}
showMessage("Macro is finished");
}
I can't get this to work, anyone who could help me?
Thanks
I would like to shorten "NSLocalizedString" to "_" so I'm using macro
_(x) NSLocalizedString(#x, #__FILE__)
.
But now, when I want to generate strings for localization with
find . -name \*.m | xargs genstrings
it generates nothing.
Any help?
You can tell genstrings to look for a different function by using the '-s' argument:
genstring -s MyFunctionName ....
However, MyFunctionName must follow the same naming and argument conventions as one of the built in NSLocalizeString macros.
In your case, you can not just specify the string key, you must also specify the documentation string. In fact, you should never generate a strings file without both the string and documentation. There are many languages where the actual phrase or word will depend on context. German is a great example where a car is "das auto" and more than one is "die autos". There are many more examples that include changes for gender, number, time, question versus statement, and yes versus no. The documentation string helps your translator figure out what translation to use.
In addition, the best practice is to use a key that is different from the native language word. That says use NSLocalizedStringWithDefaultValue(key, table, bundle, val, comment).
You can specify nil for the table and [NSBundle mainBundle] for the bundle argument.
You can wrap this in a shorthand, but you still have to follow the StringWithDefaultValue name and the arguments for genstrings to work.
I strongly recommend you look at the WWDC 2012 session on Localization Tips and Tricks.
Maurice
You can use the -s option of genstrings. From the man page :
-s routine
Substitutes routine for NSLocalizedString. For example, -s MyLocalString will catch calls to MyLocalString and MyLocalStringFromTable.
So I think you could try :
genstrings -s _
I had the same problem when my NSLocalizedString macro was taking 1 argument instead of 2 like genstrings expects, so i wrote i python script that does the job.
the first argument for the script is the macro name and the second is the path to your project.
import fnmatch
import os
from xml.dom import minidom
function = sys.argv[1]
rootdir = sys.argv[2]
# Generate strings from .m files
files = []
for root, dirnames, filenames in os.walk(rootdir):
for filename in fnmatch.filter(filenames, '*.m'):
files.append(os.path.join(root, filename))
strings = []
for file in files:
lineNumber = 0
for line in open(file):
lineNumber += 1
index = line.find(function)
if (index != -1):
callStr = line[index:]
index = callStr.find('#')
if (index == -1):
print 'call with a variable/macro. file: ' + file + ' line: %d' % lineNumber
else:
callStr = callStr[index+1:]
index = callStr.find('")')
callStr = callStr[:index+1]
if callStr not in strings:
strings.append(callStr)
# Write strings to file
f = open('Localizable.strings', 'w+')
for string in strings:
f.write(string + ' = ' + string + ';\n\n')
f.close()
I have improved Or Arbel's script to include the cases where there's multiple macro-calls on a single line:
import fnmatch
import os
from xml.dom import minidom
import sys
function = sys.argv[1]
rootdir = sys.argv[2]
# Generate strings from .m files
files = []
for root, dirnames, filenames in os.walk(rootdir):
for filename in fnmatch.filter(filenames, '*.m'):
files.append(os.path.join(root, filename))
strings = []
for file in files:
lineNumber = 0
for line in open(file):
lineNumber += 1
index = line.find(function)
startIndex = 0
while (index != -1):
startIndex = index+1
callStr = line[index:]
index = callStr.find('#')
if (index == -1):
print 'call with a variable/macro. file: ' + file + ' line: %d' % lineNumber
else:
callStr = callStr[index+1:]
index = callStr.find('")')
callStr = callStr[:index+1]
if callStr not in strings:
strings.append(callStr)
index = line.find(function, startIndex)
# Write strings to file
f = open('Localizable.strings', 'w+')
for string in strings:
f.write(string + ' = ' + string + ';\n\n')
f.close()
for Temp = 1000:10:6000
cp_CO2 = ((2e-18)*Temp.^5) - ((4e-14)*Temp.^4) + ((3e-10)*Temp.^3) - ((8e-07)*Temp.^2) + (0.0013*Temp) + 0.5126;
cp_CO = ((5e-12)*Temp.^3) - ((7e-08)*Temp.^2) + (0.0003*Temp) + 0.9657;
cp_H2O = ((7e-12)*Temp.^3) - ((1e-07)*Temp.^2) + (0.0008*Temp) + 1.6083;
cp_N2 = ((-1e-18)*Temp.^5) + ((2e-14)*Temp.^4) - ((8e-11)*Temp.^3) + ((1e-07)*Temp.^2) + (0.0001*Temp) + 0.9985;
D_H = (y(1)*cp_CO2*44*(25-Temp)) + (y(2)*cp_CO*28*(25-Temp)) + (y(3)*cp_H2O*18*(25-Temp)) + (percent_air*x_final(2)*3.76*28*(25-Temp));
DELTA_H = round(D_H);
if DELTA_H == delta_h
break
end
end
The 'for' loop in my code is above, the variables delta_h, y and percent_air have been defined and calculated/input earlier. If I work on the loop as a cell and manually increase Temp then the values of D_H etc. all change. But for some reason when I try and execute the loop the 'if' statement doesn't seem to come into effect and the final values where Temp = 6000 are displayed in the workspace instead of the value of Temp where it produces a DELTA_H equal to that of delta_h. It's the first time I've used MATLAB for about 2 years (I'm a 3rd Year Mech Eng student) so please forgive me if it's a simple error to fix.
If either of the variables are floating-point, doing an exact compare like that is problematic. A <= or >= comparison might work better.
I have recovered some Word documents from a corrupted hard drive using a piece of software called photorec. The problem is that the documents' names can't be recovered; they are all renamed by a sequence of numbers. There are over 2000 documents to sort through and I was wondering if I could rename them using some automated process.
Is there a script I could use to find the first 10 letters in the document and rename it with that? It would have to be able to cope with multiple documents having the same first 10 letters and so not write over documents with the same name. Also, it would have to avoid renaming the document with illegal characters (such as '?', '*', '/', etc.)
I only have a little bit of experience with Python, C, and even less with bash programming in Linux, so bear with me if I don't know exactly what I'm doing if I have to write a new script.
How about VBScript? Here is a sketch:
FolderName = "C:\Docs\"
Set fs = CreateObject("Scripting.FileSystemObject")
Set fldr = fs.GetFolder(Foldername)
Set ws = CreateObject("Word.Application")
For Each f In fldr.Files
If Left(f.name,2)<>"~$" Then
If InStr(f.Type, "Microsoft Word") Then
MsgBox f.Name
Set doc = ws.Documents.Open(Foldername & f.Name)
s = vbNullString
i = 1
Do While Trim(s) = vbNullString And i <= doc.Paragraphs.Count
s = doc.Paragraphs(i)
s = CleanString(Left(s, 10))
i = i + 1
Loop
doc.Close False
If s = "" Then s = "NoParas"
s1 = s
i = 1
Do While fs.FileExists(s1)
s1 = s & i
i = i + 1
Loop
MsgBox "Name " & Foldername & f.Name & " As " & Foldername & s1 _
& Right(f.Name, InStrRev(f.Name, "."))
'' This uses copy, because it seems safer
f.Copy Foldername & s1 & Right(f.Name, InStrRev(f.Name, ".")), False
'' MoveFile will copy the file:
'' fs.MoveFile Foldername & f.Name, Foldername & s1 _
'' & Right(f.Name, InStrRev(f.Name, "."))
End If
End If
Next
msgbox "Done"
ws.Quit
Set ws = Nothing
Set fs = Nothing
Function CleanString(StringToClean)
''http://msdn.microsoft.com/en-us/library/ms974570.aspx
Dim objRegEx
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.Global = True
''Find anything not a-z, 0-9
objRegEx.Pattern = "[^a-z0-9]"
CleanString = objRegEx.Replace(StringToClean, "")
End Function
Word documents are stored in a custom format which places a load of binary cruft on the beginning of the file.
The simplest thing would be to knock something up in Python that searched for the first line beginning with ASCII chars. Here you go:
#!/usr/bin/python
import glob
import os
for file in glob.glob("*.doc"):
f = open(file, "rb")
new_name = ""
chars = 0
char = f.read(1)
while char != "":
if 0 < ord(char) < 128:
if ord("a") <= ord(char) <= ord("z") or ord("A") <= ord(char) <= ord("Z") or ord("0") <= ord(char) <= ord("9"):
new_name += char
else:
new_name += "_"
chars += 1
if chars == 100:
new_name = new_name[:20] + ".doc"
print "renaming " + file + " to " + new_name
f.close()
break;
else:
new_name = ""
chars = 0
char = f.read(1)
if new_name != "":
os.rename(file, new_name)
NOTE: if you want to glob multiple directories you'll need to change the glob line accordingly. Also this takes no account of whether the file you're trying to rename to already exists, so if you have multiple docs with the same first few chars then you'll need to handle that.
I found the first chunk of 100 ASCII chars in a row (if you look for less than that you end up picking up doc keywords and such) and then used the first 20 of these to make the new name, replacing anything that's not a-z A-Z or 0-9 with underscores to avoid file name issues.