#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FrameInfo.h" using namespace Magick; using namespace std; // One of these output streams will be used. If directed towards null, nothing happens, towards output, it will be printed ofstream nullLog; ostream* output; // Our output files for debugging and information ofstream foutLPS; ofstream foutSt; ofstream foutDebugCen; ofstream foutDebugSpeed; 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; bool isInFemaleBlob; int maskImageHeight; int maskImageWidth; int diagLength; vector > bresenhamLine; Image* residual; vector fOVector; vector fIVector; // temporary store of the frames for finding initial head direction vector 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 largeCollisionBeforeDirection; pair 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; // This decides if we want to output an overlay. You'll get the same results // either way but you won't be able to verify it. taken as an argument. bool writeFinalImages = false; // GLOBAL PATHS string inputFileName; string maskImagePath; string origImagePath; string finalOutputPath; string outputFilePrefix; vector > velocityDirectionsF; vector > velocityDirectionsS; vector fnVector; pair avgVelocityF; pair avgVelocityS; pair overAllVelocityF; pair overAllVelocityS; vector > evDirectionF; vector > evDirectionS; // Information about frames that will be written out at the end of proessing. int totalMaleLookingAtFemale = 0; int totalFemaleLookingAtMale = 0; int totalSingleBlob = 0; int totalUnprocessedFrame = 0; int totalSeparated = 0; map centroidDistanceMap; map headDirAngleMap; map 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 & fov) { for(unsigned int i=1; i dataMap) { *output << "In the beginning of the write hist" << endl; *output << "dataMap size " << dataMap.size() << endl; if (dataMap.size() == 0) { *output << "Empty histogram" << endl; ofstream fout(filename); fout <<"No entry in the histogram and size is " << dataMap.size() << endl; fout.close(); return; } map::iterator front = dataMap.begin(), back = dataMap.end(); back--; unsigned int first = front->first, last = back->first; *output << "Min: " << first << " " << "Max: " << last << " " << "Count: " << last-first << endl; vector hist(last+1, 0); try { for (unsigned int j = 0; j v, pair eV); void calculateHeadVector(FlyObject fO, pair &headDirection); vector covariantDecomposition(vector > & points); void determineHeadDirection(int fileCounter); 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); void eightConnObj(Image* img, int x, int y, vector > & obj, bool color=true); double euclideanDist(FlyObject a, FlyObject b); void findObj(Image* img, int x, int y, vector > & shape ,bool eightCon=true, bool colorLookingFor=true); void fourConnObj(Image* img, int x, int y, vector > & obj, bool color=true); pair getCentroid(vector > & points); bool isInterface(Image* orig, unsigned int x, unsigned int y); bool identifyFlyObjectFromFrameToFrame(FrameInfo prevFI, FrameInfo& currentFI, bool gotRidOfSingleBlob=false) ; int roundT(double v) {return int(v+0.5);} void normalizeVector(pair &a); void writeFrameImage(int fn, string imS); void normalizeVector(pair &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 v, pair eV) { return (v.first*eV.first + v.second*eV.second); } void calculateHeadVector(FlyObject fO, pair &headDirection) { bool headDirectionBool = fO.getHeadIsInDirectionMAEV(); pair 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 pFOVector = prevFI.getFOVector(); vector cFOVector = currentFI.getFOVector(); FlyObject pFLargeFO = pFOVector[0]; FlyObject pFSmallFO = pFOVector[1]; FlyObject cFLargeFO = cFOVector[0]; FlyObject cFSmallFO = cFOVector[1]; // calculate velocity pair pFLCentroid = pFLargeFO.getCentroid(); pair pFSCentroid = pFSmallFO.getCentroid(); pair cFLCentroid = cFLargeFO.getCentroid(); pair cFSCentroid = cFSmallFO.getCentroid(); double velocityXLarge = static_cast (cFLCentroid.first) - static_cast (pFLCentroid.first); double velocityYLarge = static_cast (cFLCentroid.second) - static_cast (pFLCentroid.second); double velocityXSmall = static_cast (cFSCentroid.first) - static_cast (pFSCentroid.first); double velocityYSmall = static_cast (cFSCentroid.second) - static_cast (pFSCentroid.second); pair cLVV(velocityXLarge,velocityYLarge); pair cSVV(velocityXSmall,velocityYSmall); cFLargeFO.setVelocityV(cLVV); cFSmallFO.setVelocityV(cSVV); // normalize the velocity cFLargeFO.normalizeVelocity(); cFSmallFO.normalizeVelocity(); // determine the head direction for larger object pair cLEV = cFLargeFO.getMajorAxisEV(); // normalize the eigenvector normalizeVector(cLEV); pair identifiedCLEV; // the head from the previous frame pair pLH = pFLargeFO.getHead(); // find the dot product with the previous frame head with current major axis both direction double largerDotProdPrevHeadAndCLEV = calculateDotProduct(pLH, cLEV); pair cLREV(-cLEV.first, -cLEV.second); //double largerDotProdPrevHeadAndCLREV = calculateDotProduct(pLH, clREV); if (largerDotProdPrevHeadAndCLEV >=0) { *output << "Current eigen is in direction with the historical head"< newHead(newHeadFirst,newHeadSecond); cFLargeFO.setHead(newHead); cFLargeFO.setHeadIsInDirectionMAEV(true); // set the identified EV identifiedCLEV = cLEV; } else { *output << "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 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); *output << "largerDotProd "<= 0) { *output<<"Larger Dot prod is positive"< cSEV = cFSmallFO.getMajorAxisEV(); normalizeVector(cSEV); pair identifiedCSEV; // head from the previous frame pair pSH = pFSmallFO.getHead(); // find the dot product with the previous frame head with current major axis both direction double smallerDotProdPrevHeadAndCSEV = calculateDotProduct(pSH, cSEV); pair cSREV(-cSEV.first, -cSEV.second); if (smallerDotProdPrevHeadAndCSEV >=0) { *output << "Current eigen is in direction with the historical head for the smaller fly object"< newHead(newHeadFirst, newHeadSecond); cFSmallFO.setHead(newHead); cFSmallFO.setHeadIsInDirectionMAEV(true); // set the identified EV to current EV identifiedCSEV = cSEV; } else { *output << "Current eigen is in direction with the historical head for the smaller fly object"< 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 previousHeadDirection; calculateHeadVector(pFSmallFO, previousHeadDirection); // find the current frame's HD pair 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 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 newHead(newHeadFirst, newHeadSecond); cFSmallFO.setHead(newHead); } else { // record this vector for history double newHeadFirst = cSREV.first; double newHeadSecond = cSREV.second; pair 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 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 newHead(newHeadFirst, newHeadSecond); cFSmallFO.setHead(newHead); } */ double smallDotProd = calculateDotProduct(cSVV, cSEV); if (smallDotProd >= 0) { *output << "Smaller dot product is positive"< updatedFOVector; updatedFOVector.push_back(cFLargeFO); updatedFOVector.push_back(cFSmallFO); currentFI.setFOVector(updatedFOVector); fIVector[fileCounter] = currentFI; // *output << "checking the update"< tempFIFOVector = tempFI.getFOVector(); // FlyObject tempFILFO = tempFIFOVector[0]; // FlyObject tempFISFO = tempFIFOVector[1]; // pair tempFILFOVV = tempFILFO.getVelocityV(); // *output << "Large object velocity vector "< tempFISFOVV = tempFISFO.getVelocityV(); // *output << "Small object velocity vector "<= 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= 1 case 1: d = dx*2 - dy; incrE = dx*2; incrNE = (dx - dy)*2; x = x0; y = y0; lookAt(x,y,img); while (y= 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 putPixel(Image* maskImage, int x, int y) { // 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; *output << "Hit the male object at "< t(x,y); bresenhamLine.push_back(t); } } 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 (dy)/static_cast (dx); int octant = -1; if (( m >= 0 and m <= 1) and x0 < x1 ) { *output << "Octant 1"< 1) and (y0 < y1)) { *output << "Octant 2"<= -1) and (x0 > x1)) { *output << "Octant 4"< 0 and m <=1) and (x0 > x1) ) { *output << "Octant 5"< 1) and (y0 > y1) ) { *output << "Octant 6"< y1) ) { *output << "Octant 7"<= -1) and (x0 < x1) ) { *output << "Octant 8"< x1 ) { if (d <= 0) { d = d + delW; x = x - 1; } else { d = d + delNW; x = x - 1; y = y + 1; } putPixel(maskImage,x, y); if (isInFemaleBlob == true) return 1; } break; case 5: d = -dx + 2*dy; delW = 2*dy; delSW = 2*(-dx+dy); x = x0; y = y0; putPixel(maskImage,x, y); 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); 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); 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); 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); 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); 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); 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; } // *output << "putpixel "< newLocation, pair initLocation) { double temp = pow((newLocation.first - initLocation.first), 2.0) + pow((newLocation.second - initLocation.second), 2.0); temp = sqrt(temp); return temp; } inline double getSpeed(pair vector) { double value = vector.first*vector.first + vector.second*vector.second; value = sqrt(value); return value; } 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) { *output << "Should draw "< pFHH = prevFO.getHead(); pair cFOEV = currentFO.getMajorAxisEV(); normalizeVector(cFOEV); pair cFOREV(-cFOEV.first, -cFOEV.second); double dotProdEVAndHH = calculateDotProduct(cFOEV, pFHH); if (dotProdEVAndHH > 0 ) { *output << "Current head is in direction with the Previous frame Head(which is the historical head from the maxDistIndex)"< newHead(newHeadX, newHeadY); currentFO.setHead(newHead); currentFO.setHeadIsInDirectionMAEV(true); } else { *output << "Current head is in direction with the previous frame head"< newHead(newHeadX, newHeadY); currentFO.setHead(newHead); currentFO.setHeadIsInDirectionMAEV(false); } // copy the velocity vector from the previous frame pair pFVV = prevFO.getVelocityV(); currentFO.setVelocityV(pFVV); } void objectHeadDirection(FlyObject prevFO, FlyObject ¤tFO, bool prevFFOHD) { // take the head direction from the previous frame //pair pFHH = prevFO.getHead(); pair pFHeadDir; calculateHeadVector(prevFO, pFHeadDir); pair cFOEV = currentFO.getMajorAxisEV(); normalizeVector(cFOEV); pair cFOREV(-cFOEV.first, -cFOEV.second); double dotProdEVAndHD = calculateDotProduct(cFOEV, pFHeadDir); if (dotProdEVAndHD > 0 ) { *output << "Current head is in direction with the Previous frame Head direction"< newHead(newHeadX, newHeadY); currentFO.setHead(newHead); currentFO.setHeadIsInDirectionMAEV(true); */ currentFO.setHead(cFOEV); currentFO.setHeadIsInDirectionMAEV(true); } else { *output << "Current head is in reverse direction with the previous frame head direction"< 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 pFVV = prevFO.getVelocityV(); currentFO.setVelocityV(pFVV); } } void objectHeadDirection(FlyObject ¤tFO, int saveEV=0) { // get the velocity vector pair cFOVV = currentFO.getVelocityV(); pair cFOEV = currentFO.getMajorAxisEV(); normalizeVector(cFOEV); pair cFOREV(-cFOEV.first, -cFOEV.second); double dotProdVVAndEV = calculateDotProduct(cFOEV, cFOVV); if (dotProdVVAndEV > 0 ) { *output << "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) { *output << "saving the eigen vector for the first object"< zero(0.0,0.0); if (saveEV == 1) { *output << "saving the zero eigen vector for the first object"< cFV) { // // get the velocity vector // pair cFOVV = currentFO.getVelocityV(); pair cFOEV = currentFO.getMajorAxisEV(); normalizeVector(cFOEV); pair cFOREV(-cFOEV.first, -cFOEV.second); double dotProdVVAndEV = calculateDotProduct(cFOEV, cFV); if (dotProdVVAndEV > 0 ) { *output << "Current head is in direction with the vector used\n"; // set the head to the eigen vector currentFO.setHead(cFOEV); currentFO.setHeadIsInDirectionMAEV(true); } else { *output << "Current head is in reverse direction with the vector used"< &velDirectionF, pair&velDirectionS) { // find the average velocity vector *output << "Finding average velocity vector from "< pFOVector = prevFI.getFOVector(); FlyObject pFFirstFO = pFOVector[0]; FlyObject pFSecondFO = pFOVector[1]; FrameInfo currentFI = fIVector[end]; vector 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 cFFCentroid = cFFirstFO.getCentroid(); pair cFSCentroid = cFSecondFO.getCentroid(); pair pFFCentroid = pFFirstFO.getCentroid(); pair 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; *output << "Velocity vector"< cFVV(static_cast (velXFirst), static_cast (velYFirst)); pair cSVV(static_cast (velXSecond), static_cast (velYSecond)); velDirectionF = cFVV; velDirectionS = cSVV; } void velocityDirections(int stIndex, int endIndex) { velocityDirectionsF.clear(); velocityDirectionsS.clear(); int i = 0; //int intervalLength = 5; *output << "Initial velocity direction calculation"< velDirectionF; pair velDirectionS; // get the velocity velocityDirection(i,i+1, velDirectionF, velDirectionS); // extract the fly object for update FrameInfo currentFI = fIVector[i]; vector 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); *output << "Normalized velocity"< updatedFOVector; updatedFOVector.push_back(cFFirstFO); updatedFOVector.push_back(cFSecondFO); currentFI.setFOVector(updatedFOVector); *output << "Updating the frame "< > velocityDirs, int &startIndex, int &endIndex) { int positiveVelSeqSize = 0; int flag = false; int maxSeqSize = 0; int st = 0; for (unsigned int j=0; j prevVel = velocityDirs[j]; pair currVel = velocityDirs[j+1]; double dotProd = calculateDotProduct(prevVel, currVel); if( dotProd > 0 && flag == false) { st = j; positiveVelSeqSize++; flag = true; //*output << "In first if positiveSize "< 0 && flag == true) { positiveVelSeqSize++; //*output << "In second if positive "< maxSeqSize) { maxSeqSize = positiveVelSeqSize; startIndex = st; endIndex = st+positiveVelSeqSize; //*output << "maxseq updated \npositiveSize "< prevVel = velocityDirs[j]; if (prevVel.first != 0 || prevVel.second != 0) { startIndex = j; endIndex = j; zero = true; break; } } if (zero != true) { *output << "All directions zero"< cFOVector = currentFI.getFOVector(); FlyObject cFFO = cFOVector[object-1]; //pair cFVV = cFFO.getVelocityV(); //*output << "Velocity before normalization "< cFEV = cFFO.getMajorAxisEV(); *output << "Eigen vector before normalization "< maxVelValue) { maxVelValue = velValue; maxVelValIndex = i; } } *output << "Maximum speed is chosen for for frame "< cFOVector = currentFI.getFOVector(); FlyObject cFFirstFO = cFOVector[0]; FlyObject cFSecondFO = cFOVector[1]; *output << "Setting representative head direction of frame "< tempVelocity = cFSecondFO.getVelocityV(); //*output << "Velocity was "< intervalLength) { *output << "Propagating in the longest positive frame interval starting the direction from the frame "< pFOVector = prevFI.getFOVector(); FlyObject pFFirstFO = pFOVector[0]; FlyObject pFSecondFO = pFOVector[1]; for (int i=t+1; i<=e; i++) { FrameInfo currentFI = fIVector[i]; vector cFOVector = currentFI.getFOVector(); FlyObject cFFirstFO = cFOVector[0]; FlyObject cFSecondFO = cFOVector[1]; if (object == 1) { //*output << "First object extract"< tempVelocity = cFSecondFO.getVelocityV(); //*output << "Velocity was "<=s; i--) { FrameInfo currentFI = fIVector[i]; vector cFOVector = currentFI.getFOVector(); FlyObject cFFirstFO = cFOVector[0]; FlyObject cFSecondFO = cFOVector[1]; if (object == 1) { //*output << "First object extract"< pFOVector = prevFI.getFOVector(); FlyObject pFFirstFO = pFOVector[0]; FlyObject pFSecondFO = pFOVector[1]; if (e < origEnd) { *output << "Propagating front from "< cFOVector = currentFI.getFOVector(); FlyObject cFFirstFO = cFOVector[0]; FlyObject cFSecondFO = cFOVector[1]; if (object == 1) { objectHeadDirection(pFFirstFO, cFFirstFO, false); cFOVector[0] = cFFirstFO; pFFirstFO = cFFirstFO; } else { objectHeadDirection(pFSecondFO, cFSecondFO, false); 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 ) { *output << "Propagating down wards from "<=origStart; i--) { FrameInfo currentFI = fIVector[i]; vector cFOVector = currentFI.getFOVector(); FlyObject cFFirstFO = cFOVector[0]; FlyObject cFSecondFO = cFOVector[1]; if (object == 1) { //*output << "First object extract"< z = velocityDirectionsF[a]; pair zEV = evDirectionF[a]; *output <<" First object velocity = "< w = velocityDirectionsS[a]; pair wEV = evDirectionS[a]; *output << "Second object velocity = "< pFOVector = prevFI.getFOVector(); vector 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); *output << "previousFirst to currentFirst "< aCentroid = a.getCentroid(); pair bCentroid = b.getCentroid(); //*output << "Distance from "< (aCentroid.first)-static_cast (bCentroid.first)), 2.0); double y2 = pow((static_cast (aCentroid.second)-static_cast (bCentroid.second)), 2.0); double dist = sqrt((x2+y2)); *output << dist< cFOVector = currentFI.getFOVector(); FlyObject cFFirstFO = cFOVector[0]; FlyObject cFSecondFO = cFOVector[1]; double currDist = euclideanDist(cFFirstFO, cFSecondFO); if (currDist > maxDist) { maxDist = currDist; maxDistIndex = i; *output << "New max distance" << maxDist << " at the frame number "<=startOfATrackSequence; i--) { FrameInfo currentFI = fIVector[i]; objectCorrespondence(prevFI, currentFI); // update the fIVector fIVector[i] = currentFI; prevFI = currentFI; } *output << "Assigning object correspondance between maxDistIndex+1 "<<(maxDistIndex+1)<<" to endIndex "< fOVector = currentFI.getFOVector(); FlyObject cFFirstFO = fOVector[0]; FlyObject cFSecondFO = fOVector[1]; sequenceFirstAverage += cFFirstFO.getArea(); sequenceSecondAverage += cFSecondFO.getArea(); *output << "For frame number "< sequenceSecondAverage) { foutLPS << "First object is the female and avg size is "< sequenceSecondAverage) { *output << "First sequence is the object A"< > shape; vector tempFOV; // to find the new head direction //bool currentlyCalculatingHead = true; while (inputFile>>fileName) { int fi = fileName.find("_"); // Be aware that this limits us to sample size of 99,999 (55.55 minutes) // 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()); //*output << frameCounter<columns(),height = img->rows(); diagLength= static_cast ( sqrt( (height*height) + (width*width) ) ); //*output << "Diagonal length is "< 0 ) { // *output << "size of the object is: " << s < eigenVal = covariantDecomposition(shape); { //objCount++; double velocity_x=0.0, velocity_y=0.0; // save the object information FlyObject tempFO(s, pair (eigenVal[6], eigenVal[7]), pair (eigenVal[4], eigenVal[5]), pair (velocity_x, velocity_y), false, pair (eigenVal[4], eigenVal[5]), 0.0); tempFOV.push_back(tempFO); } } } } delete img; delete residual; // *output<<"Sorting the objects according to size"< 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; *output << "Only one object StartIndex "<= 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) { *output << "StartIndex "< 15 when the size of the sequence is > 16. if ((endOfATrackSequence - startOfATrackSequence) >=15 ) { processASequence(startOfATrackSequence, endOfATrackSequence); *output << "Done processing"< 15 ) { *output << "Last sequence that does not stick to a single blob status startIndex "<(totalMaleLookingAtFemale+totalFemaleLookingAtMale)/static_cast(totalSeparated); percentageLookingAt *= 100.0; double percentageSingleBlob = static_cast(totalSingleBlob)/static_cast(fileCounter); percentageSingleBlob *= 100.0; foutSt<<"Total number of single blob "<=0; i--) { pair tempP = bresenhamLine[i]; int x = tempP.first; int y = tempP.second; ColorMono currPixelColor = ColorMono(maskImage->pixelColor(x,y)); if (currPixelColor.mono() == true) { *output << "Hit the target fly"<<" "< > foundShape; vector > shape; Image *image, *mask; cout << "Segmented image "<columns(); height = image->rows(); sprintf(buffer,"%ix%i",width,height); // the residual image should be newed residual = new Image(buffer, "black"); *output<<"Detecting the male object for finding the start point"< 0 ) { *output << "size of the object is: " << s < tmpCentroid = getCentroid(shape); foutDebugCen<<"tmpCentroid.first, tmpCentroid.second = ("< point = shape[l]; *output << "point.first, point.second "< eigenVal = covariantDecomposition(foundShape); if (eVDirection == true) { ev_x = static_cast (x0) + static_cast (diagLength)*eigenVal[4]; ev_y = static_cast (y0) + static_cast (diagLength)*eigenVal[5]; } else { ev_x = static_cast (x0) - static_cast (diagLength)*eigenVal[4]; ev_y = static_cast (y0) - static_cast (diagLength)*eigenVal[5]; } x1 = static_cast (ev_x); y1 = static_cast (ev_y); *output<<"Endpoint: centroid (x0,y0)==("< point = foundShape[i]; mask->pixelColor(point.first, point.second,"white"); } /*int hits= */ draw_line_bm(mask, x1, y1, x0, y0); //mask->strokeColor("red"); //mask->draw(DrawableLine(x1, y1, x0, y0)); //mask->write("test.png"); *output<<"BresenhamLine size is "< 0) { pair temp = bresenhamLine[bresenhamLine.size()-1]; *output << "Finding the starting point: Hits source at "<pixelColor(temp.first, temp.second); //maleSP_x = prev_x; //maleSP_y = prev_y; if (c.mono() == true) { *output << "start point from the source object should be black"< 0) { pair temp = bresenhamLine[bresenhamLine.size()-1]; *output << "Finding the starting point: Hits source at "<pixelColor(temp.first, temp.second); //maleSP_x = prev_x; //maleSP_y = prev_y; if (c.mono() == true) { *output << "start point from the source object should be black"< fOVector = currentFI.getFOVector(); if (singleBlob == false and unprocessed == false) { FlyObject maleFO = fOVector[isFirst]; FlyObject femaleFO = fOVector[1-isFirst]; pair maleCentroid = maleFO.getCentroid(); pair femaleCentroid = femaleFO.getCentroid(); pair maleMajorAxisEV = maleFO.getMajorAxisEV(); pair femaleMajorAxisEV = femaleFO.getMajorAxisEV(); bool maleEVDir = maleFO.getHeadIsInDirectionMAEV(); bool femaleEVDir = femaleFO.getHeadIsInDirectionMAEV(); // 1. finding the distance between the centroids double tempDist = pow(static_cast(maleCentroid.first - femaleCentroid.first),2) + pow(static_cast(maleCentroid.second-femaleCentroid.second),2); tempDist = sqrt(tempDist); // round the function unsigned int dist = roundT(tempDist); centroidDistanceMap[dist] = centroidDistanceMap[dist] + 1; foutSt << "Centroid distance "< maleHeadDir; pair femaleHeadDir; if (maleEVDir == true) { maleHeadDir = maleMajorAxisEV; foutSt<<"Male Head In direction of ev"<(dp)); *output<<"Angle in radian "<(PI); *output<<"Angle in deg "<(roundT(static_cast(deg))); *output<<"Angle after rounding "< fOVector = currentFI.getFOVector(); *output << "While drawing it found objects = "< femaleCentroid = fO.getCentroid(); bool eVDirectionFemale = fO.getHeadIsInDirectionMAEV(); FlyObject currentFO = fOVector[isFirst]; pair centroid = currentFO.getCentroid(); bool eVDirection = currentFO.getHeadIsInDirectionMAEV(); // debug: //*output<<"Calling the findTheStartPoint() function"< centroid = currentFO.getCentroid(); pair majorAxisEV = currentFO.getMajorAxisEV(); bool eVDirection = currentFO.getHeadIsInDirectionMAEV(); double ev_x, ev_y; double prev_x, prev_y; if(writeFinalImages) { // 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(centroid.first) + 50.0 * majorAxisEV.first; ev_y = static_cast(centroid.second) + 50.0 * majorAxisEV.second; img->strokeColor("green"); img->draw( DrawableLine( centroid.first, centroid.second, static_cast(ev_x), static_cast(ev_y) )); } else { ev_x = static_cast(centroid.first) - 50.0 * majorAxisEV.first; ev_y = static_cast(centroid.second) - 50.0 * majorAxisEV.second; img->strokeColor("green"); img->draw( DrawableLine( centroid.first, centroid.second, static_cast(ev_x), static_cast(ev_y) )); } // draw the velocity vector img->strokeColor("blue"); pair velocityV = currentFO.getVelocityV(); ev_x = static_cast(centroid.first) + 30.0 * velocityV.first; ev_y = static_cast(centroid.second) + 30.0 * velocityV.second; img->draw(DrawableLine( centroid.first, centroid.second, static_cast(ev_x), static_cast(ev_y) )); // draw the historical head vector img->strokeColor("white"); pair headV = currentFO.getHead(); ev_x = static_cast (centroid.first) + 25.0*headV.first; ev_y = static_cast (centroid.second) + 25.0*headV.second; img->draw( DrawableLine(centroid.first, centroid.second, static_cast (ev_x), static_cast (ev_y)) ); //draw the object tracking circle if (n == isFirst and n==0) { *output << "Tracking the n = "<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) { *output << "Tracking the "<strokeColor("yellow"); img->fillColor("none"); img->pixelColor(prev_x, prev_y, "red"); img->draw(DrawableCircle(centroid.first, centroid.second, centroid.first+5, centroid.second)); } } } } if(writeFinalImages) { img->write(outputFileName.c_str()); delete img; } delete maskImage; // TODO: Wtf is going on here? 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 > & 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 > & 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 p; p.first = x; p.second = y; obj.push_back(p); // 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 > & 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 p; p.first = x; p.second = y; obj.push_back(p); // 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 getCentroid(vector > & points) { pair centroid; centroid.first = 0; centroid.second = 0; for (unsigned int i = 0; i covariantDecomposition(vector > & points) { unsigned int i,j,k; pair centroid = getCentroid(points); vector retval; gsl_matrix* matrice = gsl_matrix_alloc(2, 2); double sumX2 = 0, sumXY = 0, sumY2 = 0; for (k = 0; ksize; i++) retval.push_back(gsl_vector_get(eigenVal, i)); for (j = 0; jsize2; j++) for (i = 0; isize1; i++) retval.push_back(gsl_matrix_get(eigenVec, i, j)); retval.push_back(static_cast(centroid.first)); retval.push_back(static_cast (centroid.second)); // for (i=0; i<2; i++) { // gsl_vector_view evec_i = gsl_matrix_column (eigenVec, i); // //printf ("eigenvalue = %g\n", eval_i); // *output<<"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; }