Random ROI generator

Hi - First time asking a question here, so hopefully I can word this to make sense.
I am attempting to analyze .jpg images of tissue, and I would like to make 50 randomly generated ROIs (all the same size) for each image, that are then saved as tiffs. My supervisor created a macro, which seemed to work fine, at first. Although the spots were randomly generated, for certain images there seemed to be a complete neglect of areas of tissue (see image 1 - I am referring to the bottom right hand corner).


We also noticed that if we increased the amount of ROIs to 100, then instead of sampling from the neglected areas, there was just more overlap of ROIs.
So my supervisor created another macro, which this time creates a grid on the image and then randomly selects boxes from this grid, thus generating ROIs. But we are running into the same problem. (See image2)
At this point, neither he nor I (although, I am a novice) know what to do. This only happens with certain images with larger pieces of tissue.

Here is the first macro:

roiManager("Reset");
run("Clear Results");

path=getDirectory("Select image folder root(spots)");
list=getFileList(path);
folderlist=newArray(0);

for (i=0; i<list.length; i++) {
if (endsWith(list[i], "/")){
folderlist=Array.concat(folderlist, list[i]);}} 


if (folderlist.length==0) exit("no profiles available");
status=newArray(folderlist.length);
Array.fill(status, false);

Dialog.create("Select folder to process");
Dialog.addCheckboxGroup(20,4,folderlist,status);
Dialog.show();
for (p=0; p<folderlist.length; p++) {status[p]=Dialog.getCheckbox();}

//channels, you can add if you need
channels=newArray("B","G","R","M");
chanselect=newArray(channels.length);
Array.fill(chanselect, false);

//Dialog.create("Channels included");
//Dialog.addCheckboxGroup(1,4,channels,chanselect);
//Dialog.show();
//chanselect=Dialog.getCheckbox();

//check the file format JPG or Tiff!!
for (i=0; i<folderlist.length; i++) {
if (status[i]==true) {
list2=getFileList(path+File.separator+folderlist[i]);
for (j=0; j<list2.length; j++) {
if (endsWith(list2[j], "B.jpg")){
dotIndex = lengthOf(list2[j]) - 5;
fileroot=substring(list2[j],0,dotIndex);
open(path+File.separator+folderlist[i]+File.separator+list2[j]);
image=getTitle();
H = getHeight();
W = getWidth();
//print

//exclude edges and areas that are not OK to include in measurements 
waitForUser("Select tissue to be included ");
run("Make Inverse");
run("Set...", "value=0");

//random selection
for (k=0;k<50;) {
if (endsWith(list2[j], "B.jpg")) {
RH = random();
RW = random();
Ht = RH * H;
Wt = RW * W;
Ht=d2s(Ht,0);
Wt=d2s(Wt,0);
makeRectangle(Ht, Wt, 500, 500);
getStatistics(area,mean);
	//only include selections with a certain dapi signal you can increase this to make sure you have areas covered by tissue or evern count nuclei
	if (mean>0) {
	roiManager("Add");
	roiManager("Select",k);
	k++;
	roiManager("Rename", "selection- "+k);	}}
}  

//save the roi's so you can inspect and check if all is OK
roiManager("Save", path+File.separator+folderlist[i]+File.separator+"ROI.zip");

//t=roiManager("count"); 
//for (m=0;m<t;m++) {
//roiManager("Select",m);
//run("Copy");
//run("Internal Clipboard");
//saveAs("tiff", path+File.separator+folderlist[i]+File.separator +"B-"+m+1 +".TIF");
//close();
//}
selectWindow(image);
close();

//check the file format jpg or tiff
for (n=0; n<channels.length; n++) {
open(path+File.separator+folderlist[i]+File.separator + fileroot +channels[n]+".JPG");
image=getTitle();
t=roiManager("count"); 
for (p=0;p<t;p++) {
roiManager("Select",p);
run("Copy");
run("Internal Clipboard");
saveAs("tiff", path+File.separator+folderlist[i]+File.separator +channels[n] +p+1 +".TIF");
close();
}
selectWindow(image);
close();
}}}}}

And here is the second macro:

roiManager("Reset");
run("Clear Results");

path=getDirectory("Select image folder root(spots)");
list=getFileList(path);
folderlist=newArray(0);

for (i=0; i<list.length; i++) {
if (endsWith(list[i], "/")){
folderlist=Array.concat(folderlist, list[i]);}} 


if (folderlist.length==0) exit("no profiles available");
status=newArray(folderlist.length);
Array.fill(status, false);

Dialog.create("Select folder to process");
Dialog.addCheckboxGroup(20,4,folderlist,status);
Dialog.show();
for (p=0; p<folderlist.length; p++) {status[p]=Dialog.getCheckbox();}

//channels, you can add if you need
channels=newArray("B","G","R","M","Y");
chanselect=newArray(channels.length);
Array.fill(chanselect, false);

//Dialog.create("Channels included");
//Dialog.addCheckboxGroup(1,4,channels,chanselect);
//Dialog.show();
//chanselect=Dialog.getCheckbox();

//check the file format JPG or Tiff!!
for (i=0; i<folderlist.length; i++) {
if (status[i]==true) {
list2=getFileList(path+File.separator+folderlist[i]);
for (j=0; j<list2.length; j++) {
if (endsWith(list2[j], "B.jpg")){
dotIndex = lengthOf(list2[j]) - 5;
fileroot=substring(list2[j],0,dotIndex);
open(path+File.separator+folderlist[i]+File.separator+list2[j]);
image=getTitle();
H = getHeight();
W = getWidth();

//exclude edges and areas that are not OK to include in measurements 
waitForUser("Select tissue to be included ");
run("Make Inverse");
run("Set...", "value=0");


//creating an array with all boxes
Dialog.create("Selection size");
  Dialog.addNumber("Width:", 500);
  Dialog.addNumber("Height:", 500);
  Dialog.show();
  boxx = Dialog.getNumber();
  boxy = Dialog.getNumber();

HN = parseInt(H/boxy);
WN = parseInt(W/boxx);
startX=W/2-boxx/2;
startY=H/2-boxy/2;

Xvalues=newArray(0);


X=startX;
while (X>0) {
	Xvalues=Array.concat(Xvalues,X);
	X=X-boxx;
	}

X=startX+boxx;
while (X<W-boxx) {
	Xvalues=Array.concat(Xvalues,X);
	X=X+boxx;
	}
Yvalues=newArray(0);
Y=startY;
while (Y>0) {
	Yvalues=Array.concat(Yvalues,Y);
	Y=Y-boxy;
	}

Y=startY+boxx;
while (Y<H-boxy) {
	Yvalues=Array.concat(Yvalues,Y);
	Y=Y+boxy;
	}

Xlist=newArray(0);
Xtemp=newArray(Yvalues.length);
Ylist=newArray(0);

for (j=0; j<Xvalues.length; j++) {
	Array.fill(Xtemp, Xvalues[j]);
	Xlist=Array.concat(Xlist,Xtemp);
	Ylist=Array.concat(Ylist,Yvalues);
}
//create a list with all possible x and y start points -- starting from the center of the image
//print(Xlist.length);
//Array.show(Xlist,Ylist);


//random selection
Rnumbers=newArray(0);

for (k=0;k<50;) {
double=false;

R = parseInt(random()*Xlist.length);
for (n=0; n<Rnumbers.length; n++) {
		if(R==Rnumbers[n]) double=true;
}

if (double==false) {

makeRectangle(Ylist[R], Xlist[R], boxy, boxx);
getStatistics(area,mean);
	
	//only include selections with a certain dapi signal you can increase this to make sure you have areas covered by tissue or evern count nuclei
	if (mean>0) {
	Rnumbers=Array.concat(Rnumbers,R);
	roiManager("Add");
	roiManager("Select",k);
	k++;
	roiManager("Rename", "selection- "+k);	}
}}  

//save the roi's so you can inspect and check if all is OK
roiManager("Save", path+File.separator+folderlist[i]+File.separator+"ROI.zip");

//t=roiManager("count"); 
//for (m=0;m<t;m++) {
//roiManager("Select",m);
//run("Copy");
//run("Internal Clipboard");
//saveAs("tiff", path+File.separator+folderlist[i]+File.separator +"B-"+m+1 +".TIF");
//close();
//}
selectWindow(image);
close();

//check the file format jpg or tiff
for (n=0; n<channels.length; n++) {
open(path+File.separator+folderlist[i]+File.separator + fileroot +channels[n]+".JPG");
image=getTitle();
t=roiManager("count"); 
for (p=0;p<t;p++) {
roiManager("Select",p);
run("Copy");
run("Internal Clipboard");
saveAs("tiff", path+File.separator+folderlist[i]+File.separator +channels[n] +p+1 +".TIF");
close();
}
selectWindow(image);
close();
}}}}}}}

