Updates to ellipse filter + get pupil distance

This commit is contained in:
Jason 2018-08-29 13:57:09 +09:00 committed by GitHub
parent 51b0b7b3a8
commit ac1b916b57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -34,6 +34,11 @@ public:
threshDebug = threshDebug0; threshDebug = threshDebug0;
}; };
double getInterpupillaryDifference(double left[], double right[]) {
return sqrt(pow(left[0] - right[0], 2) + pow(left[1] - right[1], 2) + pow(left[2] - right[2], 2));
}
/** /**
Fits an ellipse to a pupil area in an image Fits an ellipse to a pupil area in an image
@param gray BGR input image (converted to grayscale during search process) @param gray BGR input image (converted to grayscale during search process)
@ -304,6 +309,28 @@ bool pupilAreaFitRR(Mat &gray, RotatedRect &rr, vector<Point2f> &allPtsReturn,
return true; return true;
} }
bool badEllipseFilter(RotatedRect current, int maxSize) {
bool isGood = true;
//test against last ttwo ellipse sizes and rotations,
//if difference is over a certain size and angle threshold, set isGood to false
if (current.size.width / current.size.height > 4 ||
current.size.height / current.size.width > 4 ||
current.size.height > maxSize ||
current.size.width > maxSize ||
current.size.height < 25 ||
current.size.width < 25 ||
current.size.width > maxSize ||
current.size.height > maxSize ||
current.size.height + current.size.width > 400) {
isGood = false;
}
previousRect = current;
return isGood;
}
private: private:
//global variables //global variables
@ -393,148 +420,148 @@ int getDarkestPixel(Mat& I)
return min; return min;
} }
/** ///**
Finds a square area of dark pixels in the image //Finds a square area of dark pixels in the image
@param I input image (converted to grayscale during search process) //@param I input image (converted to grayscale during search process)
@param I2 copy of input image onto which green block of pixels is drawn (BGR), null ok //@param I2 copy of input image onto which green block of pixels is drawn (BGR), null ok
@return a point within the pupil region //@return a point within the pupil region
*/ //*/
Point getDarkestPixelArea(Mat& I, Mat& I2) //Point getDarkestPixelArea(Mat& I, Mat& I2)
{ //{
cv::cvtColor(I, I, CV_BGR2GRAY); // cv::cvtColor(I, I, CV_BGR2GRAY);
//
// accept only char type matrices // // accept only char type matrices
CV_Assert(I.depth() == CV_8U); // CV_Assert(I.depth() == CV_8U);
//
Point ROI; // Point ROI;
//
int channels = I.channels(); // int channels = I.channels();
//
//for searching image // //for searching image
int sArea = 20; //bound of outer search in any direction // int sArea = 20; //bound of outer search in any direction
int outerSearchDivisor = 4; //sets spacing of outer search, equal to sArea*2/outerSearchDivisor // int outerSearchDivisor = 4; //sets spacing of outer search, equal to sArea*2/outerSearchDivisor
//
//darkness calculation // //darkness calculation
int width = 10; //width of darkness search area // int width = 10; //width of darkness search area
int searchDivisor = 2; // int searchDivisor = 2;
//
//stdev calculation // //stdev calculation
int widthSmall = width; // int widthSmall = width;
int searchDivisorDev = widthSmall / 5; // int searchDivisorDev = widthSmall / 5;
//
int min = 255; // int min = 255;
int areaMin = 255 * (9 * searchDivisor*searchDivisor); // int areaMin = 255 * (9 * searchDivisor*searchDivisor);
float stDevMin = 1000; // float stDevMin = 1000;
//
int count = 0; // int count = 0;
//
bool draw = true; // bool draw = true;
int finalColorCount = 0; // int finalColorCount = 0;
//
for (int i = sArea * width / sArea + pupilSearchYMin; i < I.rows - sArea* width / sArea; i = i + sArea / outerSearchDivisor){ // for (int i = sArea * width / sArea + pupilSearchYMin; i < I.rows - sArea* width / sArea; i = i + sArea / outerSearchDivisor){
for (int j = sArea* width / sArea + pupilSearchXMin; j < I.cols - sArea* width / sArea; j = j + sArea / outerSearchDivisor){ // for (int j = sArea* width / sArea + pupilSearchXMin; j < I.cols - sArea* width / sArea; j = j + sArea / outerSearchDivisor){
//
int tempSum = 0; //holds current sum of pixel intensities // int tempSum = 0; //holds current sum of pixel intensities
float tempStDev = 1000; // float tempStDev = 1000;
//
int colorCount = 0; //counts the number of pixels summed // int colorCount = 0; //counts the number of pixels summed
//
//darkness testing for single square // //darkness testing for single square
for (int d = -width; d < width + 1; d = d + width / searchDivisor){ // for (int d = -width; d < width + 1; d = d + width / searchDivisor){
for (int c = -width; c < width + 1; c = c + width / searchDivisor){ // for (int c = -width; c < width + 1; c = c + width / searchDivisor){
//
if (d == -width&&c == -width || d == width&&c == -width || d == -width&&c == width || d == width&&c == width){ // if (d == -width&&c == -width || d == width&&c == -width || d == -width&&c == width || d == width&&c == width){
//no comparison at corners // //no comparison at corners
} // }
else{ // else{
tempSum += I.at<uchar>(i + d, j + c); // tempSum += I.at<uchar>(i + d, j + c);
} // }
//
//for efficiency, exit if darkness > current // //for efficiency, exit if darkness > current
if (tempSum > areaMin){ // if (tempSum > areaMin){
c = 10000; // c = 10000;
d = 10000; // d = 10000;
} // }
//
colorCount++; // colorCount++;
} // }
}//end darkness calculation // }//end darkness calculation
//
//color with darkness level (heatmap) // //color with darkness level (heatmap)
//if ((255 * colorCount - tempSum) / colorCount > 220){ // //if ((255 * colorCount - tempSum) / colorCount > 220){
// I2.at<Vec3b>(i, j)[0] = 0; // // I2.at<Vec3b>(i, j)[0] = 0;
// I2.at<Vec3b>(i, j)[1] = 0; // // I2.at<Vec3b>(i, j)[1] = 0;
// I2.at<Vec3b>(i, j)[2] = (255 * colorCount - tempSum) / colorCount; // // I2.at<Vec3b>(i, j)[2] = (255 * colorCount - tempSum) / colorCount;
//} // //}
//
//is darker than last calculated area? // //is darker than last calculated area?
if (tempSum < areaMin){ // if (tempSum < areaMin){
//
//progress to stdev calculation if area was darker // //progress to stdev calculation if area was darker
//float stDev = 0; // //float stDev = 0;
//vector<float> data; // //vector<float> data;
//
//for (int d2 = -widthSmall; d2 < widthSmall + 1; d2 = d2 + widthSmall / searchDivisorDev){ // //for (int d2 = -widthSmall; d2 < widthSmall + 1; d2 = d2 + widthSmall / searchDivisorDev){
// for (int c2 = -widthSmall; c2 < widthSmall + 1; c2 = c2 + widthSmall / searchDivisorDev){ // // for (int c2 = -widthSmall; c2 < widthSmall + 1; c2 = c2 + widthSmall / searchDivisorDev){
// data.push_back(I.at<uchar>(i + d2, j + c2)); // // data.push_back(I.at<uchar>(i + d2, j + c2));
// //I2.at<Vec3b>(i, j)[0] = 0; // // //I2.at<Vec3b>(i, j)[0] = 0;
// //I2.at<Vec3b>(i, j)[1] = 0; // // //I2.at<Vec3b>(i, j)[1] = 0;
// //I2.at<Vec3b>(i, j)[2] = 255; // // //I2.at<Vec3b>(i, j)[2] = 255;
// } // // }
//} // //}
//tempStDev = standard_deviation(&data[0], data.size()); // //tempStDev = standard_deviation(&data[0], data.size());
//
//in our videos, pupils don't exceed y>160 or x>530, remove for videos where pupil could be anywhere on the screen // //in our videos, pupils don't exceed y>160 or x>530, remove for videos where pupil could be anywhere on the screen
if (i > 50 && j < 530){ // if (i > 50 && j < 530){
//
ROI = Point(j, i); // ROI = Point(j, i);
//cout << "tempsum = " << tempSum << " @ " << j << ", " << i << endl; // //cout << "tempsum = " << tempSum << " @ " << j << ", " << i << endl;
areaMin = tempSum; // areaMin = tempSum;
count++; // count++;
//
finalColorCount = colorCount; // finalColorCount = colorCount;
//
//color points that are progressively darker // //color points that are progressively darker
//I2.at<Vec3b>(ROI)[0] = 0; // //I2.at<Vec3b>(ROI)[0] = 0;
//I2.at<Vec3b>(ROI)[1] = 0; // //I2.at<Vec3b>(ROI)[1] = 0;
//I2.at<Vec3b>(ROI)[2] = 255; // //I2.at<Vec3b>(ROI)[2] = 255;
} // }
//
stDevMin = tempStDev; // stDevMin = tempStDev;
} // }
//
}//end outerX for // }//end outerX for
}//end outerY for // }//end outerY for
//
//std::cout << "min avg pixel value was " << areaMin / finalColorCount; // //std::cout << "min avg pixel value was " << areaMin / finalColorCount;
//
//float stDev = 0; // //float stDev = 0;
//vector<float> data; // //vector<float> data;
//
//double test = stDevMin; // //double test = stDevMin;
//cout.precision(5); // //cout.precision(5);
//cout << "stdev: " << fixed << test << " darkness: " << areaMin << endl; // //cout << "stdev: " << fixed << test << " darkness: " << areaMin << endl;
//
//only draw if image was passed to I2 // //only draw if image was passed to I2
if (&I2 != nullptr){ // if (&I2 != nullptr){
//draw pupil marker // //draw pupil marker
for (int d2 = -widthSmall; d2 < widthSmall + 1; d2 = d2 + widthSmall / searchDivisorDev / 2){ // for (int d2 = -widthSmall; d2 < widthSmall + 1; d2 = d2 + widthSmall / searchDivisorDev / 2){
for (int c2 = -widthSmall; c2 < widthSmall + 1; c2 = c2 + widthSmall / searchDivisorDev / 2){ // for (int c2 = -widthSmall; c2 < widthSmall + 1; c2 = c2 + widthSmall / searchDivisorDev / 2){
//
if (d2 == -width&&c2 == -width || d2 == width&&c2 == -width || d2 == -width&&c2 == width || d2 == width&&c2 == width){ // if (d2 == -width&&c2 == -width || d2 == width&&c2 == -width || d2 == -width&&c2 == width || d2 == width&&c2 == width){
//do nothing // //do nothing
} // }
else if (areaMin / finalColorCount < 80 && areaMin / finalColorCount > 0){ // else if (areaMin / finalColorCount < 80 && areaMin / finalColorCount > 0){
I2.at<Vec3b>(ROI.y + c2, ROI.x + d2)[0] = 15; // I2.at<Vec3b>(ROI.y + c2, ROI.x + d2)[0] = 15;
I2.at<Vec3b>(ROI.y + c2, ROI.x + d2)[1] = 255; // I2.at<Vec3b>(ROI.y + c2, ROI.x + d2)[1] = 255;
I2.at<Vec3b>(ROI.y + c2, ROI.x + d2)[2] = 15; // I2.at<Vec3b>(ROI.y + c2, ROI.x + d2)[2] = 15;
} // }
} // }
} // }
} // }
//
return ROI; // return ROI;
} //}
/** /**
Finds the approximate darkest pixels (an average of many), used on ROI images generated by getDarkestPixel area Finds the approximate darkest pixels (an average of many), used on ROI images generated by getDarkestPixel area
@ -596,7 +623,6 @@ int getDarkestPixelBetter(Mat& I)
/** /**
Finds a square area of dark pixels in the image Finds a square area of dark pixels in the image
@param I input image (converted to grayscale during search process) @param I input image (converted to grayscale during search process)
@param I2 copy of input image onto which green block of pixels is drawn (BGR), null ok
@return a point within the pupil region @return a point within the pupil region
*/ */
Point getDarkestPixelArea(Mat& I) Point getDarkestPixelArea(Mat& I)
@ -609,6 +635,8 @@ Point getDarkestPixelArea(Mat& I)
// accept only char type matrices // accept only char type matrices
CV_Assert(I.depth() == CV_8U); CV_Assert(I.depth() == CV_8U);
//Mat I2 = I.clone();
Point ROI; Point ROI;
int channels = I.channels(); int channels = I.channels();
@ -630,96 +658,65 @@ Point getDarkestPixelArea(Mat& I)
float stDevMin = 1000; float stDevMin = 1000;
int count = 0; int count = 0;
bool draw = true;
int finalColorCount = 0; int finalColorCount = 0;
int ignoreCornerDepth = 150; //number of pixels to ignore away from corners
for (int i = sArea * width / sArea + pupilSearchYMin; i < I.rows - sArea* width / sArea; i = i + sArea / outerSearchDivisor){ //for (int i = sArea * width / sArea ; i < I.rows - sArea * width / sArea; i = i + sArea / outerSearchDivisor) {
for (int j = sArea* width / sArea + pupilSearchXMin; j < I.cols - sArea* width / sArea; j = j + sArea / outerSearchDivisor){ // for (int j = sArea * width / sArea ; j < I.cols - sArea * width / sArea; j = j + sArea / outerSearchDivisor) {
for (int i = width; i < I.rows - width; i = i + sArea / outerSearchDivisor) {
for (int j = width; j < I.cols - width; j = j + sArea / outerSearchDivisor) {
if (i + j > ignoreCornerDepth && //top left corner
i + I.cols - j > ignoreCornerDepth && //bottom left corner
I.rows - i + j > ignoreCornerDepth && //top right corner
I.rows - i + I.cols - j > ignoreCornerDepth)
{ //bottom right corner
int tempSum = 0; //holds current sum of pixel intensities int tempSum = 0; //holds current sum of pixel intensities
float tempStDev = 1000; float tempStDev = 1000;
int colorCount = 0; //counts the number of pixels summed int colorCount = 0; //counts the number of pixels summed
//darkness testing for single square //darkness testing for single square
for (int d = -width; d < width + 1; d = d + width / searchDivisor){ for (int d = -width; d < width + 1; d = d + width / searchDivisor) {
for (int c = -width; c < width + 1; c = c + width / searchDivisor){ for (int c = -width; c < width + 1; c = c + width / searchDivisor) {
if (d == -width&&c == -width || d == width&&c == -width || d == -width&&c == width || d == width&&c == width){ if (d == -width && c == -width || d == width && c == -width || d == -width && c == width || d == width && c == width) {
//no comparison at corners //no comparison at corners
} }
else{ else {
tempSum += I.at<uchar>(i + d, j + c); tempSum += I.at<uchar>(i + d, j + c);
}
//for efficiency, exit if darkness > current
if (tempSum > areaMin) {
c = 10000;
d = 10000;
}
colorCount++;
}
}//end darkness calculation
//is darker than last calculated area?
if (tempSum < areaMin) {
ROI = Point(j, i);
//cout << "tempsum = " << tempSum << " @ " << j << ", " << i << endl;
areaMin = tempSum;
count++;
finalColorCount = colorCount;
stDevMin = tempStDev;
} }
//for efficiency, exit if darkness > current //color a point
if (tempSum > areaMin){ //I2.at<uchar>(i, j) = 255;
c = 10000;
d = 10000;
}
colorCount++; }//end ignore corners code
} }//end outerX for
}//end darkness calculation }//end outerY for
//color with darkness level (heatmap)
//if ((255 * colorCount - tempSum) / colorCount > 220){
// I2.at<Vec3b>(i, j)[0] = 0;
// I2.at<Vec3b>(i, j)[1] = 0;
// I2.at<Vec3b>(i, j)[2] = (255 * colorCount - tempSum) / colorCount;
//}
//is darker than last calculated area?
if (tempSum < areaMin){
//progress to stdev calculation if area was darker
//float stDev = 0;
//vector<float> data;
//for (int d2 = -widthSmall; d2 < widthSmall + 1; d2 = d2 + widthSmall / searchDivisorDev){
// for (int c2 = -widthSmall; c2 < widthSmall + 1; c2 = c2 + widthSmall / searchDivisorDev){
// data.push_back(I.at<uchar>(i + d2, j + c2));
// //I2.at<Vec3b>(i, j)[0] = 0;
// //I2.at<Vec3b>(i, j)[1] = 0;
// //I2.at<Vec3b>(i, j)[2] = 255;
// }
//}
//tempStDev = standard_deviation(&data[0], data.size());
//in our videos, pupils don't exceed y>160 or x>530, remove for videos where pupil could be anywhere on the screen
if (i > 60 && j < 530){
ROI = Point(j, i);
//cout << "tempsum = " << tempSum << " @ " << j << ", " << i << endl;
areaMin = tempSum;
count++;
finalColorCount = colorCount;
//color points that are progressively darker
//I2.at<Vec3b>(ROI)[0] = 0;
//I2.at<Vec3b>(ROI)[1] = 0;
//I2.at<Vec3b>(ROI)[2] = 255;
}
stDevMin = tempStDev;
}
}//end outerX for
}//end outerY for
//std::cout << "min avg pixel value was " << areaMin / finalColorCount;
//float stDev = 0;
//vector<float> data;
//double test = stDevMin;
//cout.precision(5);
//cout << "stdev: " << fixed << test << " darkness: " << areaMin << endl;
//cv::cvtColor(I, I, CV_GRAY2BGR);
//imshow("debug", I2);
return ROI; return ROI;
} }
@ -907,7 +904,7 @@ vector<Point> getCandidates(std::vector<std::vector<cv::Point>>contours, int big
} }
} }
else{ else{
cout << "contours.size was < 10. size = " << contours.size() << endl; //cout << "contours.size was < 10. size = " << contours.size() << endl;
} }
return allPts; return allPts;
@ -1006,32 +1003,6 @@ vector<Point> refinePoints(vector<Point> allPts, Mat gray, int checkThickness, i
}//end point refinement }//end point refinement
bool badEllipseFilter(RotatedRect current, int maxSize){
bool isGood = true;
//test against last ttwo ellipse sizes and rotations,
//if difference is over a certain size and angle threshold, set isGood to false
if (current.size.width / current.size.height > 2 ||
current.size.height / current.size.width > 2 ||
current.size.height > maxSize ||
current.size.width > maxSize ||
current.size.height < 10 ||
current.size.width < 10 ||
current.size.width > maxSize ||
current.size.height > maxSize ||
//current.center.y < 40 ||
current.size.height / previousRect.size.height > 1.3 ||
previousRect.size.height / current.size.height > 1.3 ||
current.size.width / previousRect.size.width > 1.3 ||
previousRect.size.width / current.size.width > 1.3){
cout << "returning false" << endl;
isGood = false;
}
previousRect = current;
return isGood;
}
}; };