You are viewing a read-only archive of the Blogs.Harvard network. Learn more.

The Rage of Thor

ø

Had a tricky decision to make this morning—get the interface finished and done, or tackle one (even just one!) of the list of deliverables I committed to for DSA last week? Well, it’s been a very busy week with non-thesis commitments, so I decided to put off the non-thesis deliverables for just a little bit longer, and give priority to the one thing that really needs getting done more than anything else.

Knocked the first item off the list before 10am, which was to sort out how the magnification/scale information was going to be saved to the filename. I wanted a way to make absolutely sure that the scale was being set for each image that was opened . In almost every case there will be multiple images per individual, and quite possibly multiple images between write-to-pipe events, so it wasn’t sufficient to use those file-write events as a trigger for a filename change. I thus had to dig around the interwebs quite a lot for a way to get at the somewhat lower-level file opening event as a trigger for running my script. Eventually found a java class “Image Listener” that will do just that, and after a bit of tinkering I got it to both work perfectly, and also to compile automagically upon startup (to avoid having to install the plugin every time ImageJ is opened).

Next on the list was to write a function for the R interface that writes a backup of the SQL database tables to CSV files, to avoid any disastrous things from happening should the .db file become corrupted or some such nasty yet unforeseeable thing. This was not difficult to accomplish and was done by lunchtime.

Next, I tried to improve the “New slide…” menu item to allow for accidentally adding a slide that already exists, and for choosing an existing slide to work on. Completed this task after DSA, and it seems to work fine. I’m ready for testing!

Finishing Touches on the Interface

ø

Gave myself a little bit of a rest this morning, as a reward for successes yesterday—took about an hour to leisurely give the houseplants a bath, as they had accumulated a thick layer of dust and were looking very dry and sad. Then turned my attention to fixing the remaining bits missing from the interface, one of which is to record the objective/magnification of the images taken. I thought I’d be able to do this by adding or modifying an entry to the JPEG EXIF metadata, but once I’d found the appropriate function I spent quite a bit of time trying to do this and not understanding why it wouldn’t work. It was only when I read the manual (I know, I know… if all else fails!) that I realized that—bizarrelyImageJ only supports saving metadata for TIFF and ZIP file formats, but not for JPGs. Very odd, but at least it explains what was going on. Saving the files as TIFFs isn’t a great option, as the file size balloons from ~600KB per file to ~30MB. I’m reluctant to add a field to the SQL database to contain this info, because that would mean tweaking both the database set-up, and several functions within the R program that handle formulating the SQL INSERT statements. Not that it’d be a lot of work—but the thing works and I don’t want to risk introducing bugs.

Aha! What about appending the objective label to the filename? The filename’s already being stored in RadData, so this would be a super low-impact way of associating the data with the file directly.

Macros Done!

ø

Well. Another somewhat slow day, but not without progress. Managed to hash out the remainder of the ImageJ portion of the measurement interface. It seems to be quite reliably making measurements, with the intervening calculations of area, and writing them successfully to the “pipe” file—all the while keeping track of the measurement number to facilitate easy reference to the image displayed by the R portion of the interface. Huzzah!

Here the product of the last two days’ work—embarrassing though it may be that it took so long, I’m proud that it seems to work. Many may have been able to do it faster, but far more would not have been able to do it at all…

