// This is a FIJI macro for tracking the heading of tethered flies (0deg - 180deg)
// over time. It will process all .AVI files within a user-defined folder and will 
// automatically save the angular data to TXT files which can then be analysed using our Matlab scripts
// (scripts with with instructions can be downloaded at www.flygen.org/skylight-navigation).
// AVI files should be uncompressed or compressed using MJPEG compression.
// Run this macro in FIJI under "Plugins" - "Macros" - "Run".

// Process all .AVI files within a user-defined folder.   
   
   dir = getDirectory("Choose the folder containing AVIs to be tracked");
   setBatchMode(true);
   count = 0;
   countFiles(dir);
   n = 0;
   processFiles(dir);
   //print(count+" files processed");
   
   function countFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              countFiles(""+dir+list[i]);
          else
              count++;
      }
  }

   function processFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              processFiles(""+dir+list[i]);
          else {
             showProgress(n++, count);
             path = dir+list[i];
             processFile(path);
          }
      }
  }

  function processFile(path) {
 if (endsWith(path, ".avi")) {
    

//Open .AVI file.
  
run("AVI...", "open=path first=1 use convert");


// Set a constant circular region of interest (ROI) which should be analyzed.
// This ROI should only contain dark background surrounding a bright fly and must be large enough to
// include the whole fly in all frames. Needs to be set manually. If camera angles are kept constant 
// during experiments these ROI values only need to be set once.

makeOval(215, 178, 130, 124);


// Load ROI into RAM

run("Duplicate...", "duplicate");
      

// Background subtraction, contrast optimization and median filter to prepare frames for proper thresholding
// Values might need to be adjusted depending on video quality.

run("Subtract Background...", "rolling=50 sliding disable stack");
run("Enhance Contrast...", "saturated=0.3 normalize process_all");
run("Median...", "radius=5 stack");


// This ROI should only contain dark background surrounding a bright fly and must be large enough to
// include the whole fly in all frames. Needs to be set manually. If ROI is kept constant during experiments, these
// values only need to be set once.

makeOval(0, 0, 130, 124);


// Theshold fly's body from background.
// Values might need to be adjusted depending on video quality and contrast.
   
run("Convert to Mask", "method=Default background=Dark");
setThreshold(64, 255);


//Save thresholded AVI for later inspection for proper thresholding

run("AVI... ", "compression=JPEG frame=60 save=["  + path + i + ".avi]");


// Measure angles of thresholded fly "blob" by fitting an ellipse around it.
// Parameters to be measured must be set in FIJI (under Set Measurements).
// There "Fit ellipse", "Display label" and "Limit to threshold" must be ticked.

run("Restore Selection");
roiManager("Add");
roiManager("Multi Measure");
roiManager("Deselect");
roiManager("Delete");


  }
  setBatchMode(false);
  
  
//Save results as .TXT file.

title = getTitle(); 
selectWindow("Results");
saveAs("txt", "C:\\"+title);
run("Close");
close();
while (nImages>0) { 
          selectImage(nImages); 
          close(); 
      } 
run("Collect Garbage");
      }

  }
