Reconstructing badly aligned bidirectional confocal files

Dear community,

Recently, one of my user has changed the setting of Phase for bidirectional scanning for my confocal, leading to misalignment between odd and even lines of her files (see Original.tif (127.1 KB) as example). A nice round object looks frayed and fuzzy. I wrote two macros to try to rectify this.

The first macro works: it constructs an series of images where odd pixel lines are offset by one extra pixel for each image. This is rather slow and clumsy but allows to eyeball the images and work out by how many pixels the lines are off. Is there a method that can be implemented to avoid this last subjective step? Here is the first macro:

//A macro to test the length of offset between lines when bidirectionality is wrong

OriginalImage=getTitle();
getDimensions(width, height, channels, slices, frames);
for (j = 0; j < 10; j++) {
newImage("New_"+OriginalImage+j, "8-bit color-mode label", width+j, height, slices);
	for (i = 1; i < height; i=i+2) {
		selectWindow(OriginalImage);
		makeRectangle(0,i,width,1);
		run("Copy");
		selectWindow("New_"+OriginalImage+j);
		makeRectangle(0,i,width,1);
		run("Paste");
	}
	for (i = 0; i < height; i=i+2) {
		selectWindow(OriginalImage);
		makeRectangle(0,i,width,1);
		run("Copy");
		selectWindow("New_"+OriginalImage+j);
		makeRectangle(j,i,width,1);
		run("Paste");
	}
}


So far, so good. With the first macro, I can guess the offset. So I try to apply it to a stack like this CompositeTest.tif (254.2 KB) with this macro:

//A macro to correct misaligned bidirectional scanning
OriginalImage=getTitle();
getDimensions(width, height, channels, slices, frames);
offset=getNumber("Please define the number of pixels to offset", 0);
roiManager("reset");

//creating new image to paste data in appropriate position
newImage("New_"+OriginalImage, "8-bit color-mode", width+offset, height, channels, slices, frames);

Stack.setChannel(1);
run("Grays");
Stack.setChannel(2);
run("Green");
Stack.setChannel(3);
run("Red");

//create two alternating arrays of rectangular ROIs, OddROI and EvenROI image-wide and one pixel high

selectWindow(OriginalImage);
getDimensions(width, height, channels, slices, frames);
for (roi = 0; roi < height; roi=roi+2) {
	makeRectangle(0,roi,width,1);
	roiManager("Add");
	}
roiManager("Select All");
roiManager("Combine");
roiManager("Add");
LastROI=roiManager("Count")-1;
RoisToDelete=Array.getSequence(LastROI); //combining all ROIs into a new one "OddROI" and then deleting individual ROIs
roiManager("Select",LastROI);
roiManager("Rename", "OddROI");
roiManager("Select",RoisToDelete);
roiManager("delete");
run("Select None");

for (roi2 = 1; roi2 < height; roi2=roi2+2) {
	makeRectangle(0,roi2,width,1);
	roiManager("Add");
	}
LastROI2=roiManager("Count");  //combining all ROIs, except OddROI, into a new one "EvenROI" and then deleting individual small ROIs
RoisToDelete2=Array.getSequence(LastROI2);
RoisToDelete2=Array.deleteValue(RoisToDelete2, 0);
roiManager("Select", RoisToDelete2);
roiManager("Combine");
roiManager("Add");
LastROIAgain=roiManager("Count")-1;
roiManager("Select",LastROIAgain);
roiManager("Rename", "EvenROI");
roiManager("Select",RoisToDelete2);
roiManager("delete");
run("Select None");

//now copying and pasting on the appropriate slices and channels with slices translated

for(c=1; c<channels+1; c++){

print("Working on Channel "+c);

	for(s=1; s<slices+1; s++){
			selectWindow(OriginalImage);
			Stack.setChannel(c);
			Stack.setSlice(s);
			roiManager("Select", "EvenROI");
			run("Copy");
			selectWindow("New_"+OriginalImage);
			Stack.setChannel(c);
			Stack.setSlice(s);
			makeRectangle(offset, 0, width, height);
			run("Paste");
			run("Select None");
		
			selectWindow(OriginalImage);
			Stack.setChannel(c);
			Stack.setSlice(s);
			roiManager("Select", "OddROI");
			run("Copy");
			selectWindow("New_"+OriginalImage);
			Stack.setChannel(c);
			Stack.setSlice(s);
			roiManager("Select", "OddROI");
			run("Paste");
			run("Select None");

			print("Channel "+c+" slice "+s+" lines pasted");
			run("Select None");
	}
	print("All slices pasted for channel "+c);
}
print("Macro done");


And there’s clearly a mistake somewhere as it’s not pasting appropriately, but I can’t work out the error. Can anyone help?

Thanks

Matthieu

Hi @MatthieuV
I have tested your 2nd macro and it works fine. I entered a shift of 6 pixel and in the output file in both channels the even lines are shifted by 6 pixel.
Your macro looks OK.
What problem do you see?

Hi Peter,

Thanks! The outcome of the macro is not what I am expecting: With the original file (see first post), I find that I need a shift of 4 pixels according to the first macro. Therefore, I gave 4 as the offset for the second macro. This is what I get:

On the left is the original file, you can see crenelation on the large white spot at the bottom. In the middle is the result of the first macro -which tells me in the title that I need a 4 pixel offset to get something that looks right. On the right is the result of the second macro. I modified the orginal picture by turning it into a stack and added a couple of vertical white lines to check that the pixel shift had happened (which is what I see). However, whilst a shift has happened, you can see that the crenelation is still there. Thing is I’m not sure where the issue is.

Sincerely,

Matthieu

Check if this version is doing a better job:

for(s=1; s<slices+1; s++){
	selectWindow(OriginalImage);
	Stack.setChannel(c);
	Stack.setSlice(s);
	//roiManager("Select", "EvenROI");
	run("Select All");
	run("Copy");
	selectWindow("New_"+OriginalImage);
	Stack.setChannel(c);
	Stack.setSlice(s);
	//makeRectangle(offset, 0, width, height);
	run("Paste");
	run("Select None");

	selectWindow(OriginalImage);
	Stack.setChannel(c);
	Stack.setSlice(s);
	//roiManager("Select", "EvenROI");
	roiManager("Select", 1);
	run("Copy");
	selectWindow("New_"+OriginalImage);
	Stack.setChannel(c);
	Stack.setSlice(s);
	//roiManager("Select", "EvenROI");
	roiManager("Select", 1);
	run("Paste");
	run("Select None");

	print("Channel "+c+" slice "+s+" lines pasted");
	run("Select None");
}
1 Like

Thanks a lot! It’s simpler, which is great but there’s a tweak: since you first paste the whole image, it goes in the middle new image, with offset pixels on either side. Therefore, the the offset needs to be doubled so the pixels look correctly aligned -I’ll modify the macro accordingly.

I’ll polish the macro and paste it next week.

Sincerely,

Matthieu

As promised…

//A macro to correct misaligned bidirectional scanning.  Matthieu Vermeren, CRM Edinburgh 1/01/2021. With kind help from Peter Haub. 

//CLEAR LOG
print("\\Clear");

// CLOSE ALL OPEN IMAGES
while (nImages>0) { 
	selectImage(nImages); 
    close(); 
}

//SET BATCH MODE 
setBatchMode(true);   //true or false, true if you don't want to see the images, which is faster

//START MESSAGE
print("**** STARTING THE MACRO ****");

//INPUT/OUPUT folders
inDir=getDirectory("Choose the input folder"); 
outputDir=getDirectory("And the output folder");
myList=getFileList(inDir);  //an array
offset=getNumber("Please define the number of pixels to offset", 0);
offset=2*offset;

