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);
Related
So this is the second time I've posted a question like this. Last time I got so much help from a user called #quantixed but I need help again.
My code isn't working, but it's something to do with me trying to isolate images from a stack because I need to analyse each layer separately and look for over lap (double positive and triple positive cells). It runs up until I try to name each layer. I've tried adding "startsWith" because each layer regardless of stack starts with c:1/3, c:2/3 or c:3.
This is the code:
macro "Process My Files" {
dir1 = getDirectory("C:/Users/laure/OneDrive/Documents/MSc Molecular Biology & Biotechnology/Masters Project - Dombrowski Lab/Project Data/LD005 CX5/CellHealthProfiling.V4_03-06-20_09;46;02/CEM-133432_200229080001/");
dir2 = getDirectory("C:/Users/laure/OneDrive/Documents/MSc Molecular Biology & Biotechnology/Masters Project - Dombrowski Lab/Project Data/LD005 CX5/CellHealthProfiling.V4_03-06-20_09;46;02/CEM-133432_200229080001/ImageJ Macro Batch Results");
list = getFileList(dir1);
// Make an array of C01 files only
C01list = newArray(0);
for (i=0; i<list.length; i++) {
if (endsWith(list[i], ".C01")) {
C01list = append(C01list, list[i]);
}
}
x=startsWith("c:1/3")
y=startsWith("c:2/3")
a=startsWith("c:3/3")
b="Result of" + x
c="Result of" + b
d="Drawing of" + x
e="Drawing of" + y
f="Drawing of" + a
g="Drawing of" + b
h="Drawing of" + g
function DAPI() {
selectWindow(x);
run("8-bit");
setThreshold(45, 255);
run("Convert to Mask");
run("Analyze Particles...", "size=30-350 show=Outlines clear summarize add");
}
function OLIG2() {
selectWindow(y);
run("8-bit");
setThreshold(25, 255);
run("Conert to Mask");
run("Analyze Particles...", "size=30-250 show=Outlines clear summarize add");
}
function MBP() {
selectWindow(a);
run("8-bit");
setThreshold(52, 255);
run("Convert to Mask");
run("Analyze Particles...", "size=30.00-250.0 show=Outlines clear summarize add");
}
function DAPI_Olig2_overlay() {
imageCalculator("AND create", x, y);
selectWindow(b);
run("Analyze Particles...", "size=30-250 show=Outlines clear summarize add");
}
function DAPI_Olig2_MBP_overlay() {
imageCalculator("AND create", b, a); //overlay DAPI, Olig2 and Ki-67
selectWindow(d);
run("Analyze Particles...", "size=30-250 show=Outlines clear summarize add");
}
setBatchMode(true);
for (i=0; i<C01list.length; i++) {
showProgress(i+1, C01list.length);
// your code goes here - an example is shown
s = "open=["+dir1+C01list[i]+"] autoscale color_mode=Composite rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT";
DAPI();
OLIG2();
Ki67orMBP();
DAPI_Olig2_overlay();
DAPI_Olig2_Ki67_overlay();
saveAs("tiff", dir2+replace(C01list[i],".C01",".tif"));
close();
// and ends here
}
setBatchMode(false);
}
function append(arr, value) {
arr2 = newArray(arr.length+1);
for (i=0; i<arr.length; i++)
arr2[i] = arr[i];
arr2[arr.length] = value;
return arr2;
}
The problem I'm having is that it reaches x=startsWith("c:1/3"), it can't go any further. I know the rest of the code works, its just having an issue selecting which layer of the stack I want it to analyse. Whenever I hit run I get this error back:
Error: Number or numeric function expected in line 14:
x = startsWith ( "c:1/3" <)>
Any ideas?
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
For my doctoral thesis I am building a 3D printer based loosely off of one from the University of Twente:
http://pwdr.github.io/
So far, everything has gone relatively smoothly. The hardware part took longer than expected, but the electronics frighten me a little bit. I can sucessfully jog all the motors and, mechanically, everything does what is supposed to do.
However, now that I am working on the software side, I am getting headaches.
The Pwder people wrote a code that uses Processing to take an .STL file and slice it into layers. Upon running the code, a Processing GUI opens where I can load a model. The model loads fine (I'm using the Utah Teapot) and shows that it will take 149 layers.
Upon hitting "convert" the program is supposed to take the .STL file and slice it into layers, followed by writing a text file that I can then upload to an SD card. The printer will then print directly from the SD card.
However, when I hit "convert" I get an "Array Index Out of Bounds" error. I'm not quite sure what this means.. can anyone enlighten me?
The code can be found below, along with a picture of the error.
Thank you.
// Convert the graphical output of the sliced STL into a printable binary format.
// The bytes are read by the Arduino firmware
PrintWriter output, outputUpper;
int loc;
int LTR = 0;
int lowernozzles = 8;
int uppernozzles = 4;
int nozzles = lowernozzles+uppernozzles;
int printXcoordinate = 120+280; // Left margin 120
int printYcoordinate = 30+190; // Top margin 30
int printWidth = 120; // Total image width 650
int printHeight = 120; // Total image height 480
int layer_size = printWidth * printHeight/nozzles * 2;
void convertModel() {
// Create config file for the printer, trailing comma for convenience
output = createWriter("PWDR/PWDRCONF.TXT"); output.print(printWidth+","+printHeight/nozzles+","+maxSlices+","+inkSaturation+ ",");
output.flush();
output.close();
int index = 0;
byte[] print_data = new byte[layer_size * 2];
// Steps of 12 nozzles in Y direction
for (int y = printYcoordinate; y < printYcoordinate+printHeight; y=y+nozzles ) {
// Set a variable to know wheter we're moving LTR of RTL
LTR++;
// Step in X direction
for (int x = 0; x < printWidth; x++) {
// Clear the temp strings
String[] LowerStr = {""};
String LowerStr2 = "";
String[] UpperStr = {""};
String UpperStr2 = "";
// For every step in Y direction, sample the 12 nozzles
for ( int i=0; i<nozzles; i++) {
// Calculate the location in the pixel array, use total window width!
// Use the LTR to determine the direction
if (LTR % 2 == 1){
loc = printXcoordinate + printWidth - x + (y+i) * width;
} else {
loc = printXcoordinate + x + (y+i) * width;
}
if (brightness(pixels[loc]) < 100) {
// Write a zero when the pixel is white (or should be white, as the preview is inverted)
if (i<uppernozzles) {
UpperStr = append(UpperStr, "0");
} else {
LowerStr = append(LowerStr, "0");
}
} else {
// Write a one when the pixel is black
if (i<uppernozzles) {
UpperStr = append(UpperStr, "1");
} else {
LowerStr = append(LowerStr, "1");
}
}
}
LowerStr2 = join(LowerStr, "");
print_data[index] = byte(unbinary(LowerStr2));
index++;
UpperStr2 = join(UpperStr, "");
print_data[index] = byte(unbinary(UpperStr2));
index++;
}
}
if (sliceNumber >= 1 && sliceNumber < 10){
String DEST_FILE = "PWDR/PWDR000"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
} else if (sliceNumber >= 10 && sliceNumber < 100){
String DEST_FILE = "PWDR/PWDR00"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
} else if (sliceNumber >= 100 && sliceNumber < 1000){
String DEST_FILE = "PWDR/PWDR0"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
} else if (sliceNumber >= 1000) {
String DEST_FILE = "PWDR/PWDR"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
}
sliceNumber++;
println(sliceNumber);
}
What's happening is that print_data is smaller than index. (For example, if index is 123, but print_data only has 122 elements.)
Size of print_data is layer_size * 2 or printWidth * printHeight/nozzles * 4 or 4800
Max size of index is printHeight/nozzles * 2 * printWidth or 20*120 or 2400.
This seems alright, so I probably missed something, and it appears to be placing data in element 4800, which is weird. I suggest a bunch of print statements to get the size of print_data and the index.
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] + "]");
When specifying the regions using a .uzn file, is there a way to then match the text output to the .uzn region where the text came from?
I found a way to do it by getting the bounding boxes for each character, and using that information to see which region every character belongs to.
// Load the .box file output by Tesseract-OCR, and match each bounding box
// to a character from the text. This is not trivial, because whitespaces
// are present in the text from the .txt, but are missing from the .box
// file.
std::vector<RECT> loadBoxFile(const wchar_t *fileName, const std::wstring &text, int imageHeight)
{
// Open file.
std::ifstream st(fileName);
if (!st.is_open())
throw std::runtime_error("Could not open .box file.");
std::string line;
std::string symbolAscii;
std::wstring symbol;
RECT r = { -1, -1, -1, -1 };
std::vector<RECT> ret;
ret.resize(text.size(), r);
size_t textPos = 0;
while (std::getline(st, line)) {
// Parse a line.
std::istringstream iss(line);
if (!(iss >> symbolAscii >> r.left >> r.top >> r.right >> r.bottom))
throw std::runtime_error("Could not parse .box file line.");
symbol = utf8to16(symbolAscii.c_str());
// We don't try to get the bounding box for '~', because sometimes
// there is a '~' in .box file that is not there in .txt file. It's
// a bug in Tesseract-OCR as far as I know. This is a workaround
// for that case.
if (L"~" == symbol)
continue;
// Now match the symbol for that line to a symbol in the .txt file.
textPos = text.find(symbol, textPos);
// If we couldn't match it then fail.
if (text.npos == textPos)
throw std::runtime_error(std::string() + "Could not match symbol \"" + symbolAscii + "\" from .box file to .txt file.");
// Write the bounding box in the array, at index matching the symbol
// in the .txt file.
r.bottom = imageHeight - r.bottom;
r.top = imageHeight - r.top;
for (int ii = 0; ii < symbol.size(); ii++)
ret[textPos + ii] = r;
// Now increment textPos() so we start searching after the last
// symbol of the currently found symbol.
textPos += symbol.size();
}
return ret;
}