Closing an empty image

Hi everyone,
I’ve made a macro that automatically divides an image in smaller images of a specified area. Since the images I’m analysing aren’t always rectangles some of these smaller images are completely empty. I would like the macro to automatically close those images that don’t have anything in them. This is what I have so far:

n = getNumber("How many pixels is one meter (i.e., one bird from head to tail)?",2);
id = getImageID();
title = getTitle();
getLocationAndSize(locX, locY, sizeW, sizeH);
width = getWidth();
height = getHeight();
tileWidth = n*5;
tileHeight = n*5;
for (y = 0; y < height/(n*5); y++) {
	offsetY = y * (n*5);
	for (x = 0; x < width/(n*5); x++) {
		offsetX = x * (n*5);
		selectImage(id);
 		call("ij.gui.ImageWindow.setNextLocation", locX + offsetX, locY + offsetY);
 		tileTitle = title + " [" + x + "," + y + "]";
 		run("Duplicate...", "title=" + tileTitle);
 		makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
		run("Crop");
		val = getStatistics(mean);
		if (val = 0) {
		close()
}
}
}

For some reason I can’t give a name to getStatistics(mean). I’m using ImageJ for the first time and have no experience coding except for some work in R.
Any help would be greatly appreciated!

Hey @EmmaC … I am also a novice myself. But I am pretty sure that getStatistics returns multiple values… it looks like this: getStatistics(area, mean, min, max, std, histogram)

So… you’d want to just make that function call and after just use the variable name ‘mean’ (though you can really name that variable anything you like really…).

For example - changing that section of code to:

...
makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
run("Crop");
getStatistics(area, mean, min, max, std, histogram)
	if (mean = 0) {
	close()
...

I think this might do it? At least getting you on the right path to start… others may have better advice on this.

eta :slight_smile:

3 Likes

Hey @etadobson
Thanks for your help! It did solve my first problem, but there is still an issue with the looping of the process now.
I get the error message: Boolean expression expected in line 20 (so after the if statement). The mean value I get is also higher than 0 even though the first image it crops is completely black.

@EmmaC

Yes! It is asking for a boolean … so the line needs to be:

...
if (mean == 0) {
     close()
... 

You need == … that asks if the variable equals the value. A single = is an assignment - assigning a value to the variable.

Sorry I missed that the first time 'round… I’m running on little sleep these days !!

eta :slight_smile:

3 Likes

Thanks @etadobson !

So far this is what I have now:

n = getNumber("How many pixels is one meter (i.e., one bird from head to tail)?",2);
id = getImageID();
title = getTitle();
getLocationAndSize(locX, locY, sizeW, sizeH);
width = getWidth();
height = getHeight();
tileWidth = n*5;
tileHeight = n*5;
for (y = 0; y < height/(n*5); y++) {
	offsetY = y * (n*5);
	for (x = 0; x < width/(n*5); x++) {
		offsetX = x * (n*5);
		selectImage(id);
 		call("ij.gui.ImageWindow.setNextLocation", locX + offsetX, locY + offsetY);
 		tileTitle = title + " [" + x + "," + y + "]";
 		run("Duplicate...", "title=" + tileTitle);
 		makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
		getStatistics(mean);
		if (mean == 0) {
		close();
		} else {
		run("Crop");
}
}
}

However I still get empty images, for some reason. Maybe it doesn’t calculate the mean of the rectangle? Or maybe it has something to do with the duplicate function?

Any help would be appreciated

Hi @EmmaC,

Could you be more specific on what is an “empty” image for you?
No pixels, all intensities = 0, etc.

Other question, what is the type and format of your images?

Best,

1 Like

Hi @pmascalchi

With an empty image I mean one were all the pixels are black, so all values=0.
The images I’m analysing are jpegs about 3000x3000 pixels in size.

Thanks for having a look at it!

Hi @EmmaC,

the problem is about how you use the getStatistics command.

getStatistics(area, mean, min, max, std, histogram);

The average intensity will be given at the second variable position. ImageJ doesn’t care if you write “mean” only. At the first position will always be the area. This is bigger 0 and therefore you keep the images. I would anyway go for the max value to be sure. So, you could specify:

getStatistics(area, mean, min, max);

In your if statement you then check for:

if(max==0) {
    close();
}
3 Likes

Hi @biovoxxel,

Thanks for helping me out! The macro works fine now :smiley:
I just have one last question. I would like to save the images in a separate folder.
This is how I’m trying to do it:

n = getNumber("How many pixels is one meter (i.e., one bird from head to tail)?",2);
id = getImageID();
title = getTitle();
getLocationAndSize(locX, locY, sizeW, sizeH);
width = getWidth();
height = getHeight();
tileWidth = n*5;
tileHeight = n*5;
for (y = 0; y < height/(n*5); y++) {
	offsetY = y * (n*5);
	for (x = 0; x < width/(n*5); x++) {
		offsetX = x * (n*5);
		selectImage(id);
 		call("ij.gui.ImageWindow.setNextLocation", locX + offsetX, locY + offsetY);
 		tileTitle = title + " [" + x + "," + y + "]";
 		run("Duplicate...", "title=" + tileTitle);
 		makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
		getStatistics(area, mean, min, max);
		if (mean > 0) {
		run("Crop");
		output = "C:\\Users\\emma_\\OneDrive\\Documenten\\School\\Thesis\\Data\\GoodPictures\\Little Skellig\\5x5\\";
		saveAs("Jpeg", output + title + ((x+0.5)*(y+0.5)));
		close();
		} else {
		close();
}
}
}

I can’t get the x y factor right so it doesn’t give me the same name for different images, someone any ideas?

This code works for me and I get a unique file name for each image. One thing you can do to clean-up the names (assuming they are JPEGs to start with is:

title = replace(title, “.jpg$”, (x+0.5)*(y+0.5));

This will remove the extension on the end of the file ($ = on the end of the name) and replace it with the XY coordinates.

Also, if you’re not running a macro in batchmode, it is always good to use selectWindow and explicit closes such as:

selectWindow(title);
...things I want to do to this image...
close(title);

This guarantees the right images are processed and closed, rather than hoping the active image is the one you want (which isn’t always the case).

1 Like

Here is a cleaned up implementation of the macro. I’m not sure of the analytical purpose of moving the window, so I removed that line, and you don’t need to get the image ID if you also have the title. I also ran it in batch mode, which is much faster since FIJI no longer has to actually render each image:

setBatchMode(true);
n = getNumber("How many pixels is one meter (i.e., one bird from head to tail)?",2);
title = getTitle();
width = getWidth();
height = getHeight();
tileWidth = n*5;
tileHeight = n*5;
for (y = 0; y < height/(n*5); y++) {
	offsetY = y * (n*5);
	for (x = 0; x < width/(n*5); x++) {
		offsetX = x * (n*5);
		selectWindow(title);
 		tileTitle = title + " (" + x + "," + y + ")";
 		run("Duplicate...", "title=[" + tileTitle + "]");
 		selectWindow(tileTitle);
 		makeRectangle(offsetX, offsetY, tileWidth, tileHeight);
		getStatistics(dummy, mean);
		if (mean > 0) {
			run("Crop");
			output = "C:\\Users\\Ben\\Desktop\\Test\\";
			outputTitle = replace(title, ".jpg$", (x+0.5)*(y+0.5) + ".jpg");
			saveAs("Jpeg", output + outputTitle);
			close(outputTitle);
		} 
		else {
			close(tileTitle);
		}
		run("Select None");
	}
}
setBatchMode(false);

Thanks @Llamero and everyone else who helped! It works smoothly now :slight_smile: