-
Notifications
You must be signed in to change notification settings - Fork 1
/
eye.cpp
175 lines (171 loc) · 5.53 KB
/
eye.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include <iostream>
using namespace cv;
using namespace std;
//eyeball radius range
#define MINRAD 10
#define MAXRAD 25
//dark pixel value threshold
#define DARKPIXELVALUE 10
//voting result threshold
#define RESULTTHRESHOLD 3.0
Point eyepoint_detect
(
Mat& imeye,
bool& is_locate_correct
)
{
Mat blurim;
//blur noise
GaussianBlur(imeye, blurim, Size(9,9), 0);
//calc gradient, curvature
float kernel[3] = {-0.5f, 0.0f, 0.5f};
Mat filterX(1, 3, CV_32F, kernel);
Mat filterY(3, 1, CV_32F, kernel);
Mat Lx, Ly;
filter2D(blurim, Lx, CV_32F, filterX, Point (-1, -1), 0, BORDER_REPLICATE);
filter2D(blurim, Ly, CV_32F, filterY, Point (-1, -1), 0, BORDER_REPLICATE);
Mat Lxx, Lxy, Lyy, Lyx;
filter2D(Lx, Lxx, CV_32F, filterX, Point (-1, -1), 0, BORDER_REPLICATE);
filter2D(Lx, Lxy, CV_32F, filterY, Point (-1, -1), 0, BORDER_REPLICATE);
filter2D(Ly, Lyx, CV_32F, filterX, Point (-1, -1), 0, BORDER_REPLICATE);
filter2D(Ly, Lyy, CV_32F, filterY, Point (-1, -1), 0, BORDER_REPLICATE);
Mat Lx2, Ly2;
pow(Ly, 2, Ly2);
pow(Lx, 2, Lx2);
Mat Lvv = Ly2.mul(Lxx) - 2 * Lx.mul(Lxy).mul(Ly) + Lx2.mul(Lyy);
Mat Lw = Lx2 + Ly2;
Mat Lw15;
pow(Lw, 1.5, Lw15);
Mat k;
divide(-Lvv, Lw15, k);
Mat LwoverLvv;
divide(Lw, Lvv, LwoverLvv);
//calc displacement
Mat Dx, Dy;
Dx = -Lx.mul(LwoverLvv);
Dy = -Ly.mul(LwoverLvv);
Mat Dx2, Dy2, magnitude_displacement;
pow(Dx, 2, Dx2);
pow(Dy, 2, Dy2);
cv::sqrt(Dx2+Dy2, magnitude_displacement);
//calc curvedness as voting weight
Mat Lxx2, Lxy2, Lyy2, curvednesstemp, curvedness;
pow(Lxx, 2, Lxx2);
pow(Lxy, 2, Lxy2);
pow(Lyy, 2, Lyy2);
cv::sqrt(Lxx2 + 2 * Lxy2 + Lyy2 , curvednesstemp);
curvedness = cv::abs(curvednesstemp);
//voting
const int srcheight = blurim.rows;
const int srcwidth = blurim.cols;
Mat center_map(srcheight, srcwidth, CV_32F, 0.0f);
for(int y = 0; y < srcheight; y++)
{
for(int x = 0; x < srcwidth; x++)
{
if(Dx.at<float>(y, x) == 0.0f && Dy.at<float>(y, x) == 0.0f)
{
continue;
}
int dstx = x + (int)Dx.at<float>(y, x);
int dsty = y + (int)Dy.at<float>(y, x);
int radius = (int)magnitude_displacement.at<float>(y, x);
if(dstx > 0 && dsty > 0 && dstx < srcwidth && dsty < srcheight)
{
//consider gradients from white to black only
if(k.at<float>(y, x) < 0)
{
//limit eyeball radius
if(radius >= MINRAD && radius <= MAXRAD)
{
//consider eyeball contour only
if(imeye.at<float>(y, x) < DARKPIXELVALUE)
{
center_map.at<float>(dsty, dstx) += curvedness.at<float>(y, x);
}
}
}
}
}
}
//smooth the result
Mat gauss_blured_center_map(srcheight, srcwidth, CV_32F, 0.0f);
GaussianBlur(center_map, gauss_blured_center_map, Size(5,5), 0);
//get location
double maxv = 0, minv = 0;
Point minlocation, maxlocation;
minMaxLoc(gauss_blured_center_map, &minv, &maxv, &minlocation, &maxlocation);
if(maxv > RESULTTHRESHOLD)
{
is_locate_correct = true;
}
else
{
is_locate_correct = false;
}
return maxlocation;
}
int main
(
void
)
{
Mat im;
Mat gray;
Mat eqgray;
VideoCapture cap;
cap.open(0);
if(!cap.isOpened())
{
cout << "Failed to open cam" << endl;
exit(EXIT_FAILURE);
}
vector<Rect> face_results;
CascadeClassifier opencv_faceclassifier;
opencv_faceclassifier.load("haarcascade_frontalface_alt2.xml");
//main loop
while(1)
{
cap >> im;
cvtColor(im, gray, CV_BGR2GRAY);
equalizeHist(gray, eqgray);
opencv_faceclassifier.detectMultiScale(eqgray, face_results, 1.2, 2, CV_HAAR_FIND_BIGGEST_OBJECT, Size(100, 100));
if(face_results.size() > 0)
{
//pick the biggest face
Rect face = face_results[0];
int dist1 = face.width >> 3;
int dist2 = face.width >> 2;
//set eye regions
Rect lefteyeroi = Rect(face.x + dist1, face.y + dist2, dist1 + dist2, dist2);
Rect righteyeroi = Rect(face.x + 2 * dist1 + dist2, face.y + dist2, dist1 + dist2, dist2);
Mat lefteyeim = eqgray(lefteyeroi);
Mat righteyeim = eqgray(righteyeroi);
bool leftfound = false;
bool rightfound = false;
//detect
Point lefteyepos = eyepoint_detect(lefteyeim, leftfound);
Point righteyepos = eyepoint_detect(righteyeim, rightfound);
//draw result
if(leftfound)
{
circle(im, lefteyepos + lefteyeroi.tl(), 4, Scalar(0, 255, 0), -1);
}
if(rightfound)
{
circle(im, righteyepos + righteyeroi.tl(), 4, Scalar(0, 255, 0), -1);
}
}
imshow("eye", im);
//press esc to end
if(waitKey(10) == 27)
{
break;
}
}
return 0;
}