How to save my counter results on my image?

Please show us how the final image should look like.

Regards

Herbie

So the final image should look something like this (this was obtained using a snipping tool).

Thanks,

Coral

Coral,

thanks for the illustration but presently I have no idea of how to manage this.

It is possible to get the content and the header of a Results table as text but without formatting and there the problems begin.

If formated text is possible, it could be introduced to your image as overlay, i.e. then it doesn’t destroy the image.

Perhaps someone else is ingenious enough to provide a solution.

Regards

Herbie

1 Like

Herbie,

Thanks for looking into it though!

Coral

Have a look at the Overlay maccro which allows you to draw text over your image. Get your results to print on the overlay from the Results table using getValue(columname, rowindex).

1 Like

[…] which allows you to draw text over your image.

Yes, but it is far from easy to format the column headers and the values. I mentioned this problem in my previous post (did you read it?) and I’m convinced the effort for a corresponding macro, that has to be adapted depending on an individual Results-table, is not worth it.

What would help is a kind of screen shot from within ImageJ (with macro command) of the Results-table, so that the resulting image can be used as an overlay.

Regards

Herbie

Wouldn’t a double loop over the results table allow you to harvest column width and in combination with a monospaced font give you the space required? From the original post I got the impression that there were not too many columns.

1 Like

Go ahead and show us a macro that does this and that is flexible enough to cope with various Results table appearances. If the effort for coding is small enough and worthwhile than you could do in a couple of minutes—no?

Looking forward to seeing your solution

Herbie

Hi Coral,

Your image looks cool :slight_smile: – is it sea lions or something like that?

To simplify the formatting issues, can you give some more details on the type of results you’ll have?

  • Will there always be just 2 counter types? If not, what’s the minimum and maximum # of counter types you’d be likely to have?

  • What’s the size range of your images (length and width in pixels)?

With a few constraints like this, I think your task can be achieved using the methods in the DrawTextWithBackground example.

In particular: Right-justified text with a white background duplicates a table fairly well. I’m thinking you’d draw one string for each column of results.

It is similar to what @eljonco suggested, except that I can’t figure out how to add a background color to an overlay. And the background color is probably needed to make the text legible.

If the number of counter types is not too big, and the image is generally large, you could come up with a way to position the values reliably near the corner as you show in the screenshot.

1 Like

Good day Theresa,

I would tackle the problem by using a separate ImageJ-window to arrange the Results table information and then use this image—after cropping it to its contents—as an overlay for the image in question. This approach should solve the background question.

If there is a convenient way to make column headers and values appear in an acceptable fashion, then we are done.

Regards

Herbie

1 Like

Hi Coral,
This does most of what you want. Further debugging, alignment, filling background further, checking for out-of-window coordinates when too many lines are present in the results, fancy row headers, handling of decimals etc. is left as an exercise.

if(!isOpen("boats.gif")){
  run("Boats (356K)");}
inimg=getImageID();
run("Clear Results");
 makePoint(250, 156);run("Measure");
makePoint(288, 351);run("Measure");
makeRectangle(274, 99, 21, 22);run("Measure");
makeRectangle(440, 227, 21, 22);run("Measure");

roiManager("reset");
drawResults();
roiManager("Set Fill Color", "#1f000000"); // argb, alpha=0.53
roiManager("Show All without labels");
selectWindow("Results");
 
function drawResults(){
	pixelplace=columnStarts();
	point=12;	px=point*2;	 setFont("mono", point); characterheight=px;
 	headings = split(String.getResultsHeadings);
	getDimensions(imageWidth, height, channels, slices, frames);

	textWidth = pixelplace[pixelplace.length-2];
	
	if(textWidth>imageWidth){
		print("printed results will be wider than image");
		return;
	}
	//build in extra checks on image size and number of rows in results table here

	//set headers
	y=0;
	for (col=0; col<lengthOf(headings); col++){
		rcresult=headings[col];
		x=pixelplace[col];
		makeText(rcresult,x,y);
		roiManager("Add", "white");
			
 	}
	//add water
	for (row=0; row<nResults; row++) { 
		y=(1+row)*characterheight;
		for (col=0; col<lengthOf(headings); col++){
			rcresult=toString(getResult(headings[col],row));
			x=pixelplace[col];
			makeText(rcresult,x,y);
			roiManager("Add", "white");
			
 		}
	}
	roiManager("Set Fill Color", "#1f000000"); // argb, alpha=0.53
	roiManager("Show All without labels");
	setOption("Show All", true);
}
function columnStarts(){
	headings = split(String.getResultsHeadings);
	columnWidths=newArray(headings.length+1);
	pipewidth=15;//getStringWidth(" | "); //if you want to print column separators
	columnWidths[0]=pipewidth;
	headings = split(String.getResultsHeadings); 
	for(c=1;c<headings.length;c++){
		cwr=headings[c];
		columnWidth=getStringWidth(cwr);
		for(i=0;i<nResults;i++){
			cwrStr=getResult(headings[c], i);
			cwr=getStringWidth(toString(cwrStr));
			if(cwr>columnWidth){
				columnWidth=cwr;
			}
		}
		newcw=columnWidths[c-1]+columnWidth+pipewidth;
		columnWidths[c]=newcw;
	}
	return columnWidths;
}
1 Like

Thanks for your effort!

This is what I get with your example macro:

boats-2
(Image cropped to the essential part.)

Regards

Herbie

Yes, that makes sense.

Another thought – if we could get the position on screen of the Results window, then we could do a screen capture and crop it, then use as an overlay as you suggest. Unfortunately I’m not sure that this can be done in the macro language.

Yes, Theresa,

that’s what I’ve proposed earlier in this thread:

What would help is a kind of screen shot from within ImageJ (with macro command) of the Results-table, so that the resulting image can be used as an overlay.

However, the screen-shot feature of ImageJ

run("Capture Image");
run("Capture Screen");

doesn’t capture tables in isolation.

Regards

Herbie

Hi tswayne,

Yes, it’s mostly sea lions. To answer your other questions, we are looking to basically count the number of animals, and occasionally there will be other species dispersed in some of these hallout groups, so I would say our counter types could range from 1-7 (ish). The size range for this image in particular is 5568X3712, but that may not always be the case. Unfortunately, this is my first time working with imagej, and I’m not really a coder, so I’m unsure how to implement the information you guys are sending me. Is there anyone to contact on this forum, or imagej help in general, who can assist me on the working coding in for these recommendations you all have? I greatly appreciate it!

Thanks again,
Coral

1 Like

Coral,

please be patient and perhaps wait until monday …

Is there anyone to contact on this forum, or imagej help in general, who can assist me on the working coding […]

We are all volunteers who help via the Forum and ImageJ is open source, not a commercial product.

Regards

Herbie

1 Like

Herbie,

Not a problem, I’m not in a rush. I appreciate any help any volunteers can give. I hope everyone has a great weekend.

Thanks,
Coral

For getting acquainted with macro coding, this post has some great suggestions.

Following the suggestions in an earlier thread, I was able to capture a screenshot of the Results window.

I know it’s not exactly what you need because it grabs the Results, not the counts directly. But it’s hopefully a step in the right direction.

Then a little more code should enable you to place that image as an overlay on the aerial photo, as Herbie suggested.

// ImageJ macro demonstrating how to capture a screenshot of the Results Window

// load a sample image
run("Blobs (25K)");
imageName = getTitle();

// make some dummy measurements
run("Clear Results");
run("Measure");

// use beanshell to get the size of the results table, and position it in a known location
resW = eval("bsh", "rt = ResultsTable.getResultsWindow();resW = rt.getWidth();return resW");
resH = eval("bsh", "rt = ResultsTable.getResultsWindow();resH = rt.getHeight();return resH");
eval("bsh", "rt = ResultsTable.getResultsWindow();rt.setLocation(100, 100)")

// put Results window on top and capture the screen
selectWindow("Results");
run("Capture Screen");

// crop the screenshot to include only the Results window
selectWindow("Screenshot");
makeRectangle(100, 100, resW, resH);
run("Crop");
rename("Results for "+imageName);

That’s because there are decimals in your results and formatting of

cwrStr=getResult(headings[c], i);
cwr=getStringWidth(toString(cwrStr));

somehow doesn’t like decimals. As said: this does most and handling of decimals is left as an exercise.
Together we can :slightly_smiling_face:.
Enjoy your weekend folks.

1 Like

Good day Coral,

after having struggled with some aspects that may be less important for you but essential for a more general user group I’m able to provide an ImageJ-macro that writes a table to an image. The number of parameters has been minimized, i.e. one could perhaps think of colour choices for text and background …

To get an idea of what is provided, here is a screen shot of the macro-dialog:
Dialog

  1. The first drop-down menu lists all tables that are open in ImageJ:
    Choose the source table!
    (The macro can deal with standard tables that are not titled “Results” such as the “Counts”-table.)
  2. The second drop-down menu lists all images that are open in ImageJ:
    Choose the destination image!
  3. The third drop-down menu lists five schemes for the table position in the image:
    Choose the destination position!
    (Four corners are possible and a free position that must be set by hand.)
  4. The desired font size can be set.
    Set the size of the table font!
  5. The opacity of the table can be set.
    Set the opacity of the table!

Here is what your table looks like:
Counts-table

And here is how it looks like when positioned in your image at the top-right position:

Please note that the table data is written to the image as an overlay which means that you can hide and show or remove it (“Image >> Overlay >> Hide/Show/Remove Overlay”). However, this is only possible if you save the image with its overlay in TIF-format. If you want to make the overlay permanent, you need to flatten the image (“Image >> Overlay >> Flatten”). Then you can save it in arbitrary formats (e.g. the image above in JPG-format) but you lose the ability to hide or remove the overlay.

Here is your image with the overlay in TIF-format:
Capture_wOverlay.tif.zip (2.4 MB)