//Macros to collect radiolarian morphometric measurements for acquisition
//to the RadData database, via its R interface.
//Written by Ben Kotrc, Mar 1st, 2011
//Declare global variables
//Measurement number (in reference to R interface image)
var counter = 0;
//Microscope magnification (e.g. 16x, 40x, etc)
var objective = “??x.”;
//Macro to write all measurements of type “Length” taken since the last
//file write operation, with the current image file name, to the pipe file
macro “Save linear measurements to file [1]” {
//Get name of currently open image file
curfname=getInfo(“image.filename”);
//Loop through each row in the Results table
for (i=counter; i<nResults; i++){
//Extract the ith row from the “Length” column of the Results table
measurement = getResult(“Length”, i);
//Concatenate row of data to be appended to pipe file (data + filename)
insertion = d2s(measurement,2) + “\t” + curfname;
//Append the ith measurement to the Results table
File.append(insertion, “/Users/Ben/Dropbox/Harvard/By-Lineage\ Rads/RadData\ Database/pipefilename.txt”);
//Increment the measurement counter
counter++;
}
//Display in log window how many measurements have been written to file
print(“\\Clear”);
print(“Scale set to ” + objective + “.”);
print(d2s(counter,0) + ” measurements recorded to file.”);
}
//Macro to calculate the pore area proportion from the measurements added
//to the results table since the last file write operation, then write the
//number to file with the current image file name
macro “Save area measurement to file [2]” {
//Get name of currently open image file
curfname=getInfo(“image.filename”);
//Find the sum of all but the first row in the Results table
sum=0;
for (i=counter+1; i<nResults; i++){
sum = sum + getResult(“Area”,i);
}
//Find the pore area proportion
measurement = sum/getResult(“Area”,counter);
//Concatenate row of data to be appended to pipe file (data + filename)
insertion = d2s(measurement,4) + “\t” + curfname;
//Append the result to file
File.append(insertion, “/Users/Ben/Dropbox/Harvard/By-Lineage\ Rads/RadData\ Database/pipefilename.txt”);
//Increment the measurement counter
counter++;
//Display in log window how many measurements have been written to file
print(“\\Clear”);
print(“Scale set to ” + objective + “.”);
print(d2s(counter,0) + ” measurements recorded to file.”);
//Tidy up the Results table
IJ.deleteRows(counter,nResults-1);
setResult(“Area”,counter-1,measurement);
}
//Macro to insert a zero-valued measurement to the pipe file, and update
//the ImageJ results table accordingly
macro “Add zero measurement to file [3]” {
measurement = 0;
curfname = “No file”;
//Concatenate row of data to be appended to pipe file (data + filename)
insertion = d2s(measurement,4) + “\t” + curfname;
//Append the result to file
File.append(insertion, “/Users/Ben/Dropbox/Harvard/By-Lineage\ Rads/RadData\ Database/pipefilename.txt”);
//Update Results table to reflect added zero “measurement”
setResult(“Area”, counter, 0);
//Increment the measurement counter
counter++;
//Display in log window how many measurements have been written to file
print(“\\Clear”);
print(“Scale set to ” + objective + “.”);
print(d2s(counter,0) + ” measurements recorded to file.”);
}
//Macro to reset the tally of the number of measurements written to file,
//as displayed in the log window, to zero (use each time a new individual
//is started)
macro “Reset measurement counter [4]” {
//Clear the Results table
selectWindow(“Results”);
run(“Close”);
//Reset counter
counter = 0;
//Display in log window
print(“\\Clear”);
print(“Scale set to ” + objective + “.”);
print(d2s(counter,0) + ” measurements recorded to file.”);
}
\\Macro to set the appropriate scale for different microscope objectives
macro “Set magnification… [5]” {
Dialog.create(“Set magnification”);
Dialog.addChoice(“Objective:”, newArray(“16x”, “40x”, “80x”, “100x”));
Dialog.show();
objective = Dialog.getChoice();
if (objective == “16x”) {
run(“Set Scale…”, “distance=1190 known=26.3 pixel=1 unit=µm”);
} else if (objective == “40x”){
run(“Set Scale…”, “distance=1190 known=26.3 pixel=1 unit=µm”);
} else if (objective == “80x”){
run(“Set Scale…”, “distance=1190 known=26.3 pixel=1 unit=µm”);
} else if (objective == “1000x”){
run(“Set Scale…”, “distance=1190 known=26.3 pixel=1 unit=µm”);
}
//Print new magnification in log window, along with # of measurements taken
print(“\\Clear”);
print(“Scale set to ” + objective + “.”);
print(d2s(counter,0) + ” measurements recorded to file.”);
}
Well, that was fun, but now it’s time to move on and figure out how to parse the measurements this script writes to file into R and, in swift succession, into SQL queries that can shuttle the measurements safely into the database.

Micro Macro Steps

ø

Started the day finishing Friday’s post—it was another busy weekend and I didn’t get around to finishing off writing up notes from the job fair. It seems that it would be wise to put together some sort of résumé sooner rather than later… It will be nice to be have something to hand out when I meet interesting and relevant people, rather than having to take their card and email them. Although that’s probably not a bad strategy to follow additionally.

Had a slow day the rest of the day, but managed to tackle a couple of the ImageJ macros I needed to make—writing linear measurements to file, and writing area measurements to file. They seem to work nicely. Now I just need macros for setting the magnification, and some way of keeping the counter going that shows which measurement number I’m on.

Shuttling Shit Between ImageJ and R

ø

Incredibly slow moving day. Monkeyed around with getting measurements written to file from ImageJ, which you’d think would be easy. And it is. Don’t know why it’s taking me this long; lack of focus, I guess. Got part of the way through doing this and figured out that I’ll need just three ImageJ macros, plus some counting trickery, to do it all:

  1. Set magnification—a macro or set of macros to set the pixel:µm scale for each of the objectives I’ll be using to make my measurements, the first step after taking a picture down the scope.
  2. Write linear results to file—a macro to extract the values from the “Length” column of the results table, pair them with the image filename, and append them to the pipe file. This will do for all of the length, width, and shell thickness measurements.
  3. Write area results to file—a macro to subtract the 2nd through nth values from the “Area” column of the results table from the 1st such value, then append that value to the pipe file along with the image filename. This will calculate the pore area percentage value from the raw measurements of total area and pore areas.
  4. Number trickery—haven’t figured out exactly how this will work, but since I’ll be making measurements on multiple images with separate results windows, I’ll need to keep track of which measurements I’ve made and which number I’m on. Haven’t figured this part out yet.

Aborted day fairly early due to DSA followed by (yet another) job talk. This the penultimate one, thank goodness.