for (files = 0 ; files < myList.length ; files++ ){
	if(endsWith(myList[files], ".lif")){
	path=inDir+myList[files];   //path to each file
	run("Bio-Formats Macro Extensions");
		Ext.setId(path);
		Ext.getSeriesCount(seriesCount);
		print(seriesCount+" series in "+myList[files]);
		for (series=1; series<seriesCount+1; series++) {
			run("Bio-Formats Importer", "open=["+path+"] color_mode=Default view=Hyperstack stack_order=XYCZT series_"+(series));//open individual series
			FileName=File.nameWithoutExtension;
			ImageID=File.name;
			OriginalImage=getTitle();
			print("Processing "+OriginalImage+" series "+series);
			roiManager("reset");

//collect voxel and image dimensions for proper calibration
			getVoxelSize(width, height, depth, unit);
			pixel_width=width;
			voxel_depth=depth;	
			getDimensions(width, height, channels, slices, frames);

//creating new image to paste data in appropriate position
			newImage("New_"+OriginalImage, "8-bit color-mode", width+offset, height, channels, slices, frames);
			setVoxelSize(pixel_width, pixel_width, voxel_depth, unit);

			Stack.setChannel(1);
			run("Grays");
			Stack.setChannel(2);
			run("Green");
			Stack.setChannel(3);
			run("Red");

//create two alternating arrays of rectangular ROIs, OddROI and EvenROI image-wide and one pixel high

			selectWindow(OriginalImage);
			getDimensions(width, height, channels, slices, frames);
			for (roi = 0; roi < height; roi=roi+2) {
				makeRectangle(0,roi,width,1);
				roiManager("Add");
				}
			roiManager("Select All");
			roiManager("Combine");
			roiManager("Add");
			LastROI=roiManager("Count")-1;
			RoisToDelete=Array.getSequence(LastROI); //combining all ROIs into a new one "OddROI" and then deleting individual ROIs
			roiManager("Select",LastROI);
			roiManager("Rename", "OddROI");
			roiManager("Select",RoisToDelete);
			roiManager("delete");
			run("Select None");

			for (roi2 = 1; roi2 < height; roi2=roi2+2) {
				makeRectangle(0,roi2,width,1);
				roiManager("Add");
				}
			LastROI2=roiManager("Count");  //combining all ROIs, except OddROI, into a new one "EvenROI" and then deleting individual small ROIs
			RoisToDelete2=Array.getSequence(LastROI2);
			RoisToDelete2=Array.deleteValue(RoisToDelete2, 0);
			roiManager("Select", RoisToDelete2);
			roiManager("Combine");
			roiManager("Add");
			LastROIAgain=roiManager("Count")-1;
			roiManager("Select",LastROIAgain);
			roiManager("Rename", "EvenROI");
			roiManager("Select",RoisToDelete2);
			roiManager("delete");
			run("Select None");

//now copying and pasting on the appropriate slices and channels with slices translated

		for(c=1; c<channels+1; c++){

			for(s=1; s<slices+1; s++){
				selectWindow(OriginalImage);
				Stack.setChannel(c);
				Stack.setSlice(s);
				run("Select All");
				run("Copy");
				selectWindow("New_"+OriginalImage);
				Stack.setChannel(c);
				Stack.setSlice(s);
				run("Paste");
				run("Select None");

				selectWindow(OriginalImage);
				Stack.setChannel(c);
				Stack.setSlice(s);
				roiManager("Select", 1);
				run("Copy");
				selectWindow("New_"+OriginalImage);
				Stack.setChannel(c);
				Stack.setSlice(s);
				roiManager("Select", 1);
				run("Paste");
				run("Select None");
			}
		}

//cropping image and saving as tiff
		print("All slices corrected for this image");
		makeRectangle(offset/2, 0, width, height);
		run("Crop");
		selectWindow("New_"+OriginalImage);
		saveAs("Tiff", outputDir+OriginalImage+" series "+series);
		close();
		selectWindow(OriginalImage);
		close();
		}
	}
}
print("Macro done");


1 Like