Finally, the macro code:

/* imagej-macro "table2image" (Herbie G., 21. April 2018) */
requires("1.51w");
setBatchMode(true);
saveSettings();
wnds = getList("window.titles");
wnds = Array.trim(wnds, listResultWnds(wnds));
if (wnds.length<1) exit("No table!");
imgs = getList("image.titles");
if (imgs.length<1) exit("No image!");
pos = newArray("Top-Left","Top-Right","Bottom-Left","Bottom-Right","Manually");
fntSz = 18;
opac = 80;
Dialog.create("table2image");
	Dialog.addChoice("Overlay table", wnds, wnds[0]);
	Dialog.addChoice("to Image", imgs, imgs[0]);
	Dialog.addChoice("at Position", pos, pos[0]);
	Dialog.addNumber("Font size", fntSz, 0, 2, "points");
	Dialog.addNumber("Opacity (0...100)", opac, 0, 3, "%");
Dialog.show();
table = Dialog.getChoice();
imge = Dialog.getChoice();
posit = Dialog.getChoice();
fntSz = round(Dialog.getNumber());
opac = round(Dialog.getNumber());
rslts = isOpen("Results");
if (table!="Results") { renameTables(table, rslts, true); re=true; } else re=false;
run("Input/Output...", "jpeg=85 gif=-1 file=.txt copy_column copy_row save_column save_row");
setFont("Monospaced", fntSz);
setColor("black");
chrW = getStringWidth("0");
colsCnt = columnCount();
String.copyResults;
tbl = String.paste;
rows = split(tbl,"\n");
rowCnt = rows.length;
if (re) renameTables(table, rslts, false);
mxLen = newArray(colsCnt);
for ( j=0; j<rowCnt; j++ ) {
	vals = split(rows[j],"\t");
	for ( i=0; i<colsCnt; i++ ) {
		len = getStringWidth(vals[i]);
		if ( len>mxLen[i] ) mxLen[i]=len;
	}
}
tblStr = " ";
for ( j=0; j<rowCnt; j++ ) {
	vals = split(rows[j],"\t");
	for ( i=0; i<colsCnt; i++ ) {
		len = getStringWidth(vals[i]);
		tblStr += vals[i];
		blnkCnt = round(mxLen[i] - len)/chrW + 2;
		for ( k=1; k<blnkCnt; k++ ) tblStr += " ";
	}
	if (j<rowCnt-1) tblStr += "\n ";
}
rows = split(tblStr,"\n");
w = getStringWidth(rows[0]) + 20;
newImage("data", "8-bit black", w, 1.2*rowCnt*fntSz, 1);
drawString(tblStr, 10, round(1.2*fntSz), "white");
doWand(0, 15);
run("Crop");
selectImage(imge);
run("Restore Selection");
coord = newArray(2);
tablePosition( coord, posit, pos );
run("Add Image...", "image=data x="+coord[0]+" y="+coord[1]+" opacity="+opac);
run("Select None");
close("data");
restoreSettings;
setBatchMode(false);
exit();
//////////////////////////
function listResultWnds( lst ) {
	k = 0;
	for ( i=0; i<lst.length; i++ ) {
		selectWindow(lst[i]);
		if (getInfo("window.type")=="ResultsTable") { 
			lst[k] = lst[i];
			k++;
		}
	}
	return k;
}
function renameTables( nme, rslt, dir ) {
	r = "Results";
	z = "ResultsZ";
	if (dir) {
		if (rslt) IJ.renameResults(z);
		IJ.renameResults(nme, r);
	} else {
		IJ.renameResults(nme);
		if (rslt) IJ.renameResults(z, r);
		selectWindow(nme);
	}
}
function columnCount() {
	str = String.getResultsHeadings;
	str = split(str, "\t");
	return str.length;
}
function tablePosition( crd, p, pA ) {
	getSelectionBounds(x, y, wS, hS);
	b = 5;
	w = getWidth();
	h = getHeight();
	if (p== pA[0]) {
		crd[0] = b; crd[1] = b;
	} else {
		if (p== pA[1]) {
			crd[0] = w-wS-b; crd[1] = b;
		} else {
			if (p== pA[2]) {
				crd[0] = b; crd[1] = h-hS-b;
			} else {
				if (p== pA[3]) {
					crd[0] = w-wS-b; crd[1] = h-hS-b;
				} else {
					setSelectionLocation((w-wS)*0.5, (h-hS)*0.5);
					waitForUser("Position the selection.");
					getSelectionBounds(x, y, wS, hS);
					crd[0]=x; crd[1]=y;
				}
			}
		}
	}
}
/* imagej-macro "table2image" (Herbie G., 21. April 2018) */

Paste the above macro code to an empty macro window (Plugins >> New >> Macro) and run it. You may install the macro, after saving it as “_table2image.ijm”, by “Plugins >> Macros >> Install…”

Please tell me if you encounter any problems.

Regards

Herbie

4 Likes