aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbatch-process3
-rw-r--r--fly-tools/FlyObject.cpp118
-rw-r--r--fly-tools/FlyObject.h49
-rw-r--r--fly-tools/FlyTrackingFilter.cpp666
-rw-r--r--fly-tools/FlyTrackingIterativeFilter.cpp707
-rw-r--r--fly-tools/FlyTrackingMain.cpp3181
-rwxr-xr-xfly-tools/FlyTrackingNoImagesbin0 -> 97256 bytes
-rw-r--r--fly-tools/FrameInfo.cpp72
-rw-r--r--fly-tools/FrameInfo.h35
-rw-r--r--fly-tools/FurthestPointAlongMajorAxis.cpp3084
-rw-r--r--fly-tools/MyPair.h30
-rw-r--r--fly-tools/StandardDeviation.cpp90
-rw-r--r--fly-tools/misc/linesweep.cpp693
-rw-r--r--fly-tools/misc/makeimage.cpp51
-rw-r--r--fly-tools/misc/test.cpp92
15 files changed, 8871 insertions, 0 deletions
diff --git a/batch-process b/batch-process
index 573295a..bdd67a9 100755
--- a/batch-process
+++ b/batch-process
@@ -1,3 +1,4 @@
+#!/bin/sh
usage()
{
cat << EOF
@@ -62,3 +63,5 @@ else
exit 1
fi
+
+
diff --git a/fly-tools/FlyObject.cpp b/fly-tools/FlyObject.cpp
new file mode 100644
index 0000000..d6cbee3
--- /dev/null
+++ b/fly-tools/FlyObject.cpp
@@ -0,0 +1,118 @@
+/*
+ * FlyObject.cpp
+ *
+ *
+ * Created by Md. Alimoor Reza on 6/26/10.
+ * Copyright 2010 Drexel University. All rights reserved.
+ *
+ */
+
+#include "FlyObject.h"
+
+FlyObject::FlyObject(int area, pair<int, int> centroid, pair<double,double> majorAxisEV, pair<double,double> velocityV,bool headIsInDirectionMAEV, pair<double,double> head, double speed) {
+//FlyObject::FlyObject(int area, pair<int, int> centroid, pair<double,double> majorAxisEV, pair<double,double> velocityV, vector<pair<int , int> > areaCoord) {
+ this->area = area;
+ this->centroid = centroid;
+ this->majorAxisEV = majorAxisEV;
+ this->velocityV = velocityV;
+ this->headIsInDirectionMAEV = headIsInDirectionMAEV;
+ this->head = head;
+ this->speed = speed;
+// this->areaCoord = areaCoord;
+}
+
+FlyObject::FlyObject(const FlyObject &f){
+ this->area = f.getArea();
+ this->centroid=f.getCentroid();
+ this->majorAxisEV =f.getMajorAxisEV();
+ this->velocityV = f.getVelocityV();
+// this->areaCoord = f.getAreaCoord();
+ this->headIsInDirectionMAEV = f.getHeadIsInDirectionMAEV();
+ this->head = f.getHead();
+ this->speed = f.getSpeed();
+}
+
+int FlyObject::getArea() const {
+ return area;
+}
+
+pair<int, int> FlyObject::getCentroid() const {
+ return this->centroid;
+}
+
+pair<double,double> FlyObject::getMajorAxisEV() const {
+ return this->majorAxisEV;
+}
+
+pair<double,double> FlyObject::getVelocityV() const {
+ return this->velocityV;
+}
+bool FlyObject::getHeadIsInDirectionMAEV() const {
+ return this->headIsInDirectionMAEV;
+}
+pair<double,double> FlyObject::getHead() const {
+ return this->head;
+}
+//vector<pair<int , int> > FlyObject::getAreaCoord() const {
+// return this->areaCoord;
+//}
+double FlyObject::getSpeed() const {
+ return this->speed;
+}
+void FlyObject::setArea(int area) {
+ this->area = area;
+}
+
+void FlyObject::setCentroid(pair<int, int> centroid) {
+ this->centroid = centroid;
+}
+
+void FlyObject::setMajorAxisEV(pair<double,double> majorAxisEV) {
+ this->majorAxisEV = majorAxisEV;
+}
+
+void FlyObject::setVelocityV(pair<double,double> velocityV) {
+ this->velocityV = velocityV;
+// cout << "velocityV is set to "<<this->velocityV.first<<","<<this->velocityV.second<<endl;
+}
+void FlyObject::setHead(pair<double, double> head) {
+ this->head = head;
+ cout << "new head is set"<<endl;
+
+}
+//void FlyObject::setAreaCoord(vector<pair<int, int> > areaCoord){
+// this->areaCoord = areaCoord;
+//}
+void FlyObject::setSpeed(double speed) {
+ this->speed = speed;
+}
+
+void FlyObject::normalizeVelocity() {
+ double temp = velocityV.first*velocityV.first + velocityV.second*velocityV.second;
+ temp = sqrt(temp);
+ cout << "sum = "<<temp<<endl;
+ cout << "unnormalized velocity "<<velocityV.first<<","<<velocityV.second<<endl;
+ if (temp != 0) {
+ velocityV.first = velocityV.first/temp;
+ velocityV.second = velocityV.second/temp;
+ cout << "unit velocity "<<velocityV.first<<","<<velocityV.second<<endl;
+ } else {
+ cout <<"velocity zero"<<endl;
+ }
+
+}
+void FlyObject::setHeadIsInDirectionMAEV(bool headIsInDirectionMAEV) {
+ this->headIsInDirectionMAEV = headIsInDirectionMAEV;
+ cout << "head flag set to "<<this->headIsInDirectionMAEV<<endl;
+}
+
+
+void FlyObject::output(ostream &out) {
+ out<<"Area : "<<area<<endl;
+ out<<"Centroid : ("<<centroid.first<<","<<centroid.second<<")"<<endl;
+ out<<"MajorAxisEV : ("<<majorAxisEV.first<<","<<majorAxisEV.second<<")"<<endl;
+ out<<"VelocityV : ("<<velocityV.first<<","<<velocityV.second<<")"<<endl;
+ out<<"HeadIsInDir : "<<this->headIsInDirectionMAEV<<endl;
+ out<<"Head : ("<<this->head.first<<","<<head.second<<endl;
+ out<<"Speed : "<<speed<<endl;
+} \ No newline at end of file
diff --git a/fly-tools/FlyObject.h b/fly-tools/FlyObject.h
new file mode 100644
index 0000000..10dbd4f
--- /dev/null
+++ b/fly-tools/FlyObject.h
@@ -0,0 +1,49 @@
+/*
+ * FlyObject.h
+ *
+ *
+ * Created by Md. Alimoor Reza on 6/26/10.
+ * Copyright 2010 Drexel University. All rights reserved.
+ *
+ */
+#include<iostream>
+#include<vector>
+#include<list>
+#include<cmath>
+using namespace std;
+
+class FlyObject {
+public:
+ //FlyObject(int area, pair<int, int> centroid, pair<double,double> majorAxisEV, pair<double,double> velocityV, vector<pair<int, int> > areaCoord);
+ FlyObject(int area, pair<int, int> centroid, pair<double,double> majorAxisEV, pair<double,double> velocityV,bool headIsInDirectionMAEV, pair<double, double> head, double speed);
+ FlyObject(const FlyObject &f);
+ int getArea() const;
+ pair<int, int> getCentroid() const;
+ pair<double,double> getMajorAxisEV() const;
+ pair<double,double> getVelocityV() const;
+ bool getHeadIsInDirectionMAEV() const;
+ pair<double,double> getHead() const;
+ double getSpeed() const;
+ //vector<pair<int, int> > getAreaCoord() const;
+ void setArea(int area);
+ void setCentroid(pair<int, int>);
+ void setMajorAxisEV(pair<double,double>);
+ void setVelocityV(pair<double,double>);
+ void normalizeVelocity();
+ void setHeadIsInDirectionMAEV(bool);
+ void setHead(pair<double, double> head);
+ void setSpeed(double speed);
+ //void setAreaCoord(vector<pair<int , int> >);
+ void output(ostream &out);
+
+
+private:
+ int area;
+ //vector<pair<int , int> > areaCoord;
+ pair<int, int> centroid;
+ pair<double,double> majorAxisEV;
+ pair<double,double> velocityV;
+ bool headIsInDirectionMAEV;
+ pair<double, double> head;
+ double speed;
+};
diff --git a/fly-tools/FlyTrackingFilter.cpp b/fly-tools/FlyTrackingFilter.cpp
new file mode 100644
index 0000000..9020522
--- /dev/null
+++ b/fly-tools/FlyTrackingFilter.cpp
@@ -0,0 +1,666 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <cmath>
+#include <vector>
+#include <list>
+#include <fstream>
+#include <cassert>
+#include <cstdlib>
+
+#include <ImageMagick/Magick++.h>
+
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_eigen.h>
+
+#include "FrameInfo.h"
+
+using namespace Magick;
+using namespace std;
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon=true, bool colorLookingFor=true);
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+vector<double> covariantDecomposition(vector<pair<int,int> > & points);
+pair<int,int> getCentroid(vector<pair<int,int> > & points);
+bool isInterface(Image* orig, unsigned int x, unsigned int y);
+void writeFrameImage(int fn, string imS);
+int roundT(double v) {return int(v+0.5);}
+
+
+const double PI = atan(1.0)*4.0;
+const double FACTOR_EIGEN = 100;
+
+Image* residual;
+
+ostream &operator<<(ostream &out, FlyObject & fO) {
+ fO.output(out);
+ return out;
+}
+
+ostream &operator<<(ostream &out, FrameInfo & fI) {
+ fI.output(out);
+ return out;
+}
+
+vector<vector<pair<int, int> > > shapeVectors;
+vector<pair<int,int> > shape;
+vector<pair<int, int> > sizeNIndexVector;
+
+void bubbleSort() {
+
+ for(int i=1; i<sizeNIndexVector.size(); i++) {
+ for(int j=0; j<sizeNIndexVector.size()-i; j++) {
+ pair<int, int> a = sizeNIndexVector[j];
+ pair<int, int> b = sizeNIndexVector[j+1];
+
+ if (a.first < b.first) {
+ pair<int, int> c = sizeNIndexVector[j];
+ sizeNIndexVector[j] = sizeNIndexVector[j+1];
+ sizeNIndexVector[j+1] = c;
+ }
+ }
+ }
+
+}
+
+void fillResidualWithObj(vector<pair<int, int> > & obj, ColorRGB c)
+{
+ for (unsigned int i = 0; i<obj.size(); i++)
+ residual->pixelColor(obj[i].first, obj[i].second, c);
+}
+
+void writeHist(const char* filename, map<unsigned int, unsigned int> & len)
+{
+ map<unsigned int,unsigned int>::iterator front = len.begin(),
+ back = len.end();
+ back--;
+
+
+ unsigned int first = front->first, last = back->first;
+ /*if (cutoff != -1 && cutoff < int(last))
+ last = cutoff;
+ */
+ cout << "Min: " << first << endl
+ << "Max: " << last << endl
+ << "Count: " << last-first << endl;
+ //vector<unsigned int> hist(last-first, 0);
+ vector<unsigned int> hist(last+1, 0);
+
+ cout << "hist size: " << hist.size() << endl;
+ try{
+ for(unsigned int j = 0; j<first; j++) {
+ hist[j] = 0;
+ }
+ for (unsigned int j = first; j<=last; j++)
+ {
+ /*if ( roundT(j-first) >= int(hist.size()) )
+ hist.resize(j-first,0);
+ hist[roundT(j-first)] = len[j];
+ */
+
+ /*if ( roundT(j) >= int(hist.size()) )
+ hist.resize(j,0);
+ hist[roundT(j)] = len[j];
+ */
+ hist[j] = len[j];
+ }
+ }
+ catch (...)
+ { cerr << "Bad histogram bucketing" << endl; }
+
+ /*if ( (cutoff >= 0) && (cutoff<int(hist.size())) )
+ hist.resize(cutoff);
+ */
+ len.clear();
+ try
+ {
+ ofstream fout(filename);
+ for (unsigned int i = 0; i<hist.size(); i++) {
+ fout << hist[i] << endl;
+ }
+ fout << first << " " << last << " " << hist.size() << endl;
+ fout.close();
+ }
+ catch (...)
+ { cerr << "Bad memory loc for opening file" << endl; }
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 5)
+ {
+ cerr << "Usage: executablename <inputFile.txt> <ratio_largest_to_second_largest> <InputLocationOfMaskImage> <outputFolderName>" << endl; // input file contains name of the
+ // input image files
+ return -1;
+ }
+
+ MagickCore::SetMagickResourceLimit(MagickCore::MemoryResource, 1536);
+ MagickCore::SetMagickResourceLimit(MagickCore::MapResource, 2048);
+
+ string fileName;
+ ifstream inputFile(argv[1]);
+ if (inputFile.fail() ) {
+ cout << "cannot open the input file that contains name of the input images\n";
+ exit(1);
+ }
+
+ // get the output file name along with the location from argv[4]
+ string outputFileLocation(argv[4]);
+ string outputFileName = outputFileLocation + "final/outputFile.txt";
+ ofstream outputFile(outputFileName.c_str());
+
+ // get the location of the input mask file
+ string inputMaskFileLocation(argv[3]);
+
+ int frameCounter = 0;
+ // use 15, 20 or 10
+ // 15 found to be working correct
+ double ratioSecondLargestToLargest = atof(argv[2]);
+
+ cout << "Ratio is 1/"<<ratioSecondLargestToLargest<< " = "<<(1/ratioSecondLargestToLargest)<<endl;
+
+ outputFile<<"Ratio given 1/"<<ratioSecondLargestToLargest<<" = "<<(1/ratioSecondLargestToLargest)<<endl;
+
+ ratioSecondLargestToLargest = 1/ratioSecondLargestToLargest;
+ // to find the largest object avg size
+
+ long totalSize = 0;
+
+ char buffer[100];
+
+ while (inputFile>>fileName) {
+
+ string savedFileName = fileName;
+
+ // get the input mask file
+// fileName = "input/"+fileName;
+ fileName = inputMaskFileLocation + fileName;
+
+ Image* img = new Image(fileName.c_str());
+ int width = img->columns(),height = img->rows();
+ Image* imgForFilter;
+ sprintf(buffer,"%ix%i",width,height);
+
+ // residual image is initialized with black representing not visited.
+ residual = new Image(buffer, "black");
+
+ imgForFilter = new Image(buffer, "white");
+ cout << "Reading "<<savedFileName<<endl;
+ cout << "Filter wxh "<<width<<","<<height<<endl;
+ shape.clear();
+ // find the black background from location (0,0)
+ findObj(img, 0, 0, shape, false, false);
+ int s = shape.size();
+ if (s > 0)
+ cout << "black object size is "<<s;
+ for (int i=0; i<s; i++) {
+ imgForFilter->pixelColor(shape[i].first, shape[i].second, "black");
+ }
+
+ // store the intermediate file in temp folder under the output location
+// string oFilteredFileName = "output/filtered/temp/"+outputFile;
+ string oFilteredFileName = outputFileLocation +"temp/"+savedFileName;
+
+ cout << "Saving the filtered image "<< oFilteredFileName<<endl;
+ imgForFilter->write(oFilteredFileName.c_str());
+
+ delete residual;
+ /*
+ residual = new Image(buffer, "black");
+
+ shapeVectors.clear();
+ sizeNIndexVector.clear();
+
+ // find the two largest object
+ int objectCounter = 0;
+ for (int x=0; x<width; x++) {
+ for (int y=0; y<height; y++) {
+ //find the white object now using eight connected neighbours
+ shape.clear();
+ findObj(imgForFilter, x, y, shape, true, true);
+ int s = shape.size();
+ if (s>0) {
+ shapeVectors.push_back(shape);
+ cout << "new object pushed back at position "<<x<<","<<y<<" of size "<<s<<endl;
+ pair<int, int> si(s, objectCounter);
+ sizeNIndexVector.push_back(si);
+ objectCounter++;
+ }
+
+ }
+ }
+
+ // sort the sizes and take the largest to find average largest
+ cout<<"shapeVectors size = "<<shapeVectors.size()<<endl;
+
+ bubbleSort();
+
+ cout <<"Largest object size is "<<sizeNIndexVector[0].first<<endl;
+
+ // add the largest size to sum
+ totalSize += static_cast<long>(sizeNIndexVector[0].first);
+
+ cout << "Current total size is "<<totalSize<<" for object "<<(frameCounter+1)<<endl;
+
+ cout << "-----------------------------------------------------------"<<endl;
+ */
+
+ frameCounter++;
+
+ delete imgForFilter;
+
+// delete residual;
+
+ delete img;
+
+
+ }
+
+ inputFile.close();
+
+ /*
+ avgLargestSize = static_cast<long> (totalSize/frameCounter);
+ cout << "Average largest size is "<<avgLargestSize<<endl;
+ */
+
+ // previous loop calculates the average largest size
+
+ inputFile.open(argv[1]);
+
+ if (inputFile.fail() == true) {
+ cout << "Cannot open the input file again"<<endl;
+ exit(1);
+ }
+
+
+ while (inputFile>>fileName) {
+
+ //string inputFileName = "output/filtered/temp/"+fileName;
+ string inputFileName = outputFileLocation + "temp/"+fileName;
+
+ Image* img = new Image(inputFileName.c_str());
+ int width = img->columns();
+ int height = img->rows();
+
+ outputFile<<"File name is "<<inputFileName<<endl;
+ outputFile<<"----------------------------------------------\n";
+
+ sprintf(buffer,"%ix%i",width,height);
+
+ // residual image is initialized with black representing not visited.
+ residual = new Image(buffer, "black");
+
+ cout << "Reading "<<inputFileName<<endl;
+ cout << "Filter wxh "<<width<<","<<height<<endl;
+
+ shapeVectors.clear();
+ sizeNIndexVector.clear();
+
+ // find the objects and sort according to size
+ int objectCounter = 0;
+ for (int x=0; x<width; x++) {
+ for (int y=0; y<height; y++) {
+ // find the white object using eight connected
+ shape.clear();
+ findObj(img, x, y, shape, true, true);
+ int s = shape.size();
+
+ if (s > 0) {
+
+ shapeVectors.push_back(shape);
+ cout << "New object found at position ("<<x<<","<<y<<") of size "<<s<<endl;
+ pair<int, int> si(s, objectCounter);
+ sizeNIndexVector.push_back(si);
+ objectCounter++;
+
+ }
+
+ }
+ }
+
+ cout << "Total object found "<<sizeNIndexVector.size()<<endl;
+
+ outputFile<<"Total objects found "<<sizeNIndexVector.size()<<endl;
+
+ bubbleSort();
+
+ // take the largest object
+ double currentLargestSize = static_cast<double>(sizeNIndexVector[0].first);
+
+ double secondLargest = 0;
+ double ratio = 0;
+ if (sizeNIndexVector.size() > 1) {
+
+ secondLargest = static_cast<double>(sizeNIndexVector[1].first);
+ ratio = secondLargest/currentLargestSize;
+ cout << "Ratio is "<<secondLargest<<"/"<<currentLargestSize<<" = "<<ratio<<endl;
+ outputFile<<"secondLargest = "<<secondLargest<<"\ncurrentLargest = "<<currentLargestSize<<"\nRatio = "<<ratio<<endl;
+
+ }
+
+ // find the largest to second largest ratio if it is less than the defined ratio then
+ // the objects are single object
+
+ int numberOfObjects = 0;
+
+ if (sizeNIndexVector.size() == 1) {
+ cout << "Frame contains one object\n";
+ outputFile << "Frame contains one object\n";
+ numberOfObjects = 1;
+ }
+ else if (ratio <= ratioSecondLargestToLargest ) {
+ cout << "Single object calculated in the frame because current ratio = "<<ratio<<" is less than defined ratio = "<<ratioSecondLargestToLargest<<endl;
+ outputFile<< "Single object calculated in the frame because current ratio = "<<ratio<<" is less than defined ratio = "<<ratioSecondLargestToLargest<<endl;
+ numberOfObjects = 1;
+ } else {
+ cout << "Two objects in the frame\n";
+ outputFile<<"Two objects in the frame\n";
+ numberOfObjects = 2;
+ }
+
+ cout << "Total object found "<<numberOfObjects<<endl;
+ outputFile << "Total object found "<<numberOfObjects<<endl;
+
+ Image* imgFinal = new Image(buffer, "black");
+
+ for (int n=0; n<numberOfObjects; n++) {
+
+ int totalPoints = sizeNIndexVector[n].first;
+
+ for (int i=0; i<totalPoints; i++) {
+
+ imgFinal->pixelColor(shapeVectors[ sizeNIndexVector[n].second ][i].first, shapeVectors[ sizeNIndexVector[n].second ][i].second, "white");
+ }
+
+
+ }
+
+ //string finalImageName = "output/filtered/final/"+fileName;
+
+ string finalImageName = outputFileLocation + "final/"+fileName;
+
+ imgFinal->write( finalImageName.c_str() );
+
+
+
+
+ // writing the single in red
+ if (numberOfObjects == 1) {
+
+ Image* singleObjectFinal = new Image(buffer, "black");
+
+ int totalPoints = sizeNIndexVector[0].first;
+
+ cout << "Output the single object of size = "<<totalPoints<<endl;
+
+ for (int i=0; i<totalPoints; i++) {
+
+ singleObjectFinal->pixelColor(shapeVectors[ sizeNIndexVector[0].second ][i].first, shapeVectors[ sizeNIndexVector[0].second ][i].second, "red");
+ }
+
+ //string singleImageName = "output/filtered/single/"+fileName;
+ string singleImageName = outputFileLocation + "single/"+fileName;
+
+ singleObjectFinal->write(singleImageName.c_str());
+
+ delete singleObjectFinal;
+
+ }
+
+ outputFile<<"----------------------------------------------------\n";
+
+
+ delete img;
+
+ delete residual;
+
+ delete imgFinal;
+
+
+ }
+
+ inputFile.close();
+ outputFile.close();
+
+ return 0;
+}
+
+
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon, bool colorLookingFor)
+{
+ assert(residual != NULL);
+
+ if (eightCon == true)
+ eightConnObj(img, x, y, shape, colorLookingFor);
+ else {
+ fourConnObj(img, x, y, shape, colorLookingFor);
+ }
+}
+
+int barrier = 1000;
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // originalpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono originalpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && originalpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && originalpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ fourConnObj(img, x+1, y, obj, color);
+ fourConnObj(img, x, y-1, obj, color);
+
+ fourConnObj(img, x-1, y, obj, color);
+ fourConnObj(img, x, y+1, obj, color);
+ }
+
+}
+
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // originalpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono originalpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && originalpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && originalpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// //cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ eightConnObj(img, x+1, y, obj, color);
+ eightConnObj(img, x+1, y-1, obj, color);
+ eightConnObj(img, x, y-1, obj, color);
+ eightConnObj(img, x-1, y-1, obj, color);
+
+ eightConnObj(img, x-1, y, obj, color);
+ eightConnObj(img, x-1, y+1, obj, color);
+ eightConnObj(img, x, y+1, obj, color);
+ eightConnObj(img, x+1, y+1, obj, color);
+
+ }
+
+}
+
+// Aspect Ratio
+pair<int,int> getCentroid(vector<pair<int,int> > & points)
+{
+ pair<int,int> centroid;
+ centroid.first = 0;
+ centroid.second = 0;
+
+ for (unsigned int i = 0; i<points.size(); i++)
+ {
+ centroid.first += points[i].first;
+ centroid.second += points[i].second;
+ }
+
+ centroid.first = roundT(double(centroid.first)/points.size());
+ centroid.second = roundT(double(centroid.second)/points.size());
+
+ return centroid;
+}
+
+
+vector<double> covariantDecomposition(vector<pair<int,int> > & points)
+{
+ unsigned int i,j,k;
+ pair<int,int> centroid = getCentroid(points);
+ vector<double> retval;
+
+ gsl_matrix* matrice = gsl_matrix_alloc(2, 2);
+
+ double sumX2 = 0, sumXY = 0, sumY2 = 0;
+ for (k = 0; k<points.size(); k++)
+ {
+ sumX2 += pow(double(points[k].first - centroid.first),2.0);
+ sumY2 += pow(double(points[k].second - centroid.second),2.0);
+ // should we take the absolute value of X*Y
+ sumXY += (points[k].first - centroid.first) * (points[k].second - centroid.second);
+ }
+ gsl_matrix_set(matrice, 0, 0, roundT(sumX2/points.size()));
+ gsl_matrix_set(matrice, 0, 1, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 0, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 1, roundT(sumY2/points.size()));
+
+ // outputMatrix("Covariant", matrice);
+
+ // This function allocates a workspace for computing eigenvalues of n-by-n
+ // real symmetric matrices. The size of the workspace is O(2n).
+ gsl_eigen_symmv_workspace* eigenSpace = gsl_eigen_symmv_alloc(2);
+ gsl_vector* eigenVal = gsl_vector_alloc(2);
+ gsl_matrix* eigenVec = gsl_matrix_alloc(2, 2);
+ // This function computes the eigenvalues and eigenvectors of the real
+ // symmetric matrix A. Additional workspace of the appropriate size must be
+ // provided in w. The diagonal and lower triangular part of A are destroyed
+ // during the computation, but the strict upper triangular part is not
+ // referenced. The eigenvalues are stored in the vector eval and are unordered.
+ // The corresponding eigenvectors are stored in the columns of the matrix evec.
+ // For example, the eigenvector in the first column corresponds to the first
+ // eigenvalue. The eigenvectors are guaranteed to be mutually orthogonal and
+ // normalised to unit magnitude.
+ gsl_eigen_symmv (matrice, eigenVal, eigenVec, eigenSpace);
+ gsl_eigen_symmv_free (eigenSpace);
+
+ gsl_eigen_symmv_sort(eigenVal, eigenVec, GSL_EIGEN_SORT_VAL_ASC);
+
+ for (i = 0; i<eigenVal->size; i++)
+ retval.push_back(gsl_vector_get(eigenVal, i));
+
+ for (j = 0; j<eigenVec->size2; j++)
+ for (i = 0; i<eigenVec->size1; i++)
+ retval.push_back(gsl_matrix_get(eigenVec, i, j));
+
+ retval.push_back(static_cast<double>(centroid.first));
+ retval.push_back(static_cast<double> (centroid.second));
+
+// for (i=0; i<2; i++) {
+// gsl_vector_view evec_i = gsl_matrix_column (eigenVec, i);
+// //printf ("eigenvalue = %g\n", eval_i);
+// cout<<"eigenvector = \n";
+// gsl_vector_fprintf (stdout, &evec_i.vector, "%g");
+// }
+
+ gsl_vector_free(eigenVal);
+ gsl_matrix_free(matrice);
+ gsl_matrix_free(eigenVec);
+
+ return retval;
+}
+
+// isInterface for binary image
+bool isInterface(Image* orig, unsigned int x, unsigned int y)
+{
+ // Get the current pixel's color
+ ColorMono currentpixel = (ColorMono)orig->pixelColor(x,y);
+ // If the current pixel is black pixel then it is not boundary pixel
+ // error check
+ if (currentpixel.mono() == false)
+ return false;
+
+ // If the current pixel is not black then it is white. So, now we need
+ // to check whether any four of its neighbor pixels (left, top, right,
+ // bottom ) is black. If any of this neighbor is black then current
+ // pixel is a neighbor pixel. Otherwise current pixel is not neighbor
+ // pixel.
+
+ ColorMono leftneighborpixel = (ColorMono)orig->pixelColor(x-1,y);
+ ColorMono topneighborpixel = (ColorMono)orig->pixelColor(x,y-1);
+ ColorMono rightneighborpixel = (ColorMono)orig->pixelColor(x+1,y);
+ ColorMono bottomneighborpixel = (ColorMono)orig->pixelColor(x,y+1);
+
+ // If leftneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ if ( leftneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If topneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ else if (topneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If rightneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (rightneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If bottomneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (bottomneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // Else all of its neighbor pixels are white so it can not be a
+ // boundary pixel
+ else
+ return false;
+
+} \ No newline at end of file
diff --git a/fly-tools/FlyTrackingIterativeFilter.cpp b/fly-tools/FlyTrackingIterativeFilter.cpp
new file mode 100644
index 0000000..8ecb55b
--- /dev/null
+++ b/fly-tools/FlyTrackingIterativeFilter.cpp
@@ -0,0 +1,707 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <cmath>
+#include <vector>
+#include <list>
+#include <fstream>
+#include <cassert>
+#include <cstdlib>
+#include <queue>
+
+#include <ImageMagick/Magick++.h>
+
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_eigen.h>
+
+#include "FrameInfo.h"
+#include "MyPair.h"
+
+using namespace Magick;
+using namespace std;
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon=true, bool colorLookingFor=true);
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+void findObjIterative(Image* img, int x, int y, vector<pair<int, int> > & shape, bool eightCon, double colorLookingFor);
+void fourConnObjIterative(Image* img, int x, int y, vector<pair<int, int> > & obj, double colorLookingFor);
+vector<double> covariantDecomposition(vector<pair<int,int> > & points);
+pair<int,int> getCentroid(vector<pair<int,int> > & points);
+bool isInterface(Image* orig, unsigned int x, unsigned int y);
+void writeFrameImage(int fn, string imS);
+int roundT(double v) {return int(v+0.5);}
+
+
+const double PI = atan(1.0)*4.0;
+const double FACTOR_EIGEN = 100;
+
+Image* residual;
+Image* imgForFilter;
+
+ostream &operator<<(ostream &out, FlyObject & fO) {
+ fO.output(out);
+ return out;
+}
+
+ostream &operator<<(ostream &out, FrameInfo & fI) {
+ fI.output(out);
+ return out;
+}
+
+vector<vector<pair<int, int> > > shapeVectors;
+vector<pair<int,int> > shape;
+vector<pair<int, int> > sizeNIndexVector;
+
+void bubbleSort() {
+
+ for(int i=1; i<sizeNIndexVector.size(); i++) {
+ for(int j=0; j<sizeNIndexVector.size()-i; j++) {
+ pair<int, int> a = sizeNIndexVector[j];
+ pair<int, int> b = sizeNIndexVector[j+1];
+
+ if (a.first < b.first) {
+ pair<int, int> c = sizeNIndexVector[j];
+ sizeNIndexVector[j] = sizeNIndexVector[j+1];
+ sizeNIndexVector[j+1] = c;
+ }
+ }
+ }
+
+}
+
+void fillResidualWithObj(vector<pair<int, int> > & obj, ColorRGB c)
+{
+ for (unsigned int i = 0; i<obj.size(); i++)
+ residual->pixelColor(obj[i].first, obj[i].second, c);
+}
+
+void writeHist(const char* filename, map<unsigned int, unsigned int> & len)
+{
+ map<unsigned int,unsigned int>::iterator front = len.begin(),
+ back = len.end();
+ back--;
+
+
+ unsigned int first = front->first, last = back->first;
+ /*if (cutoff != -1 && cutoff < int(last))
+ last = cutoff;
+ */
+ cout << "Min: " << first << endl
+ << "Max: " << last << endl
+ << "Count: " << last-first << endl;
+ //vector<unsigned int> hist(last-first, 0);
+ vector<unsigned int> hist(last+1, 0);
+
+ cout << "hist size: " << hist.size() << endl;
+ try{
+ for(unsigned int j = 0; j<first; j++) {
+ hist[j] = 0;
+ }
+ for (unsigned int j = first; j<=last; j++)
+ {
+ /*if ( roundT(j-first) >= int(hist.size()) )
+ hist.resize(j-first,0);
+ hist[roundT(j-first)] = len[j];
+ */
+
+ /*if ( roundT(j) >= int(hist.size()) )
+ hist.resize(j,0);
+ hist[roundT(j)] = len[j];
+ */
+ hist[j] = len[j];
+ }
+ }
+ catch (...)
+ { cerr << "Bad histogram bucketing" << endl; }
+
+ /*if ( (cutoff >= 0) && (cutoff<int(hist.size())) )
+ hist.resize(cutoff);
+ */
+ len.clear();
+ try
+ {
+ ofstream fout(filename);
+ for (unsigned int i = 0; i<hist.size(); i++) {
+ fout << hist[i] << endl;
+ }
+ fout << first << " " << last << " " << hist.size() << endl;
+ fout.close();
+ }
+ catch (...)
+ { cerr << "Bad memory loc for opening file" << endl; }
+}
+
+
+int main(int argc, char* argv[])
+{
+ if (argc < 5)
+ {
+
+ cerr << "Usage: executablename <filename> <ratio_largest_to_second_largest> <InputLocationOfMaskImage> <outputFolderName>" << endl; // input file contains name of the
+ // input image files
+ return -1;
+ }
+
+ //MagickCore::SetMagickResourceLimit(MagickCore::MemoryResource, 1536);
+ //MagickCore::SetMagickResourceLimit(MagickCore::MapResource, 2048);
+
+
+ // Arg 1 is a file name, this is the actual name (First10MinSet48_0000001.png)
+ string fileName = argv[1];
+ // Arg 2 is the ratio of the second largest to largest. Use 15.
+ double ratioSecondLargestToLargest = atof(argv[2]);
+ // Arg 3 is the location of the Masks
+ string inputMaskFileLocation(argv[3]);
+ // Arg 4 is the output folder for the Filtered images.
+ string outputFileLocation(argv[4]);
+
+ ratioSecondLargestToLargest = 1/ratioSecondLargestToLargest;
+
+ char buffer[100];
+
+ string savedFileName = fileName;
+ string finalImageName = outputFileLocation + "final/"+ savedFileName;
+
+ // get the input mask file
+ fileName = inputMaskFileLocation + fileName;
+
+ Image* original = new Image(fileName.c_str());
+ int width = original->columns();
+ int height = original->rows();
+ sprintf(buffer,"%ix%i",width,height);
+
+ imgForFilter = new Image(buffer, "white");
+ shape.clear();
+
+ // find the black background from location (0,0)
+ ColorMono topLeftColor = ColorMono(original->pixelColor(0,0));
+ ColorMono topRightColor = ColorMono(original->pixelColor(width-1,0));
+ ColorMono bottomRightColor = ColorMono(original->pixelColor(width-1,height-1));
+ ColorMono bottomLeftColor = ColorMono(original->pixelColor(0,height-1));
+
+ if (topLeftColor.mono() == false) {
+
+ findObjIterative(original, 0, 0, shape, false, 0.0);
+
+ } else if (topRightColor.mono() == false) {
+
+ cout << "Top left is not black pixel for FLOOD FILLING so flood filling from top right\n";
+ findObjIterative(original, width-1, 0, shape, false, 0.0);
+
+ } else if (bottomRightColor.mono() == false) {
+
+ cout << "Top left/Top right are not black pixel for FLOOD FILLING so flood filling from bottom right\n";
+ findObjIterative(original, width-1, height-1, shape, false, 0.0);
+
+ } else {
+
+ cout << "Top left/top right/bottom right are not black pixel for FLOOD FILLING so flood filling from the bottomleft\n";
+ findObjIterative(original, 0, height-1, shape, false, 0.0);
+
+ }
+
+ string inputFileName = outputFileLocation + "temp/" + savedFileName;
+
+ Image* final_image = imgForFilter;
+
+
+ sprintf(buffer,"%ix%i",width,height);
+
+ // residual image is initialized with black representing not visited.
+ residual = new Image(buffer, "black");
+
+
+ shapeVectors.clear();
+ sizeNIndexVector.clear();
+
+ // find the objects and sort according to size
+ int objectCounter = 0;
+ for (int x=0; x<width; x++) {
+ for (int y=0; y<height; y++) {
+ // find the white object using eight connected
+ shape.clear();
+ findObj(final_image, x, y, shape, true, true);
+ int s = shape.size();
+
+ if (s > 0) {
+ shapeVectors.push_back(shape);
+ pair<int, int> si(s, objectCounter);
+ sizeNIndexVector.push_back(si);
+ objectCounter++;
+ }
+ }
+ }
+
+
+ bubbleSort();
+
+ // take the largest object
+ double currentLargestSize = static_cast<double>(sizeNIndexVector[0].first);
+ double secondLargest = 0;
+ double ratio = 0;
+
+ if (sizeNIndexVector.size() > 1) {
+
+ secondLargest = static_cast<double>(sizeNIndexVector[1].first);
+ ratio = secondLargest/currentLargestSize;
+
+ }
+
+ // find the largest to second largest ratio if it is less than the defined ratio then
+ // the objects are single object
+
+ int numberOfObjects = 0;
+
+ if (sizeNIndexVector.size() == 1) {
+ numberOfObjects = 1;
+ }
+ else if (ratio <= ratioSecondLargestToLargest ) {
+ numberOfObjects = 1;
+ } else {
+ numberOfObjects = 2;
+ }
+
+ Image* imgFinal = new Image(buffer, "black");
+
+ for (int n=0; n<numberOfObjects; n++) {
+
+ int totalPoints = sizeNIndexVector[n].first;
+
+ for (int i=0; i<totalPoints; i++) {
+
+ imgFinal->pixelColor(shapeVectors[ sizeNIndexVector[n].second ][i].first, shapeVectors[ sizeNIndexVector[n].second ][i].second, "white");
+ }
+
+ }
+
+ // write final image
+ cout << finalImageName << " \r";
+ imgFinal->write( finalImageName.c_str() );
+
+{
+// // writing the single in red
+// if (numberOfObjects == 1) {
+//
+// Image* singleObjectFinal = new Image(buffer, "black");
+//
+// int totalPoints = sizeNIndexVector[0].first;
+//
+// cout << "Output the single object of size = "<<totalPoints<<endl;
+//
+// for (int i=0; i<totalPoints; i++) {
+//
+// singleObjectFinal->pixelColor(shapeVectors[ sizeNIndexVector[0].second ][i].first, shapeVectors[ sizeNIndexVector[0].second ][i].second, "red");
+// }
+//
+// //string singleImageName = "output/filtered/single/"+fileName;
+// string singleImageName = outputFileLocation + "single/"+ savedFileName;
+//
+// singleObjectFinal->write(singleImageName.c_str());
+//
+// }
+//
+}
+
+ return 0;
+}
+
+void findObjIterative(Image* img, int x, int y, vector<pair<int, int> > & shape, bool eightCon, double colorLookingFor) {
+
+ assert(imgForFilter != NULL);
+
+ //if (eightCon == true)
+ // eightConnObjIterative(img, x, y, shape, colorLookingFor);
+ //else {
+ fourConnObjIterative(img, x, y, shape, colorLookingFor);
+
+ //}
+
+
+}
+
+void fourConnObjIterative(Image* img, int x, int y, vector<pair<int, int> > & obj, double colorLookingFor) {
+
+ /*
+ Flood-fill (node, target-color, replacement-color):
+ 1. Set Q to the empty queue.
+ 2. If the color of node is not equal to target-color, return.
+ 3. Add node to Q.
+ 4. For each element n of Q:
+ 5. If the color of n is equal to target-color:
+ 6. Set w and e equal to n.
+ 7. Move w to the west until the color of the node to the west of w no longer matches target-color.
+ 8. Move e to the east until the color of the node to the east of e no longer matches target-color.
+ 9. Set the color of nodes between w and e to replacement-color.
+ 10. For each node n between w and e:
+ 11. If the color of the node to the north of n is target-color, add that node to Q.
+ If the color of the node to the south of n is target-color, add that node to Q.
+ 12. Continue looping until Q is exhausted.
+ 13. Return.
+
+ */
+
+
+ queue< MyPair > Q;
+
+ ColorRGB imgpixel = ColorRGB(img->pixelColor(x,y));
+
+ if ( (imgpixel.red() != colorLookingFor) and (imgpixel.green() != colorLookingFor) and (imgpixel.blue() != colorLookingFor)) {
+
+ cout << "Returning without floodfilling because the first pixel is not the colorLookingFor"<<endl;
+ return;
+
+ }
+
+ Q.push( MyPair(x,y));
+
+ int width = img->columns(),height = img->rows();
+
+ while (Q.empty() != true) {
+
+ MyPair n = Q.front();
+ Q.pop();
+
+ ColorRGB westColor;
+ ColorRGB eastColor;
+ ColorRGB nColor;
+ MyPair i,j;
+
+ nColor = ColorRGB(img->pixelColor(n.first, n.second));
+
+ if ( (nColor.red() == colorLookingFor) and (nColor.green() == colorLookingFor) and (nColor.blue() == colorLookingFor)) {
+
+ //cout << "Current pixel is of the black color ("<<n.first<<","<<n.second<<") and Q size is = "<<Q.size()<<endl;
+ MyPair w, e;
+ w = n;
+ e = n;
+
+ // move w to the west until the color of the node to the west of w no longer matches target-color.
+ do {
+ // move to west
+ i = w;
+ w.first = w.first - 1;
+ // color at w
+ if ( w.first >=0 )
+ westColor = ColorRGB(img->pixelColor(w.first, w.second));
+ else {
+ //cout << "outside of the image boundary in x direction so break the while loop for west"<<endl;
+ break;
+ }
+
+
+ } while ( (westColor.red() == colorLookingFor) and (westColor.green() == colorLookingFor) and (westColor.blue() == colorLookingFor) );
+
+
+
+ // move e to the east until the color of the node to the east of e no longer matches target-color.
+ do {
+
+ j = e;
+ // move to east
+ e.first = e.first + 1;
+ // color of e
+ if ( e.first < width )
+ eastColor = ColorRGB(img->pixelColor(e.first, e.second));
+ else {
+ //cout << "outside of the image boundary in x direction so break the while loop for east"<<endl;
+ break;
+ }
+
+ } while ((eastColor.red() == colorLookingFor) and (eastColor.green() == colorLookingFor) and (eastColor.blue() == colorLookingFor));
+
+
+ //cout << "Current pixel west to east span is from ("<<i.first<<","<<i.second<<") to "<<j.first<<","<<j.second<<")"<<endl;
+ // Set the color of nodes between w and e to replacement-color
+ while ( i.first <= j.first ) {
+
+ // set the color to black which is the replacement color
+ // for our algorithm it is the colorLookingFor
+ imgForFilter->pixelColor(i.first, i.second, ColorRGB(colorLookingFor, colorLookingFor, colorLookingFor) );
+
+ // change the color to green to indicate that it is visited
+ img->pixelColor(i.first, i.second, ColorRGB(0.0, 1.0, 0.0));
+
+ //cout << "Current pixel visited "<<i.first<<","<<i.second<<endl;
+
+ // If the color of the node to the north of n is target-color, add that node to Q.
+ if ( i.second-1 >=0 ) {
+
+ MyPair n(i.first, i.second-1);
+ ColorRGB northColor = ColorRGB(img->pixelColor(n.first, n.second));
+ if ((northColor.red() == colorLookingFor) and (northColor.green() == colorLookingFor) and (northColor.blue() == colorLookingFor)) {
+ Q.push(n);
+ //cout << "North pixel not visited so pushed "<<n.first<<","<<n.second<<endl;
+ }// else {
+ //cout << "North pixel visited so not pushed"<<endl;
+ //}
+
+ }
+
+
+ // If the color of the node to the south of n is target-color, add that node to Q.
+ if (i.second+1 < height) {
+ MyPair s(i.first, i.second+1);
+ ColorRGB southColor = ColorRGB(img->pixelColor(s.first, s.second));
+ //cout << "South color "<<southColor.red() << " "<< southColor.green() <<" "<< southColor.blue()<< endl;
+ if ((southColor.red() == colorLookingFor) and (southColor.green() == colorLookingFor) and (southColor.blue() == colorLookingFor)) {
+ Q.push(s);
+ //cout<<"South pixel not visited so pushed "<<s.first<<","<<s.second<<endl;
+ } //else {
+ //cout<<"South pixel visited so not pushed"<<endl;
+ //}
+
+ }
+
+ i.first = i.first + 1;
+
+ }
+
+ // next step of the main while loop
+ //cout << "Processed "<<n.first<<","<<n.second<<endl;
+
+ } //else {
+ //cout << "Current pixel is not of the black color so just discarded ("<<n.first<<","<<n.second<<") and Q size is = "<<Q.size()<<endl;
+ //}
+
+
+ }
+
+}
+
+
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon, bool colorLookingFor)
+{
+ assert(residual != NULL);
+
+ if (eightCon == true)
+ eightConnObj(img, x, y, shape, colorLookingFor);
+ else {
+ fourConnObj(img, x, y, shape, colorLookingFor);
+ }
+}
+
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // imgpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono imgpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && imgpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && imgpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ fourConnObj(img, x+1, y, obj, color);
+ fourConnObj(img, x, y-1, obj, color);
+
+ fourConnObj(img, x-1, y, obj, color);
+ fourConnObj(img, x, y+1, obj, color);
+ }
+
+}
+
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // imgpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono imgpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && imgpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && imgpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// //cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ eightConnObj(img, x+1, y, obj, color);
+ eightConnObj(img, x+1, y-1, obj, color);
+ eightConnObj(img, x, y-1, obj, color);
+ eightConnObj(img, x-1, y-1, obj, color);
+
+ eightConnObj(img, x-1, y, obj, color);
+ eightConnObj(img, x-1, y+1, obj, color);
+ eightConnObj(img, x, y+1, obj, color);
+ eightConnObj(img, x+1, y+1, obj, color);
+
+ }
+
+}
+
+
+// Aspect Ratio
+pair<int,int> getCentroid(vector<pair<int,int> > & points)
+{
+ pair<int,int> centroid;
+ centroid.first = 0;
+ centroid.second = 0;
+
+ for (unsigned int i = 0; i<points.size(); i++)
+ {
+ centroid.first += points[i].first;
+ centroid.second += points[i].second;
+ }
+
+ centroid.first = roundT(double(centroid.first)/points.size());
+ centroid.second = roundT(double(centroid.second)/points.size());
+
+ return centroid;
+}
+
+
+vector<double> covariantDecomposition(vector<pair<int,int> > & points)
+{
+ unsigned int i,j,k;
+ pair<int,int> centroid = getCentroid(points);
+ vector<double> retval;
+
+ gsl_matrix* matrice = gsl_matrix_alloc(2, 2);
+
+ double sumX2 = 0, sumXY = 0, sumY2 = 0;
+ for (k = 0; k<points.size(); k++)
+ {
+ sumX2 += pow(double(points[k].first - centroid.first),2.0);
+ sumY2 += pow(double(points[k].second - centroid.second),2.0);
+ // should we take the absolute value of X*Y
+ sumXY += (points[k].first - centroid.first) * (points[k].second - centroid.second);
+ }
+ gsl_matrix_set(matrice, 0, 0, roundT(sumX2/points.size()));
+ gsl_matrix_set(matrice, 0, 1, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 0, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 1, roundT(sumY2/points.size()));
+
+ // outputMatrix("Covariant", matrice);
+
+ // This function allocates a workspace for computing eigenvalues of n-by-n
+ // real symmetric matrices. The size of the workspace is O(2n).
+ gsl_eigen_symmv_workspace* eigenSpace = gsl_eigen_symmv_alloc(2);
+ gsl_vector* eigenVal = gsl_vector_alloc(2);
+ gsl_matrix* eigenVec = gsl_matrix_alloc(2, 2);
+ // This function computes the eigenvalues and eigenvectors of the real
+ // symmetric matrix A. Additional workspace of the appropriate size must be
+ // provided in w. The diagonal and lower triangular part of A are destroyed
+ // during the computation, but the strict upper triangular part is not
+ // referenced. The eigenvalues are stored in the vector eval and are unordered.
+ // The corresponding eigenvectors are stored in the columns of the matrix evec.
+ // For example, the eigenvector in the first column corresponds to the first
+ // eigenvalue. The eigenvectors are guaranteed to be mutually orthogonal and
+ // normalised to unit magnitude.
+ gsl_eigen_symmv (matrice, eigenVal, eigenVec, eigenSpace);
+ gsl_eigen_symmv_free (eigenSpace);
+
+ gsl_eigen_symmv_sort(eigenVal, eigenVec, GSL_EIGEN_SORT_VAL_ASC);
+
+ for (i = 0; i<eigenVal->size; i++)
+ retval.push_back(gsl_vector_get(eigenVal, i));
+
+ for (j = 0; j<eigenVec->size2; j++)
+ for (i = 0; i<eigenVec->size1; i++)
+ retval.push_back(gsl_matrix_get(eigenVec, i, j));
+
+ retval.push_back(static_cast<double>(centroid.first));
+ retval.push_back(static_cast<double> (centroid.second));
+
+// for (i=0; i<2; i++) {
+// gsl_vector_view evec_i = gsl_matrix_column (eigenVec, i);
+// //printf ("eigenvalue = %g\n", eval_i);
+// cout<<"eigenvector = \n";
+// gsl_vector_fprintf (stdout, &evec_i.vector, "%g");
+// }
+
+ gsl_vector_free(eigenVal);
+ gsl_matrix_free(matrice);
+ gsl_matrix_free(eigenVec);
+
+ return retval;
+}
+
+// isInterface for binary image
+bool isInterface(Image* orig, unsigned int x, unsigned int y)
+{
+ ColorMono currentpixel = (ColorMono)orig->pixelColor(x,y);
+ // If the current pixel is black pixel then it is not boundary pixel
+ // error check
+ if (currentpixel.mono() == false)
+ return false;
+
+ // If the current pixel is not black then it is white. So, now we need
+ // to check whether any four of its neighbor pixels (left, top, right,
+ // bottom ) is black. If any of this neighbor is black then current
+ // pixel is a neighbor pixel. Otherwise current pixel is not neighbor
+ // pixel.
+
+ ColorMono leftneighborpixel = (ColorMono)orig->pixelColor(x-1,y);
+ ColorMono topneighborpixel = (ColorMono)orig->pixelColor(x,y-1);
+ ColorMono rightneighborpixel = (ColorMono)orig->pixelColor(x+1,y);
+ ColorMono bottomneighborpixel = (ColorMono)orig->pixelColor(x,y+1);
+
+ // If leftneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ if ( leftneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If topneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ else if (topneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If rightneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (rightneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If bottomneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (bottomneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // Else all of its neighbor pixels are white so it can not be a
+ // boundary pixel
+ else
+ return false;
+
+}
diff --git a/fly-tools/FlyTrackingMain.cpp b/fly-tools/FlyTrackingMain.cpp
new file mode 100644
index 0000000..4114a08
--- /dev/null
+++ b/fly-tools/FlyTrackingMain.cpp
@@ -0,0 +1,3181 @@
+#include <iostream>
+#include<iomanip>
+#include <string>
+#include <sstream>
+#include <cmath>
+#include <vector>
+#include <list>
+#include <fstream>
+#include <cassert>
+#include <cstdlib>
+
+#include <ImageMagick/Magick++.h>
+
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_eigen.h>
+
+#include "FrameInfo.h"
+
+using namespace Magick;
+using namespace std;
+
+const double PI = atan(1.0)*4.0;
+const double FACTOR_EIGEN = 100;
+const int STUCKING_TO_A_SINGLE_BLOB = 1;
+const int SEPARATING_FROM_SINGLE_BLOB = 2;
+
+
+Image* residual;
+
+vector<FlyObject > fOVector;
+vector<FrameInfo > fIVector;
+// temporary store of the frames for finding initial head direction
+vector<FrameInfo > fIForHeadVector;
+// since for the first time the head is automatically need to be set
+int startIndexToFindNewHead=0;
+int endIndexToFindNewHead;
+double initLargeLocationX=-1;
+double initLargeLocationY=-1;
+double initSmallLocationX=-1;
+double initSmallLocationY=-1;
+pair<double, double> largeCollisionBeforeDirection;
+pair<double, double> smallCollisionBeforeDirection;
+
+// start location in the vector where two object get together
+int startIndexSingleBlob=-1;
+int endIndexSingleBlob =-1;
+
+// indices of the new set of sequences
+int startOfATrackSequence = 0; // fix it later on inside main
+int endOfATrackSequence=-1;
+int sequenceSize=1;
+
+// indices for printing the one object frames
+int startOfAOneObject = -1;
+int endOfAOneObject = -1;
+
+vector<string> fnVector;
+string inputFileName;
+
+// GLOBAL PATHS
+string maskImagePath;
+string origImagePath;
+string finalOutputPath;
+string outputFilePrefix;
+
+vector<pair<double, double> > velocityDirectionsF;
+vector<pair<double, double> > velocityDirectionsS;
+
+pair<double, double> avgVelocityF;
+pair<double, double> avgVelocityS;
+
+pair<double, double> overAllVelocityF;
+pair<double, double> overAllVelocityS;
+
+vector<pair<double, double> > evDirectionF;
+vector<pair<double, double> > evDirectionS;
+
+int totalMaleLookingAtFemale = 0;
+int totalFemaleLookingAtMale = 0;
+int totalSingleBlob = 0;
+int totalUnprocessedFrame = 0;
+int totalSeparated = 0;
+map<unsigned int, unsigned int> centroidDistanceMap;
+map<unsigned int, unsigned int> headDirAngleMap;
+map<unsigned int, unsigned int> speedMap;
+
+void initSequence(){
+
+ startOfATrackSequence = -1;
+ endOfATrackSequence = -1;
+ sequenceSize = 1;
+
+
+}
+
+ostream &operator<<(ostream &out, FlyObject & fO) {
+ fO.output(out);
+ return out;
+}
+
+ostream &operator<<(ostream &out, FrameInfo & fI) {
+ fI.output(out);
+ return out;
+}
+
+void bubbleSort(vector<FlyObject > & fov) {
+
+ //FlyObject a,b,c;
+ for(int i=1; i<fov.size(); i++) {
+ for(int j=0; j<fov.size()-i; j++) {
+ FlyObject a = fov[j];
+ FlyObject b = fov[j+1];
+
+ if (a.getArea() < b.getArea()) {
+ FlyObject c = fov[j];
+ fov[j] = fov[j+1];
+ fov[j+1] = c;
+
+ }
+
+ }
+
+ }
+
+}
+
+void writeHist(const char* filename, map<unsigned int, unsigned int> dataMap)
+{
+ cout << "In the beginning of the write hist\n";
+ cout << "dataMap size "<<dataMap.size()<<endl;
+ if (dataMap.size() == 0) {
+ cout << "Empty histogram"<<endl;
+ ofstream fout(filename);
+ fout <<"No entry in the histogram and size is " << dataMap.size() << endl;
+ fout.close();
+ return;
+
+ }
+
+ map<unsigned int, unsigned int>::iterator front = dataMap.begin(),
+ back = dataMap.end();
+ back--;
+
+
+ unsigned int first = front->first, last = back->first;
+ cout << "Min: " << first << endl<< "Max: " << last << endl<< "Count: " << last-first << endl;
+ //vector<unsigned int> hist(last-first, 0);
+ vector<unsigned int> hist(last+1, 0);
+
+ cout << "hist size: " << hist.size() << endl;
+ try{
+ for(unsigned int j = 0; j<first; j++) {
+ hist[j] = 0;
+ }
+ for (unsigned int j = first; j<=last; j++)
+ {
+ /*if ( roundT(j-first) >= int(hist.size()) )
+ hist.resize(j-first,0);
+ hist[roundT(j-first)] = len[j];
+ */
+
+ /*if ( roundT(j) >= int(hist.size()) )
+ hist.resize(j,0);
+ hist[roundT(j)] = len[j];
+ */
+ hist[j] = dataMap[j];
+ }
+ }
+ catch (...)
+ { cerr << "Bad histogram bucketing" << endl; }
+
+ try
+ {
+ ofstream fout(filename);
+ for (unsigned int i = 0; i<hist.size(); i++) {
+ fout << hist[i] << endl;
+ }
+ fout << first << " " << last << " " << hist.size() << endl;
+ fout.close();
+ }
+ catch (...)
+ { cerr << "Bad memory loc for opening file" << endl; }
+}
+
+
+
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon=true, bool colorLookingFor=true);
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+vector<double> covariantDecomposition(vector<pair<int,int> > & points);
+pair<int,int> getCentroid(vector<pair<int,int> > & points);
+bool isInterface(Image* orig, unsigned int x, unsigned int y);
+void writeFrameImage(int fn, string imS);
+void drawTheFlyObject(FrameInfo currentFI, string fileName, int isFirst, bool singleBlob=false,bool unprocessed = false);
+void drawTheSequence(int startIndex, int endIndex, int isFirst, bool singleBlob = false, bool unprocessed = false);
+double euclideanDist(FlyObject a, FlyObject b);
+bool identifyFlyObjectFromFrameToFrame(FrameInfo prevFI, FrameInfo& currentFI, bool gotRidOfSingleBlob=false) ;
+int roundT(double v) {return int(v+0.5);}
+void determineHeadDirection(int fileCounter);
+
+
+void normalizeVector(pair<double,double> &a);
+double calculateDotProduct(pair<double, double> v, pair<double, double> eV);
+void calculateHeadVector(FlyObject fO, pair<double,double> &headDirection);
+
+void normalizeVector(pair<double,double> &a) {
+ double temp = a.first*a.first + a.second*a.second;
+ temp = sqrt(temp);
+ if (temp != 0) {
+ a.first = a.first/temp;
+ a.second = a.second/temp;
+ }
+}
+double calculateDotProduct(pair<double, double> v, pair<double, double> eV) {
+ return (v.first*eV.first + v.second*eV.second);
+}
+void calculateHeadVector(FlyObject fO, pair<double,double> &headDirection) {
+ bool headDirectionBool = fO.getHeadIsInDirectionMAEV();
+ pair<double,double> fOMajorAxis = fO.getMajorAxisEV();
+ if (headDirectionBool == true) {
+ headDirection.first = fOMajorAxis.first;
+ headDirection.second = fOMajorAxis.second;
+ } else {
+ headDirection.first = -fOMajorAxis.first;
+ headDirection.second = -fOMajorAxis.second;
+ }
+}
+
+void determineHeadDirection(int fileCounter) {
+
+ FrameInfo prevFI = fIVector[fileCounter-1];
+ FrameInfo currentFI = fIVector[fileCounter];
+
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ FlyObject pFLargeFO = pFOVector[0];
+ FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ // calculate velocity
+ pair<int,int> pFLCentroid = pFLargeFO.getCentroid();
+ pair<int,int> pFSCentroid = pFSmallFO.getCentroid();
+
+ pair<int,int> cFLCentroid = cFLargeFO.getCentroid();
+ pair<int,int> cFSCentroid = cFSmallFO.getCentroid();
+
+ double velocityXLarge = static_cast<double> (cFLCentroid.first) - static_cast<double> (pFLCentroid.first);
+ double velocityYLarge = static_cast<double> (cFLCentroid.second) - static_cast<double> (pFLCentroid.second);
+
+ double velocityXSmall = static_cast<double> (cFSCentroid.first) - static_cast<double> (pFSCentroid.first);
+ double velocityYSmall = static_cast<double> (cFSCentroid.second) - static_cast<double> (pFSCentroid.second);
+
+ pair<double,double> cLVV(velocityXLarge,velocityYLarge);
+ pair<double,double> cSVV(velocityXSmall,velocityYSmall);
+
+ cFLargeFO.setVelocityV(cLVV);
+ cFSmallFO.setVelocityV(cSVV);
+
+ // normalize the velocity
+ cFLargeFO.normalizeVelocity();
+ cFSmallFO.normalizeVelocity();
+
+ // determine the head direction for larger object
+ pair<double, double> cLEV = cFLargeFO.getMajorAxisEV();
+ // normalize the eigenvector
+ normalizeVector(cLEV);
+ pair<double,double> identifiedCLEV;
+
+ // the head from the previous frame
+ pair<double, double> pLH = pFLargeFO.getHead();
+
+ // find the dot product with the previous frame head with current major axis both direction
+ double largerDotProdPrevHeadAndCLEV = calculateDotProduct(pLH, cLEV);
+ pair<double,double> cLREV(-cLEV.first, -cLEV.second);
+ //double largerDotProdPrevHeadAndCLREV = calculateDotProduct(pLH, clREV);
+ if (largerDotProdPrevHeadAndCLEV >=0) {
+ cout << "Current eigen is in direction with the historical head"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cLEV.first+0.9*pLH.first;
+ double newHeadSecond = 0.1*cLEV.second+0.9*pLH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ cFLargeFO.setHead(newHead);
+ cFLargeFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ identifiedCLEV = cLEV;
+
+ } else {
+ cout << "Current eigen is in opposite direction of the historical head\n";
+ // record this vector
+ double newHeadFirst = 0.1*cLREV.first + 0.9*pLH.first;
+ double newHeadSecond =0.1*cLREV.second+0.9*pLH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ cFLargeFO.setHead(newHead);
+ cFLargeFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV to reverse direction of the current EV
+ identifiedCLEV = cLREV;
+
+ }
+
+
+ // tracking the forward and backward movement of the fly object
+ double largeDotProd = calculateDotProduct(cLVV, identifiedCLEV);
+ cout << "largerDotProd "<<largeDotProd<<endl;
+ if (largeDotProd >= 0) {
+ cout<<"Larger Dot prod is positive"<<endl;
+ // cFLargeFO.setHeadIsInDirectionMAEV(true);
+ } else {
+ cout<<"Larger Dot prod is negative"<<endl;
+ // cFLargeFO.setHeadIsInDirectionMAEV(false);
+ }
+
+
+ pair<double, double > cSEV = cFSmallFO.getMajorAxisEV();
+ normalizeVector(cSEV);
+ pair<double,double> identifiedCSEV;
+ // head from the previous frame
+ pair<double,double> pSH = pFSmallFO.getHead();
+
+ // find the dot product with the previous frame head with current major axis both direction
+ double smallerDotProdPrevHeadAndCSEV = calculateDotProduct(pSH, cSEV);
+ pair<double, double> cSREV(-cSEV.first, -cSEV.second);
+ if (smallerDotProdPrevHeadAndCSEV >=0) {
+ cout << "Current eigen is in direction with the historical head for the smaller fly object"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cSEV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSEV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+ cFSmallFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV to current EV
+ identifiedCSEV = cSEV;
+ } else {
+ cout << "Current eigen is in direction with the historical head for the smaller fly object"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cSREV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSREV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+ cFSmallFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV to reverse direction of current EV
+ identifiedCSEV = cSREV;
+
+ }
+
+ // to detect the swift change of head direction with 2 frames
+ // find previous frame's HD
+ pair<double, double> previousHeadDirection;
+ calculateHeadVector(pFSmallFO, previousHeadDirection);
+ // find the current frame's HD
+ pair<double, double> currentHeadDirection;
+ calculateHeadVector(cFSmallFO, currentHeadDirection);
+
+ // calculate the dot product of previous head direction and current head direction.
+ double previousHDDotCurrentHD = calculateDotProduct(previousHeadDirection, currentHeadDirection);
+ if (previousHDDotCurrentHD < 0 and fileCounter > 1) {
+
+ // now check if velocity direction( for the future historical velocity might be considered too) and
+ // current head direction dot product is also less than zero
+ // asssumption that current velocity and new head direction are towards same direction
+ // pair<double, double> currentVelocity = cFSmallFO.getVelocityV();
+ // double currentVVDotCurrentHD = calculateDotProduct(currentVelocity, currentHeadDirection);
+ // if (currentVVDotCurrentHD < 0)
+ {
+ // toggle current head direction
+ bool currentHeadDirectionBool = cFSmallFO.getHeadIsInDirectionMAEV();
+ if (currentHeadDirectionBool == true)
+ cFSmallFO.setHeadIsInDirectionMAEV(false);
+ else {
+ cFSmallFO.setHeadIsInDirectionMAEV(true);
+
+ }
+
+ // update the historical head
+ // reset historical head to conform to the swift change in head direction
+ bool cFSmallFOFinalHeadDirectionBool = cFSmallFO.getHeadIsInDirectionMAEV();
+ if (cFSmallFOFinalHeadDirectionBool == true) {
+ // record this vector for history
+ double newHeadFirst = cSEV.first;
+ double newHeadSecond = cSEV.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ } else {
+ // record this vector for history
+ double newHeadFirst = cSREV.first;
+ double newHeadSecond = cSREV.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ }
+
+
+ }
+ }
+
+ /* retain historical head
+ bool cFSmallFOFinalHeadDirectionBool = cFSmallFO.getHeadIsInDirectionMAEV();
+ if (cFSmallFOFinalHeadDirectionBool == true) {
+ // record this vector for history
+ double newHeadFirst = 0.1*cSEV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSEV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ } else {
+ // record this vector for history
+ double newHeadFirst = 0.1*cSREV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSREV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ }
+ */
+
+ double smallDotProd = calculateDotProduct(cSVV, cSEV);
+
+ if (smallDotProd >= 0) {
+ cout << "Smaller dot product is positive"<<endl;
+ // cFSmallFO.setHeadIsInDirectionMAEV(true);
+ } else {
+ cout << "Smaller dot product is negative"<<endl;
+ // cFSmallFO.setHeadIsInDirectionMAEV(false);
+ }
+
+
+ // update the flyobject vector
+ vector<FlyObject > updatedFOVector;
+ updatedFOVector.push_back(cFLargeFO);
+ updatedFOVector.push_back(cFSmallFO);
+
+ currentFI.setFOVector(updatedFOVector);
+
+ fIVector[fileCounter] = currentFI;
+
+ // cout << "checking the update"<<endl;
+ // FrameInfo tempFI = fIVector[fileCounter];
+ //
+ // vector<FlyObject > tempFIFOVector = tempFI.getFOVector();
+ // FlyObject tempFILFO = tempFIFOVector[0];
+ // FlyObject tempFISFO = tempFIFOVector[1];
+ // pair<double, double> tempFILFOVV = tempFILFO.getVelocityV();
+ // cout << "Large object velocity vector "<<tempFILFOVV.first<<","<<tempFILFOVV.second<<endl;
+ // pair<double,double > tempFISFOVV = tempFISFO.getVelocityV();
+ // cout << "Small object velocity vector "<<tempFISFOVV.first<<","<<tempFISFOVV.second<<endl;
+
+
+}
+
+/*
+void lookAt(int x, int y, jzImage& img)
+{
+ int imageWidth =img.width();
+ int imageHeight = img.height();
+ // if current pixel is white
+ if (img.pixelColor(x,y) == 1) {
+ // if it was the first white pixel then
+ if (!inWhite)
+ {
+ // check whether it started as a white pixel; if it started as white pixel then this line segment should
+ // not be counted. because it is part of the larger white blob
+ if ( (x == 0 || x == (imageWidth -1) ) || ( y == 0 || y == (imageHeight - 1)))
+ startedWhite = true;
+ inWhite = true;
+ x_init = x;
+ y_init = y;
+ }
+ // if we are on a white region
+ //else {
+
+ //}
+
+ }
+
+ if (img.pixelColor(x,y) == 0) {
+ // if we are going through a white line and reached the black pixel
+ if (inWhite)
+ {
+ // if the line started as a white pixel then discard the line fragment
+ if (startedWhite == false) {
+ int val = roundT(dist(x_init, y_init, x, y));
+ //cout<<" val is = " << val << " at (x0,y0) = " << x_init << "," << y_init << " to (x1,y1) = " << x << "," << y <<endl;
+ len[val]++;
+ } else
+ startedWhite = false;
+
+ inWhite = false;
+ }
+ }
+}
+
+void drawLine(int x0, int y0, int x1, int y1, jzImage& img)
+{
+ inWhite = false;
+ startedWhite = false;
+
+ // always go from x0 -> x1
+ if (x0 > x1)
+ {
+ int temp = x0;
+ x0 = x1;
+ x1 = temp;
+ temp = y0;
+ y0 = y1;
+ y1 = temp;
+ }
+
+ int dx, dy, d, x, y, incrE, incrNE;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ y = y0;
+ x = x0;
+
+ // if they are on a vertical line
+ if (dx == 0)
+ {
+ if (y0 < y1)
+ for (int i = y0; i<=y1; i++)
+ lookAt(x,i,img);
+ else
+ for (int i = y1; i<=y0; i++)
+ lookAt(x,i,img);
+ return;
+ }
+
+ // if they are on a horizontal line
+ if (dy == 0)
+ {
+ for (int i = x0; i<=x1; i++)
+ lookAt(i,y,img);
+ return;
+ }
+
+ int dir = 0;
+ double m = double(dy)/double(dx);
+ if (m >= 1.0)
+ dir = 1;
+ else if ( (m < 0.0) && (m > -1.0) )
+ dir = 2;
+ else if (m <= -1.0)
+ dir = 3;
+
+ switch(dir)
+ {
+ // when slope m: 0< m <1
+ case 0:
+ d = dy*2 - dx;
+ incrE = dy*2;
+ incrNE = (dy - dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ // when slope m: m >= 1
+ case 1:
+ d = dx*2 - dy;
+ incrE = dx*2;
+ incrNE = (dx - dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y<y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ case 2:
+ d = dy*2 + dx;
+ incrE = dy*2;
+ incrNE = (dy + dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d >= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+
+ lookAt(x,y,img);
+ }
+ break;
+ // since initially we swapped the P0 with P1 so that P0 always holds values with smaller x cooridinate
+ // so we are sure that m<0 is the result of y0 being greater that
+ case 3:
+ d = dx*2 + dy;
+ incrE = dx*2;
+ incrNE = (dx + dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y>y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y--;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ }
+
+
+ if (inWhite)
+ {
+ // it is a fraction of the blob so dont count it
+ //len[dist(x_init,y_init,x,y)+1]++;
+ inWhite = false;
+ startedWhite = false;
+ }
+}*/
+
+bool isInFemaleBlob;
+int maskImageHeight;
+int maskImageWidth;
+vector<pair<int,int> > bresenhamLine;
+
+
+void putPixel(Image* maskImage, int x, int y, int color) {
+
+
+ // ignore the pixels outside of the image boundary
+ // if outside maximum y
+ if (y >= maskImageHeight) return;
+ if (y < 0) return;
+ if (x >= maskImageWidth) return;
+ if (x < 0) return;
+
+ ColorMono currPixelColor = ColorMono(maskImage->pixelColor(x,y));
+
+ if (currPixelColor.mono() == true) {
+ isInFemaleBlob = true;
+ //isInBlackZone = false;
+ cout << "Hit the male object at "<<x<<","<<y<<endl;
+
+ } else {
+ cout << "Going through "<<x<<","<<y<<endl;
+ pair<int,int> temp(x,y);
+ bresenhamLine.push_back(temp);
+ }
+
+
+}
+
+
+int draw_line_bm(Image* maskImage, int x0, int y0, int x1, int y1) {
+
+ isInFemaleBlob = false;
+ bresenhamLine.clear();
+
+ maskImageHeight = maskImage->rows();
+ maskImageWidth = maskImage->columns();
+
+ int x, y;
+ int dx, dy;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ double m = static_cast<double> (dy)/static_cast<double> (dx);
+
+ int octant = -1;
+ if (( m >= 0 and m <= 1) and x0 < x1 ) {
+ cout << "Octant 1"<<endl;
+ octant = 1;
+ } else if ((m > 1) and (y0 < y1)) {
+ cout << "Octant 2"<<endl;
+ octant = 2;
+ } else if ((m < -1) and (y0 < y1)) {
+ cout << "Octant 3"<<endl;
+ octant = 3;
+ } else if ((m <=0 and m >= -1) and (x0 > x1)) {
+ cout << "Octant 4"<<endl;
+ octant = 4;
+ } else if ((m > 0 and m <=1) and (x0 > x1) ) {
+ cout << "Octant 5"<<endl;
+ octant = 5;
+ }else if ((m > 1) and (y0 > y1) ) {
+ cout << "Octant 6"<<endl;
+ octant = 6;
+ }else if ((m < -1) and (y0 > y1) ) {
+ cout << "Octant 7"<<endl;
+ octant = 7;
+ } else if ((m <=0 and m >= -1) and (x0 < x1) ) {
+ cout << "Octant 8"<<endl;
+ octant = 8;
+ }
+
+ int d;
+ int delE, delN, delW, delNE, delNW, delSW, delS, delSE;
+
+ dx = abs(dx);
+ dy = abs(dy);
+
+ switch (octant) {
+ case 1:
+ //----------------------------
+ d = 2*dy - dx;
+ delE = 2*dy;
+ delNE = 2*(dy-dx);
+
+ x = x0;
+ y = y0;
+
+
+ putPixel(maskImage,x, y, 1);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ while (x < x1) {
+ // if we choose E because midpoint is above the line
+ if (d <= 0) {
+
+ d = d + delE;
+
+ x = x+1;
+
+ } else {
+
+ d = d + delNE;
+
+ x = x + 1;
+ y = y + 1;
+ }
+
+ putPixel(maskImage,x, y, 1);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ }
+ break;
+
+ case 2:
+
+ d = 2*dx - dy;
+ delN = 2*dx;
+ delNE = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+
+ putPixel(maskImage,x, y, 2);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ while (y < y1) {
+ // if we choose N because midpoint is above the line
+ if (d<=0) {
+
+ d = d + delN;
+
+ y = y + 1;
+
+ } else {
+
+ d = d + delNE;
+
+
+ x = x + 1;
+ y = y + 1;
+
+ }
+ putPixel(maskImage,x, y, 2);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ }
+ break;
+
+ case 3:
+
+ d = dy - 2*dx;
+ delN = 2*dx;
+ delNW = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 3);
+ if (isInFemaleBlob == true)
+ return 1;
+
+
+ while (y < y1) {
+
+ if (d <= 0) {
+
+ d = d + delN;
+
+ y = y + 1;
+
+ } else {
+
+ d = d + delNW;
+
+ y = y + 1;
+
+ x = x - 1;
+
+ }
+ putPixel(maskImage,x, y, 3);
+ if (isInFemaleBlob == true)
+ return 1;
+
+
+ }
+
+ break;
+
+ case 4:
+
+ d = -dx + 2*dy;
+ delW = 2*dy;
+ delNW = 2*(-dx + dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 4);
+ if (isInFemaleBlob == true)
+ return 1;
+
+
+ while ( x > x1 ) {
+
+ if (d <= 0) {
+
+ d = d + delW;
+
+ x = x - 1;
+
+
+ } else {
+ d = d + delNW;
+
+
+ x = x - 1;
+ y = y + 1;
+
+ }
+
+ putPixel(maskImage,x, y, 4);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ }
+
+ break;
+
+ /*case 4:
+
+ d = dx - 2*dy;
+ cout << "dx - 2*dy = "<<(dx-2*dy)<<endl;
+ delW = -2*dy;
+ cout << "-2*dy = "<<(-2*dy)<<endl;
+ delNW = 2*(dx - dy);
+ cout << "2*(dx - dy) = "<<(2*(dx - dy))<<endl;
+
+ x = x0;
+ y = y0;
+
+ putpixel(x, y, 4);
+
+ while ( x >= x1 ) {
+
+ if (d <= 0) {
+
+ d = d + delW;
+ x = x - 1;
+ cout << "At pixel(" <<x<<","<<y<<") Going W since d <= 0 "<<d<<endl;
+
+
+ } else {
+ d = d + delNW;
+
+ cout << "At pixel(" <<x<<","<<y<<") Going NW since d > 0 "<<d<<endl;
+
+ x = x - 1;
+ y = y + 1;
+ }
+
+ putpixel(x, y, 4);
+ }
+
+ break;
+ */
+
+ case 5:
+
+ d = -dx + 2*dy;
+ delW = 2*dy;
+ delSW = 2*(-dx+dy);
+
+ x = x0;
+ y = y0;
+
+
+
+ putPixel(maskImage,x, y, 5);
+ if (isInFemaleBlob == true)
+ return 1;
+
+
+ while (x > x1) {
+
+ if (d<=0) {
+
+ d = d + delW;
+
+
+ x = x - 1;
+
+ } else {
+
+ d = d + delSW;
+
+
+ x = x - 1;
+
+ y = y - 1;
+
+
+ }
+
+ putPixel(maskImage,x, y, 5);
+ if (isInFemaleBlob == true)
+ return 1;
+
+
+ }
+
+ break;
+
+
+ case 6:
+
+ d = 2*dx - dy;
+ delS = 2*dx;
+ delSW = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+
+ putPixel(maskImage,x,y,6);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ while (y > y1) {
+
+ if (d<=0) {
+
+ d = d + delS;
+
+ y = y -1;
+ }
+ else {
+
+ d = d + delSW;
+
+ y = y -1;
+ x = x -1;
+ }
+
+ putPixel(maskImage,x, y, 6);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ }
+
+ break;
+
+ case 7:
+
+ d = 2*dx - dy;
+ delS = 2*dx;
+ delSE = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x,y,7);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ while (y > y1) {
+
+ if (d<=0) {
+ d = d + delS;
+ y = y -1;
+ }
+ else {
+ d = d + delSE;
+
+
+ y = y - 1;
+ x = x + 1;
+ }
+
+ putPixel(maskImage,x, y, 7);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ }
+
+ break;
+
+ case 8:
+
+ d = 2*dy - dx;
+ delE = 2*dy;
+ delSE = 2*(dy - dx);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x,y,8);
+ if (isInFemaleBlob == true)
+ return 1;
+
+
+ while (x < x1) {
+
+ if (d<=0) {
+ d = d + delE;
+
+ x = x + 1;
+ }
+ else {
+ d = d + delSE;
+
+
+ y = y - 1;
+ x = x + 1;
+ }
+ cout << "putpixel "<<x<<","<<y<<endl;
+ putPixel(maskImage,x, y, 8);
+ if (isInFemaleBlob == true)
+ return 1;
+
+ }
+
+ break;
+
+ default:
+ cout << "No octant which should be a bug\n";
+ exit(0);
+ break;
+
+
+ }
+
+ return 0;
+
+}
+
+
+double euclideanDist(pair<int, int > newLocation, pair<int, int> initLocation) {
+
+ double temp = pow((newLocation.first - initLocation.first), 2.0) + pow((newLocation.second - initLocation.second), 2.0);
+ temp = sqrt(temp);
+ return temp;
+
+}
+
+int sequenceCondition(FrameInfo prevFI,FrameInfo currentFI) {
+ bool prevFIsSingleBlob = prevFI.getIsSingleBlob();
+ bool currentFIsSingleBlob = currentFI.getIsSingleBlob();
+
+ if (prevFIsSingleBlob == false and currentFIsSingleBlob == true)
+ return STUCKING_TO_A_SINGLE_BLOB;
+ else if (prevFIsSingleBlob == true and currentFIsSingleBlob == false)
+ return SEPARATING_FROM_SINGLE_BLOB;
+ else
+ return -1;
+
+}
+
+
+
+
+void drawTheSequence(int startIndex, int endIndex, int isFirst, bool singleBlob, bool unprocessed) {
+
+ cout << "Should draw "<<isFirst<<endl;
+ //ifstream inputFile;
+ //inputFile.open(inputFileName.c_str());
+ /*if (inputFile.fail() ) {
+ cout << "cannot open the input file that contains name of the input images\n";
+ exit(1);
+ }*/
+
+ string fileName = fnVector[startIndex];
+ //inputFile>>fileName;
+ //inputFileName = "output/identified/"+fileName;
+ FrameInfo prevFI = fIVector[startIndex];
+ cout << "Extracting information for image "<< fnVector[startIndex] << endl;
+ cout << "----------------------------------------\n";
+ cout<<prevFI;
+ drawTheFlyObject(prevFI, fileName, isFirst, singleBlob, unprocessed);
+ for (int i=startIndex+1; i<=endIndex; i++) {
+ FrameInfo nextFI = fIVector[i];
+ cout << "Extracting information for image "<< fnVector[i] << endl;
+ cout << "----------------------------------------\n";
+ //FrameInfo na = &nextFI;
+ cout<<nextFI;
+ //inputFile>>fileName;
+ fileName = fnVector[i];
+ // inputFileName = "output/identified/"+fileName;
+ drawTheFlyObject(nextFI, fileName, isFirst, singleBlob, unprocessed);
+ }
+
+ //inputFile.close();
+}
+
+
+
+void objectHeadDirection(FlyObject prevFO, FlyObject &currentFO) {
+
+ // take the head direction from the previous frame
+ pair<double, double> pFHH = prevFO.getHead();
+
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdEVAndHH = calculateDotProduct(cFOEV, pFHH);
+ if (dotProdEVAndHH > 0 ) {
+ cout << "Current head is in direction with the Previous frame Head(which is the historical head from the maxDistIndex)"<<endl;
+ double newHeadX = 0.1*cFOEV.first+0.9*pFHH.first;
+ double newHeadY = 0.1*cFOEV.second+0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(true);
+
+ } else {
+ cout << "Current head is in direction with the previous frame head"<<endl;
+ double newHeadX = 0.1*cFOREV.first + 0.9*pFHH.first;
+ double newHeadY = 0.1*cFOREV.second + 0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(false);
+
+ }
+
+ // copy the velocity vector from the previous frame
+ pair<double, double> pFVV = prevFO.getVelocityV();
+ currentFO.setVelocityV(pFVV);
+
+}
+
+void objectHeadDirection(FlyObject prevFO, FlyObject &currentFO, bool prevFFOHD) {
+
+ // take the head direction from the previous frame
+ //pair<double, double> pFHH = prevFO.getHead();
+
+ pair<double,double> pFHeadDir;
+ calculateHeadVector(prevFO, pFHeadDir);
+
+
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdEVAndHD = calculateDotProduct(cFOEV, pFHeadDir);
+ if (dotProdEVAndHD > 0 ) {
+ cout << "Current head is in direction with the Previous frame Head direction"<<endl;
+ /*double newHeadX = 0.1*cFOEV.first+0.9*pFHH.first;
+ double newHeadY = 0.1*cFOEV.second+0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(true);
+ */
+ currentFO.setHead(cFOEV);
+ currentFO.setHeadIsInDirectionMAEV(true);
+
+ } else {
+ cout << "Current head is in reverse direction with the previous frame head direction"<<endl;
+ /*double newHeadX = 0.1*cFOREV.first + 0.9*pFHH.first;
+ double newHeadY = 0.1*cFOREV.second + 0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(false);
+ */
+ currentFO.setHead(cFOREV);
+ currentFO.setHeadIsInDirectionMAEV(false);
+
+ }
+
+ // copy the velocity vector from the previous frame
+ if (prevFFOHD == true) {
+ pair<double, double> pFVV = prevFO.getVelocityV();
+ currentFO.setVelocityV(pFVV);
+ }
+
+}
+
+void objectHeadDirection(FlyObject &currentFO, int saveEV=0) {
+
+ // get the velocity vector
+ pair<double, double> cFOVV = currentFO.getVelocityV();
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdVVAndEV = calculateDotProduct(cFOEV, cFOVV);
+ if (dotProdVVAndEV > 0 ) {
+ cout << "Current head is in direction with the velocity vector\n";
+ // set the head to the eigen vector
+ currentFO.setHead(cFOEV);
+ currentFO.setHeadIsInDirectionMAEV(true);
+
+ if (saveEV == 1) {
+ cout << "saving the eigen vector for the first object"<<endl;
+ evDirectionF.push_back(cFOEV);
+ } else if (saveEV == 2){
+ cout << "saving the eigen vector for the second object"<<endl;
+ evDirectionS.push_back(cFOEV);
+ }
+
+ } else if (dotProdVVAndEV < 0 ){
+ cout << "Current head is in reverse direction of the velocity vector"<<endl;
+ currentFO.setHead(cFOREV);
+ currentFO.setHeadIsInDirectionMAEV(false);
+
+ if (saveEV == 1) {
+ cout << "saving the eigen vector for the first object"<<endl;
+ evDirectionF.push_back(cFOREV);
+ } else if (saveEV == 2) {
+ cout << "saving the eigen vector for the second object"<<endl;
+ evDirectionS.push_back(cFOREV);
+ }
+
+ } else {
+
+ pair<double, double> zero(0.0,0.0);
+
+ if (saveEV == 1) {
+ cout << "saving the zero eigen vector for the first object"<<endl;
+ evDirectionF.push_back(zero);
+ } else if (saveEV == 2) {
+ cout << "saving the zero eigen vector for the second object"<<endl;
+ evDirectionS.push_back(zero);
+ }
+
+ }
+
+
+}
+
+void objectHeadDirection(FlyObject &currentFO, pair<double, double> cFV) {
+
+// // get the velocity vector
+// pair<double, double> cFOVV = currentFO.getVelocityV();
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdVVAndEV = calculateDotProduct(cFOEV, cFV);
+ if (dotProdVVAndEV > 0 ) {
+ cout << "Current head is in direction with the vector used\n";
+ // set the head to the eigen vector
+ currentFO.setHead(cFOEV);
+ currentFO.setHeadIsInDirectionMAEV(true);
+ } else {
+ cout << "Current head is in reverse direction with the vector used"<<endl;
+ currentFO.setHead(cFOREV);
+ currentFO.setHeadIsInDirectionMAEV(false);
+ }
+
+
+}
+
+
+void velocityDirection(int st, int end, pair<double, double > &velDirectionF, pair<double, double>&velDirectionS) {
+
+ // find the average velocity vector
+ cout << "Finding average velocity vector from "<<fnVector[st]<<" to "<<fnVector[end]<<endl;
+ FrameInfo prevFI = fIVector[st];
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ FlyObject pFFirstFO = pFOVector[0];
+ FlyObject pFSecondFO = pFOVector[1];
+
+
+ FrameInfo currentFI = fIVector[end];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ // get the summation of (velocity direction from start frame to half of the frames in this interval)
+ pair<int, int> cFFCentroid = cFFirstFO.getCentroid();
+ pair<int, int> cFSCentroid = cFSecondFO.getCentroid();
+
+
+ pair<int, int> pFFCentroid = pFFirstFO.getCentroid();
+ pair<int, int> pFSCentroid = pFSecondFO.getCentroid();
+
+
+ int velXFirst = cFFCentroid.first - pFFCentroid.first;
+ int velYFirst = cFFCentroid.second - pFFCentroid.second;
+
+ int velXSecond = cFSCentroid.first - pFSCentroid.first;
+ int velYSecond = cFSCentroid.second - pFSCentroid.second;
+
+ cout << "Velocity vector"<<endl;
+ cout << "First = "<<velXFirst<<","<<velYFirst<<endl;
+ cout << "Second = "<<velXSecond<<","<<velYSecond<<endl;
+
+ pair<double, double> cFVV(static_cast<double> (velXFirst), static_cast<double> (velYFirst));
+ pair<double, double> cSVV(static_cast<double> (velXSecond), static_cast<double> (velYSecond));
+
+ velDirectionF = cFVV;
+ velDirectionS = cSVV;
+
+
+}
+
+double getSpeed(pair<double, double> vector) {
+ double value = vector.first*vector.first + vector.second*vector.second;
+ value = sqrt(value);
+
+ return value;
+
+
+}
+
+void velocityDirections(int stIndex, int endIndex) {
+
+
+ velocityDirectionsF.clear();
+ velocityDirectionsS.clear();
+
+ //int intervalLength = 5;
+ cout << "Initial velocity direction calculation"<<endl;
+ cout << "From index "<<stIndex<<" to "<<endIndex<<endl;
+ cout << "From "<<fnVector[stIndex]<<" to "<<fnVector[endIndex]<<endl;
+
+ /*overAllVelocityF.first = 0;
+ overAllVelocityF.second = 0;
+ overAllVelocityS.first = 0;
+ overAllVelocityS.second = 0;
+ */
+
+ for (int i=stIndex; i<endIndex; i=i++) {
+
+ pair<double, double > velDirectionF;
+ pair<double, double > velDirectionS;
+
+ // get the velocity
+ velocityDirection(i,i+1, velDirectionF, velDirectionS);
+
+ // extract the fly object for update
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+ // get the speed of the velocity
+ double speedF = getSpeed(velDirectionF);
+ cFFirstFO.setSpeed(speedF);
+ double speedS = getSpeed(velDirectionS);
+ cFSecondFO.setSpeed(speedS);
+
+ // save the velocity direction
+ normalizeVector(velDirectionF);
+ velocityDirectionsF.push_back(velDirectionF);
+ normalizeVector(velDirectionS);
+ velocityDirectionsS.push_back(velDirectionS);
+
+ cout << "Normalized velocity"<<endl;
+ cout << "First = " <<velDirectionF.first<<","<<velDirectionF.second<<endl;
+ cout << "Second = " <<velDirectionS.first<<","<<velDirectionS.second<<endl;
+
+ // set the velocity vector in the objects
+ cFFirstFO.setVelocityV(velDirectionF);
+ cFSecondFO.setVelocityV(velDirectionS);
+
+ // find the first object head
+ cout<<fnVector[i]<<endl;
+ cout << "Calculating initial head direction from velocity direction for the first object and storing the ev in direction to the vv"<<endl;
+ objectHeadDirection(cFFirstFO,1);
+
+ cout << "Calculating initial head direction from the velocity direction for the second object and storing the ev in direction to the vv"<<endl;
+ objectHeadDirection(cFSecondFO,2);
+
+
+ // update the flyobject vector
+ vector<FlyObject > updatedFOVector;
+ updatedFOVector.push_back(cFFirstFO);
+ updatedFOVector.push_back(cFSecondFO);
+ currentFI.setFOVector(updatedFOVector);
+ cout << "Updating the frame "<<fnVector[i]<<" after calculating its direction from velocity vector\n";
+ fIVector[i] = currentFI;
+
+ /*//cout << fIVector[i];
+ // first object overall velocity
+ overAllVelocityF.first += velDirectionF.first;
+ overAllVelocityF.second += velDirectionF.second;
+ // second object overall velocity
+ overAllVelocityS.first += velDirectionS.first;
+ overAllVelocityS.second += velDirectionS.second;
+ */
+
+ }
+
+
+
+}
+
+
+ofstream foutLPS;
+void largestIncreasingPositiveDotProductSeq(vector<pair<double, double> > velocityDirs, int &startIndex, int &endIndex) {
+
+ int positiveVelSeqSize = 0;
+ int flag = false;
+ int maxSeqSize = 0;
+ int st = 0;
+ for (int j=0; j<velocityDirs.size()-1; j++) {
+ pair<double,double> prevVel = velocityDirs[j];
+ pair<double, double> currVel = velocityDirs[j+1];
+
+ double dotProd = calculateDotProduct(prevVel, currVel);
+
+ if( dotProd > 0 && flag == false) {
+ st = j;
+ positiveVelSeqSize++;
+ flag = true;
+ //cout << "In first if positiveSize "<<positiveVelSeqSize<<endl;
+
+ } else if (dotProd > 0 && flag == true) {
+ positiveVelSeqSize++;
+ //cout << "In second if positive "<<positiveVelSeqSize<<endl;
+ } else {
+ positiveVelSeqSize = 0;
+ flag = false;
+ //cout << "Else\n";
+
+ }
+
+ if (positiveVelSeqSize > maxSeqSize) {
+ maxSeqSize = positiveVelSeqSize;
+ startIndex = st;
+ endIndex = st+positiveVelSeqSize;
+ //cout << "maxseq updated \npositiveSize "<<positiveVelSeqSize<<endl;
+ //cout << "st "<<startIndex<<endl;
+ //cout << "end "<<endIndex<<endl;
+ }
+
+
+
+ }
+
+ // if dot product is alternately 0 and nonzero then nothing will be updated. In that case take the first nonzero velocity index
+ if (maxSeqSize == 0) {
+ bool zero = false;
+ for (int j=0; j<velocityDirs.size(); j++) {
+ pair<double, double > prevVel = velocityDirs[j];
+ if (prevVel.first != 0 || prevVel.second != 0) {
+ startIndex = j;
+ endIndex = j;
+ zero = true;
+ break;
+ }
+ }
+
+ if (zero != true) {
+ cout << "All directions zero"<<endl;
+ startIndex = 0;
+ endIndex = 0;
+ }
+
+ }
+
+}
+
+
+void propagateDirections(int object, int s, int e, int origStart, int origEnd) {
+
+ if (object == 1) {
+ cout << "For first"<<endl;
+ } else {
+ cout << "For second"<<endl;
+ }
+
+
+ /*double maxDotProduct = -1;
+ int maxDotProductIndex = -1;
+ */
+ double maxVelValue = -1;
+ int maxVelValIndex = -1;
+
+ // find the representative frame
+ for (int i=s; i<=e; i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFO = cFOVector[object-1];
+ pair<double , double> cFVV = cFFO.getVelocityV();
+ //cout << "Velocity before normalization "<<cFVV.first<<","<<cFVV.second<<endl;
+ //normalizeVector(cFVV);
+ /*cout << "Velocity after normalization "<<cFVV.first<<","<<cFVV.second<<endl;
+ pair<double, double> cFEV = cFFO.getMajorAxisEV();
+ cout << "Eigen vector before normalization "<<cFEV.first<<","<<cFEV.second<<endl;
+ normalizeVector(cFEV);
+ cout << "Eigen vector after normalization "<<cFEV.first<<","<<cFEV.second<<endl;
+
+ double dotProd = calculateDotProduct(cFEV, cFVV);
+ cout << "Dot product absolute value for frame "<<fnVector[i]<<" : "<<abs(dotProd)<<" real value was "<<dotProd<<endl;
+
+ if (maxDotProduct < abs(dotProd) ) {
+ maxDotProduct = abs(dotProd);
+ maxDotProductIndex = i;
+ }*/
+
+ double velValue = cFFO.getSpeed();
+ cout << "speed at "<<fnVector[i]<<" "<<velValue<<endl;
+ if (velValue > maxVelValue) {
+ maxVelValue = velValue;
+ maxVelValIndex = i;
+ }
+
+
+ }
+
+ cout << "Maximum speed is chosen for for frame "<<fnVector[maxVelValIndex]<<" : "<<maxVelValue<<endl;
+
+ // set the head direction according to the represntative velocity
+ int t = maxVelValIndex;
+ FrameInfo currentFI = fIVector[t];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+ cout << "Setting representative head direction of frame "<<fnVector[t]<<endl;
+ foutLPS << "Setting representative head direction of frame "<<fnVector[t]<<endl;
+
+ if (object == 1) {
+ cout << "Setting the head dir according to the representative velocity in the longest positive sequence at "<<fnVector[t]<<endl;
+ bool evDirFlag = cFFirstFO.getHeadIsInDirectionMAEV();
+ cout << "Before for the first object setting ev in velocity direction it is "<<evDirFlag<<endl;
+ objectHeadDirection(cFFirstFO);
+ evDirFlag = cFFirstFO.getHeadIsInDirectionMAEV();
+ cout << "After setting ev in velocity direction it is "<<evDirFlag<<endl;
+ cFOVector[0] = cFFirstFO;
+ currentFI.setFOVector(cFOVector);
+ fIVector[t] = currentFI;
+ }
+ else {
+ pair<double, double> tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity was "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ cout << "Setting the head direction according to the representative velocity in the longest positive sequence"<<endl;
+
+ bool evDirFlag = cFSecondFO.getHeadIsInDirectionMAEV();
+ cout << "Before for the second object setting ev in velocity direction it is "<<evDirFlag<<endl;
+ objectHeadDirection(cFSecondFO);
+ evDirFlag = cFSecondFO.getHeadIsInDirectionMAEV();
+ cout << "After setting ev in velocity direction it is "<<evDirFlag<<endl;
+
+ //tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity became "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ cFOVector[1] = cFSecondFO;
+ currentFI.setFOVector(cFOVector);
+ fIVector[t] = currentFI;
+ }
+
+
+
+ int intervalLength = 1;
+ if ((e-s)> intervalLength) {
+
+ cout << "Propagating in the longest positive frame interval starting the direction from the frame "<<fnVector[t];
+ cout << " to "<<fnVector[e]<<endl;
+ FrameInfo prevFI = fIVector[t];
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ FlyObject pFFirstFO = pFOVector[0];
+ FlyObject pFSecondFO = pFOVector[1];
+
+ for (int i=t+1; i<=e; i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ pair<double, double> tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity was "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity became "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+
+ }
+
+ cout << "propagating from "<<fnVector[t]<<" to "<<fnVector[s]<<endl;
+ prevFI = fIVector[t];
+ pFOVector = prevFI.getFOVector();
+ pFFirstFO = pFOVector[0];
+ pFSecondFO = pFOVector[1];
+
+ for (int i=t-1; i>=s; i--) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+
+ }
+
+
+
+ }
+ // propagate upwards
+ FrameInfo prevFI = fIVector[e];
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ FlyObject pFFirstFO = pFOVector[0];
+ FlyObject pFSecondFO = pFOVector[1];
+
+ if (e < origEnd) {
+ cout << "Propagating front from "<<fnVector[e]<<" to "<<fnVector[origEnd]<<endl;
+
+ for (int i=e+1; i<=origEnd; i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+
+ }
+
+ }
+
+
+
+ // propagate downwards
+ prevFI = fIVector[s];
+ pFOVector = prevFI.getFOVector();
+ pFFirstFO = pFOVector[0];
+ pFSecondFO = pFOVector[1];
+
+ if (s > origStart ) {
+ cout << "Propagating down wards from "<<fnVector[s]<<" to "<<fnVector[origStart]<<endl;
+ for (int i=s-1; i>=origStart; i--) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+ }
+
+ }
+
+}
+
+
+// find the head direction from the collsion point to backward
+void calculateHeadDirection(int st, int end, int maxDistIndex) {
+
+ cout << "From file "<<fnVector[st]<<" to "<<fnVector[end]<<endl;
+ //cout << "Assigning object head direction between Index "<<mid<<" to startIndex "<<st<<endl;
+
+ // calculate the velocity directions first
+ // clear evDirectionF and evDirectionS to store the new evs for the current sequence
+ evDirectionF.clear();
+ evDirectionS.clear();
+
+ velocityDirections(st, end);
+
+ cout << "Size of evDirectionF "<<evDirectionF.size()<<endl;
+ cout << "Size of evDirectionS "<<evDirectionS.size()<<endl;
+
+
+ // debug
+ cout << "------------ALL VELOCITY AND CORRESPONDING EV-------------\n";
+ int a;
+ for (a=0; a < velocityDirectionsF.size(); a++) {
+
+ cout << "For frame "<<fnVector[a+st]<<endl;
+
+ pair<double, double> z = velocityDirectionsF[a];
+ pair<double, double> zEV = evDirectionF[a];
+ cout <<" First object velocity = "<<z.first<<","<<z.second<<endl;
+ cout <<" First object ev = "<<zEV.first<<","<<zEV.second<<endl;
+
+ pair<double, double> w = velocityDirectionsS[a];
+ pair<double, double> wEV = evDirectionS[a];
+
+ cout << "Second object velocity = "<<w.first<<","<<w.second<<endl;
+ cout << "Second object ev = "<<wEV.first<<","<<wEV.second<<endl;
+
+
+ }
+ cout << "Last frame index wont have velocity a+st("<<(a+st)<<") = end("<<end<<") "<<fnVector[a+st]<<endl;
+ cout << "------------END-------------\n";
+
+ int s;
+ int e;
+ int fs,fe;
+ foutLPS<<"------------------------------------------------------------------"<<endl;
+ largestIncreasingPositiveDotProductSeq(evDirectionF, s, e);
+ cout << "Positive indexes are "<<fnVector[st+s]<<" to "<<fnVector[st+e]<<endl;
+ int si = s + st;
+ int ei = e + st;
+ foutLPS << "For first object max positive directions from "<<fnVector[si]<<" to "<<fnVector[ei]<<endl;
+ propagateDirections(1, si, ei, st, end);
+
+ s = 0;
+ e = 0;
+
+ largestIncreasingPositiveDotProductSeq(evDirectionS, s, e);
+ cout << "Positive indexes are "<<fnVector[st+s]<<" to "<<fnVector[st+e]<<endl;
+ si = s + st;
+ ei = e + st;
+ foutLPS << "For second object max positive directions from "<<fnVector[si]<<" to "<<fnVector[ei]<<endl;
+ propagateDirections(2, si, ei, st, end);
+
+}
+// min dist from prev frame's 0th index object
+void objectCorrespondence(FrameInfo &prevFI, FrameInfo &currentFI) {
+
+ // simplest assumption that the larger object will remain close to larger one
+ // and the smaller one will remain close to smaller
+ // just find the min distance from any one of them
+ // initially just find the min distance from the first object to the other two
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ // bool currentlySingleBlob = currentFI.getIsSingleBlob();
+
+ // if (currentlySingleBlob == false) {
+
+ FlyObject pFLargeFO = pFOVector[0];
+ FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ double distLTL = euclideanDist(pFLargeFO, cFLargeFO);
+ cout << "previousFirst to currentFirst "<<distLTL<<endl;
+
+ double distLTS = euclideanDist(pFLargeFO, cFSmallFO);
+ cout << "prevFirst to currentSecond "<<distLTS<<endl;
+
+ double min1 = min(distLTL, distLTS);
+ cout<<"min of FTF and FTS is "<<min1<<endl;
+
+ double distSTL = euclideanDist(pFSmallFO, cFLargeFO);
+ cout << "previousSecond to currentLarge "<<distSTL<<endl;
+
+ double distSTS =euclideanDist(pFSmallFO, cFSmallFO);
+ cout << "prevSecond to currentSecond "<<distSTS<<endl;
+
+ double min2 = min(distSTL, distSTS);
+
+ // if prev frame larger object is closer to current frame smaller object
+ // this might happen for two cases i) the smaller object is closer in the current frame (so this situation should be handled with some other heuristics)
+ // ii)the segmentation process toggles the size (error in the segmentation process)
+
+ if (min1 < min2) {
+ if (distLTS == min1) {
+ cout<<"Shortest distance is from the previous frame first object. And shortest distance is from previos first object to current second object so we need to swap the objects in current frame"<<endl;
+ currentFI.swapTheFlyObject();
+ }
+ } else {
+ if (distSTL == min2) {
+ cout << "Shortest distance is from the previous frame second object. And shortest distance is from previous second object to current first object so we need to swap the objects in the current frame"<<endl;
+ currentFI.swapTheFlyObject();
+ }
+ }
+
+
+}
+
+double euclideanDist(FlyObject a, FlyObject b) {
+
+ pair<int, int> aCentroid = a.getCentroid();
+ pair<int,int> bCentroid = b.getCentroid();
+
+ //cout << "Distance from "<<aCentroid.first<<","<<aCentroid.second<<" to "<<bCentroid.first<<","<<bCentroid.second<<endl;
+ double x2 = pow((static_cast<double> (aCentroid.first)-static_cast<double> (bCentroid.first)), 2.0);
+ double y2 = pow((static_cast<double> (aCentroid.second)-static_cast<double> (bCentroid.second)), 2.0);
+ double dist = sqrt((x2+y2));
+ cout << dist<<endl;
+
+ return dist;
+}
+
+void processASequence(int startOfATrackSequence, int endOfATrackSequence) {
+
+ // find the frame that gives us the furthest distance between the two objects
+ double maxDist = -1;
+ int maxDistIndex = -1;
+ for (int i=startOfATrackSequence; i<=(endOfATrackSequence); i++) {
+ FrameInfo currentFI = fIVector[i];
+
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ double currDist = euclideanDist(cFFirstFO, cFSecondFO);
+
+ if (currDist > maxDist) {
+ maxDist = currDist;
+ maxDistIndex = i;
+ cout << "New max distance" << maxDist << " at the frame number "<<i;
+ cout << endl;
+ }
+
+
+
+ }
+
+ cout << "Maximum distance between the frame found at the index "<<maxDistIndex<<endl;
+ cout << "Assigning object correspondance between maxDistIndex "<<maxDistIndex<<" to startIndex "<<startOfATrackSequence<<endl;
+ // assign closest distance object association before the between frames startOfASeq to maxDistIndex
+ FrameInfo prevFI = fIVector[maxDistIndex];
+ for (int i=maxDistIndex-1; i>=startOfATrackSequence; i--) {
+ FrameInfo currentFI = fIVector[i];
+ objectCorrespondence(prevFI, currentFI);
+
+ // update the fIVector
+ fIVector[i] = currentFI;
+ prevFI = currentFI;
+
+ }
+ cout << "Assigning object correspondance between maxDistIndex+1 "<<(maxDistIndex+1)<<" to endIndex "<<endOfATrackSequence<<endl;
+ // assign closest distance object association after the maxDistIndex to endOfSeq
+ prevFI = fIVector[maxDistIndex];
+ for (int i=maxDistIndex+1; i<=(endOfATrackSequence); i++) {
+ FrameInfo currentFI = fIVector[i];
+
+ cout << "Object correspondance frame number "<<i<<endl;
+
+ objectCorrespondence(prevFI, currentFI);
+
+ // update the fIVector
+ fIVector[i] = currentFI;
+ prevFI = currentFI;
+
+
+ }
+
+ double sequenceFirstAverage = 0;
+ double sequenceSecondAverage = 0;
+ // find the average area of the two sequences and choose the larger
+ for (int i=startOfATrackSequence; i<=(endOfATrackSequence); i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > fOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = fOVector[0];
+ FlyObject cFSecondFO = fOVector[1];
+
+ sequenceFirstAverage += cFFirstFO.getArea();
+ sequenceSecondAverage += cFSecondFO.getArea();
+
+ cout << "For frame number "<<i<<"\n";
+ cout << "SequenceFirst area sum = "<<sequenceFirstAverage<<endl;
+ cout << "SequenceSecond area sum = "<<sequenceSecondAverage<<endl;
+ }
+
+ sequenceFirstAverage /= (endOfATrackSequence-startOfATrackSequence + 1);
+ sequenceSecondAverage /= (endOfATrackSequence-startOfATrackSequence + 1);
+
+ cout << "----------------------------------------------------\n";
+ cout << "SequenceFirst average area = "<<sequenceFirstAverage<<endl;
+ cout << "SequenceSecond average area = "<<sequenceSecondAverage<<endl;
+ cout << "----------------------------------------------------\n";
+
+ if (sequenceFirstAverage > sequenceSecondAverage) {
+ foutLPS << "First object is the female and avg size is "<<sequenceFirstAverage<<" and "<<sequenceSecondAverage<<endl;
+ } else {
+ foutLPS<<"Second object is femaleand avg size is "<<sequenceFirstAverage<<" and "<<sequenceSecondAverage<<endl;
+ }
+
+ // calculating the head direction from the collision time to backward
+ cout << "calculating the head direction "<<startOfATrackSequence<<" to "<<endOfATrackSequence<<endl;
+ foutLPS<<"calculating the head direction "<<startOfATrackSequence<<" to "<<endOfATrackSequence<<endl;
+ calculateHeadDirection(startOfATrackSequence, endOfATrackSequence, maxDistIndex);
+
+ if (sequenceFirstAverage > sequenceSecondAverage) {
+ cout << "First sequence is the object A"<<endl;
+ drawTheSequence(startOfATrackSequence, endOfATrackSequence, 1, false, false);
+ }
+ else {
+ cout << "Second sequence is the object A"<<endl;
+ drawTheSequence(startOfATrackSequence, endOfATrackSequence, 0, false, false);
+ }
+
+
+}
+
+int diagLength;
+ofstream foutSt;
+ofstream foutDebugCen;
+ofstream foutDebugSpeed;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 5)
+ {
+ cerr << "Usage: executablename <inputFile.txt> <originalImagePath> <finalOutputPath> <maskImagePath> <outputFilePrefix>" << endl; // input file contains name of the
+ // input image files
+ return -1;
+ }
+
+ MagickCore::SetMagickResourceLimit(MagickCore::MemoryResource, 1536);
+ MagickCore::SetMagickResourceLimit(MagickCore::MapResource, 4092);
+
+ string ifns(argv[1]);
+ inputFileName = ifns;
+// cout << "input file name is "<<inputFileName<<endl;
+
+ string fileName;
+ ifstream inputFile(inputFileName.c_str());
+ // save the input file name
+
+ if (inputFile.fail() ) {
+ cout << "cannot open the input file that contains name of the input images\n";
+ exit(1);
+ }
+
+ //cout<<"come here ------------------------- 1"<<endl;
+ // set the global paths
+ string tempOIP(argv[2]);
+ origImagePath = tempOIP;
+
+ //cout<<"come here ------------------------- 2"<<endl;
+
+ string tempFOP(argv[3]);
+ finalOutputPath = tempFOP;
+
+ //cout<<"come here ------------------------- 3"<<endl;
+
+ string tempOFP(argv[5]);
+ outputFilePrefix = tempOFP;
+
+ //cout<<"come here ------------------------- 4"<<endl;
+
+ string statFileName = tempFOP + outputFilePrefix + "_statFile.txt";
+ //cout << "Statfilename is "<<statFileName<<endl;
+ foutSt.open(statFileName.c_str());
+ if (foutSt.fail()) {
+ cerr<<"cannot open the statfile"<<endl;
+ exit(1);
+ }
+
+ // debug file
+ string foutDebugCenFN = tempFOP + outputFilePrefix + "_statFileDebug.txt";
+ foutDebugCen.open(foutDebugCenFN.c_str());
+ if (foutDebugCen.fail()) {
+ cout << "cannot open the statDebug file"<<endl;
+ exit(1);
+ }
+
+
+ // debug file speed distribution
+ string foutDebugSpeedFN = tempFOP + outputFilePrefix + "_speedDebug.txt";
+ foutDebugSpeed.open(foutDebugSpeedFN.c_str());
+ if (foutDebugSpeed.fail()) {
+ cout << "cannot open the speedDebug file"<<endl;
+ exit(1);
+ }
+
+ string tempMIP(argv[4]);
+ maskImagePath = tempMIP;
+
+ // open the file for statistics
+ string lPSFileName("LongestPositive.txt");
+ lPSFileName = finalOutputPath + outputFilePrefix + "_" + lPSFileName;
+ cout << "LongestPositive.txt file name is "<<lPSFileName<<endl;
+ foutLPS.open(lPSFileName.c_str());
+
+
+ unsigned int objCount = 0;
+ int i;
+
+ int frameCounter = 0;
+ int fileCounter=0;
+
+ char buffer[100];
+ string imgSize;
+// FlyObject a,b;
+ vector<pair<int,int> > shape;
+ vector<FlyObject > tempFOV;
+
+ // to find the new head direction
+ bool currentlyCalculatingHead = true;
+
+
+
+ while (inputFile>>fileName) {
+
+// Image* img = new Image(argv[1]);// = new Image(argv[1]);
+
+ int fi = fileName.find("_");
+ // current sequence numbers spans from 0 - 18019, so 5 digits are needed
+ int span = 5;
+ string tempString = fileName.substr(fi+1,span);
+ int frameCounter = atoi(tempString.c_str());
+ //cout << frameCounter<<endl;
+
+ string fileNameForSave = fileName;
+
+ // save the name in the vector
+ fnVector.push_back(fileName);
+
+ //fileName = "output/filtered/final/"+fileName;
+ fileName = maskImagePath + fileName;
+ cout << "Reading file "<<fileName<<endl;
+ Image* img = new Image(fileName.c_str());
+ int width = img->columns(),height = img->rows();
+ diagLength= static_cast<int> ( sqrt( (height*height) + (width*width) ) );
+ //cout << "Diagonal length is "<<diagLength<<endl;
+// Image* imgWithInfo;
+// imgWithInfo = new Image(fileName.c_str());
+ sprintf(buffer,"%ix%i",width,height);
+ string imsize(buffer);
+ imgSize = imsize;
+ // residual image is initialized with black representing not visited.
+ residual = new Image(buffer, "black");
+
+ //cout<<"reading file "<<fileName<<endl;
+
+ tempFOV.clear();
+
+ for (int x = 0; x<width; x++) {
+ for (int y = 0; y<height; y++) {
+
+ //cout<<"comes here"<<endl;
+ shape.clear();
+ findObj(img, x, y, shape, true, true);
+ unsigned int s = shape.size();
+
+ if ( s > 0 )
+ {
+
+ // cout << "size of the object is: " << s <<endl;
+ vector<double> eigenVal = covariantDecomposition(shape);
+
+ {
+// objCount++;
+
+ double velocity_x=0.0, velocity_y=0.0;
+ // save the object information
+ FlyObject tempFO(s,
+ pair<int, int> (eigenVal[6], eigenVal[7]),
+ pair<double, double> (eigenVal[4], eigenVal[5]),
+ pair<double,double> (velocity_x, velocity_y),
+ false,
+ pair<double, double> (eigenVal[4], eigenVal[5]),
+ 0.0);
+ tempFOV.push_back(tempFO);
+
+ }
+ }
+
+ }
+ }
+
+
+ delete img;
+
+ delete residual;
+
+// cout<<"Sorting the objects according to size"<<endl;
+// bubbleSort(tempFOV);
+
+ fOVector.clear();
+
+ for (int ti=0; ti<tempFOV.size(); ti++){
+
+ FlyObject a = tempFOV[ti];
+ fOVector.push_back(a);
+
+ }
+
+ bool currentFrameIsSingleBlob = false;
+ // if there is only one object then state of the system is single blob
+ if (fOVector.size() == 1 and currentFrameIsSingleBlob == false) {
+ currentFrameIsSingleBlob = true;
+
+ // if start as a single blob
+ if (fileCounter == 0) {
+ // cout << "Start as a single blob"<<endl;
+ startOfAOneObject = fileCounter;
+ }
+
+ }
+
+ FrameInfo tempFI(frameCounter, fOVector, currentFrameIsSingleBlob);
+ fIVector.push_back(tempFI);
+ bool flag;
+ FrameInfo currentFI = fIVector[fileCounter];
+
+ /******** single image test *******/
+ // debuging a single drawTheFlyObject
+ //drawTheFlyObject(nextFI, fileName, isFirst, singleBlob, unprocessed);
+ //drawTheFlyObject(currentFI, fileNameForSave, 1, false, false);
+
+ //open this after debug
+ /**/
+ // start processing the sequence if applicable
+ if (sequenceSize > 1) {
+
+ FrameInfo prevFI = fIVector[fileCounter-1];
+
+ int seqCond = sequenceCondition(prevFI, currentFI);
+
+ if (seqCond == STUCKING_TO_A_SINGLE_BLOB) {
+
+ endOfATrackSequence = fileCounter-1;
+
+ // save the index for printing the one object later on
+ startOfAOneObject = fileCounter;
+
+ } else if (seqCond == SEPARATING_FROM_SINGLE_BLOB) {
+
+ startOfATrackSequence = fileCounter;
+
+ // draw the single blob sequence
+ endOfAOneObject = fileCounter - 1;
+ cout << "Only one object StartIndex "<<startOfAOneObject<<" endIndex "<<endOfAOneObject<<" and seqSize "<<sequenceSize<<endl;
+ // use the two variables (startOfAOneObject, endOfAOneObject) pair to draw the single-blob objects.
+ // third parameter is used to indicate whether the current sequence is SINGLE_BLOB. So true is passed.
+ // fourth parameter is used to indicate whether the current sequence is processed(to separate it from the actual single blob state).
+ // since we are considering the sequence length >= 15 to be a single blob state, so pass false parameter.
+ drawTheSequence(startOfAOneObject, endOfAOneObject,0, true, false);
+ startOfAOneObject = -1;
+ endOfAOneObject = -1;
+ //startOfATrackSequence = 1;
+ sequenceSize = 1;
+ }
+
+
+ if(seqCond == STUCKING_TO_A_SINGLE_BLOB) {
+ cout << "StartIndex "<<startOfATrackSequence<<" endIndex "<<endOfATrackSequence<<" and seqSize "<<sequenceSize<<endl;
+ // if a sequence size is greater than 15 then it is processed. endOfATrackSequence - startOfATrackSequence == 15 when the size of the sequence is 16.
+ // endOfATrackSequence - startOfATrackSequence > 15 when the size of the sequence is > 16.
+ if ((endOfATrackSequence - startOfATrackSequence) >=15 ) {
+ processASequence(startOfATrackSequence, endOfATrackSequence);
+ cout << "Done processing"<<endl;
+ } else {
+ // use the two variables (startOfATrackSequence, endOfATrackSequence) pair to draw the unprocessed frames.
+ // third parameter is used to indicate whether the current sequence is not actual SINGLE_BLOB. So false is passed.
+ // fourth parameter is used to indicate whether the current sequence is processed(to separate it from the actual single blob state).
+ // since we are considering the sequence length < 15 to be a single blob state, so pass false parameter.
+ cout << "Sequence is only "<<(endOfATrackSequence-startOfATrackSequence+1)<<" images long so assumed as a single blob"<<endl;
+ drawTheSequence(startOfATrackSequence, endOfATrackSequence, 0, false, true);
+
+ // increase the unprocessed frame counter
+ //totalUnprocessedFrame = totalUnprocessedFrame + (endOfATrackSequence - startOfATrackSequence + 1);
+ foutSt<<"-------------------------------"<<endl;
+ foutSt<<"Unprocessed size "<<(endOfATrackSequence-startOfATrackSequence+1)<<endl;
+ foutSt<<"Total unprocessed size "<<totalUnprocessedFrame<<endl;
+ foutSt<<"-------------------------------"<<endl;
+ }
+
+ initSequence();
+ //cout << "Start of a single blob "<<startOfAOneObject<<" and end of a single blob "<<endOfAOneObject<<endl;
+
+ }
+ //cout << "Done for "<<fnVector[fileCounter-1]<<endl;
+ }
+
+ sequenceSize++;
+
+ // increase the frame Counter
+ fileCounter++;
+
+
+ //cout << "Going to the next step"<<endl;
+
+ //open this after debug
+ /**/
+
+
+ }
+
+ //cout << "No more files "<<startOfAOneObject<<" "<<endOfAOneObject<<endl;
+ inputFile.close();
+
+ //open this after debug
+ /**/
+ if (startOfATrackSequence!=-1 && endOfATrackSequence == -1) {
+ if ((sequenceSize-1) > 15 ) {
+
+ cout << "Last sequence that does not stick to a single blob status startIndex "<<startOfATrackSequence<<" endIndex "<<(sequenceSize+startOfATrackSequence-2)<<endl;
+ processASequence(startOfATrackSequence, (sequenceSize+startOfATrackSequence-2));
+ cout << "Done processing"<<endl;
+
+ } else {
+ // this case was not handled earlier. It can happen that the flies are separated during the last sequences and less than 15 frames long.
+ cout << "Sequence is only "<<(sequenceSize-1)<<" images long so assumed as a single blob"<<endl;
+ drawTheSequence(startOfATrackSequence, (sequenceSize+startOfATrackSequence-2), 0, false, true);
+ foutSt<<"-------------------------------"<<endl;
+ foutSt<<"Unprocessed size "<<(sequenceSize-1)<<endl;
+ foutSt<<"Total unprocessed size "<<totalUnprocessedFrame<<endl;
+ foutSt<<"-------------------------------"<<endl;
+
+ }
+ initSequence();
+
+ } else if (startOfAOneObject != -1 && endOfAOneObject == -1) {
+ cout << "Last sequence that does not separate from one object state\n";
+ drawTheSequence(startOfAOneObject, (sequenceSize+startOfAOneObject - 2), 0, true, false);
+ endOfAOneObject = -1;
+ startOfAOneObject = -1;
+ sequenceSize = 1;
+ }
+
+
+ string cDDistFileName = finalOutputPath + outputFilePrefix + "_centroidDist.txt";
+
+ string hDAngleDistFileName = finalOutputPath + outputFilePrefix + "_headDirAngleDist.txt";
+
+ // speed distribution filename
+ string speedDistFileName = finalOutputPath + outputFilePrefix + "_speedDist.txt";
+
+ writeHist(cDDistFileName.c_str(), centroidDistanceMap);
+
+ writeHist(hDAngleDistFileName.c_str(), headDirAngleMap);
+
+ writeHist(speedDistFileName.c_str(), speedMap);
+
+
+ //double percentageLookingAt = static_cast<double>(totalMaleLookingAtFemale)/static_cast<double> (fileCounter-totalUnprocessedFrame);
+ //percentageLookingAt *= 100.0;
+
+ //double percentageSingleBlob = static_cast<double>(totalSingleBlob)/static_cast<double>(fileCounter);
+ //percentageSingleBlob *= 100.0;
+
+
+ // new calculation of percentage look at should consider only those frames where the flies are separated
+ double percentageLookingAt = static_cast<double>(totalMaleLookingAtFemale+totalFemaleLookingAtMale)/static_cast<double>(totalSeparated);
+ percentageLookingAt *= 100.0;
+
+ double percentageSingleBlob = static_cast<double>(totalSingleBlob)/static_cast<double>(fileCounter);
+ percentageSingleBlob *= 100.0;
+
+ foutSt<<"Total number of single blob "<<totalSingleBlob<<endl;
+ foutSt<<"Total number of male looking at "<<totalMaleLookingAtFemale<<endl;
+ foutSt<<"Total number of female looking at "<<totalFemaleLookingAtMale<<endl;
+ foutSt<<"Total number of looking at "<<(totalMaleLookingAtFemale+totalFemaleLookingAtMale)<<endl;
+ foutSt<<"Total number of unprocessed frame "<<totalUnprocessedFrame<<endl;
+ foutSt<<"Total number of frame where flies are separated (from the counter totalSeparated) "<<totalSeparated<<endl;
+ foutSt<<"Total number of frame where flies are separated "<<(fileCounter-totalUnprocessedFrame-totalSingleBlob)<<endl;
+ foutSt<<"Total number of frame "<<fileCounter<<endl;
+ foutSt<<"Percentage of frame in looking at mode "<<percentageLookingAt<<endl;
+ foutSt<<"Percentage of frame single blob "<<percentageSingleBlob<<endl;
+
+ //open this after debug
+ /**/
+
+ foutSt.close();
+
+ foutDebugCen.close();
+
+ foutLPS.close();
+
+ foutDebugSpeed.close();
+
+ return 0;
+}
+// is set each time the start is found
+// useful when one blob is detected on the border of the mask image
+bool isFoundStartPoint = false;
+int hitTheFly(Image* maskImage, int &intersectX, int &intersectY) {
+
+ //Image* maskImage = new Image(fileName.c_str());
+
+ for (int i=bresenhamLine.size()-1; i>=0; i--) {
+
+ pair<int,int> tempP = bresenhamLine[i];
+
+ int x = tempP.first;
+
+ int y = tempP.second;
+
+ ColorMono currPixelColor = ColorMono(maskImage->pixelColor(x,y));
+
+ if (currPixelColor.mono() == true) {
+ cout << "Hit the target fly"<<" "<<x<<","<<y<<endl;
+ intersectX = x;
+ intersectY = y;
+ return 1;
+ } else if (currPixelColor.mono() == false and ( x == 0 || x == (maskImageWidth-1) || y == 0 || y == (maskImageHeight-1))) {
+ cout << "Is at the boundary"<<endl;
+ return 2;
+ }
+ else {
+ cout << "Going through "<<x<<" "<<y<<endl;
+ }
+
+
+ }
+ return -1;
+
+}
+
+void findTheStartPoint(string fileName, int desiredSize, int otherSize, int cen_x, int cen_y, bool eVDirection) {
+
+
+ string segmImageFileName = maskImagePath + fileName;
+
+ cout << "Segmented image "<<segmImageFileName<<"\n";
+ if (desiredSize == otherSize) {
+ foutDebugCen<<"File name "<<segmImageFileName<<endl;
+ foutDebugCen<<"MaleSize == FemaleSize\n";
+ foutDebugCen<<"DesiredCentroid.first, DesiredCentroid.second = ("<<cen_x<<","<<cen_y<<")"<<endl;
+ }
+
+ Image* image = new Image(segmImageFileName.c_str());
+
+
+ int width = image->columns();
+ int height = image->rows();
+
+ char buffer[100];
+ sprintf(buffer,"%ix%i",width,height);
+
+ // the residual image should be newed
+ residual = new Image(buffer, "black");
+
+ bool found = false;
+ vector<pair<int, int> > foundShape;
+ vector<pair<int,int> > shape;
+ cout<<"Detecting the male object for finding the start point"<<endl;
+ for (int x = 0; x<width and found == false; x++) {
+ for (int y = 0; y<height and found == false; y++) {
+
+ //cout<<"comes here"<<endl;
+ shape.clear();
+ findObj(image, x, y, shape, true, true);
+ unsigned int s = shape.size();
+
+ if ( s > 0 )
+ {
+
+ cout << "size of the object is: " << s <<endl;
+
+ if (desiredSize == otherSize) {
+
+ // debug:
+ cout << "Inside the maleSize == femaleSize where (cen_x, cen_y) = "<<cen_x<<","<<cen_y<<endl;
+ pair<int, int> tmpCentroid = getCentroid(shape);
+ foutDebugCen<<"tmpCentroid.first, tmpCentroid.second = ("<<tmpCentroid.first<<","<<tmpCentroid.second<<")"<<endl;
+ if (tmpCentroid.first == cen_x and tmpCentroid.second == cen_y) {
+
+ found = true;
+ cout << "Detected the desired object when the sizes are equal"<<endl;
+ foundShape = shape;
+ foutDebugCen<<"Found by desired object after recomputing the centroid"<<endl;
+ }
+
+ // not correct logic when the centroid can be black pixel
+ /*for (int l=0; l<s and found == false; l++) {
+
+ pair<int, int> point = shape[l];
+ cout << "point.first, point.second "<<point.first<<","<<point.second<<endl;
+
+ // this should give most of the time when the centroid is not a black pixel
+ // a centroid can be black pixel when the shape of the fly is distorted inside
+ if (point.first == cen_x and point.second == cen_y) {
+ found = true;
+ cout << "Detected the male object when the sizes of male/female are equal"<<endl;
+ foundShape = shape;
+ }
+ }*/
+
+
+ } else {
+
+ cout<<"Elseblock: Inside the desiredSize is not equal the otherSize"<<endl;
+ if (s == desiredSize) {
+ found = true;
+ cout << "Detected the desired object just comparing the sizes"<<endl;
+ foundShape = shape;
+ cout<<"foundshape size "<<foundShape.size()<<endl;
+ }
+ }
+
+
+
+ }
+
+ }
+ }
+
+ if (found == true) {
+ cout<<"foundshape is assigned a value"<<endl;
+ } else {
+ cout<<"ERROR: foundshape is not assigned a value so the next step would draw a line over an empty image"<<endl;
+ exit(0);
+ }
+
+ vector<double> eigenVal = covariantDecomposition(foundShape);
+
+ int x0, y0, x1, y1;
+
+ x0 = cen_x;
+ y0 = cen_y;
+
+ double ev_x;
+ double ev_y;
+
+ if (eVDirection == true) {
+ ev_x = static_cast<double> (x0) + static_cast<double> (diagLength)*eigenVal[4];
+ ev_y = static_cast<double> (y0) + static_cast<double> (diagLength)*eigenVal[5];
+ }
+ else {
+ ev_x = static_cast<double> (x0) - static_cast<double> (diagLength)*eigenVal[4];
+ ev_y = static_cast<double> (y0) - static_cast<double> (diagLength)*eigenVal[5];
+
+ }
+
+ x1 = static_cast<int> (ev_x);
+ y1 = static_cast<int> (ev_y);
+
+ cout<<"Endpoint: centroid (x0,y0)==("<<x0<<","<<y0<<")"<<endl;
+ cout<<"Startpoint: OutsidePointInEVDirection (x1,y1)==("<<x1<<","<<y1<<")"<<endl;
+
+ Image* maskImage = new Image(buffer, "black");
+
+ for (int i=0; i<foundShape.size(); i++) {
+ pair<int,int > point = foundShape[i];
+ maskImage->pixelColor(point.first, point.second,"white");
+ }
+
+
+ int hits = draw_line_bm(maskImage, x1, y1, x0, y0);
+
+
+ //maskImage->strokeColor("red");
+ //maskImage->draw(DrawableLine(x1, y1, x0, y0));
+ //maskImage->write("test.png");
+
+ cout<<"BresenhamLine size is "<<bresenhamLine.size()<<endl;
+/* if (hits == 1) {
+
+ // if the object is at the border then bresenhamLine should be empty; because we start saving the coordinate
+ // when the line enters into the mask image
+ if (bresenhamLine.size() > 0) {
+ pair<int, int> temp = bresenhamLine[bresenhamLine.size()-1];
+ cout << "Finding the starting point: Hits source at "<<temp.first<<","<<temp.second<<endl;
+ ColorMono c = maskImage->pixelColor(temp.first, temp.second);
+ //maleSP_x = prev_x;
+ //maleSP_y = prev_y;
+
+ if (c.mono() == true) {
+ cout << "start point from the source object should be black"<<endl;
+ exit(0);
+ }
+ isFoundStartPoint = true;
+ // reset it after its corresponding hitTheFly() function call
+
+ }
+ else {
+ isFoundStartPoint = false;
+ cout<<"The object is at the border in the mask image. BresenhamLine vector is empty. Size : "<<bresenhamLine.size()<<endl;
+ }
+
+ } else {
+ cout << "Error: The brsenham line must intersect to the source object."<<endl;
+ exit(0);
+ }
+*/
+ // if the object is at the border then bresenhamLine should be empty; because we start saving the coordinate
+ // when the line enters into the mask image
+ if (bresenhamLine.size() > 0) {
+ pair<int, int> temp = bresenhamLine[bresenhamLine.size()-1];
+ cout << "Finding the starting point: Hits source at "<<temp.first<<","<<temp.second<<endl;
+ ColorMono c = maskImage->pixelColor(temp.first, temp.second);
+ //maleSP_x = prev_x;
+ //maleSP_y = prev_y;
+
+ if (c.mono() == true) {
+ cout << "start point from the source object should be black"<<endl;
+ exit(0);
+ }
+ isFoundStartPoint = true;
+ // reset it after its corresponding hitTheFly() function call
+
+ }
+ else {
+ isFoundStartPoint = false;
+ cout<<"The object is at the border in the mask image. BresenhamLine vector is empty. Size : "<<bresenhamLine.size()<<endl;
+ }
+
+
+ delete residual;
+
+ delete image;
+
+ delete maskImage;
+
+}
+
+void calculateStatistics(FrameInfo currentFI, string fileName, int isFirst, bool singleBlob, bool isHitting, bool isHittingFemaleToMale, bool unprocessed) {
+
+ foutSt<< "Statistics generation for "<<fileName<<endl;
+ foutSt<< "----------------------------------------------\n";
+ vector<FlyObject > fOVector = currentFI.getFOVector();
+
+ if (singleBlob == false and unprocessed == false) {
+
+ FlyObject maleFO = fOVector[isFirst];
+ FlyObject femaleFO = fOVector[1-isFirst];
+
+ pair<int, int> maleCentroid = maleFO.getCentroid();
+
+ pair<double, double> maleMajorAxisEV = maleFO.getMajorAxisEV();
+
+ bool maleEVDir = maleFO.getHeadIsInDirectionMAEV();
+
+ pair<int, int> femaleCentroid = femaleFO.getCentroid();
+
+ pair<double, double > femaleMajorAxisEV = femaleFO.getMajorAxisEV();
+
+ bool femaleEVDir = femaleFO.getHeadIsInDirectionMAEV();
+
+
+ // 1. finding the distance between the centroids
+ double tempDist = pow(static_cast<double>(maleCentroid.first - femaleCentroid.first),2) + pow(static_cast<double>(maleCentroid.second-femaleCentroid.second),2);
+
+ tempDist = sqrt(tempDist);
+
+ // round the function
+ unsigned int dist = roundT(tempDist);
+
+ centroidDistanceMap[dist] = centroidDistanceMap[dist] + 1;
+
+ foutSt << "Centroid distance "<<dist<<endl;
+
+ // 2. finding the angle between the head direction
+ normalizeVector(maleMajorAxisEV);
+ normalizeVector(femaleMajorAxisEV);
+ pair<double, double> maleHeadDir;
+ pair<double, double> femaleHeadDir;
+
+ if (maleEVDir == true) {
+ maleHeadDir = maleMajorAxisEV;
+ foutSt<<"Male Head In direction of ev"<<endl;
+
+ } else {
+ foutSt<<"Male Head is in opposite of ev"<<endl;
+ maleHeadDir.first = -maleMajorAxisEV.first;
+ maleHeadDir.second = -maleMajorAxisEV.second;
+ }
+
+ if (femaleEVDir == true) {
+ femaleHeadDir = femaleMajorAxisEV;
+ foutSt<<"Female Head In direction of ev"<<endl;
+ } else {
+ femaleHeadDir.first = -femaleMajorAxisEV.first;
+ femaleHeadDir.second = -femaleMajorAxisEV.second;
+ foutSt<<"Female Head is in opposite of ev"<<endl;
+ }
+
+ double dp = calculateDotProduct(femaleHeadDir, maleHeadDir);
+
+ cout<<"Dot product "<<fixed<<setprecision(8)<<dp<<endl;
+
+ float rad = acos(static_cast<float>(dp));
+ cout<<"Angle in radian "<<rad<<endl;
+
+ float deg = rad*180.0/static_cast<float>(PI);
+ cout<<"Angle in deg "<<deg<<endl;
+
+ unsigned int a = static_cast<unsigned int>(roundT(static_cast<double>(deg)));
+ cout<<"Angle after rounding "<<a<<endl;
+
+ headDirAngleMap[a]++;
+
+ foutSt<<"Dot product was "<<dp<<endl;
+ foutSt<<"Angle between ("<<maleHeadDir.first<<","<<maleHeadDir.second<<") and ("<<femaleHeadDir.first<<","<<femaleHeadDir.second<<") : "<<a<<endl;
+ if(a == -2147483648 || a == 2147483648) {
+ cout<<"Angle between ("<<maleHeadDir.first<<","<<maleHeadDir.second<<") and ("<<femaleHeadDir.first<<","<<femaleHeadDir.second<<") : "<<a<<endl;
+ cout<<"Incorrect angle calculation :"<<a<<endl;
+ exit(1);
+ }
+ // 3. generate number of times male is looking at the female
+ if (isHitting == true) {
+ totalMaleLookingAtFemale = totalMaleLookingAtFemale + 1;
+ foutSt << "Male is looking at female"<<endl;
+ }
+ // generate number of times female is looking at the male
+ if (isHittingFemaleToMale == true) {
+ totalFemaleLookingAtMale = totalFemaleLookingAtMale + 1;
+ foutSt <<"Female is looking at male"<<endl;
+ }
+
+
+ // 4. generate speed distribution consider speeds of both
+ double speedMale = maleFO.getSpeed();
+ double speedFemale = femaleFO.getSpeed();
+ foutSt<<"Male speed is "<<speedMale<<" and Female speed is "<<speedFemale<<endl;
+ int spM = roundT(speedMale);
+ int spF = roundT(speedFemale);
+ foutDebugSpeed<<fileName<<"\t"<<"Male "<<speedMale<<"\t"<<"Female "<<speedFemale<<endl;
+ foutDebugSpeed<<fileName<<"\t"<<"Male "<<spM<<"\t"<<"Female "<<spF<<endl;
+ foutDebugSpeed<<"---------------------------------------"<<endl;
+ speedMap[spM] = speedMap[spM] + 1;
+ speedMap[spF] = speedMap[spF] + 1;
+
+
+ totalSeparated = totalSeparated + 1;
+ foutSt<<"Frame contains separated flies\n";
+ //foutSt<<"Male speed "<<speedMale<<endl;
+ //foutSt<<"Female speed "<<speedFemale<<endl;
+
+ } else if (singleBlob == true and unprocessed == false) {
+ // 4. generate the number of times they are as single blob
+ totalSingleBlob++;
+ cout << "Current frame is single blob\n";
+ foutSt << "Frame is a single blob\n";
+ } // singleBlob == false and unprocessed == true
+ else if (unprocessed == true) {
+ totalUnprocessedFrame = totalUnprocessedFrame + 1;
+ cout <<"Current frame is unprocessed"<<endl;
+ foutSt <<"Current frame is unprocessed"<<endl;
+ } // else condition would never be generated singleBlob == true and unprocessed == true.
+ // so it is not checked.
+
+
+}
+void drawTheFlyObject(FrameInfo currentFI, string fileName, int isFirst, bool singleBlob, bool unprocessed) {
+
+ cout << "isFirst is "<<isFirst<<endl;
+
+ //string inputFileName = origImagePath + fileName;
+ // string inputFileName = "output/identified/"+fileName;
+
+ // when do not want to identify on the original comment the line below and uncomment the above line
+ // debugging for drawing the circle
+ //string outputFileName = finalOutputPath + fileName;
+ // string outputFileName = "output/identified_with_cropped/" + fileName;
+
+ //Image* img = new Image(inputFileName.c_str());
+
+ vector<FlyObject > fOVector = currentFI.getFOVector();
+
+ cout << "While drawing it found objects = "<<fOVector.size()<<endl;
+
+ string maskFile = maskImagePath + fileName;
+ Image* maskImage = new Image(maskFile.c_str());
+ int intersectX=-1, intersectY=-1;
+ int isHitting=-1;
+ int isHittingFemaleToMale = -1;
+
+ // the unprocessed flag is used to handle those sequence that are less than 15 frames long and flies are separated there.
+ if (singleBlob == false and unprocessed == false) {
+
+ /////////// find the sizes for finding the start point
+ FlyObject fO = fOVector[isFirst];
+ int maleSize = fO.getArea();
+ fO = fOVector[1-isFirst];
+ int femaleSize = fO.getArea();
+ pair<int, int> femaleCentroid = fO.getCentroid();
+ bool eVDirectionFemale = fO.getHeadIsInDirectionMAEV();
+ ///////////
+
+ FlyObject currentFO = fOVector[isFirst];
+
+ pair<int, int> centroid = currentFO.getCentroid();
+
+ bool eVDirection = currentFO.getHeadIsInDirectionMAEV();
+
+ // debug:
+ cout<<"Calling the findTheStartPoint() function"<<endl;
+ cout<<"Female size "<<femaleSize<<" maleSize "<<maleSize<<" MaleCentroid = "<<centroid.first<<", "<<centroid.second<<endl;
+
+ // initialize the flag with false for the next found of findTheStartPoint()
+ isFoundStartPoint = false;
+
+ // finding male hitting the female
+ findTheStartPoint(fileName, maleSize, femaleSize, centroid.first, centroid.second, eVDirection);
+ if (isFoundStartPoint == true) {
+ isHitting = hitTheFly(maskImage, intersectX, intersectY);
+ cout<<"Male intersects the female at "<<intersectX<<","<<intersectY<<endl;
+ foutSt<<"Male intersects the female at "<<intersectX<<","<<intersectY<<endl;
+ } else {
+ isHitting = -1;
+ cout<<"Male head direction doesn't intersect with the female"<<endl;
+ foutSt<<"Male head direction doesn't interesect with the female"<<endl;
+ }
+
+ intersectX = -1;
+ intersectY = -1;
+ // initialize the flag with false for the next found of findTheStartPoint
+ isFoundStartPoint = false;
+
+ // female hitting the male
+ findTheStartPoint(fileName, femaleSize, maleSize, femaleCentroid.first, femaleCentroid.second, eVDirectionFemale);
+ if ( isFoundStartPoint == true ) {
+ isHittingFemaleToMale = hitTheFly(maskImage, intersectX, intersectY);
+ cout<<"Female intersects the male at "<<intersectX<<","<<intersectY<<endl;
+ foutSt<<"Female intersects the male at "<<intersectX<<","<<intersectY<<endl;
+ } else {
+ isHittingFemaleToMale = -1;
+ cout<<"Female head direction doesn't intersect with the male"<<endl;
+ foutSt<<"Female head direction doesn't intersect with the male"<<endl;
+ }
+
+ for (int n=0; n<fOVector.size(); n++) {
+
+ FlyObject currentFO = fOVector[n];
+
+ pair<int, int> centroid = currentFO.getCentroid();
+ pair<double, double> majorAxisEV = currentFO.getMajorAxisEV();
+
+ bool eVDirection = currentFO.getHeadIsInDirectionMAEV();
+
+ double ev_x, ev_y;
+
+ // draw the female when tracked by the male fly
+ if (isHitting == 1) {
+ if (n != isFirst and n == 0) {
+ ///img->strokeColor("red");
+
+ //img->draw(DrawableRectangle(centroid.first - 6, centroid.second - 6, centroid.first + 6, centroid.second + 6));
+ } else if (n != isFirst and n==1) {
+
+ // img->strokeColor("red");
+
+ //img->draw(DrawableRectangle(centroid.first - 6, centroid.second - 6, centroid.first + 6, centroid.second + 6));
+ }
+ }
+
+
+ // draw the male when tracked by the female fly
+ // this situation will draw the YELLOW circle as well as the ORANGE rectangle around the
+ // male object. This double color ensure that this situation is incorrectly detects the male
+ // as female. Because our assumption is that female never tracks the male. So the actual female
+ // tracking male will occur very insignificant times.
+ if (isHittingFemaleToMale == 1) {
+ if (n == isFirst and n == 0) {
+ // img->strokeColor("Red");
+
+ // img->draw(DrawableRectangle(centroid.first - 6, centroid.second - 6, centroid.first + 6, centroid.second + 6));
+ } else if (n == isFirst and n==1) {
+
+ //img->strokeColor("Red");
+
+ //img->draw(DrawableRectangle(centroid.first - 6, centroid.second - 6, centroid.first + 6, centroid.second + 6));
+ }
+ }
+
+
+ // draw the Axis direction
+ if (eVDirection == true) {
+ //ev_x = static_cast<double>(centroid.first) + 50.0 * majorAxisEV.first;
+ //ev_y = static_cast<double>(centroid.second) + 50.0 * majorAxisEV.second;
+ //img->strokeColor("green");
+ //img->draw( DrawableLine( centroid.first, centroid.second, static_cast<int>(ev_x), static_cast<int>(ev_y) ));
+ } else {
+ //ev_x = static_cast<double>(centroid.first) - 50.0 * majorAxisEV.first;
+ //ev_y = static_cast<double>(centroid.second) - 50.0 * majorAxisEV.second;
+ //img->strokeColor("green");
+ //img->draw( DrawableLine( centroid.first, centroid.second, static_cast<int>(ev_x), static_cast<int>(ev_y) ));
+ }
+
+ // draw the velocity vector
+
+ /*img->strokeColor("blue");
+ pair<double, double> velocityV = currentFO.getVelocityV();
+ ev_x = static_cast<double>(centroid.first) + 30.0 * velocityV.first;
+ ev_y = static_cast<double>(centroid.second) + 30.0 * velocityV.second;
+ img->draw(DrawableLine( centroid.first, centroid.second, static_cast<int>(ev_x), static_cast<int>(ev_y) ));
+ */
+
+ /*
+ // draw the historical head vector
+ img->strokeColor("white");
+ pair<double, double> headV = currentFO.getHead();
+ ev_x = static_cast<double> (centroid.first) + 25.0*headV.first;
+ ev_y = static_cast<double> (centroid.second) + 25.0*headV.second;
+ img->draw( DrawableLine(centroid.first, centroid.second, static_cast<int> (ev_x), static_cast<int> (ev_y)) );
+ */
+
+ //draw the object tracking circle
+ if (n == isFirst and n==0) {
+ cout << "Tracking the n = "<<n<<endl;
+ // img->strokeColor("yellow");
+ //img->draw(DrawableCircle(centroid.first, centroid.second, centroid.first+5, centroid.second));
+ //img->pixelColor(prev_x, prev_y, "red");
+
+ } else if ( n == isFirst and n==1) {
+
+ cout << "Tracking the "<<n<<endl;
+ // img->strokeColor("yellow");
+ //img->fillColor("none");
+ //img->pixelColor(prev_x, prev_y, "red");
+ //img->draw(DrawableCircle(centroid.first, centroid.second, centroid.first+5, centroid.second));
+
+
+ }
+
+
+ }
+ }
+
+ // overwrite the file now with axis
+ // img->write(inputFileName.c_str());
+
+ // when do not want to identify on the original comment below line and uncomment the above one
+ //img->write(outputFileName.c_str());
+ delete maskImage;
+ if (isHitting == 1 || isHittingFemaleToMale == 0)
+ calculateStatistics(currentFI, fileName, isFirst, singleBlob, true, false, unprocessed);
+ else if (isHitting == 0 || isHittingFemaleToMale == 1)
+ calculateStatistics(currentFI, fileName, isFirst, singleBlob, false, true, unprocessed);
+ else if (isHitting == 1 || isHittingFemaleToMale == 1)
+ calculateStatistics(currentFI, fileName, isFirst, singleBlob, true, true, unprocessed);
+ else
+ calculateStatistics(currentFI, fileName, isFirst, singleBlob, false, false, unprocessed);
+
+}
+
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon, bool colorLookingFor)
+{
+ assert(residual != NULL);
+
+ if (eightCon == true)
+ eightConnObj(img, x, y, shape, colorLookingFor);
+ else {
+ fourConnObj(img, x, y, shape, colorLookingFor);
+ }
+}
+
+int barrier = 1000;
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // originalpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono originalpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && originalpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && originalpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// //cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ fourConnObj(img, x+1, y, obj, color);
+ fourConnObj(img, x, y-1, obj, color);
+
+ fourConnObj(img, x-1, y, obj, color);
+ fourConnObj(img, x, y+1, obj, color);
+ }
+
+}
+
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // originalpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono originalpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && originalpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && originalpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// //cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ eightConnObj(img, x+1, y, obj, color);
+ eightConnObj(img, x+1, y-1, obj, color);
+ eightConnObj(img, x, y-1, obj, color);
+ eightConnObj(img, x-1, y-1, obj, color);
+
+ eightConnObj(img, x-1, y, obj, color);
+ eightConnObj(img, x-1, y+1, obj, color);
+ eightConnObj(img, x, y+1, obj, color);
+ eightConnObj(img, x+1, y+1, obj, color);
+
+ }
+
+}
+
+// Aspect Ratio
+pair<int,int> getCentroid(vector<pair<int,int> > & points)
+{
+ pair<int,int> centroid;
+ centroid.first = 0;
+ centroid.second = 0;
+
+ for (unsigned int i = 0; i<points.size(); i++)
+ {
+ centroid.first += points[i].first;
+ centroid.second += points[i].second;
+ }
+
+ centroid.first = roundT(double(centroid.first)/points.size());
+ centroid.second = roundT(double(centroid.second)/points.size());
+
+ return centroid;
+}
+
+
+vector<double> covariantDecomposition(vector<pair<int,int> > & points)
+{
+ unsigned int i,j,k;
+ pair<int,int> centroid = getCentroid(points);
+ vector<double> retval;
+
+ gsl_matrix* matrice = gsl_matrix_alloc(2, 2);
+
+ double sumX2 = 0, sumXY = 0, sumY2 = 0;
+ for (k = 0; k<points.size(); k++)
+ {
+ sumX2 += pow(double(points[k].first - centroid.first),2.0);
+ sumY2 += pow(double(points[k].second - centroid.second),2.0);
+ // should we take the absolute value of X*Y
+ sumXY += (points[k].first - centroid.first) * (points[k].second - centroid.second);
+ }
+ gsl_matrix_set(matrice, 0, 0, roundT(sumX2/points.size()));
+ gsl_matrix_set(matrice, 0, 1, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 0, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 1, roundT(sumY2/points.size()));
+
+ // outputMatrix("Covariant", matrice);
+
+ // This function allocates a workspace for computing eigenvalues of n-by-n
+ // real symmetric matrices. The size of the workspace is O(2n).
+ gsl_eigen_symmv_workspace* eigenSpace = gsl_eigen_symmv_alloc(2);
+ gsl_vector* eigenVal = gsl_vector_alloc(2);
+ gsl_matrix* eigenVec = gsl_matrix_alloc(2, 2);
+ // This function computes the eigenvalues and eigenvectors of the real
+ // symmetric matrix A. Additional workspace of the appropriate size must be
+ // provided in w. The diagonal and lower triangular part of A are destroyed
+ // during the computation, but the strict upper triangular part is not
+ // referenced. The eigenvalues are stored in the vector eval and are unordered.
+ // The corresponding eigenvectors are stored in the columns of the matrix evec.
+ // For example, the eigenvector in the first column corresponds to the first
+ // eigenvalue. The eigenvectors are guaranteed to be mutually orthogonal and
+ // normalised to unit magnitude.
+ gsl_eigen_symmv (matrice, eigenVal, eigenVec, eigenSpace);
+ gsl_eigen_symmv_free (eigenSpace);
+
+ gsl_eigen_symmv_sort(eigenVal, eigenVec, GSL_EIGEN_SORT_VAL_ASC);
+
+ for (i = 0; i<eigenVal->size; i++)
+ retval.push_back(gsl_vector_get(eigenVal, i));
+
+ for (j = 0; j<eigenVec->size2; j++)
+ for (i = 0; i<eigenVec->size1; i++)
+ retval.push_back(gsl_matrix_get(eigenVec, i, j));
+
+ retval.push_back(static_cast<double>(centroid.first));
+ retval.push_back(static_cast<double> (centroid.second));
+
+// for (i=0; i<2; i++) {
+// gsl_vector_view evec_i = gsl_matrix_column (eigenVec, i);
+// //printf ("eigenvalue = %g\n", eval_i);
+// cout<<"eigenvector = \n";
+// gsl_vector_fprintf (stdout, &evec_i.vector, "%g");
+// }
+
+ gsl_vector_free(eigenVal);
+ gsl_matrix_free(matrice);
+ gsl_matrix_free(eigenVec);
+
+ return retval;
+}
+
+// isInterface for binary image
+bool isInterface(Image* orig, unsigned int x, unsigned int y)
+{
+ // Get the current pixel's color
+ ColorMono currentpixel = (ColorMono)orig->pixelColor(x,y);
+ // If the current pixel is black pixel then it is not boundary pixel
+ // error check
+ if (currentpixel.mono() == false)
+ return false;
+
+ // If the current pixel is not black then it is white. So, now we need
+ // to check whether any four of its neighbor pixels (left, top, right,
+ // bottom ) is black. If any of this neighbor is black then current
+ // pixel is a neighbor pixel. Otherwise current pixel is not neighbor
+ // pixel.
+
+ ColorMono leftneighborpixel = (ColorMono)orig->pixelColor(x-1,y);
+ ColorMono topneighborpixel = (ColorMono)orig->pixelColor(x,y-1);
+ ColorMono rightneighborpixel = (ColorMono)orig->pixelColor(x+1,y);
+ ColorMono bottomneighborpixel = (ColorMono)orig->pixelColor(x,y+1);
+
+ // If leftneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ if ( leftneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If topneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ else if (topneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If rightneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (rightneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If bottomneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (bottomneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // Else all of its neighbor pixels are white so it can not be a
+ // boundary pixel
+ else
+ return false;
+
+}
diff --git a/fly-tools/FlyTrackingNoImages b/fly-tools/FlyTrackingNoImages
new file mode 100755
index 0000000..b61fcd9
--- /dev/null
+++ b/fly-tools/FlyTrackingNoImages
Binary files differ
diff --git a/fly-tools/FrameInfo.cpp b/fly-tools/FrameInfo.cpp
new file mode 100644
index 0000000..d00e4cd
--- /dev/null
+++ b/fly-tools/FrameInfo.cpp
@@ -0,0 +1,72 @@
+/*
+ * FrameInfo.cpp
+ *
+ *
+ * Created by Md. Alimoor Reza on 6/26/10.
+ * Copyright 2010 Drexel University. All rights reserved.
+ *
+ */
+
+#include "FrameInfo.h"
+
+FrameInfo::FrameInfo(int frameNo, vector<FlyObject > fOVector, bool isSingleBlob) {
+ this->frameNo = frameNo;
+ this->fOVector = fOVector;
+ this->isSingleBlob = isSingleBlob;
+
+}
+FrameInfo::FrameInfo(const FrameInfo &f) {
+ this->frameNo = f.getFrameNo();
+ this->fOVector = f.getFOVector();
+ this->isSingleBlob = f.getIsSingleBlob();
+
+}
+int FrameInfo::getFrameNo() const {
+ return frameNo;
+}
+bool FrameInfo::getIsSingleBlob() const {
+ return isSingleBlob;
+}
+vector<FlyObject > FrameInfo::getFOVector() const{
+ return fOVector;
+}
+
+void FrameInfo::setFrameNo(int fn) {
+ this->frameNo = fn;
+}
+void FrameInfo::setIsSingleBlob(bool isSingleBlob) {
+ this->isSingleBlob = isSingleBlob;
+}
+void FrameInfo::setFOVector(vector<FlyObject > fov) {
+ this->fOVector = fov;
+
+// cout << "setting fov \n";
+// FlyObject a = fOVector[0];
+// pair<double,double> av = a.getVelocityV();
+// cout << "velocity "<<av.first<<","<<av.second<<endl;
+//
+// FlyObject b = fOVector[1];
+// pair<double,double> bv = b.getVelocityV();
+// cout << "velocity "<<bv.first<<","<<bv.second<<endl;
+
+
+
+}
+void FrameInfo ::swapTheFlyObject() {
+ if (fOVector.size() > 1) {
+ cout << "swapping\n";
+ FlyObject a = fOVector[0];
+ fOVector[0] = fOVector[1];
+ fOVector[1] = a;
+ }
+}
+void FrameInfo::output(ostream &out) {
+ out<<"FrameNo : "<<frameNo<<endl;
+ out<<"IsSingleBlob : "<<isSingleBlob<<endl;
+// out<<"fOVector size "<<fOVector.size()<<endl;
+ for (int i=0; i<fOVector.size(); i++) {
+ FlyObject a = fOVector[i];
+// out<<"FlyObject "<<i<<endl;
+ a.output(out);
+ }
+}
diff --git a/fly-tools/FrameInfo.h b/fly-tools/FrameInfo.h
new file mode 100644
index 0000000..58452e0
--- /dev/null
+++ b/fly-tools/FrameInfo.h
@@ -0,0 +1,35 @@
+/*
+ * FrameInfo.h
+ *
+ *
+ * Created by Md. Alimoor Reza on 6/26/10.
+ * Copyright 2010 Drexel University. All rights reserved.
+ *
+ */
+
+#include<iostream>
+#include<vector>
+#include<fstream>
+#include "FlyObject.h"
+using namespace std;
+
+class FrameInfo {
+public:
+ FrameInfo(int frameNo, vector<FlyObject > fOVector, bool isSingleBlob);
+ FrameInfo(const FrameInfo &f);
+ int getFrameNo() const;
+ bool getIsSingleBlob() const;
+ vector<FlyObject > getFOVector() const;
+
+ void setFrameNo(int fn);
+ void setIsSingleBlob(bool isSingleBlob);
+ void setFOVector(vector<FlyObject > fov);
+ void swapTheFlyObject();
+ void output(ostream &out);
+
+
+private:
+ bool isSingleBlob;
+ int frameNo;
+ vector<FlyObject > fOVector;
+};
diff --git a/fly-tools/FurthestPointAlongMajorAxis.cpp b/fly-tools/FurthestPointAlongMajorAxis.cpp
new file mode 100644
index 0000000..8c8a086
--- /dev/null
+++ b/fly-tools/FurthestPointAlongMajorAxis.cpp
@@ -0,0 +1,3084 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <cmath>
+#include <vector>
+#include <list>
+#include <fstream>
+#include <cassert>
+#include <cstdlib>
+
+#include <ImageMagick/Magick++.h>
+
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_eigen.h>
+
+#include "FrameInfo.h"
+
+using namespace Magick;
+using namespace std;
+
+const double PI = atan(1.0)*4.0;
+const double FACTOR_EIGEN = 100;
+const int STUCKING_TO_A_SINGLE_BLOB = 1;
+const int SEPARATING_FROM_SINGLE_BLOB = 2;
+
+
+Image* residual;
+
+vector<FlyObject > fOVector;
+vector<FrameInfo > fIVector;
+// temporary store of the frames for finding initial head direction
+vector<FrameInfo > fIForHeadVector;
+// since for the first time the head is automatically need to be set
+int startIndexToFindNewHead=0;
+int endIndexToFindNewHead;
+double initLargeLocationX=-1;
+double initLargeLocationY=-1;
+double initSmallLocationX=-1;
+double initSmallLocationY=-1;
+pair<double, double> largeCollisionBeforeDirection;
+pair<double, double> smallCollisionBeforeDirection;
+
+// start location in the vector where two object get together
+int startIndexSingleBlob=-1;
+int endIndexSingleBlob =-1;
+
+// indices of the new set of sequences
+int startOfATrackSequence = 0; // fix it later on inside main
+int endOfATrackSequence=-1;
+int sequenceSize=1;
+
+// indices for printing the one object frames
+int startOfAOneObject = -1;
+int endOfAOneObject = -1;
+
+vector<string> fnVector;
+string inputFileName;
+
+// GLOBAL PATHS
+string maskImagePath;
+string origImagePath;
+string finalOutputPath;
+
+vector<pair<double, double> > velocityDirectionsF;
+vector<pair<double, double> > velocityDirectionsS;
+
+pair<double, double> avgVelocityF;
+pair<double, double> avgVelocityS;
+
+pair<double, double> overAllVelocityF;
+pair<double, double> overAllVelocityS;
+
+vector<pair<double, double> > evDirectionF;
+vector<pair<double, double> > evDirectionS;
+
+void initSequence(){
+
+ startOfATrackSequence = -1;
+ endOfATrackSequence = -1;
+ sequenceSize = 1;
+
+
+}
+
+ostream &operator<<(ostream &out, FlyObject & fO) {
+ fO.output(out);
+ return out;
+}
+
+ostream &operator<<(ostream &out, FrameInfo & fI) {
+ fI.output(out);
+ return out;
+}
+
+void bubbleSort(vector<FlyObject > & fov) {
+
+ //FlyObject a,b,c;
+ for(int i=1; i<fov.size(); i++) {
+ for(int j=0; j<fov.size()-i; j++) {
+ FlyObject a = fov[j];
+ FlyObject b = fov[j+1];
+
+ if (a.getArea() < b.getArea()) {
+ FlyObject c = fov[j];
+ fov[j] = fov[j+1];
+ fov[j+1] = c;
+
+ }
+
+ }
+
+ }
+
+}
+
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon=true, bool colorLookingFor=true);
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color=true);
+vector<double> covariantDecomposition(vector<pair<int,int> > & points);
+pair<int,int> getCentroid(vector<pair<int,int> > & points);
+bool isInterface(Image* orig, unsigned int x, unsigned int y);
+void writeFrameImage(int fn, string imS);
+void drawTheFlyObject(FrameInfo currentFI, string fileName, int isFirst, bool singleBlob=false);
+void drawTheSequence(int startIndex, int endIndex, int isFirst, bool singleBlob = false);
+double euclideanDist(FlyObject a, FlyObject b);
+bool identifyFlyObjectFromFrameToFrame(FrameInfo prevFI, FrameInfo& currentFI, bool gotRidOfSingleBlob=false) ;
+int roundT(double v) {return int(v+0.5);}
+void determineHeadDirection(int fileCounter);
+
+
+void normalizeVector(pair<double,double> &a);
+double calculateDotProduct(pair<double, double> v, pair<double, double> eV);
+void calculateHeadVector(FlyObject fO, pair<double,double> &headDirection);
+
+/*
+void lookAt(int x, int y, jzImage& img)
+{
+ int imageWidth =img.width();
+ int imageHeight = img.height();
+ // if current pixel is white
+ if (img.pixelColor(x,y) == 1) {
+ // if it was the first white pixel then
+ if (!inWhite)
+ {
+ // check whether it started as a white pixel; if it started as white pixel then this line segment should
+ // not be counted. because it is part of the larger white blob
+ if ( (x == 0 || x == (imageWidth -1) ) || ( y == 0 || y == (imageHeight - 1)))
+ startedWhite = true;
+ inWhite = true;
+ x_init = x;
+ y_init = y;
+ }
+ // if we are on a white region
+ //else {
+
+ //}
+
+ }
+
+ if (img.pixelColor(x,y) == 0) {
+ // if we are going through a white line and reached the black pixel
+ if (inWhite)
+ {
+ // if the line started as a white pixel then discard the line fragment
+ if (startedWhite == false) {
+ int val = roundT(dist(x_init, y_init, x, y));
+ //cout<<" val is = " << val << " at (x0,y0) = " << x_init << "," << y_init << " to (x1,y1) = " << x << "," << y <<endl;
+ len[val]++;
+ } else
+ startedWhite = false;
+
+ inWhite = false;
+ }
+ }
+}
+
+void drawLine(int x0, int y0, int x1, int y1, jzImage& img)
+{
+ inWhite = false;
+ startedWhite = false;
+
+ // always go from x0 -> x1
+ if (x0 > x1)
+ {
+ int temp = x0;
+ x0 = x1;
+ x1 = temp;
+ temp = y0;
+ y0 = y1;
+ y1 = temp;
+ }
+
+ int dx, dy, d, x, y, incrE, incrNE;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ y = y0;
+ x = x0;
+
+ // if they are on a vertical line
+ if (dx == 0)
+ {
+ if (y0 < y1)
+ for (int i = y0; i<=y1; i++)
+ lookAt(x,i,img);
+ else
+ for (int i = y1; i<=y0; i++)
+ lookAt(x,i,img);
+ return;
+ }
+
+ // if they are on a horizontal line
+ if (dy == 0)
+ {
+ for (int i = x0; i<=x1; i++)
+ lookAt(i,y,img);
+ return;
+ }
+
+ int dir = 0;
+ double m = double(dy)/double(dx);
+ if (m >= 1.0)
+ dir = 1;
+ else if ( (m < 0.0) && (m > -1.0) )
+ dir = 2;
+ else if (m <= -1.0)
+ dir = 3;
+
+ switch(dir)
+ {
+ // when slope m: 0< m <1
+ case 0:
+ d = dy*2 - dx;
+ incrE = dy*2;
+ incrNE = (dy - dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ // when slope m: m >= 1
+ case 1:
+ d = dx*2 - dy;
+ incrE = dx*2;
+ incrNE = (dx - dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y<y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ case 2:
+ d = dy*2 + dx;
+ incrE = dy*2;
+ incrNE = (dy + dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d >= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+
+ lookAt(x,y,img);
+ }
+ break;
+ // since initially we swapped the P0 with P1 so that P0 always holds values with smaller x cooridinate
+ // so we are sure that m<0 is the result of y0 being greater that
+ case 3:
+ d = dx*2 + dy;
+ incrE = dx*2;
+ incrNE = (dx + dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y>y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y--;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ }
+
+
+ if (inWhite)
+ {
+ // it is a fraction of the blob so dont count it
+ //len[dist(x_init,y_init,x,y)+1]++;
+ inWhite = false;
+ startedWhite = false;
+ }
+}*/
+
+bool isInMaleBlob;
+bool isInBlackZone;
+bool isInFemaleBlob;
+bool isAtTheBoundary;
+int maskImageHeight;
+int maskImageWidth;
+void putPixel(Image* maskImage, int x, int y, int color) {
+
+ ColorMono currPixelColor = ColorMono(maskImage->pixelColor(x,y));
+
+ // if current pixel is still inside the male fly do nothing
+ // if current pixel is black and prior to that it was inside the male fly then enter the black zone
+ if (currPixelColor.mono() == false and isInMaleBlob == true) {
+ isInBlackZone = true;
+ isInMaleBlob = false;
+ cout << "Enters black zone "<<x<<","<<y<<endl;
+ } else if (currPixelColor.mono() == true and isInBlackZone == true) {
+ isInFemaleBlob = true;
+ cout << "Hit the female fly"<<" "<<x<<","<<y<<endl;
+ } else if (currPixelColor.mono() == false and isInBlackZone == true and ( x == 0 || x == (maskImageWidth-1) || y == 0 || y == (maskImageHeight-1) ) ) {
+ isAtTheBoundary = true;
+ cout << "Is at the boundary"<<endl;
+ }
+
+
+}
+
+
+int draw_line_bm(Image* maskImage, int x0, int y0, int x1, int y1) {
+
+ // mark the flag to indicate that it is still inside the male blob
+ isInMaleBlob = true;
+ isInBlackZone = false;
+ isInFemaleBlob = false;
+ isAtTheBoundary = false;
+ maskImageHeight = maskImage->rows();
+ maskImageWidth = maskImage->columns();
+
+ int x, y;
+ int dx, dy;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ double m = static_cast<double> (dy)/static_cast<double> (dx);
+
+ int octant = -1;
+ if (( m >= 0 and m <= 1) and x0 < x1 ) {
+ cout << "Octant 1"<<endl;
+ octant = 1;
+ } else if ((m > 1) and (y0 < y1)) {
+ cout << "Octant 2"<<endl;
+ octant = 2;
+ } else if ((m < -1) and (y0 < y1)) {
+ cout << "Octant 3"<<endl;
+ octant = 3;
+ } else if ((m <=0 and m >= -1) and (x0 > x1)) {
+ cout << "Octant 4"<<endl;
+ octant = 4;
+ } else if ((m > 0 and m <=1) and (x0 > x1) ) {
+ cout << "Octant 5"<<endl;
+ octant = 5;
+ }else if ((m > 1) and (y0 > y1) ) {
+ cout << "Octant 6"<<endl;
+ octant = 6;
+ }else if ((m < -1) and (y0 > y1) ) {
+ cout << "Octant 7"<<endl;
+ octant = 7;
+ } else if ((m <=0 and m >= -1) and (x0 < x1) ) {
+ cout << "Octant 8"<<endl;
+ octant = 8;
+ }
+
+ int d;
+ int delE, delN, delW, delNE, delNW, delSW, delS, delSE;
+
+ dx = abs(dx);
+ dy = abs(dy);
+
+ switch (octant) {
+ case 1:
+ //----------------------------
+ d = 2*dy - dx;
+ delE = 2*dy;
+ delNE = 2*(dy-dx);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 1);
+
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+ while (x<=x1) {
+ // if we choose E because midpoint is above the line
+ if (d <= 0) {
+
+ d = d + delE;
+ x = x+1;
+ } else {
+
+ d = d + delNE;
+ x = x + 1;
+ y = y + 1;
+ }
+
+ putPixel(maskImage,x, y, 1);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+ }
+ break;
+
+ case 2:
+
+ d = 2*dx - dy;
+ delN = 2*dx;
+ delNE = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 2);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while (y<=y1) {
+ // if we choose N because midpoint is above the line
+ if (d<=0) {
+ d = d + delN;
+ y = y + 1;
+ } else {
+ d = d + delNE;
+ x = x + 1;
+ y = y + 1;
+ }
+ putPixel(maskImage,x, y, 2);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+ }
+ break;
+
+ case 3:
+
+ d = dy - 2*dx;
+ delN = 2*dx;
+ delNW = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 3);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while (y<=y1) {
+
+ if (d <= 0) {
+
+ d = d + delN;
+ //cout << "Going N d <= 0\n";
+ y = y + 1;
+
+ } else {
+ d = d + delNW;
+ //cout << "Going NW d > 0\n";
+ y = y + 1;
+ x = x - 1;
+ }
+ putPixel(maskImage,x, y, 3);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ }
+
+ break;
+
+ case 4:
+
+ d = -dx + 2*dy;
+ //cout << "-dx + 2*dy = "<<(-dx+2*dy)<<endl;
+ delW = 2*dy;
+ //cout << "-2*dy = "<<(2*dy)<<endl;
+ delNW = 2*(-dx + dy);
+ //cout << "2*(-dx + dy) = "<<(2*(-dx + dy))<<endl;
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 4);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while ( x >= x1 ) {
+
+ if (d <= 0) {
+
+ d = d + delW;
+ x = x - 1;
+ //cout << "At pixel(" <<x<<","<<y<<") Going W since d <= 0 "<<d<<endl;
+
+
+ } else {
+ d = d + delNW;
+
+ //cout << "At pixel(" <<x<<","<<y<<") Going NW since d > 0 "<<d<<endl;
+
+ x = x - 1;
+ y = y + 1;
+ }
+
+ putPixel(maskImage,x, y, 4);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+ }
+
+ break;
+
+ /*case 4:
+
+ d = dx - 2*dy;
+ cout << "dx - 2*dy = "<<(dx-2*dy)<<endl;
+ delW = -2*dy;
+ cout << "-2*dy = "<<(-2*dy)<<endl;
+ delNW = 2*(dx - dy);
+ cout << "2*(dx - dy) = "<<(2*(dx - dy))<<endl;
+
+ x = x0;
+ y = y0;
+
+ putpixel(x, y, 4);
+
+ while ( x >= x1 ) {
+
+ if (d <= 0) {
+
+ d = d + delW;
+ x = x - 1;
+ cout << "At pixel(" <<x<<","<<y<<") Going W since d <= 0 "<<d<<endl;
+
+
+ } else {
+ d = d + delNW;
+
+ cout << "At pixel(" <<x<<","<<y<<") Going NW since d > 0 "<<d<<endl;
+
+ x = x - 1;
+ y = y + 1;
+ }
+
+ putpixel(x, y, 4);
+ }
+
+ break;
+ */
+
+ case 5:
+
+ d = -dx + 2*dy;
+ delW = 2*dy;
+ delSW = 2*(-dx+dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x, y, 5);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while (x>=x1) {
+
+ if (d<=0) {
+
+ //cout << "Going W since d<0"<<endl;
+ d = d + delW;
+ x = x - 1;
+
+ } else {
+ d = d + delSW;
+
+ x = x - 1;
+
+ y = y - 1;
+
+ //cout << "Going SW since d > 0"<<endl;
+
+ }
+
+ putPixel(maskImage,x, y, 5);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ }
+
+ break;
+
+
+ case 6:
+
+ d = 2*dx - dy;
+ delS = 2*dx;
+ delSW = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x,y,6);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while (y>=y1) {
+
+ if (d<=0) {
+ d = d + delS;
+ y = y -1;
+ }
+ else {
+ d = d + delSW;
+ y = y -1;
+ x = x -1;
+ }
+
+ putPixel(maskImage,x, y, 6);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ }
+
+ break;
+
+ case 7:
+
+ d = 2*dx - dy;
+ delS = 2*dx;
+ delSE = 2*(dx-dy);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x,y,7);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while (y>=y1) {
+
+ if (d<=0) {
+ d = d + delS;
+ y = y -1;
+ }
+ else {
+ d = d + delSE;
+ y = y - 1;
+ x = x + 1;
+ }
+
+ putPixel(maskImage,x, y, 7);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+ }
+
+ break;
+
+ case 8:
+
+ d = 2*dy - dx;
+ delE = 2*dy;
+ delSE = 2*(dy - dx);
+
+ x = x0;
+ y = y0;
+
+ putPixel(maskImage,x,y,8);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ while (x<=x1) {
+
+ if (d<=0) {
+ d = d + delE;
+ x = x + 1;
+ }
+ else {
+ d = d + delSE;
+ y = y - 1;
+ x = x + 1;
+ }
+
+ putPixel(maskImage,x, y, 8);
+ if (isInFemaleBlob == true)
+ return 1;
+ else if (isAtTheBoundary == true)
+ return 2;
+
+
+ }
+
+ break;
+
+ default:
+ cout << "No octant which should be a bug\n";
+ exit(0);
+ break;
+
+
+ }
+
+ return 0;
+
+}
+
+
+void fillResidualWithObj(vector<pair<int, int> > & obj, ColorRGB c)
+{
+ for (unsigned int i = 0; i<obj.size(); i++)
+ residual->pixelColor(obj[i].first, obj[i].second, c);
+}
+double euclideanDist(pair<int, int > newLocation, pair<int, int> initLocation) {
+
+ double temp = pow((newLocation.first - initLocation.first), 2.0) + pow((newLocation.second - initLocation.second), 2.0);
+ temp = sqrt(temp);
+ return temp;
+
+}
+bool calculateDisplacement(FrameInfo prevFI, FrameInfo currentFI) {
+
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ FlyObject pFLargeFO = pFOVector[0];
+ FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ pair<int, int> cFLargeCentroid = cFLargeFO.getCentroid();
+ pair<int, int> initLarge(initLargeLocationX, initLargeLocationY);
+
+ double largeDist = euclideanDist(cFLargeCentroid, initLarge);
+ cout << "Large object current position "<<cFLargeCentroid.first<<" , "<<cFLargeCentroid.second<<endl;
+ cout << "Large object went to "<<largeDist<<endl;
+
+ pair<int, int> cFSmallCentroid = cFSmallFO.getCentroid();
+ pair<int, int> initSmall(initSmallLocationX, initSmallLocationY);
+
+ double smallDist = euclideanDist(cFSmallCentroid, initSmall);
+ cout << "Small object current position "<<cFSmallCentroid.first<<" , "<<cFSmallCentroid.second<<endl;
+ cout << "Small object went to "<<smallDist<<endl;
+
+ // try first checking only one distance change
+ // 20 pixel distance is too much to get away. It creates oscillation of forward and backward movement
+ // in the small fly since it follows the larger.
+// if (largeDist >= 20 || smallDist >=20)
+// return true;
+// else
+// return false;
+ if (largeDist >= 5 || smallDist >=5)
+ return true;
+ else
+ return false;
+
+
+}
+
+int sequenceCondition(FrameInfo prevFI,FrameInfo currentFI) {
+ bool prevFIsSingleBlob = prevFI.getIsSingleBlob();
+ bool currentFIsSingleBlob = currentFI.getIsSingleBlob();
+
+ if (prevFIsSingleBlob == false and currentFIsSingleBlob == true)
+ return STUCKING_TO_A_SINGLE_BLOB;
+ else if (prevFIsSingleBlob == true and currentFIsSingleBlob == false)
+ return SEPARATING_FROM_SINGLE_BLOB;
+ else
+ return -1;
+
+}
+
+
+bool isStuckToSingleBlob(FrameInfo prevFI,FrameInfo currentFI) {
+ bool prevFIsSingleBlob = prevFI.getIsSingleBlob();
+ bool currentFIsSingleBlob = currentFI.getIsSingleBlob();
+
+ if (prevFIsSingleBlob == false and currentFIsSingleBlob == true)
+ return true;
+ else
+ return false;
+
+}
+
+
+bool isStartOfNewHeadDirectionSearch(FrameInfo prevFI, FrameInfo currentFI) {
+
+ bool prevFIsSingleBlob = prevFI.getIsSingleBlob();
+ bool currentFIsSingleBlob = currentFI.getIsSingleBlob();
+
+ if (prevFIsSingleBlob == true and currentFIsSingleBlob == false)
+ return true;
+ else
+ return false;
+
+}
+
+void separateObjectAndInitForNewHeadCalculation(FrameInfo prevFI, FrameInfo currentFI) {
+
+ // ASSUMPTION : the bigger object retains the previous frame head direction. And the smaller frame head calculation starts
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ // previous frame should have only one frame when this function is called
+ if (pFOVector.size() > 1) {
+ cerr<<"Previous frame does contain more than one fly object in the funciton separateObjectAndInitForNewHeadCalculation()"<<endl;
+ }
+
+ FlyObject pFLargeFO = pFOVector[0];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ pair<int, int> currentFLargeCentroid = cFLargeFO.getCentroid();
+ initLargeLocationX = currentFLargeCentroid.first;
+ initLargeLocationY = currentFLargeCentroid.second;
+
+ cout << "Init location of the large object when get departed first ("<<initLargeLocationX<<" , "<<initLargeLocationY<<")"<<endl;
+
+ pair<int, int> currentFSmallCentroid = cFSmallFO.getCentroid();
+ initSmallLocationX = currentFSmallCentroid.first;
+ initSmallLocationY = currentFSmallCentroid.second;
+
+
+ cout << "Init location of the small object when get departed first ("<<initSmallLocationX<<" , "<<initSmallLocationY<<")"<<endl;
+
+ // Later on may try to find the object that moves toward the previous frames direction
+
+}
+
+
+pair<double, double> windowLargeHeadDirection;
+
+
+void computeHeadBackward(FrameInfo nextFI, FrameInfo &currentFI) {
+ vector<FlyObject > nextFOVector = nextFI.getFOVector();
+ vector<FlyObject > currentFOVector = currentFI.getFOVector();
+
+ // next frame objects
+ FlyObject nextFLargeFO = nextFOVector[0];
+ FlyObject nextFSmallFO = nextFOVector[1];
+
+ // current frame objects
+ FlyObject currentFLargeFO = currentFOVector[0];
+ FlyObject currentFSmallFO = currentFOVector[1];
+
+ // larger
+ pair<double, double> cLEV = currentFLargeFO.getMajorAxisEV();
+ normalizeVector(cLEV);
+ // historical head
+ pair<double, double> nLHH = nextFLargeFO.getHead();
+ // next frame head direction
+// pair<double, double> nLHD;
+// calculateHeadVector(nextFLargeFO, nLHD);
+ // take the minimum angle with the historical head
+ pair<int, int> nCentroid = nextFLargeFO.getCentroid();
+ cout << "Next Large was at "<<nCentroid.first<<","<<nCentroid.second<<endl;
+ cout << "Next large Historical Head was at direction "<<nLHH.first<<","<<nLHH.second<<endl;
+ double largeDotProdNHWCEV = calculateDotProduct(nLHH, cLEV);
+ pair<double, double> cLREV(-cLEV.first, -cLEV.second);
+ if (largeDotProdNHWCEV >=0) {
+ cout << "Current eigen is in direction with the historical head"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cLEV.first+0.9*nLHH.first;
+ double newHeadSecond = 0.1*cLEV.second+0.9*nLHH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ currentFLargeFO.setHead(newHead);
+ currentFLargeFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ //identifiedELEV = eLEV;
+
+ } else {
+ cout << "Current eigen is in opposite direction of the historical head\n";
+ // record this vector
+ double newHeadFirst = 0.1*cLREV.first+0.9*nLHH.first;
+ double newHeadSecond = 0.1*cLREV.second+0.9*nLHH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ currentFLargeFO.setHead(newHead);
+ currentFLargeFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV
+ //identifiedELEV = eLEV;
+
+ }
+
+
+ // small
+
+ pair<double, double> cSEV = currentFSmallFO.getMajorAxisEV();
+ normalizeVector(cSEV);
+ // small historical head
+ pair<double, double> nSHH = nextFSmallFO.getHead();
+ // next frame head direction
+// pair<double, double> nSHD;
+// calculateHeadVector(nextFSmallFO, nSHD);
+ // take the minimum angle with the historical head
+ pair<int,int> nSCentroid = nextFSmallFO.getCentroid();
+ cout << "Next small centroid at "<<nSCentroid.first<<","<<nSCentroid.second<<endl;
+ cout << "Next small historical head direction "<<nSHH.first<<","<<nSHH.second<<endl;
+
+ double smallDotProdNHWCEV = calculateDotProduct(nSHH, cSEV);
+ pair<double, double> cSREV(-cSEV.first, -cSEV.second);
+ if (smallDotProdNHWCEV >=0) {
+ cout << "Current eigen is in direction with the historical head"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cSEV.first+0.9*nSHH.first;
+ double newHeadSecond = 0.1*cSEV.second+0.9*nSHH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ currentFSmallFO.setHead(newHead);
+ currentFSmallFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ //identifiedELEV = eLEV;
+
+ } else {
+ cout << "Current eigen is in opposite direction of the historical head\n";
+ // record this vector
+ double newHeadFirst = 0.1*cSREV.first+0.9*nSHH.first;
+ double newHeadSecond = 0.1*cSREV.second+0.9*nSHH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ currentFSmallFO.setHead(newHead);
+ currentFSmallFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV
+ //identifiedELEV = eLEV;
+
+ }
+
+
+ // update the currentFrame
+ // update the fIForHeadVector update
+ vector<FlyObject > updatedFOVector;
+ updatedFOVector.push_back(currentFLargeFO);
+ updatedFOVector.push_back(currentFSmallFO);
+
+ currentFI.setFOVector(updatedFOVector);
+
+
+}
+
+void calculateNewHeadDirection() {
+
+ cout << "Start calculating new head direction for large,small fly objects"<<endl;
+ cout << "StartIndex "<<startIndexToFindNewHead<<" endIndex "<<endIndexToFindNewHead<<endl;
+
+ FrameInfo firstFI = fIForHeadVector[0];
+ FrameInfo endFI = fIForHeadVector[endIndexToFindNewHead-startIndexToFindNewHead];
+
+ // movement direction detection
+ vector<FlyObject > firstFOVector = firstFI.getFOVector();
+ vector<FlyObject > endFOVector = endFI.getFOVector();
+
+ // init frame objects
+ FlyObject firstFLargeFO = firstFOVector[0];
+ FlyObject firstFSmallFO = firstFOVector[1];
+
+ // end frame objects
+ FlyObject endFLargeFO = endFOVector[0];
+ FlyObject endFSmallFO = endFOVector[1];
+
+ // large
+ pair<int, int > firstFLargeFOCentroid = firstFLargeFO.getCentroid();
+ pair<int, int > endFLargeFOCentroid = endFLargeFO.getCentroid();
+ double largeDirectionX = endFLargeFOCentroid.first - firstFLargeFOCentroid.first;
+ double largeDirectionY = endFLargeFOCentroid.second - firstFLargeFOCentroid.second;
+ pair<double, double > largeDirection(largeDirectionX, largeDirectionY);
+ normalizeVector(largeDirection);
+
+
+ // find for the large object
+ cout << "For the larger end frame head finding \n";
+ pair<double, double> eLEV = endFLargeFO.getMajorAxisEV();
+ // normalize the eigenvector
+ normalizeVector(eLEV);
+ pair<double,double> identifiedELEV;
+
+// // the head from the previous frame
+// pair<double, double> pLH = pFLargeFO.getHead();
+
+ // find the whether the object is moving forward or backward
+ double largerDotProdMovDirAndLCBD = calculateDotProduct(largeDirection, largeCollisionBeforeDirection);
+
+ // find the dot product with the large object movement direction with end frames major axis both direction
+ double largerDotProdMovDirAndELEV = calculateDotProduct(largeDirection, eLEV);
+ pair<double,double> eLREV(-eLEV.first, -eLEV.second);
+ //double largerDotProdMovDirAndELEV = calculateDotProduct(pLH, clREV);
+ if (largerDotProdMovDirAndELEV >=0 and largerDotProdMovDirAndLCBD >= 0) {
+ cout << "Current eigen is in direction with the movement direction and moving forward \n";
+ // record this vector for history
+ double newHeadFirst = 0.1*eLEV.first+0.9*largeDirection.first;
+ double newHeadSecond = 0.1*eLEV.second+0.9*largeDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFLargeFO.setHead(newHead);
+ endFLargeFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ identifiedELEV = eLEV;
+
+ } else if (largerDotProdMovDirAndELEV <0 and largerDotProdMovDirAndLCBD >=0){
+ cout << "Current eigen is in opposite direction of the movement direction and moving forward\n";
+ // record this vector
+ double newHeadFirst = 0.1*eLREV.first+0.9*largeDirection.first;
+ double newHeadSecond = 0.1*eLREV.second+0.9*largeDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFLargeFO.setHead(newHead);
+ endFLargeFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV to reverse direction of the current EV
+ identifiedELEV = eLREV;
+
+ }
+
+ // moving backward
+ else if (largerDotProdMovDirAndELEV <0 and largerDotProdMovDirAndLCBD <0) {
+ cout << "Current eigen is in direction with the movement direction and moving backward"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*eLEV.first+0.9*largeDirection.first;
+ double newHeadSecond = 0.1*eLEV.second+0.9*largeDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFLargeFO.setHead(newHead);
+ endFLargeFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ identifiedELEV = eLEV;
+
+ } else if (largerDotProdMovDirAndELEV >=0 and largerDotProdMovDirAndLCBD <0 ) {
+ cout << "Current eigen is in opposite direction of movement direction and moving backward\n";
+ // record this vector
+ double newHeadFirst = 0.1*eLREV.first+0.9*largeDirection.first;
+ double newHeadSecond = 0.1*eLREV.second+0.9*largeDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFLargeFO.setHead(newHead);
+ endFLargeFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV to reverse direction of the current EV
+ identifiedELEV = eLREV;
+
+ }
+
+
+
+
+ // small
+ pair<int, int > firstFSmallFOCentroid = firstFSmallFO.getCentroid();
+ pair<int, int > endFSmallFOCentroid = endFSmallFO.getCentroid();
+ double smallDirectionX = endFSmallFOCentroid.first - firstFSmallFOCentroid.first;
+ double smallDirectionY = endFSmallFOCentroid.second - firstFSmallFOCentroid.second;
+ pair<double, double > smallDirection(smallDirectionX, smallDirectionY);
+ cout << "Small Direction "<<smallDirectionX<<","<<smallDirectionY<<endl;
+ normalizeVector(smallDirection);
+ cout << "Normalized small Direction "<<smallDirection.first<<","<<smallDirection.second<<endl;
+ pair<double, double> smallRevDirection(-smallDirection.first, -smallDirection.second);
+ cout << "Normalized small Reverse Direction "<<smallRevDirection.first<<","<<smallRevDirection.second<<endl;
+
+ // find for the small object
+ pair<double, double> eSEV = endFSmallFO.getMajorAxisEV();
+ // normalize the eigenvector
+ normalizeVector(eSEV);
+ pair<double,double> identifiedESEV;
+
+ // find the whether the object is moving forward or backward
+ double smallerDotProdMovDirAndSCBD = calculateDotProduct(smallDirection, smallCollisionBeforeDirection);
+
+ // find the dot product with the small object movement direction with end frames major axis both direction
+ double smallerDotProdMovDirAndESEV = calculateDotProduct(smallDirection, eSEV);
+ pair<double,double> eSREV(-eSEV.first, -eSEV.second);
+
+ if (smallerDotProdMovDirAndESEV >=0 && smallerDotProdMovDirAndSCBD >=0) {
+ cout << "Current eigen is in direction with the movement direction and moving forward "<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*eSEV.first+0.9*smallDirection.first;
+ double newHeadSecond = 0.1*eSEV.second+0.9*smallDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFSmallFO.setHead(newHead);
+ endFSmallFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ identifiedESEV = eSEV;
+
+ } else if (smallerDotProdMovDirAndESEV <0 and smallerDotProdMovDirAndSCBD >=0) {
+ cout << "Current eigen is in opposite direction of the movement direction and moving forward \n";
+ // record this vector
+ double newHeadFirst = 0.1*eSREV.first+0.9*smallDirection.first;
+ double newHeadSecond = 0.1*eSREV.second+0.9*smallDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFSmallFO.setHead(newHead);
+ endFSmallFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV
+ identifiedESEV = eSREV;
+
+ } else if (smallerDotProdMovDirAndESEV <0 and smallerDotProdMovDirAndSCBD <0 ) {
+ cout << "Current eigen is in direction with the movement direction and moving backward"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*eSEV.first+0.9*smallRevDirection.first;
+ double newHeadSecond = 0.1*eSEV.second+0.9*smallRevDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFSmallFO.setHead(newHead);
+ endFSmallFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ identifiedESEV = eSEV;
+
+ } else if (smallerDotProdMovDirAndESEV >=0 and smallerDotProdMovDirAndSCBD <0 ) {
+ cout << "Current eigen is in opposite direction with the movement direction and moving backward\n";
+ // record this vector
+ double newHeadFirst = 0.1*eSREV.first+0.9*smallRevDirection.first;
+ double newHeadSecond = 0.1*eSREV.second+0.9*smallRevDirection.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ endFSmallFO.setHead(newHead);
+ endFSmallFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV
+ identifiedESEV = eSREV;
+
+ }
+
+
+
+ // update the fIForHeadVector update
+ vector<FlyObject > updatedFOVector;
+ updatedFOVector.push_back(endFLargeFO);
+ updatedFOVector.push_back(endFSmallFO);
+
+ endFI.setFOVector(updatedFOVector);
+
+ // update the vector with the correct info
+ fIForHeadVector[endIndexToFindNewHead-startIndexToFindNewHead] = endFI;
+
+ // calculate the head directions from end to first backwards
+ FrameInfo nextFI = fIForHeadVector[endIndexToFindNewHead-startIndexToFindNewHead];
+
+ cout << "fIForHeadVector size "<<fIForHeadVector.size()<<endl;
+
+ for (int i=fIForHeadVector.size()-2; i>=0; i--) {
+
+ cout << "Calculating backwards head direction i "<<i<<endl;
+ FrameInfo currentFI = fIForHeadVector[i];
+ computeHeadBackward(nextFI, currentFI);
+ // update the frame after calculating the information
+ fIForHeadVector[i] = currentFI;
+
+ nextFI = currentFI;
+
+ }
+
+ cout << "New head direction done size "<<fIForHeadVector.size()<<endl;
+ cout << "Copying into the fIVector from position "<<startIndexToFindNewHead<<" to "<<endIndexToFindNewHead<<endl;
+ for (int i=0; i<=(endIndexToFindNewHead-startIndexToFindNewHead); i++) {
+ cout << "Copying to fIVector[(startIndex + i)="<<(startIndexToFindNewHead+i)<<" from fIForNewHead[i="<<i<<endl;
+ fIVector[startIndexToFindNewHead+i] = fIForHeadVector[i];
+ }
+}
+
+void drawTheSequence(int startIndex, int endIndex, int isFirst, bool singleBlob) {
+
+ cout << "Should draw "<<isFirst<<endl;
+ //ifstream inputFile;
+ //inputFile.open(inputFileName.c_str());
+ /*if (inputFile.fail() ) {
+ cout << "cannot open the input file that contains name of the input images\n";
+ exit(1);
+ }*/
+
+ string fileName = fnVector[startIndex];
+ //inputFile>>fileName;
+ //inputFileName = "output/identified/"+fileName;
+ FrameInfo prevFI = fIVector[startIndex];
+ cout << "Extracting information for image "<< prevFI.getFrameNo() << endl;
+ cout << "----------------------------------------\n";
+ cout<<prevFI;
+ drawTheFlyObject(prevFI, fileName, isFirst, singleBlob);
+
+ for (int i=startIndex+1; i<=endIndex; i++) {
+ FrameInfo nextFI = fIVector[i];
+ cout << "Extracting information for image "<< nextFI.getFrameNo() << endl;
+ cout << "----------------------------------------\n";
+ //FrameInfo na = &nextFI;
+ cout<<nextFI;
+ //inputFile>>fileName;
+ fileName = fnVector[i];
+ // inputFileName = "output/identified/"+fileName;
+ drawTheFlyObject(nextFI, fileName, isFirst, singleBlob);
+ }
+
+ //inputFile.close();
+
+}
+
+void normalizeVector(pair<double,double> &a) {
+ double temp = a.first*a.first + a.second*a.second;
+ temp = sqrt(temp);
+ if (temp != 0) {
+ a.first = a.first/temp;
+ a.second = a.second/temp;
+ }
+}
+double calculateDotProduct(pair<double, double> v, pair<double, double> eV) {
+ return (v.first*eV.first + v.second*eV.second);
+}
+void calculateHeadVector(FlyObject fO, pair<double,double> &headDirection) {
+ bool headDirectionBool = fO.getHeadIsInDirectionMAEV();
+ pair<double,double> fOMajorAxis = fO.getMajorAxisEV();
+ if (headDirectionBool == true) {
+ headDirection.first = fOMajorAxis.first;
+ headDirection.second = fOMajorAxis.second;
+ } else {
+ headDirection.first = -fOMajorAxis.first;
+ headDirection.second = -fOMajorAxis.second;
+ }
+}
+void determineHeadDirection(int fileCounter) {
+
+ FrameInfo prevFI = fIVector[fileCounter-1];
+ FrameInfo currentFI = fIVector[fileCounter];
+
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ FlyObject pFLargeFO = pFOVector[0];
+ FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ // calculate velocity
+ pair<int,int> pFLCentroid = pFLargeFO.getCentroid();
+ pair<int,int> pFSCentroid = pFSmallFO.getCentroid();
+
+ pair<int,int> cFLCentroid = cFLargeFO.getCentroid();
+ pair<int,int> cFSCentroid = cFSmallFO.getCentroid();
+
+ double velocityXLarge = static_cast<double> (cFLCentroid.first) - static_cast<double> (pFLCentroid.first);
+ double velocityYLarge = static_cast<double> (cFLCentroid.second) - static_cast<double> (pFLCentroid.second);
+
+ double velocityXSmall = static_cast<double> (cFSCentroid.first) - static_cast<double> (pFSCentroid.first);
+ double velocityYSmall = static_cast<double> (cFSCentroid.second) - static_cast<double> (pFSCentroid.second);
+
+ pair<double,double> cLVV(velocityXLarge,velocityYLarge);
+ pair<double,double> cSVV(velocityXSmall,velocityYSmall);
+
+ cFLargeFO.setVelocityV(cLVV);
+ cFSmallFO.setVelocityV(cSVV);
+
+ // normalize the velocity
+ cFLargeFO.normalizeVelocity();
+ cFSmallFO.normalizeVelocity();
+
+ // determine the head direction for larger object
+ pair<double, double> cLEV = cFLargeFO.getMajorAxisEV();
+ // normalize the eigenvector
+ normalizeVector(cLEV);
+ pair<double,double> identifiedCLEV;
+
+ // the head from the previous frame
+ pair<double, double> pLH = pFLargeFO.getHead();
+
+ // find the dot product with the previous frame head with current major axis both direction
+ double largerDotProdPrevHeadAndCLEV = calculateDotProduct(pLH, cLEV);
+ pair<double,double> cLREV(-cLEV.first, -cLEV.second);
+ //double largerDotProdPrevHeadAndCLREV = calculateDotProduct(pLH, clREV);
+ if (largerDotProdPrevHeadAndCLEV >=0) {
+ cout << "Current eigen is in direction with the historical head"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cLEV.first+0.9*pLH.first;
+ double newHeadSecond = 0.1*cLEV.second+0.9*pLH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ cFLargeFO.setHead(newHead);
+ cFLargeFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV
+ identifiedCLEV = cLEV;
+
+ } else {
+ cout << "Current eigen is in opposite direction of the historical head\n";
+ // record this vector
+ double newHeadFirst = 0.1*cLREV.first + 0.9*pLH.first;
+ double newHeadSecond =0.1*cLREV.second+0.9*pLH.second;
+ pair<double, double> newHead(newHeadFirst,newHeadSecond);
+ cFLargeFO.setHead(newHead);
+ cFLargeFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV to reverse direction of the current EV
+ identifiedCLEV = cLREV;
+
+ }
+
+
+ // tracking the forward and backward movement of the fly object
+ double largeDotProd = calculateDotProduct(cLVV, identifiedCLEV);
+ cout << "largerDotProd "<<largeDotProd<<endl;
+ if (largeDotProd >= 0) {
+ cout<<"Larger Dot prod is positive"<<endl;
+ // cFLargeFO.setHeadIsInDirectionMAEV(true);
+ } else {
+ cout<<"Larger Dot prod is negative"<<endl;
+ // cFLargeFO.setHeadIsInDirectionMAEV(false);
+ }
+
+
+ pair<double, double > cSEV = cFSmallFO.getMajorAxisEV();
+ normalizeVector(cSEV);
+ pair<double,double> identifiedCSEV;
+ // head from the previous frame
+ pair<double,double> pSH = pFSmallFO.getHead();
+
+ // find the dot product with the previous frame head with current major axis both direction
+ double smallerDotProdPrevHeadAndCSEV = calculateDotProduct(pSH, cSEV);
+ pair<double, double> cSREV(-cSEV.first, -cSEV.second);
+ if (smallerDotProdPrevHeadAndCSEV >=0) {
+ cout << "Current eigen is in direction with the historical head for the smaller fly object"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cSEV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSEV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+ cFSmallFO.setHeadIsInDirectionMAEV(true);
+ // set the identified EV to current EV
+ identifiedCSEV = cSEV;
+ } else {
+ cout << "Current eigen is in direction with the historical head for the smaller fly object"<<endl;
+ // record this vector for history
+ double newHeadFirst = 0.1*cSREV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSREV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+ cFSmallFO.setHeadIsInDirectionMAEV(false);
+ // set the identified EV to reverse direction of current EV
+ identifiedCSEV = cSREV;
+
+ }
+
+ // to detect the swift change of head direction with 2 frames
+ // find previous frame's HD
+ pair<double, double> previousHeadDirection;
+ calculateHeadVector(pFSmallFO, previousHeadDirection);
+ // find the current frame's HD
+ pair<double, double> currentHeadDirection;
+ calculateHeadVector(cFSmallFO, currentHeadDirection);
+
+ // calculate the dot product of previous head direction and current head direction.
+ double previousHDDotCurrentHD = calculateDotProduct(previousHeadDirection, currentHeadDirection);
+ if (previousHDDotCurrentHD < 0 and fileCounter > 1) {
+
+ // now check if velocity direction( for the future historical velocity might be considered too) and
+ // current head direction dot product is also less than zero
+ // asssumption that current velocity and new head direction are towards same direction
+ // pair<double, double> currentVelocity = cFSmallFO.getVelocityV();
+ // double currentVVDotCurrentHD = calculateDotProduct(currentVelocity, currentHeadDirection);
+ // if (currentVVDotCurrentHD < 0)
+ {
+ // toggle current head direction
+ bool currentHeadDirectionBool = cFSmallFO.getHeadIsInDirectionMAEV();
+ if (currentHeadDirectionBool == true)
+ cFSmallFO.setHeadIsInDirectionMAEV(false);
+ else {
+ cFSmallFO.setHeadIsInDirectionMAEV(true);
+
+ }
+
+ // update the historical head
+ // reset historical head to conform to the swift change in head direction
+ bool cFSmallFOFinalHeadDirectionBool = cFSmallFO.getHeadIsInDirectionMAEV();
+ if (cFSmallFOFinalHeadDirectionBool == true) {
+ // record this vector for history
+ double newHeadFirst = cSEV.first;
+ double newHeadSecond = cSEV.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ } else {
+ // record this vector for history
+ double newHeadFirst = cSREV.first;
+ double newHeadSecond = cSREV.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ }
+
+
+ }
+ }
+
+ /* retain historical head
+ bool cFSmallFOFinalHeadDirectionBool = cFSmallFO.getHeadIsInDirectionMAEV();
+ if (cFSmallFOFinalHeadDirectionBool == true) {
+ // record this vector for history
+ double newHeadFirst = 0.1*cSEV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSEV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ } else {
+ // record this vector for history
+ double newHeadFirst = 0.1*cSREV.first + 0.9*pSH.first;
+ double newHeadSecond = 0.1*cSREV.second + 0.9*pSH.second;
+ pair<double,double> newHead(newHeadFirst, newHeadSecond);
+ cFSmallFO.setHead(newHead);
+
+ }
+ */
+
+ double smallDotProd = calculateDotProduct(cSVV, cSEV);
+
+ if (smallDotProd >= 0) {
+ cout << "Smaller dot product is positive"<<endl;
+ // cFSmallFO.setHeadIsInDirectionMAEV(true);
+ } else {
+ cout << "Smaller dot product is negative"<<endl;
+ // cFSmallFO.setHeadIsInDirectionMAEV(false);
+ }
+
+
+ // update the flyobject vector
+ vector<FlyObject > updatedFOVector;
+ updatedFOVector.push_back(cFLargeFO);
+ updatedFOVector.push_back(cFSmallFO);
+
+ currentFI.setFOVector(updatedFOVector);
+
+ fIVector[fileCounter] = currentFI;
+
+ // cout << "checking the update"<<endl;
+ // FrameInfo tempFI = fIVector[fileCounter];
+ //
+ // vector<FlyObject > tempFIFOVector = tempFI.getFOVector();
+ // FlyObject tempFILFO = tempFIFOVector[0];
+ // FlyObject tempFISFO = tempFIFOVector[1];
+ // pair<double, double> tempFILFOVV = tempFILFO.getVelocityV();
+ // cout << "Large object velocity vector "<<tempFILFOVV.first<<","<<tempFILFOVV.second<<endl;
+ // pair<double,double > tempFISFOVV = tempFISFO.getVelocityV();
+ // cout << "Small object velocity vector "<<tempFISFOVV.first<<","<<tempFISFOVV.second<<endl;
+
+
+}
+
+
+void objectHeadDirection(FlyObject prevFO, FlyObject &currentFO) {
+
+ // take the head direction from the previous frame
+ pair<double, double> pFHH = prevFO.getHead();
+
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdEVAndHH = calculateDotProduct(cFOEV, pFHH);
+ if (dotProdEVAndHH > 0 ) {
+ cout << "Current head is in direction with the Previous frame Head(which is the historical head from the maxDistIndex)"<<endl;
+ double newHeadX = 0.1*cFOEV.first+0.9*pFHH.first;
+ double newHeadY = 0.1*cFOEV.second+0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(true);
+
+ } else {
+ cout << "Current head is in direction with the previous frame head"<<endl;
+ double newHeadX = 0.1*cFOREV.first + 0.9*pFHH.first;
+ double newHeadY = 0.1*cFOREV.second + 0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(false);
+
+ }
+
+ // copy the velocity vector from the previous frame
+ pair<double, double> pFVV = prevFO.getVelocityV();
+ currentFO.setVelocityV(pFVV);
+
+}
+
+void objectHeadDirection(FlyObject prevFO, FlyObject &currentFO, bool prevFFOHD) {
+
+ // take the head direction from the previous frame
+ //pair<double, double> pFHH = prevFO.getHead();
+
+ pair<double,double> pFHeadDir;
+ calculateHeadVector(prevFO, pFHeadDir);
+
+
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdEVAndHD = calculateDotProduct(cFOEV, pFHeadDir);
+ if (dotProdEVAndHD > 0 ) {
+ cout << "Current head is in direction with the Previous frame Head direction"<<endl;
+ /*double newHeadX = 0.1*cFOEV.first+0.9*pFHH.first;
+ double newHeadY = 0.1*cFOEV.second+0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(true);
+ */
+ currentFO.setHead(cFOEV);
+ currentFO.setHeadIsInDirectionMAEV(true);
+
+ } else {
+ cout << "Current head is in reverse direction with the previous frame head direction"<<endl;
+ /*double newHeadX = 0.1*cFOREV.first + 0.9*pFHH.first;
+ double newHeadY = 0.1*cFOREV.second + 0.9*pFHH.second;
+ pair<double, double> newHead(newHeadX, newHeadY);
+ currentFO.setHead(newHead);
+ currentFO.setHeadIsInDirectionMAEV(false);
+ */
+ currentFO.setHead(cFOREV);
+ currentFO.setHeadIsInDirectionMAEV(false);
+
+ }
+
+ // copy the velocity vector from the previous frame
+ if (prevFFOHD == true) {
+ pair<double, double> pFVV = prevFO.getVelocityV();
+ currentFO.setVelocityV(pFVV);
+ }
+
+}
+
+void objectHeadDirection(FlyObject &currentFO, int saveEV=0) {
+
+ // get the velocity vector
+ pair<double, double> cFOVV = currentFO.getVelocityV();
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdVVAndEV = calculateDotProduct(cFOEV, cFOVV);
+ if (dotProdVVAndEV > 0 ) {
+ cout << "Current head is in direction with the velocity vector\n";
+ // set the head to the eigen vector
+ currentFO.setHead(cFOEV);
+ currentFO.setHeadIsInDirectionMAEV(true);
+
+ if (saveEV == 1) {
+ cout << "saving the eigen vector for the first object"<<endl;
+ evDirectionF.push_back(cFOEV);
+ } else if (saveEV == 2){
+ cout << "saving the eigen vector for the second object"<<endl;
+ evDirectionS.push_back(cFOEV);
+ }
+
+ } else if (dotProdVVAndEV < 0 ){
+ cout << "Current head is in reverse direction of the velocity vector"<<endl;
+ currentFO.setHead(cFOREV);
+ currentFO.setHeadIsInDirectionMAEV(false);
+
+ if (saveEV == 1) {
+ cout << "saving the eigen vector for the first object"<<endl;
+ evDirectionF.push_back(cFOREV);
+ } else if (saveEV == 2) {
+ cout << "saving the eigen vector for the second object"<<endl;
+ evDirectionS.push_back(cFOREV);
+ }
+
+ } else {
+
+ pair<double, double> zero(0.0,0.0);
+
+ if (saveEV == 1) {
+ cout << "saving the zero eigen vector for the first object"<<endl;
+ evDirectionF.push_back(zero);
+ } else if (saveEV == 2) {
+ cout << "saving the zero eigen vector for the second object"<<endl;
+ evDirectionS.push_back(zero);
+ }
+
+ }
+
+
+}
+
+void objectHeadDirection(FlyObject &currentFO, pair<double, double> cFV) {
+
+// // get the velocity vector
+// pair<double, double> cFOVV = currentFO.getVelocityV();
+ pair<double, double> cFOEV = currentFO.getMajorAxisEV();
+ normalizeVector(cFOEV);
+ pair<double, double> cFOREV(-cFOEV.first, -cFOEV.second);
+
+ double dotProdVVAndEV = calculateDotProduct(cFOEV, cFV);
+ if (dotProdVVAndEV > 0 ) {
+ cout << "Current head is in direction with the vector used\n";
+ // set the head to the eigen vector
+ currentFO.setHead(cFOEV);
+ currentFO.setHeadIsInDirectionMAEV(true);
+ } else {
+ cout << "Current head is in reverse direction with the vector used"<<endl;
+ currentFO.setHead(cFOREV);
+ currentFO.setHeadIsInDirectionMAEV(false);
+ }
+
+
+}
+
+
+void outputInfo(int midIndex) {
+
+ FrameInfo midFI = fIVector[midIndex];
+ vector<FlyObject > mFOVector = midFI.getFOVector();
+ FlyObject mFFirstFO = mFOVector[0];
+ FlyObject mFSecondFO = mFOVector[1];
+
+ pair<int, int> midFCentroid = mFFirstFO.getCentroid();
+ pair<int, int> midSCentroid = mFSecondFO.getCentroid();
+
+ cout << "mid index is "<<midIndex<<endl;
+ cout << "file name is "<<fnVector[midIndex]<<endl;
+ cout << "Mid Large Centroid is "<<midFCentroid.first<<" "<<midFCentroid.second<<endl;
+ cout << "Mid Small Centroid is "<<midSCentroid.first<<" "<<midSCentroid.second<<endl;
+
+}
+
+void velocityDirection(int st, int end, pair<double, double > &velDirectionF, pair<double, double>&velDirectionS) {
+
+ // find the average velocity vector
+ cout << "Finding average velocity vector from "<<fnVector[st]<<" to "<<fnVector[end]<<endl;
+ FrameInfo prevFI = fIVector[st];
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ FlyObject pFFirstFO = pFOVector[0];
+ FlyObject pFSecondFO = pFOVector[1];
+
+
+ FrameInfo currentFI = fIVector[end];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ // get the summation of (velocity direction from start frame to half of the frames in this interval)
+ pair<int, int> cFFCentroid = cFFirstFO.getCentroid();
+ pair<int, int> cFSCentroid = cFSecondFO.getCentroid();
+
+
+ pair<int, int> pFFCentroid = pFFirstFO.getCentroid();
+ pair<int, int> pFSCentroid = pFSecondFO.getCentroid();
+
+
+ int velXFirst = cFFCentroid.first - pFFCentroid.first;
+ int velYFirst = cFFCentroid.second - pFFCentroid.second;
+
+ int velXSecond = cFSCentroid.first - pFSCentroid.first;
+ int velYSecond = cFSCentroid.second - pFSCentroid.second;
+
+ cout << "Velocity vector"<<endl;
+ cout << "First = "<<velXFirst<<","<<velYFirst<<endl;
+ cout << "Second = "<<velXSecond<<","<<velYSecond<<endl;
+
+ pair<double, double> cFVV(static_cast<double> (velXFirst), static_cast<double> (velYFirst));
+ pair<double, double> cSVV(static_cast<double> (velXSecond), static_cast<double> (velYSecond));
+
+ velDirectionF = cFVV;
+ velDirectionS = cSVV;
+
+
+}
+double getSpeed(pair<double, double> vector) {
+ double value = vector.first*vector.first + vector.second*vector.second;
+ value = sqrt(value);
+
+ return value;
+
+
+}
+
+void velocityDirections(int stIndex, int endIndex) {
+
+
+ velocityDirectionsF.clear();
+ velocityDirectionsS.clear();
+
+ //int intervalLength = 5;
+ cout << "Initial velocity direction calculation"<<endl;
+ cout << "From index "<<stIndex<<" to "<<endIndex<<endl;
+ cout << "From "<<fnVector[stIndex]<<" to "<<fnVector[endIndex]<<endl;
+
+ /*overAllVelocityF.first = 0;
+ overAllVelocityF.second = 0;
+ overAllVelocityS.first = 0;
+ overAllVelocityS.second = 0;
+ */
+
+ for (int i=stIndex; i<endIndex; i=i++) {
+
+ pair<double, double > velDirectionF;
+ pair<double, double > velDirectionS;
+
+ // get the velocity
+ velocityDirection(i,i+1, velDirectionF, velDirectionS);
+
+ // extract the fly object for update
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+ // get the speed of the velocity
+ double speedF = getSpeed(velDirectionF);
+ cFFirstFO.setSpeed(speedF);
+ double speedS = getSpeed(velDirectionS);
+ cFSecondFO.setSpeed(speedS);
+
+ // save the velocity direction
+ normalizeVector(velDirectionF);
+ velocityDirectionsF.push_back(velDirectionF);
+ normalizeVector(velDirectionS);
+ velocityDirectionsS.push_back(velDirectionS);
+
+ cout << "Normalized velocity"<<endl;
+ cout << "First = " <<velDirectionF.first<<","<<velDirectionF.second<<endl;
+ cout << "Second = " <<velDirectionS.first<<","<<velDirectionS.second<<endl;
+
+ // set the velocity vector in the objects
+ cFFirstFO.setVelocityV(velDirectionF);
+ cFSecondFO.setVelocityV(velDirectionS);
+
+ // find the first object head
+ cout<<fnVector[i]<<endl;
+ cout << "Calculating initial head direction from velocity direction for the first object and storing the ev in direction to the vv"<<endl;
+ objectHeadDirection(cFFirstFO,1);
+
+ cout << "Calculating initial head direction from the velocity direction for the second object and storing the ev in direction to the vv"<<endl;
+ objectHeadDirection(cFSecondFO,2);
+
+
+ // update the flyobject vector
+ vector<FlyObject > updatedFOVector;
+ updatedFOVector.push_back(cFFirstFO);
+ updatedFOVector.push_back(cFSecondFO);
+ currentFI.setFOVector(updatedFOVector);
+ cout << "Updating the frame "<<fnVector[i]<<" after calculating its direction from velocity vector\n";
+ fIVector[i] = currentFI;
+
+ /*//cout << fIVector[i];
+ // first object overall velocity
+ overAllVelocityF.first += velDirectionF.first;
+ overAllVelocityF.second += velDirectionF.second;
+ // second object overall velocity
+ overAllVelocityS.first += velDirectionS.first;
+ overAllVelocityS.second += velDirectionS.second;
+ */
+
+ }
+
+
+
+}
+
+
+ofstream fout("LongestPositive.txt");
+void largestIncreasingPositiveDotProductSeq(vector<pair<double, double> > velocityDirs, int &startIndex, int &endIndex) {
+
+ int positiveVelSeqSize = 0;
+ int flag = false;
+ int maxSeqSize = 0;
+ int st = 0;
+ for (int j=0; j<velocityDirs.size()-1; j++) {
+ pair<double,double> prevVel = velocityDirs[j];
+ pair<double, double> currVel = velocityDirs[j+1];
+
+ double dotProd = calculateDotProduct(prevVel, currVel);
+
+ if( dotProd > 0 && flag == false) {
+ st = j;
+ positiveVelSeqSize++;
+ flag = true;
+ //cout << "In first if positiveSize "<<positiveVelSeqSize<<endl;
+
+ } else if (dotProd > 0 && flag == true) {
+ positiveVelSeqSize++;
+ //cout << "In second if positive "<<positiveVelSeqSize<<endl;
+ } else {
+ positiveVelSeqSize = 0;
+ flag = false;
+ //cout << "Else\n";
+
+ }
+
+ if (positiveVelSeqSize > maxSeqSize) {
+ maxSeqSize = positiveVelSeqSize;
+ startIndex = st;
+ endIndex = st+positiveVelSeqSize;
+ //cout << "maxseq updated \npositiveSize "<<positiveVelSeqSize<<endl;
+ //cout << "st "<<startIndex<<endl;
+ //cout << "end "<<endIndex<<endl;
+ }
+
+
+
+ }
+
+ // if dot product is alternately 0 and nonzero then nothing will be updated. In that case take the first nonzero velocity index
+ if (maxSeqSize == 0) {
+ bool zero = false;
+ for (int j=0; j<velocityDirs.size(); j++) {
+ pair<double, double > prevVel = velocityDirs[j];
+ if (prevVel.first != 0 || prevVel.second != 0) {
+ startIndex = j;
+ endIndex = j;
+ zero = true;
+ break;
+ }
+ }
+
+ if (zero != true) {
+ cout << "All directions zero"<<endl;
+ startIndex = 0;
+ endIndex = 0;
+ }
+
+ }
+
+}
+
+
+void propagateDirections(int object, int s, int e, int origStart, int origEnd) {
+
+ if (object == 1) {
+ cout << "For first"<<endl;
+ } else {
+ cout << "For second"<<endl;
+ }
+
+
+ /*double maxDotProduct = -1;
+ int maxDotProductIndex = -1;
+ */
+ double maxVelValue = -1;
+ int maxVelValIndex = -1;
+
+ // find the representative frame
+ for (int i=s; i<=e; i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFO = cFOVector[object-1];
+ pair<double , double> cFVV = cFFO.getVelocityV();
+ //cout << "Velocity before normalization "<<cFVV.first<<","<<cFVV.second<<endl;
+ //normalizeVector(cFVV);
+ /*cout << "Velocity after normalization "<<cFVV.first<<","<<cFVV.second<<endl;
+ pair<double, double> cFEV = cFFO.getMajorAxisEV();
+ cout << "Eigen vector before normalization "<<cFEV.first<<","<<cFEV.second<<endl;
+ normalizeVector(cFEV);
+ cout << "Eigen vector after normalization "<<cFEV.first<<","<<cFEV.second<<endl;
+
+ double dotProd = calculateDotProduct(cFEV, cFVV);
+ cout << "Dot product absolute value for frame "<<fnVector[i]<<" : "<<abs(dotProd)<<" real value was "<<dotProd<<endl;
+
+ if (maxDotProduct < abs(dotProd) ) {
+ maxDotProduct = abs(dotProd);
+ maxDotProductIndex = i;
+ }*/
+
+ double velValue = cFFO.getSpeed();
+ cout << "speed at "<<fnVector[i]<<" "<<velValue<<endl;
+ if (velValue > maxVelValue) {
+ maxVelValue = velValue;
+ maxVelValIndex = i;
+ }
+
+
+ }
+
+ cout << "Maximum speed is chosen for for frame "<<fnVector[maxVelValIndex]<<" : "<<maxVelValue<<endl;
+
+ // set the head direction according to the represntative velocity
+ int t = maxVelValIndex;
+ FrameInfo currentFI = fIVector[t];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+ cout << "Setting representative head direction of frame "<<fnVector[t]<<endl;
+ fout << "Setting representative head direction of frame "<<fnVector[t]<<endl;
+
+ if (object == 1) {
+ cout << "Setting the head dir according to the representative velocity in the longest positive sequence at "<<fnVector[t]<<endl;
+ bool evDirFlag = cFFirstFO.getHeadIsInDirectionMAEV();
+ cout << "Before for the first object setting ev in velocity direction it is "<<evDirFlag<<endl;
+ objectHeadDirection(cFFirstFO);
+ evDirFlag = cFFirstFO.getHeadIsInDirectionMAEV();
+ cout << "After setting ev in velocity direction it is "<<evDirFlag<<endl;
+ cFOVector[0] = cFFirstFO;
+ currentFI.setFOVector(cFOVector);
+ fIVector[t] = currentFI;
+ }
+ else {
+ pair<double, double> tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity was "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ cout << "Setting the head direction according to the representative velocity in the longest positive sequence"<<endl;
+
+ bool evDirFlag = cFSecondFO.getHeadIsInDirectionMAEV();
+ cout << "Before for the second object setting ev in velocity direction it is "<<evDirFlag<<endl;
+ objectHeadDirection(cFSecondFO);
+ evDirFlag = cFSecondFO.getHeadIsInDirectionMAEV();
+ cout << "After setting ev in velocity direction it is "<<evDirFlag<<endl;
+
+ //tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity became "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ cFOVector[1] = cFSecondFO;
+ currentFI.setFOVector(cFOVector);
+ fIVector[t] = currentFI;
+ }
+
+
+
+ int intervalLength = 1;
+ if ((e-s)> intervalLength) {
+
+ cout << "Propagating in the longest positive frame interval starting the direction from the frame "<<fnVector[t];
+ cout << " to "<<fnVector[e]<<endl;
+ FrameInfo prevFI = fIVector[t];
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ FlyObject pFFirstFO = pFOVector[0];
+ FlyObject pFSecondFO = pFOVector[1];
+
+ for (int i=t+1; i<=e; i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ pair<double, double> tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity was "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ tempVelocity = cFSecondFO.getVelocityV();
+ //cout << "Velocity became "<<tempVelocity.first<<","<<tempVelocity.second<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+
+ }
+
+ cout << "propagating from "<<fnVector[t]<<" to "<<fnVector[s]<<endl;
+ prevFI = fIVector[t];
+ pFOVector = prevFI.getFOVector();
+ pFFirstFO = pFOVector[0];
+ pFSecondFO = pFOVector[1];
+
+ for (int i=t-1; i>=s; i--) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+
+ }
+
+
+
+ }
+ // propagate upwards
+ FrameInfo prevFI = fIVector[e];
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ FlyObject pFFirstFO = pFOVector[0];
+ FlyObject pFSecondFO = pFOVector[1];
+
+ if (e < origEnd) {
+ cout << "Propagating front from "<<fnVector[e]<<" to "<<fnVector[origEnd]<<endl;
+
+ for (int i=e+1; i<=origEnd; i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+
+ }
+
+ }
+
+
+
+ // propagate downwards
+ prevFI = fIVector[s];
+ pFOVector = prevFI.getFOVector();
+ pFFirstFO = pFOVector[0];
+ pFSecondFO = pFOVector[1];
+
+ if (s > origStart ) {
+ cout << "Propagating down wards from "<<fnVector[s]<<" to "<<fnVector[origStart]<<endl;
+ for (int i=s-1; i>=origStart; i--) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ if (object == 1) {
+ //cout << "First object extract"<<endl;
+ objectHeadDirection(pFFirstFO, cFFirstFO, false);
+ //cout << "First object update"<<endl;
+ cFOVector[0] = cFFirstFO;
+
+ pFFirstFO = cFFirstFO;
+
+ } else {
+ //cout << "Second object extract"<<endl;
+ objectHeadDirection(pFSecondFO, cFSecondFO, false);
+ //cout << "Second object update"<<endl;
+ cFOVector[1] = cFSecondFO;
+
+ pFSecondFO = cFSecondFO;
+
+ }
+
+ currentFI.setFOVector(cFOVector);
+
+ fIVector[i] = currentFI;
+ }
+
+ }
+
+}
+
+
+// find the head direction from the collsion point to backward
+void calculateHeadDirection(int st, int end, int maxDistIndex) {
+
+ cout << "From file "<<fnVector[st]<<" to "<<fnVector[end]<<endl;
+ //cout << "Assigning object head direction between Index "<<mid<<" to startIndex "<<st<<endl;
+
+ // calculate the velocity directions first
+ // clear evDirectionF and evDirectionS to store the new evs for the current sequence
+ evDirectionF.clear();
+ evDirectionS.clear();
+
+ velocityDirections(st, end);
+
+ cout << "Size of evDirectionF "<<evDirectionF.size()<<endl;
+ cout << "Size of evDirectionS "<<evDirectionS.size()<<endl;
+
+
+ // debug
+ cout << "------------ALL VELOCITY AND CORRESPONDING EV-------------\n";
+ int a;
+ for (a=0; a < velocityDirectionsF.size(); a++) {
+
+ cout << "For frame "<<fnVector[a+st]<<endl;
+
+ pair<double, double> z = velocityDirectionsF[a];
+ pair<double, double> zEV = evDirectionF[a];
+ cout <<" First object velocity = "<<z.first<<","<<z.second<<endl;
+ cout <<" First object ev = "<<zEV.first<<","<<zEV.second<<endl;
+
+ pair<double, double> w = velocityDirectionsS[a];
+ pair<double, double> wEV = evDirectionS[a];
+
+ cout << "Second object velocity = "<<w.first<<","<<w.second<<endl;
+ cout << "Second object ev = "<<wEV.first<<","<<wEV.second<<endl;
+
+
+ }
+ cout << "Last frame index wont have velocity a+st("<<(a+st)<<") = end("<<end<<") "<<fnVector[a+st]<<endl;
+ cout << "------------END-------------\n";
+
+ int s;
+ int e;
+ int fs,fe;
+ fout<<"------------------------------------------------------------------"<<endl;
+ largestIncreasingPositiveDotProductSeq(evDirectionF, s, e);
+ cout << "Positive indexes are "<<fnVector[st+s]<<" to "<<fnVector[st+e]<<endl;
+ int si = s + st;
+ int ei = e + st;
+ fout << "For first object max positive directions from "<<fnVector[si]<<" to "<<fnVector[ei]<<endl;
+ propagateDirections(1, si, ei, st, end);
+
+ s = 0;
+ e = 0;
+
+ largestIncreasingPositiveDotProductSeq(evDirectionS, s, e);
+ cout << "Positive indexes are "<<fnVector[st+s]<<" to "<<fnVector[st+e]<<endl;
+ si = s + st;
+ ei = e + st;
+ fout << "For second object max positive directions from "<<fnVector[si]<<" to "<<fnVector[ei]<<endl;
+ propagateDirections(2, si, ei, st, end);
+
+}
+// min dist from prev frame's 0th index object
+void objectCorrespondence(FrameInfo &prevFI, FrameInfo &currentFI) {
+
+ // simplest assumption that the larger object will remain close to larger one
+ // and the smaller one will remain close to smaller
+ // just find the min distance from any one of them
+ // initially just find the min distance from the first object to the other two
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ // bool currentlySingleBlob = currentFI.getIsSingleBlob();
+
+ // if (currentlySingleBlob == false) {
+
+ FlyObject pFLargeFO = pFOVector[0];
+ FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ double distLTL = euclideanDist(pFLargeFO, cFLargeFO);
+ cout << "previousFirst to currentFirst "<<distLTL<<endl;
+
+ double distLTS = euclideanDist(pFLargeFO, cFSmallFO);
+ cout << "prevFirst to currentSecond "<<distLTS<<endl;
+
+ double min1 = min(distLTL, distLTS);
+ cout<<"min of FTF and FTS is "<<min1<<endl;
+
+ double distSTL = euclideanDist(pFSmallFO, cFLargeFO);
+ cout << "previousSecond to currentLarge "<<distSTL<<endl;
+
+ double distSTS =euclideanDist(pFSmallFO, cFSmallFO);
+ cout << "prevSecond to currentSecond "<<distSTS<<endl;
+
+ double min2 = min(distSTL, distSTS);
+
+ // if prev frame larger object is closer to current frame smaller object
+ // this might happen for two cases i) the smaller object is closer in the current frame (so this situation should be handled with some other heuristics)
+ // ii)the segmentation process toggles the size (error in the segmentation process)
+
+ if (min1 < min2) {
+ if (distLTS == min1) {
+ cout<<"Shortest distance is from the previous frame first object. And shortest distance is from previos first object to current second object so we need to swap the objects in current frame"<<endl;
+ currentFI.swapTheFlyObject();
+ }
+ } else {
+ if (distSTL == min2) {
+ cout << "Shortest distance is from the previous frame second object. And shortest distance is from previous second object to current first object so we need to swap the objects in the current frame"<<endl;
+ currentFI.swapTheFlyObject();
+ }
+ }
+
+
+}
+
+double euclideanDist(FlyObject a, FlyObject b) {
+
+ pair<int, int> aCentroid = a.getCentroid();
+ pair<int,int> bCentroid = b.getCentroid();
+
+ //cout << "Distance from "<<aCentroid.first<<","<<aCentroid.second<<" to "<<bCentroid.first<<","<<bCentroid.second<<endl;
+ double x2 = pow((static_cast<double> (aCentroid.first)-static_cast<double> (bCentroid.first)), 2.0);
+ double y2 = pow((static_cast<double> (aCentroid.second)-static_cast<double> (bCentroid.second)), 2.0);
+ double dist = sqrt((x2+y2));
+ cout << dist<<endl;
+
+ return dist;
+}
+
+void processASequence(int startOfATrackSequence, int endOfATrackSequence) {
+
+ // find the frame that gives us the furthest distance between the two objects
+ double maxDist = -1;
+ int maxDistIndex = -1;
+ for (int i=startOfATrackSequence; i<=(endOfATrackSequence); i++) {
+ FrameInfo currentFI = fIVector[i];
+
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = cFOVector[0];
+ FlyObject cFSecondFO = cFOVector[1];
+
+ double currDist = euclideanDist(cFFirstFO, cFSecondFO);
+
+ if (currDist > maxDist) {
+ maxDist = currDist;
+ maxDistIndex = i;
+ cout << "New max distance" << maxDist << " at the frame number "<<i;
+ cout << endl;
+ }
+
+
+
+ }
+
+ cout << "Maximum distance between the frame found at the index "<<maxDistIndex<<endl;
+ cout << "Assigning object correspondance between maxDistIndex "<<maxDistIndex<<" to startIndex "<<startOfATrackSequence<<endl;
+ // assign closest distance object association before the between frames startOfASeq to maxDistIndex
+ FrameInfo prevFI = fIVector[maxDistIndex];
+ for (int i=maxDistIndex-1; i>=startOfATrackSequence; i--) {
+ FrameInfo currentFI = fIVector[i];
+ objectCorrespondence(prevFI, currentFI);
+
+ // update the fIVector
+ fIVector[i] = currentFI;
+ prevFI = currentFI;
+
+ }
+ cout << "Assigning object correspondance between maxDistIndex+1 "<<(maxDistIndex+1)<<" to endIndex "<<endOfATrackSequence<<endl;
+ // assign closest distance object association after the maxDistIndex to endOfSeq
+ prevFI = fIVector[maxDistIndex];
+ for (int i=maxDistIndex+1; i<=(endOfATrackSequence); i++) {
+ FrameInfo currentFI = fIVector[i];
+
+ cout << "Object correspondance frame number "<<i<<endl;
+
+ objectCorrespondence(prevFI, currentFI);
+
+ // update the fIVector
+ fIVector[i] = currentFI;
+ prevFI = currentFI;
+
+
+ }
+
+ double sequenceFirstAverage = 0;
+ double sequenceSecondAverage = 0;
+ // find the average area of the two sequences and choose the larger
+ for (int i=startOfATrackSequence; i<=(endOfATrackSequence); i++) {
+ FrameInfo currentFI = fIVector[i];
+ vector<FlyObject > fOVector = currentFI.getFOVector();
+ FlyObject cFFirstFO = fOVector[0];
+ FlyObject cFSecondFO = fOVector[1];
+
+ sequenceFirstAverage += cFFirstFO.getArea();
+ sequenceSecondAverage += cFSecondFO.getArea();
+
+ cout << "For frame number "<<i<<"\n";
+ cout << "SequenceFirst area sum = "<<sequenceFirstAverage<<endl;
+ cout << "SequenceSecond area sum = "<<sequenceSecondAverage<<endl;
+ }
+
+ sequenceFirstAverage /= (endOfATrackSequence-startOfATrackSequence + 1);
+ sequenceSecondAverage /= (endOfATrackSequence-startOfATrackSequence + 1);
+
+ cout << "----------------------------------------------------\n";
+ cout << "SequenceFirst average area = "<<sequenceFirstAverage<<endl;
+ cout << "SequenceSecond average area = "<<sequenceSecondAverage<<endl;
+ cout << "----------------------------------------------------\n";
+
+ if (sequenceFirstAverage > sequenceSecondAverage) {
+ fout << "First object is the female"<<endl;
+ } else {
+ fout<<"Second object is female"<<endl;
+ }
+
+ // calculating the head direction from the collision time to backward
+ cout << "calculating the head direction "<<startOfATrackSequence<<" to "<<endOfATrackSequence<<endl;
+ fout<<"calculating the head direction "<<startOfATrackSequence<<" to "<<endOfATrackSequence<<endl;
+ calculateHeadDirection(startOfATrackSequence, endOfATrackSequence, maxDistIndex);
+
+ if (sequenceFirstAverage > sequenceSecondAverage) {
+ cout << "First sequence is the object A"<<endl;
+ drawTheSequence(startOfATrackSequence, endOfATrackSequence, 1);
+ }
+ else {
+ cout << "Second sequence is the object A"<<endl;
+ drawTheSequence(startOfATrackSequence, endOfATrackSequence, 0);
+ }
+
+
+}
+
+int diagLength;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 5)
+ {
+ cerr << "Usage: executablename <inputFile.txt> <originalImagePath> <finalOutputPath> <maskImagePath>" << endl; // input file contains name of the
+ // input image files
+ return -1;
+ }
+
+ MagickCore::SetMagickResourceLimit(MagickCore::MemoryResource, 1536);
+ MagickCore::SetMagickResourceLimit(MagickCore::MapResource, 4092);
+
+ string fileName;
+ ifstream inputFile(argv[1]);
+
+ // save the input file name
+ string ifns(argv[1]);
+ inputFileName = ifns;
+
+ if (inputFile.fail() ) {
+ cout << "cannot open the input file that contains name of the input images\n";
+ exit(1);
+ }
+
+ // set the global paths
+ string tempOIP(argv[2]);
+ origImagePath = tempOIP;
+
+ string tempFOP(argv[3]);
+ finalOutputPath = tempFOP;
+
+ string tempMIP(argv[4]);
+ maskImagePath = tempMIP;
+
+ unsigned int objCount = 0;
+ int i;
+
+ int frameCounter = 0;
+ int fileCounter=0;
+
+ char buffer[100];
+ string imgSize;
+// FlyObject a,b;
+ vector<pair<int,int> > shape;
+ vector<FlyObject > tempFOV;
+
+ // to find the new head direction
+ bool currentlyCalculatingHead = true;
+
+
+
+ while (inputFile>>fileName) {
+
+// Image* img = new Image(argv[1]);// = new Image(argv[1]);
+
+ int fi = fileName.find("Test");
+ // current sequence numbers spans from 0 - 18019, so 5 digits are needed
+ int span = 5;
+ string tempString = fileName.substr(fi+4,span);
+ int frameCounter = atoi(tempString.c_str());
+ cout << frameCounter<<endl;
+
+ string fileNameForSave = fileName;
+
+ // save the name in the vector
+ fnVector.push_back(fileName);
+
+ fileName = "output/filtered/final/"+fileName;
+ Image* img = new Image(fileName.c_str());
+ int width = img->columns(),height = img->rows();
+ diagLength= static_cast<int> ( sqrt( (height*height) + (width*width) ) );
+ cout << "Diagonal length is "<<diagLength<<endl;
+// Image* imgWithInfo;
+// imgWithInfo = new Image(fileName.c_str());
+ sprintf(buffer,"%ix%i",width,height);
+ string imsize(buffer);
+ imgSize = imsize;
+ // residual image is initialized with black representing not visited.
+ residual = new Image(buffer, "black");
+
+ cout<<"reading file "<<fileName<<endl;
+
+ tempFOV.clear();
+
+ for (int x = 0; x<width; x++) {
+ for (int y = 0; y<height; y++) {
+
+ //cout<<"comes here"<<endl;
+ shape.clear();
+ findObj(img, x, y, shape, true, true);
+ unsigned int s = shape.size();
+
+ if ( s > 0 )
+ {
+
+ cout << "size of the object is: " << s <<endl;
+ vector<double> eigenVal = covariantDecomposition(shape);
+
+ {
+// objCount++;
+
+ double velocity_x=0.0, velocity_y=0.0;
+ // save the object information
+ FlyObject tempFO(s,
+ pair<int, int> (eigenVal[6], eigenVal[7]),
+ pair<double, double> (eigenVal[4], eigenVal[5]),
+ pair<double,double> (velocity_x, velocity_y),
+ false,
+ pair<double, double> (eigenVal[4], eigenVal[5]),
+ 0.0);
+ tempFOV.push_back(tempFO);
+
+
+
+
+ }
+ }
+
+ }
+ }
+
+// cout<<"Sorting the objects according to size"<<endl;
+// bubbleSort(tempFOV);
+
+ fOVector.clear();
+
+ for (int ti=0; ti<tempFOV.size(); ti++){
+
+ FlyObject a = tempFOV[ti];
+ fOVector.push_back(a);
+
+ }
+
+ bool currentFrameIsSingleBlob = false;
+ // if there is only one object then state of the system is single blob
+ if (fOVector.size() == 1 and currentFrameIsSingleBlob == false) {
+ currentFrameIsSingleBlob = true;
+
+ // if start as a single blob
+ if (fileCounter == 0) {
+ cout << "Start as a single blob"<<endl;
+ startOfAOneObject = fileCounter;
+ }
+
+ }
+
+ FrameInfo tempFI(frameCounter, fOVector, currentFrameIsSingleBlob);
+ fIVector.push_back(tempFI);
+ bool flag;
+ FrameInfo currentFI = fIVector[fileCounter];
+
+ sequenceSize++;
+
+ // increase the frame Counter
+ fileCounter++;
+
+ delete img;
+
+ delete residual;
+
+
+ }
+
+ inputFile.close();
+
+ if (startOfATrackSequence!=-1 && endOfATrackSequence == -1) {
+ cout << "Last sequence that does not stick to a single blob status startIndex "<<startOfATrackSequence<<" endIndex "<<(sequenceSize+startOfATrackSequence-2)<<endl;
+ processASequence(startOfATrackSequence, (sequenceSize+startOfATrackSequence-2));
+ }
+ else if (startOfAOneObject != -1 && endOfAOneObject == -1) {
+ cout << "Last sequence that does not separate from one object state\n";
+ drawTheSequence(startOfAOneObject, (sequenceSize+startOfAOneObject - 2), 0, true);
+ }
+
+
+ // reopen the file name list to read the name of the file. This should be changed to rename the filtered file
+ // and establish a link between the file name and the framenumber so that this file need not be read again.
+
+
+ return 0;
+}
+
+// min dist from prev frame's 0th index object
+bool identifyFlyObjectFromFrameToFrame(FrameInfo prevFI, FrameInfo &currentFI, bool gotRidOfSingleBlob) {
+
+ // simplest assumption that the larger object will remain close to larger one
+ // and the smaller one will remain close to smaller
+ // just find the min distance from any one of them
+ // initially just find the min distance from the first object to the other two
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ bool currentlySingleBlob = currentFI.getIsSingleBlob();
+
+ if (currentlySingleBlob == false) {
+
+ FlyObject pFLargeFO = pFOVector[0];
+ //FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ // if just got rid off the single blob then the distance from the centroid of the large object before collision
+ // which is saved to the new two centroids needs to be calculated. This will give two direction
+ // dot product with the saved large object direction and directions are calculated the positive direction
+ // gives the new large object
+ /// ASSUMPTION is that the large object tends to go toward the direction before collision
+ // the smaller object will go either opposite or will be behind the object
+ // find the minimum distance among the centroids and chose the close one
+ // find minimum distance from the larger object = min1
+ double distLTL = euclideanDist(pFLargeFO, cFLargeFO);
+ cout << "previousL to currentL "<<distLTL<<endl;
+
+ double distLTS = euclideanDist(pFLargeFO, cFSmallFO);
+ cout << "prevL to currentS "<<distLTS<<endl;
+
+ double min1 = min(distLTL, distLTS);
+ cout<<"min of LTL and LTS is "<<min1<<endl;
+ // if prev frame larger object is closer to current frame smaller object
+ // this might happen for two cases i) the smaller object is closer in the current frame (so this situation should be handled with some other heuristics)
+ // ii)the segmentation process toggles the size (error in the segmentation process)
+ if (distLTS == min1) {
+ cout<<"The object should be swapped"<<endl;
+ currentFI.swapTheFlyObject();
+ }
+ }
+ // return value ignorable from where it is called
+ return false;
+}
+
+// with area and min dist when objects area are almost same
+/*
+bool identifyFlyObjectFromFrameToFrame(FrameInfo prevFI, FrameInfo &currentFI) {
+
+ // simplest assumption that the larger object will remain close to larger one
+ // and the smaller one will remain close to smaller
+ // just find the min distance from any one of them
+ // initially just find the min distance from the first object to the other two
+ vector<FlyObject > pFOVector = prevFI.getFOVector();
+ vector<FlyObject > cFOVector = currentFI.getFOVector();
+
+ FlyObject pFLargeFO = pFOVector[0];
+ FlyObject pFSmallFO = pFOVector[1];
+
+ FlyObject cFLargeFO = cFOVector[0];
+ FlyObject cFSmallFO = cFOVector[1];
+
+ // find the area ratio of the current two objects.
+ // if they are within 5 percent, calculate the minimum distance from previous larger to current larger and smaller
+ double curr_larger = cFLargeFO.getArea();
+ double curr_smaller = cFSmallFO.getArea();
+ double ratio = (curr_smaller/curr_larger) * 100.0;
+ if (ratio >= 95.0) {
+ cout <<"Current ratio greater than equal 95.0 percent. Areas are : "<<curr_larger<<" and "<<curr_smaller<<endl;
+ // find minimum distance from the larger object = min1
+ double distLTL = euclideanDist(pFLargeFO, cFLargeFO);
+ cout << "L to L "<<distLTL<<endl;
+
+ double distLTS = euclideanDist(pFLargeFO, cFSmallFO);
+ cout << "L to S "<<distLTS<<endl;
+
+ double min1 = min(distLTL, distLTS);
+ cout<<"min of LTL and LTS is "<<min1<<endl;
+ if (distLTS == min1) {
+ cout<<"The object should be swapped"<<endl;
+ currentFI.swapTheFlyObject();
+ }
+ }
+ return false;
+}
+*/
+
+void drawTheFlyObject(FrameInfo currentFI, string fileName, int isFirst, bool singleBlob) {
+
+ cout << "isFirst is "<<isFirst<<endl;
+
+ string inputFileName = origImagePath + fileName;
+ // string inputFileName = "output/identified/"+fileName;
+
+ // when do not want to identify on the original comment the line below and uncomment the above line
+ // debugging for drawing the circle
+ string outputFileName = finalOutputPath + fileName;
+ // string outputFileName = "output/identified_with_cropped/" + fileName;
+
+ cout<<"file name "<<inputFileName<<endl;
+ Image* img = new Image(inputFileName.c_str());
+
+ // cout<<"img width "<<img->columns()<<" and height "<<img->rows()<<endl;
+ string object1Color("blue");
+ string object2Color("red");
+ vector<FlyObject > fOVector = currentFI.getFOVector();
+ cout << "While drawing it found objects = "<<fOVector.size()<<endl;
+
+ int x0, x1, y0, y1;
+ string maskFile = maskImagePath + fileName;
+ Image* maskImage = new Image(maskFile.c_str());
+
+ if (singleBlob == false) {
+
+
+ FlyObject currentFO = fOVector[isFirst];
+
+ pair<int, int> centroid = currentFO.getCentroid();
+ pair<double, double> majorAxisEV = currentFO.getMajorAxisEV();
+
+ bool eVDirection = currentFO.getHeadIsInDirectionMAEV();
+
+ double ev_x, ev_y;
+
+ if (eVDirection == true) {
+
+ x0 = centroid.first;
+ y0 = centroid.second;
+ ev_x = static_cast<double>(centroid.first) + static_cast<double>(diagLength)* majorAxisEV.first;
+ ev_y = static_cast<double>(centroid.second) + static_cast<double>(diagLength)* majorAxisEV.second;
+
+ x1 = static_cast<int> (ev_x);
+ y1 = static_cast<int> (ev_y);
+
+ } else {
+
+ x0 = centroid.first;
+ y0 = centroid.second;
+ ev_x = static_cast<double>(centroid.first) - static_cast<double>(diagLength)* majorAxisEV.first;
+ ev_y = static_cast<double>(centroid.second) - static_cast<double>(diagLength)* majorAxisEV.second;
+
+ x1 = static_cast<int> (ev_x);
+ y1 = static_cast<int> (ev_y);
+
+
+ }
+
+ int isHitting = draw_line_bm(maskImage, x0, y0, x1, y1 );
+
+
+
+
+
+ for (int n=0; n<fOVector.size(); n++) {
+
+ FlyObject currentFO = fOVector[n];
+
+ pair<int, int> centroid = currentFO.getCentroid();
+ pair<double, double> majorAxisEV = currentFO.getMajorAxisEV();
+
+ bool eVDirection = currentFO.getHeadIsInDirectionMAEV();
+
+ double ev_x, ev_y;
+ //draw the object tracking circle
+ if (n == isFirst and n==0) {
+ cout << "Tracking the n = "<<n<<endl;
+ img->strokeColor("yellow");
+ img->draw(DrawableCircle(centroid.first, centroid.second, centroid.first+5, centroid.second));
+
+ } else if ( n == isFirst and n==1) {
+
+ cout << "Tracking the "<<n<<endl;
+ img->strokeColor("yellow");
+ //img->fillColor("none");
+ img->draw(DrawableCircle(centroid.first, centroid.second, centroid.first+5, centroid.second));
+
+
+ }
+
+
+ // draw the female when tracked by the male fly
+ if (isHitting == 1) {
+ if (n != isFirst and n == 0) {
+ img->strokeColor("red");
+
+ /*img->draw(DrawableLine(centroid.first - 5, centroid.second - 5, centroid.first + 5, centroid.second - 5));
+ img->draw(DrawableLine(centroid.first + 5, centroid.second - 5, centroid.first + 5, centroid.second + 5));
+ img->draw(DrawableLine(centroid.first + 5, centroid.second + 5, centroid.first - 5, centroid.second + 5));
+ img->draw(DrawableLine(centroid.first - 5, centroid.second + 5, centroid.first - 5, centroid.second - 5));
+ */
+ img->draw(DrawableRectangle(centroid.first - 5, centroid.second - 5, centroid.first + 5, centroid.second + 5));
+ } else if (n != isFirst and n==1) {
+
+ img->strokeColor("red");
+
+ /*img->draw(DrawableLine(centroid.first - 5, centroid.second - 5, centroid.first + 5, centroid.second - 5));
+ img->draw(DrawableLine(centroid.first + 5, centroid.second - 5, centroid.first + 5, centroid.second + 5));
+ img->draw(DrawableLine(centroid.first + 5, centroid.second + 5, centroid.first - 5, centroid.second + 5));
+ img->draw(DrawableLine(centroid.first - 5, centroid.second + 5, centroid.first - 5, centroid.second - 5));*/
+
+ img->draw(DrawableRectangle(centroid.first - 5, centroid.second - 5, centroid.first + 5, centroid.second + 5));
+ }
+ }
+
+ // draw the Axis direction
+ if (eVDirection == true) {
+ ev_x = static_cast<double>(centroid.first) + 50.0 * majorAxisEV.first;
+ ev_y = static_cast<double>(centroid.second) + 50.0 * majorAxisEV.second;
+ img->strokeColor("green");
+ img->draw( DrawableLine( centroid.first, centroid.second, static_cast<int>(ev_x), static_cast<int>(ev_y) ));
+ } else {
+ ev_x = static_cast<double>(centroid.first) - 50.0 * majorAxisEV.first;
+ ev_y = static_cast<double>(centroid.second) - 50.0 * majorAxisEV.second;
+ img->strokeColor("green");
+ img->draw( DrawableLine( centroid.first, centroid.second, static_cast<int>(ev_x), static_cast<int>(ev_y) ));
+ }
+
+ // draw the velocity vector
+
+ /*img->strokeColor("blue");
+ pair<double, double> velocityV = currentFO.getVelocityV();
+ ev_x = static_cast<double>(centroid.first) + 30.0 * velocityV.first;
+ ev_y = static_cast<double>(centroid.second) + 30.0 * velocityV.second;
+ img->draw(DrawableLine( centroid.first, centroid.second, static_cast<int>(ev_x), static_cast<int>(ev_y) ));
+ */
+
+ /*
+ // draw the historical head vector
+ img->strokeColor("white");
+ pair<double, double> headV = currentFO.getHead();
+ ev_x = static_cast<double> (centroid.first) + 25.0*headV.first;
+ ev_y = static_cast<double> (centroid.second) + 25.0*headV.second;
+ img->draw( DrawableLine(centroid.first, centroid.second, static_cast<int> (ev_x), static_cast<int> (ev_y)) );
+ */
+
+ /*
+ // overall velocity direction
+ if (n == 0) {
+ ev_x = static_cast<double> (centroid.first) + 10*overAllVelocityF.first;
+ ev_y = static_cast<double> (centroid.second)+ 10*overAllVelocityF.second;
+ img->strokeColor("cyan");
+ img->draw(DrawableLine(centroid.first, centroid.second, static_cast<int> (ev_x), static_cast<int> (ev_y) ) );
+ } else {
+ ev_x = static_cast<double> (centroid.first) + 10*overAllVelocityS.first;
+ ev_y = static_cast<double> (centroid.second)+ 10*overAllVelocityS.second;
+ img->strokeColor("cyan");
+ img->draw(DrawableLine(centroid.first, centroid.second, static_cast<int> (ev_x), static_cast<int> (ev_y) ) );
+
+ }
+
+ */
+ // average velocity direction
+ /*if (n == 0) {
+ ev_x = static_cast<double> (centroid.first) + 10*avgVelocityF.first;
+ ev_y = static_cast<double> (centroid.second)+ 10*avgVelocityF.second;
+ img->strokeColor("cyan");
+ img->draw(DrawableLine(centroid.first, centroid.second, static_cast<int> (ev_x), static_cast<int> (ev_y) ) );
+ } else {
+ ev_x = static_cast<double> (centroid.first) + 10*avgVelocityS.first;
+ ev_y = static_cast<double> (centroid.second)+ 10*avgVelocityS.second;
+ img->strokeColor("cyan");
+ img->draw(DrawableLine(centroid.first, centroid.second, static_cast<int> (ev_x), static_cast<int> (ev_y) ) );
+
+ }*/
+
+
+ }
+ }
+ // overwrite the file now with axis
+ // img->write(inputFileName.c_str());
+
+ // when do not want to identify on the original comment below line and uncomment the above one
+ img->write(outputFileName.c_str());
+ delete img;
+ delete maskImage;
+
+}
+
+void findObj(Image* img, int x, int y, vector<pair<int,int> > & shape ,bool eightCon, bool colorLookingFor)
+{
+ assert(residual != NULL);
+
+ if (eightCon == true)
+ eightConnObj(img, x, y, shape, colorLookingFor);
+ else {
+ fourConnObj(img, x, y, shape, colorLookingFor);
+ }
+}
+
+int barrier = 1000;
+void fourConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // originalpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono originalpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && originalpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && originalpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// //cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ fourConnObj(img, x+1, y, obj, color);
+ fourConnObj(img, x, y-1, obj, color);
+
+ fourConnObj(img, x-1, y, obj, color);
+ fourConnObj(img, x, y+1, obj, color);
+ }
+
+}
+
+void eightConnObj(Image* img, int x, int y, vector<pair<int, int> > & obj, bool color)
+{
+ int width = img->columns(),height = img->rows();
+
+ // boundary violation check
+ if ( (x >= (width)) || (x < 0) || (y >= (height) ) || (y < 0) )
+ return;
+
+ // residualpixel.mono() == true implies it is visited. Otherwise not visited.
+ ColorMono residualpixel = ColorMono(residual->pixelColor(x,y));
+ // originalpixel.mono() == true implies it is an object pixel. Otherwise it is blank region pixel.
+ ColorMono originalpixel = ColorMono(img->pixelColor(x,y));
+
+ // If the current pixel is already visited then return
+ if (residualpixel.mono() == true)
+ return;
+
+ // Else if current pixel is not visited and it is black, which means it is not an object pixel; so return
+ else if (residualpixel.mono() == false && originalpixel.mono() != color)
+ return;
+ // If current pixel is not visited and its value is white, which means a new object is found.
+ else if (residualpixel.mono() == false && originalpixel.mono() == color) {
+ // Save the coordinates of the current pixel into the vector and make the pixel visited in the residual image
+ pair<int,int> p;
+ p.first = x;
+ p.second = y;
+ obj.push_back(p);
+
+// if (obj.size() > barrier) {
+// //cout<<obj.size()<<endl;
+// barrier = barrier + 1000;
+// }
+ // setting the residual image at pixel(x,y) to white.
+ residual->pixelColor(x,y, ColorMono(true));
+
+ // Recursively call all of it's eight neighbours.
+ eightConnObj(img, x+1, y, obj, color);
+ eightConnObj(img, x+1, y-1, obj, color);
+ eightConnObj(img, x, y-1, obj, color);
+ eightConnObj(img, x-1, y-1, obj, color);
+
+ eightConnObj(img, x-1, y, obj, color);
+ eightConnObj(img, x-1, y+1, obj, color);
+ eightConnObj(img, x, y+1, obj, color);
+ eightConnObj(img, x+1, y+1, obj, color);
+
+ }
+
+}
+
+// Aspect Ratio
+pair<int,int> getCentroid(vector<pair<int,int> > & points)
+{
+ pair<int,int> centroid;
+ centroid.first = 0;
+ centroid.second = 0;
+
+ for (unsigned int i = 0; i<points.size(); i++)
+ {
+ centroid.first += points[i].first;
+ centroid.second += points[i].second;
+ }
+
+ centroid.first = roundT(double(centroid.first)/points.size());
+ centroid.second = roundT(double(centroid.second)/points.size());
+
+ return centroid;
+}
+
+
+vector<double> covariantDecomposition(vector<pair<int,int> > & points)
+{
+ unsigned int i,j,k;
+ pair<int,int> centroid = getCentroid(points);
+ vector<double> retval;
+
+ gsl_matrix* matrice = gsl_matrix_alloc(2, 2);
+
+ double sumX2 = 0, sumXY = 0, sumY2 = 0;
+ for (k = 0; k<points.size(); k++)
+ {
+ sumX2 += pow(double(points[k].first - centroid.first),2.0);
+ sumY2 += pow(double(points[k].second - centroid.second),2.0);
+ // should we take the absolute value of X*Y
+ sumXY += (points[k].first - centroid.first) * (points[k].second - centroid.second);
+ }
+ gsl_matrix_set(matrice, 0, 0, roundT(sumX2/points.size()));
+ gsl_matrix_set(matrice, 0, 1, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 0, roundT(sumXY/points.size()));
+ gsl_matrix_set(matrice, 1, 1, roundT(sumY2/points.size()));
+
+ // outputMatrix("Covariant", matrice);
+
+ // This function allocates a workspace for computing eigenvalues of n-by-n
+ // real symmetric matrices. The size of the workspace is O(2n).
+ gsl_eigen_symmv_workspace* eigenSpace = gsl_eigen_symmv_alloc(2);
+ gsl_vector* eigenVal = gsl_vector_alloc(2);
+ gsl_matrix* eigenVec = gsl_matrix_alloc(2, 2);
+ // This function computes the eigenvalues and eigenvectors of the real
+ // symmetric matrix A. Additional workspace of the appropriate size must be
+ // provided in w. The diagonal and lower triangular part of A are destroyed
+ // during the computation, but the strict upper triangular part is not
+ // referenced. The eigenvalues are stored in the vector eval and are unordered.
+ // The corresponding eigenvectors are stored in the columns of the matrix evec.
+ // For example, the eigenvector in the first column corresponds to the first
+ // eigenvalue. The eigenvectors are guaranteed to be mutually orthogonal and
+ // normalised to unit magnitude.
+ gsl_eigen_symmv (matrice, eigenVal, eigenVec, eigenSpace);
+ gsl_eigen_symmv_free (eigenSpace);
+
+ gsl_eigen_symmv_sort(eigenVal, eigenVec, GSL_EIGEN_SORT_VAL_ASC);
+
+ for (i = 0; i<eigenVal->size; i++)
+ retval.push_back(gsl_vector_get(eigenVal, i));
+
+ for (j = 0; j<eigenVec->size2; j++)
+ for (i = 0; i<eigenVec->size1; i++)
+ retval.push_back(gsl_matrix_get(eigenVec, i, j));
+
+ retval.push_back(static_cast<double>(centroid.first));
+ retval.push_back(static_cast<double> (centroid.second));
+
+// for (i=0; i<2; i++) {
+// gsl_vector_view evec_i = gsl_matrix_column (eigenVec, i);
+// //printf ("eigenvalue = %g\n", eval_i);
+// cout<<"eigenvector = \n";
+// gsl_vector_fprintf (stdout, &evec_i.vector, "%g");
+// }
+
+ gsl_vector_free(eigenVal);
+ gsl_matrix_free(matrice);
+ gsl_matrix_free(eigenVec);
+
+ return retval;
+}
+
+// isInterface for binary image
+bool isInterface(Image* orig, unsigned int x, unsigned int y)
+{
+ // Get the current pixel's color
+ ColorMono currentpixel = (ColorMono)orig->pixelColor(x,y);
+ // If the current pixel is black pixel then it is not boundary pixel
+ // error check
+ if (currentpixel.mono() == false)
+ return false;
+
+ // If the current pixel is not black then it is white. So, now we need
+ // to check whether any four of its neighbor pixels (left, top, right,
+ // bottom ) is black. If any of this neighbor is black then current
+ // pixel is a neighbor pixel. Otherwise current pixel is not neighbor
+ // pixel.
+
+ ColorMono leftneighborpixel = (ColorMono)orig->pixelColor(x-1,y);
+ ColorMono topneighborpixel = (ColorMono)orig->pixelColor(x,y-1);
+ ColorMono rightneighborpixel = (ColorMono)orig->pixelColor(x+1,y);
+ ColorMono bottomneighborpixel = (ColorMono)orig->pixelColor(x,y+1);
+
+ // If leftneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ if ( leftneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If topneighborpixel is black and currentpixel is white then it is
+ // boundary pixel
+ else if (topneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If rightneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (rightneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // If bottomneighborpixel is black and currentpixel is white then it
+ // is boundary pixel
+ else if (bottomneighborpixel.mono() != currentpixel.mono())
+ return true;
+ // Else all of its neighbor pixels are white so it can not be a
+ // boundary pixel
+ else
+ return false;
+
+}
diff --git a/fly-tools/MyPair.h b/fly-tools/MyPair.h
new file mode 100644
index 0000000..6a2a4fa
--- /dev/null
+++ b/fly-tools/MyPair.h
@@ -0,0 +1,30 @@
+class MyPair {
+
+public:
+ int first, second;
+ MyPair(int x, int y) {
+
+ this->first = x;
+ this->second = y;
+
+ }
+ MyPair() {
+
+ this->first = -1;
+ this->second = -1;
+
+ }
+ MyPair(const MyPair &f) {
+ this->first = f.getX();
+ this->second = f.getY();
+
+ }
+ int getX() const {
+ return this->first;
+ }
+
+ int getY() const {
+ return this->second;
+ }
+
+};
diff --git a/fly-tools/StandardDeviation.cpp b/fly-tools/StandardDeviation.cpp
new file mode 100644
index 0000000..a157d11
--- /dev/null
+++ b/fly-tools/StandardDeviation.cpp
@@ -0,0 +1,90 @@
+#include<iostream>
+#include<fstream>
+#include<iomanip>
+#include<cmath>
+#include<vector>
+using namespace std;
+
+vector<double> currentHistogramValues;
+
+int main(int argc, char* argv[]) {
+
+ // argv[0] name of the executable
+ // argv[1] input file containing the list of files
+ // argv[2] output file containing the standard deviation and file name pair
+ // argv[3] data file path
+ // argv[4] data file postfix of metricname
+
+ if (argc < 3) {
+ cout<<"Please provide the parameters ./executable iputfilename outputfilename"<<endl;
+ exit(0);
+ }
+
+ ifstream inputFileNames(argv[1]);
+ if (inputFileNames.fail() == true) {
+ cout << "Input File can not be opened"<<endl;
+ exit(0);
+ }
+
+ ofstream outputFile(argv[2]);
+ outputFile<<left<<setw(20)<<"File Name"<<left<<setw(20)<<"Standard deviation"<<left<<setw(20)<<"Mean"<<endl;
+
+ string prefixPath(argv[3]);
+
+ string metricName(argv[4]);
+
+ string currentFileName;
+ while(inputFileNames>>currentFileName) {
+
+ string currentFileWithExtension = prefixPath + currentFileName + "/" + currentFileName + "_"+ metricName +".txt";
+ ifstream currentFile(currentFileWithExtension.c_str());
+ if (currentFile.fail() == true) {
+ cout << currentFileName + " cannot be opened"<<endl;
+ exit(0);
+ }
+
+ // N = sum(H_i) for i = 0 to M-1, M = number of samples in the histogram
+ // mean = 1/N*(sum(i*H_i)) for i = 0 to M-1
+ double currentValueOfHistogram;
+ double sumOfValues = 0.0;
+ currentHistogramValues.clear();
+ double i = 0.0;
+ double N = 0.0;
+ double M = 0.0;
+ while (currentFile >> currentValueOfHistogram) {
+ sumOfValues = sumOfValues + i*currentValueOfHistogram;
+ currentHistogramValues.push_back(currentValueOfHistogram);
+
+ N = N + currentValueOfHistogram;
+ i=i+1.0;
+ }
+
+ M = currentHistogramValues.size();
+ // mean
+ double mean = sumOfValues/N;
+
+
+ // sigma^2 = (sum( (i-mean)^2*H_i ) )/(N-1) for i = 0 to M-1
+ double standardDev = 0.0;
+ double sumSquaredResults = 0.0;
+ int j = 0;
+ for (i=0.0; i<M; i=i+1.0) {
+ sumSquaredResults += pow((i-mean), 2.0)*currentHistogramValues[j];
+ j++;
+ }
+
+ // standard deviation
+
+ standardDev = sumSquaredResults/(N-1);
+ standardDev = sqrt(standardDev);
+
+
+ outputFile<<left<<setw(20)<<currentFileName<<left<<setw(20)<<standardDev<<left<<setw(20)<<mean<<endl;
+
+ currentFile.close();
+ }
+
+ inputFileNames.close();
+ outputFile.close();
+
+} \ No newline at end of file
diff --git a/fly-tools/misc/linesweep.cpp b/fly-tools/misc/linesweep.cpp
new file mode 100644
index 0000000..fa55522
--- /dev/null
+++ b/fly-tools/misc/linesweep.cpp
@@ -0,0 +1,693 @@
+#include <iostream>
+#include <map>
+#include <vector>
+#include <fstream>
+#include <cassert>
+#include <cmath>
+#include <Magick++.h>
+#include "jzImage.h"
+
+using namespace Magick;
+using namespace std;
+
+unsigned int jzImage::_h;
+unsigned int jzImage::_w;
+char* jzImage::data = NULL;
+
+// colors in debugging
+const int C = 10;
+
+static map<unsigned int, long unsigned int> len;
+bool inWhite;
+bool startedWhite;
+int x_init, y_init;
+
+inline int roundT(double v) { return int(v+0.5); }
+inline int dist(int x0, int y0, int x1, int y1) {return roundT(sqrt(pow(double(x1)-x0, 2.0)+pow(double(y1)-y0, 2.0)));}
+
+inline void drawLine(int x0, int y0, int x1, int y1, jzImage& img);
+inline void lookAt(int x, int y, jzImage& img);
+
+
+void writeHist(const char* filename)
+{
+ map<unsigned int,long unsigned int>::iterator front = len.begin(),
+ back = len.end();
+ back--;
+
+
+ unsigned int first = front->first, last = back->first;
+ /*if (cutoff != -1 && cutoff < int(last))
+ last = cutoff;
+ */
+ cout << "Min: " << first << endl
+ << "Max: " << last << endl
+ << "Count: " << last-first << endl;
+ //vector<unsigned int> hist(last-first, 0);
+ vector<long unsigned int> hist(last+1, 0);
+
+ cout << "hist size: " << hist.size() << endl;
+ try{
+ for(unsigned int j = 0; j<first; j++) {
+ hist[j] = 0;
+ }
+ for (unsigned int j = first; j<=last; j++)
+ {
+ /*if ( roundT(j-first) >= int(hist.size()) )
+ hist.resize(j-first,0);
+ hist[roundT(j-first)] = len[j];
+ */
+
+ /*if ( roundT(j) >= int(hist.size()) )
+ hist.resize(j,0);
+ hist[roundT(j)] = len[j];
+ */
+ hist[j] = len[j];
+ }
+ }
+ catch (...)
+ { cerr << "Bad histogram bucketing" << endl; }
+
+ /*if ( (cutoff >= 0) && (cutoff<int(hist.size())) )
+ hist.resize(cutoff);
+ */
+ //len.clear();
+ try
+ {
+ ofstream fout(filename);
+ for (unsigned int i = 0; i<hist.size(); i++) {
+ fout << hist[i] << endl;
+ }
+ fout << first << " " << last << " " << hist.size() << endl;
+ fout.close();
+ }
+ catch (...)
+ { cerr << "Bad memory loc for opening file" << endl; }
+}
+
+void writeHistLog( const char* filename,map<unsigned int, double> len)
+{
+ map<unsigned int, double >::iterator front = len.begin(),
+ back = len.end();
+ back--;
+
+
+ unsigned int first = front->first, last = back->first;
+ /*if (cutoff != -1 && cutoff < int(last))
+ last = cutoff;
+ */
+ cout<< "Min: " << first << endl
+ << "Max: " << last << endl
+ << "Count: " << last-first << endl;
+ //vector<unsigned int> hist(last-first, 0);
+ vector<double> hist(last+1, 0);
+
+ cout << "hist size: " << hist.size() << endl;
+ try{
+ for(unsigned int j = 0; j<first; j++) {
+ hist[j] = 0;
+ }
+ for (unsigned int j = first; j<=last; j++)
+ {
+ /*if ( roundT(j-first) >= int(hist.size()) )
+ hist.resize(j-first,0);
+ hist[roundT(j-first)] = len[j];
+ */
+
+ /*if ( roundT(j) >= int(hist.size()) )
+ hist.resize(j,0);
+ hist[roundT(j)] = len[j];
+ */
+ hist[j] = len[j];
+ }
+ }
+ catch (...)
+ { cerr << "Bad histogram bucketing" << endl; }
+
+ /*if ( (cutoff >= 0) && (cutoff<int(hist.size())) )
+ hist.resize(cutoff);
+ */
+ len.clear();
+ try
+ {
+ ofstream fout(filename);
+ for (unsigned int i = 0; i<hist.size(); i++) {
+ fout << hist[i] << endl;
+ }
+ fout << first << " " << last << " " << hist.size() << endl;
+ fout.close();
+ }
+ catch (...)
+ { cerr << "Bad memory loc for opening file" << endl; }
+}
+
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3)
+ {
+ cerr << "Usage: lineSweep <inputFile> <outputFile>" << endl;
+ return -1;
+ }
+
+ int i, j;
+
+ inWhite = false;
+ len.clear();
+
+ MagickCore::SetMagickResourceLimit(MagickCore::MemoryResource, 1536);
+ MagickCore::SetMagickResourceLimit(MagickCore::MapResource, 4096);
+ Image* img = new Image(argv[1]);
+
+ int width = img->columns(),
+ height = img->rows();
+
+ jzImage &myImg = jzImage::Instance(img);
+
+ delete img;
+
+ /*
+ // doesn't take pixel(0,0) and also takes pixel(width-1, height-1) twice
+ //map<pair<pair<int,int>, pair<int,int> >, bool> hitMap;
+ const int boundSize = 2*(width+height-2);
+ static pair<int, int>* boundary = new pair<int,int>[boundSize];
+
+ for (i = 0; i<width-1; i++)
+ {
+ boundary[i].first = i+1;
+ boundary[i].second = 0;
+ boundary[width+height+i-2].first = i+1;
+ boundary[width+height+i-2].second = height-1;
+ }
+
+ for (i = 0; i<height-1; i++)
+ {
+ boundary[width+i-1].first = width-1;
+ boundary[width+i-1].second = i+1;
+ boundary[height+2*width+i-3].first = 0;
+ boundary[height+2*width+i-3].second = i+1;
+ }
+
+ for (i = 0; i<boundSize-1; i++)
+ {
+ cerr << "At: " << i << " of " << boundSize << endl;
+ // not considering boundary-1 th pixel ?????
+ for (j = i+1; j<boundSize-1; j++)
+ if ( !myImg.isOnSameBoundaryAs(
+ myImg.indexOf(boundary[i].first,boundary[i].second),
+ myImg.indexOf(boundary[j].first,boundary[j].second)) )
+ drawLine(boundary[i].first,boundary[i].second,boundary[j].first,boundary[j].second,myImg);
+ }
+
+ */
+
+ //map<pair<pair<int,int>, pair<int,int> >, bool> hitMap;
+ const int boundSize = 2*(width+height-2);
+ static pair<int, int>* boundary = new pair<int,int>[boundSize];
+
+ for (i = 0; i<=width-1; i++)
+ {
+ boundary[i].first = i;
+ boundary[i].second = 0;
+ boundary[width+(height-2)+i].first = i;
+ boundary[width+(height-2)+i].second = height-1;
+ }
+
+ for (i = 0; i<height-2; i++)
+ {
+ boundary[width+i].first = width-1;
+ boundary[width+i].second = i+1;
+ boundary[width+(height-2)+width+i].first = 0;
+ boundary[width+(height-2)+width+i].second = i+1;
+ }
+
+
+ for (i = 0; i<boundSize; i++)
+ cerr<<"boundr["<<i<<"] == "<<boundary[i].first<<","<<boundary[i].second<<endl;
+
+
+ //drawLine(7,1,4,7,myImg);
+ // m >= 1
+ //drawLine(3,2,5,5,myImg);
+ // 0<=m<1
+ //drawLine(5,5,1,4,myImg);
+ // -1< m < 0
+ //drawLine(7,0,2,3,myImg);
+ // m<-1
+ //drawLine(1,7,3,2,myImg);
+ // dx = 0
+ //drawLine(5,0,5,5,myImg);
+ // dy = 0
+ //drawLine(0,3,7,3,myImg);
+ // multiple length
+ //drawLine(1,7,7,1,myImg);
+
+
+
+ for (i = 0; i<boundSize-1; i++)
+ {
+ //cerr << "At: " << i << " of " << boundSize << endl;
+ for (j = i+1; j<boundSize; j++)
+ if ( !myImg.isOnSameBoundaryAs(
+ myImg.indexOf(boundary[i].first,boundary[i].second),
+ myImg.indexOf(boundary[j].first,boundary[j].second)) ) {
+ drawLine(boundary[i].first,boundary[i].second,boundary[j].first,boundary[j].second,myImg);
+ } /*else
+ cerr << i <<" and "<< j << " are on the same boundary"<<endl;
+ */
+ }
+
+ writeHist(argv[2]);
+
+ /*ofstream newFile("output.txt");
+ newFile<<"size == " << len.size()<<endl;
+ for ( unsigned int i=0; i<len.size(); i++) {
+ newFile<<"len["<<i<<"] == " <<len[i]<<endl;
+
+ }
+ newFile.close();
+ */
+ // compute the logarithmic distribution.
+
+ map< unsigned int, double> lineSweepValLog;
+ map<unsigned int,long unsigned int>::iterator front = len.begin(), back = len.end();
+
+ for( front; front != back; front++ ) {
+ double logvalue = log(front->second);
+ lineSweepValLog[front->first] = logvalue;
+ }
+
+ string fileNameLog(argv[2]);
+ fileNameLog = fileNameLog + "_log_hist.txt";
+ writeHistLog(fileNameLog.c_str(), lineSweepValLog);
+
+
+ delete[] boundary;
+
+ return 0;
+}
+
+/*
+void lookAt(int x, int y, jzImage& img)
+{
+ if (img.pixelColor(x,y) == 1)
+ // if it was the first white pixel then
+ if (!inWhite)
+ {
+ inWhite = true;
+ x_init = x;
+ y_init = y;
+ }
+
+ if (img.pixelColor(x,y) == 0)
+ if (inWhite)
+ {
+ int val = roundT(dist(x_init, y_init, x, y));
+ len[val]++;
+ inWhite = false;
+ }
+}
+*/
+
+void lookAt(int x, int y, jzImage& img)
+{
+ int imageWidth =img.width();
+ int imageHeight = img.height();
+ // if current pixel is white
+ if (img.pixelColor(x,y) == 1) {
+ // if it was the first white pixel then
+ if (!inWhite)
+ {
+ // check whether it started as a white pixel; if it started as white pixel then this line segment should
+ // not be counted. because it is part of the larger white blob
+ if ( (x == 0 || x == (imageWidth -1) ) || ( y == 0 || y == (imageHeight - 1)))
+ startedWhite = true;
+ inWhite = true;
+ x_init = x;
+ y_init = y;
+ }
+ // if we are on a white region
+ /*else {
+
+ }
+ */
+ }
+
+ if (img.pixelColor(x,y) == 0) {
+ // if we are going through a white line and reached the black pixel
+ if (inWhite)
+ {
+ // if the line started as a white pixel then discard the line fragment
+ if (startedWhite == false) {
+ int val = roundT(dist(x_init, y_init, x, y));
+ //cout<<" val is = " << val << " at (x0,y0) = " << x_init << "," << y_init << " to (x1,y1) = " << x << "," << y <<endl;
+ len[val]++;
+ } else
+ startedWhite = false;
+
+ inWhite = false;
+ }
+ }
+}
+
+/*
+void drawLine(int x0, int y0, int x1, int y1, jzImage& img)
+{
+ inWhite = false;
+ startedWhite = false;
+
+ // always go from x0 -> x1
+ if (x0 > x1)
+ {
+ int temp = x0;
+ x0 = x1;
+ x1 = temp;
+ temp = y0;
+ y0 = y1;
+ y1 = temp;
+ }
+
+ int dx, dy, d, x, y, incrE, incrNE;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ y = y0;
+ x = x0;
+
+ // if they are on a vertical line
+ if (dx == 0)
+ {
+ if (y0 < y1)
+ for (int i = y0; i<=y1; i++)
+ lookAt(x,i,img);
+ else
+ for (int i = y1; i<=y0; i++)
+ lookAt(x,i,img);
+ return;
+ }
+
+ // if they are on a horizontal line
+ if (dy == 0)
+ {
+ for (int i = x0; i<=x1; i++)
+ lookAt(i,y,img);
+ return;
+ }
+
+ int dir = 0;
+ double m = double(dy)/double(dx);
+ if (m >= 1.0)
+ dir = 1;
+ else if ( (m < 0.0) && (m > -1.0) )
+ dir = 2;
+ else if (m <= -1.0)
+ dir = 3;
+
+ switch(dir)
+ {
+ // when slope m: 0< m <1
+ case 0:
+ d = dy*2 - dx;
+ incrE = dy*2;
+ incrNE = (dy - dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ // when slope m: m >= 1
+ case 1:
+ d = dx*2 - dy;
+ incrE = dx*2;
+ incrNE = (dx - dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y<y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ case 2:
+ d = dy*2 + dx;
+ incrE = dy*2;
+ incrNE = (dy + dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d >= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+
+ lookAt(x,y,img);
+ }
+ break;
+ // since initially we swapped the P0 with P1 so that P0 always holds values with smaller x cooridinate
+ // so we are sure that m<0 is the result of y0 being greater that
+ case 3:
+ d = dx*2 + dy;
+ incrE = dx*2;
+ incrNE = (dx + dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y>y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y--;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ }
+
+
+ if (inWhite)
+ {
+ // it is a fraction of the blob so dont count it
+ //len[dist(x_init,y_init,x,y)+1]++;
+ inWhite = false;
+ startedWhite = false;
+ }
+}
+*/
+
+void drawLine(int x0, int y0, int x1, int y1, jzImage& img)
+{
+ inWhite = false;
+ startedWhite = false;
+
+ // always go from x0 -> x1
+ if (x0 > x1)
+ {
+ int temp = x0;
+ x0 = x1;
+ x1 = temp;
+ temp = y0;
+ y0 = y1;
+ y1 = temp;
+ }
+
+ int dx, dy, d, x, y, incrE, incrNE;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ y = y0;
+ x = x0;
+
+ // if they are on a vertical line
+ if (dx == 0)
+ {
+ if (y0 < y1)
+ for (int i = y0; i<=y1; i++)
+ lookAt(x,i,img);
+ else
+ for (int i = y1; i<=y0; i++)
+ lookAt(x,i,img);
+ return;
+ }
+
+ // if they are on a horizontal line
+ if (dy == 0)
+ {
+ for (int i = x0; i<=x1; i++)
+ lookAt(i,y,img);
+ return;
+ }
+
+ int dir = 0;
+ double m = double(dy)/double(dx);
+ if (m >= 1.0)
+ dir = 1;
+ else if ( (m < 0.0) && (m > -1.0) )
+ dir = 2;
+ else if (m <= -1.0)
+ dir = 3;
+
+ switch(dir)
+ {
+ // when slope m: 0< m <1
+ case 0:
+ d = dy*2 - dx;
+ incrE = dy*2;
+ incrNE = (dy - dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ // when slope m: m >= 1
+ case 1:
+ d = dx*2 - dy;
+ incrE = dx*2;
+ incrNE = (dx - dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y<y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y++;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ case 2:
+ d = dy*2 + dx;
+ incrE = dy*2;
+ incrNE = (dy + dx)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (x<x1)
+ {
+ if (d >= 0)
+ {
+ d+= incrE;
+ x++;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+
+ lookAt(x,y,img);
+ }
+ break;
+ // since initially we swapped the P0 with P1 so that P0 always holds values with smaller x cooridinate
+ // so we are sure that m<0 is the result of y0 being greater that
+ case 3:
+ d = dx*2 + dy;
+ incrE = dx*2;
+ incrNE = (dx + dy)*2;
+ x = x0;
+ y = y0;
+
+ lookAt(x,y,img);
+
+ while (y>y1)
+ {
+ if (d <= 0)
+ {
+ d+= incrE;
+ y--;
+ }
+ else
+ {
+ d+= incrNE;
+ x++;
+ y--;
+ }
+ lookAt(x,y,img);
+ }
+ break;
+ }
+
+
+ if (inWhite)
+ {
+ // it is a fraction of the blob so dont count it
+ //len[dist(x_init,y_init,x,y)+1]++;
+ inWhite = false;
+ startedWhite = false;
+ }
+}
diff --git a/fly-tools/misc/makeimage.cpp b/fly-tools/misc/makeimage.cpp
new file mode 100644
index 0000000..06e2897
--- /dev/null
+++ b/fly-tools/misc/makeimage.cpp
@@ -0,0 +1,51 @@
+#include <Magick++.h>
+#include <iostream>
+#include<fstream>
+#include<string>
+using namespace std;
+using namespace Magick;
+
+int main(int argc,char **argv)
+
+{
+ // Construct the image object. Seperating image construction from the
+ // the read operation ensures that a failure to read the image file
+ // doesn't render the image object useless.
+
+ Image* img;
+ char buffer[100];
+ sprintf(buffer,"%ix%i",7,7);
+
+ // residual image is initialized with black representing not visited.
+ //residual = new Image(buffer, "black");
+
+ img = new Image(buffer, "white");
+
+ for (int j=0; j<=3;j++) {
+ for (int i=0; i<=3-j; i++) {
+ img->pixelColor(i,j, "black");
+ img->pixelColor(6-i,j, "black");
+ }
+ }
+
+ int k;
+ for (int j=4; j<=6;j++) {
+ for (int i=0; i<=j-3; i++) {
+ img->pixelColor(i,j, "black");
+ img->pixelColor(6-i,j, "black");
+ }
+ }
+
+
+ //img->pixelColor(0,3, "red");
+
+
+ string namei = "7x7.png";
+ img->write(namei.c_str());
+
+ delete img;
+
+ return 0;
+
+}
+
diff --git a/fly-tools/misc/test.cpp b/fly-tools/misc/test.cpp
new file mode 100644
index 0000000..a709482
--- /dev/null
+++ b/fly-tools/misc/test.cpp
@@ -0,0 +1,92 @@
+#include<iostream>
+#include<vector>
+
+using namespace std;
+
+void largestIncreasingPositiveDotProductSeq(vector<double> velocityDirs, int &startIndex, int &endIndex) {
+
+ int positiveVelSeqSize = 0;
+ int flag = false;
+ int maxSeqSize = 0;
+ int st = 0;
+ for (int j=0; j<velocityDirs.size()-1; j++) {
+ double prevVel = velocityDirs[j];
+ double currVel = velocityDirs[j+1];
+
+ double dotProd = prevVel*currVel;
+
+ if( dotProd > 0 && flag == false) {
+ st = j;
+ positiveVelSeqSize++;
+ flag = true;
+ cout << "In first if positiveSize "<<positiveVelSeqSize<<endl;
+
+ } else if (dotProd > 0 && flag == true) {
+ positiveVelSeqSize++;
+ cout << "In second if positive "<<positiveVelSeqSize<<endl;
+ } else {
+ positiveVelSeqSize = 0;
+ flag = false;
+ cout << "Else\n";
+
+ }
+
+ if (positiveVelSeqSize > maxSeqSize) {
+ maxSeqSize = positiveVelSeqSize;
+ startIndex = st;
+ endIndex = st+positiveVelSeqSize;
+ cout << "maxseq updated \npositiveSize "<<positiveVelSeqSize<<endl;
+ cout << "st "<<startIndex<<endl;
+ cout << "end "<<endIndex<<endl;
+ }
+
+
+
+ }
+
+}
+
+int main () {
+
+ vector<double> test(4);
+ test[0]=0;
+ test[1]=7;
+ test[2]=0;
+ test[3]=7;
+ /*test[4]=5;
+ test[5]=2;
+ test[6]=-3;
+ test[7]=-4;
+ test[8]=2;
+ test[9]=3;
+ */
+ int st;
+ int endIndex;
+
+ largestIncreasingPositiveDotProductSeq(test,st, endIndex );
+ for (int i=st; i<=endIndex; i++) {
+ cout << test[i]<<endl;
+ }
+ cout << st << endl;
+ cout << endIndex<<endl;
+
+ /*cout << "index"<<endl;
+ int size = 0;
+ int i;
+ int end = 14;
+ st = 0;
+ int c;
+ for (i=end; i>=st; i=i-5) {
+ c = i;
+ cout << c << endl;
+ size++;
+ }
+ if ((c-st) != 0) {
+ cout <<"additional " <<st<<endl;
+ size++;
+ }
+ cout << "last i "<<i;
+ cout << "size = ";
+ cout << size <<endl;
+ */
+}