Any help would be greatly appreciated!
Thanks!
L

Hi @gradstudent

And welcome to the ImageJ-Forum.

Based on you information I created this KNIME workflow which creates 50 random ROIs (10x10px) and saves them as tiffs.

This is the workflow RandomROIs.zip (198.0 KB).

@tibuch I think the goal was to create ROIs only on regions where there is some tissue, but randomly distributed on all the tissue area.

Hi,

I don’t know what is the problem with your macro, but here is the block of code I use to generate random ROIs, adapted from http://imagej.net/macros/RandomSampleAndMeasure.txt

imagewidth = getWidth();
imageheight = getHeight();
imagearea = imagewidth*imageheight;
randomroidivisor = 100/randomroifraction;
randomroitotalarea = imagearea/randomroidivisor;
randomroiarea = randomroitotalarea/roi;
w = sqrt(randomroiarea);
h = sqrt(randomroiarea);
trials = roi*10; //maximum trials to avoid infinite loop
setForegroundColor(255,0,0);
kk=0;

run("Duplicate...", "title=randomroi");
randomroiID = getImageID();
run("8-bit"); //make it greyscale
run("RGB Color"); //RGB to display colours

do {

    if (kk==10) {
        beep();
        exit("Not enough space to draw random non-overlapping ROIs on the image. Reduce random ROIs fraction.");
    }

    ii=0;
    jj=0;
    xa=newArray(roi);
    ya=newArray(roi);

    while (ii<roi && jj<trials) {
        x = random()*(imagewidth-w);
        y = random()*(imageheight-h);
        jj++;
        //Check for pixels with value (255,0,0):
        flag= -1;
        makeRectangle(x, y, w, h);
        //Scanning the rectangle perimeter should be faster than scanning the whole box.
        //This is slower, as checks all the points in the box:
        for (xs=x;xs<x+w;xs++){
            for (ys=y;ys<y+h;ys++){
                if (getPixel(xs,ys)==-65536) // pixel is (255,0,0)
                    flag=0;
            }
        }
        if (flag==-1) {
            xa[ii]=x;
            ya[ii]=y;
            run("Fill");
            ii++;
        }
    }

    kk++;

} while (xa[roi-1]==0 && ya[roi-1]==0);

    for (z=0;z<roi;z++) {
        makeRectangle(xa[z], ya[z], w, h);
           roiManager("Add");
        roiManager("select", roiManager("count")-1);
        roiManager("Rename", z+1);
    }

selectImage(randomroiID);
close();

You need to specify the variables roi (number of ROIs) and randomroifraction (as a percentage of the total image area).
Only non-overlapping ROIs are drawn and added to the ROI manager.

Hope it helps.

Hi Lora,

From your screenshots, it seems that there are no ROIs having a y coordinate larger than the width of the image.
And indeed, that’s where the problem is in both your macros: you are using the makeRectangle(x, y, width, height) function in an incorrect way, swapping x and y coordinates.

So:

should be changed to:

makeRectangle(Wt, Ht, 500, 500);

And for your second macro, respectively:

should be:

makeRectangle(Xlist[R], Ylist[R], boxx, boxy);
3 Likes

Thank you thank you thank you to everyone who replied (@tibuch @imagejan @albertoberto). It is now fixed! Now I can actually proceed with data analysis!

1 Like

Thanks @imagejan - this was a great quick fix. Solved the problem!