Now that we have all our GUI elements drawn, we need to process mouse events. When we initialized the display window, we told OpenCV that we want a mouse event callback to our onMouse function.
We don't care about mouse movement, only the mouse clicks, so first we skip the mouse events that aren't for the left mouse button click as follows:
void onMouse(int event, int x, int y, int, void*)
{
if (event != CV_EVENT_LBUTTONDOWN)
return;
Point pt = Point(x,y);
... (handle mouse clicks)
...
}
As we obtained the drawn rectangle bounds of the buttons when drawing them, we just check whether the mouse click location is in any of our button regions by calling OpenCV's inside() function. Now, we can check for each button we have created.
When the user clicks on the Add Person button, we add one to the m_numPersons variable, allocate more space in the m_latestFaces variable, select the new person for the collection, and begin the Collection mode (no matter which mode we were previously in).
But there is one complication: to ensure that we have at least one face for each person when training, we will only allocate space for a new person if there isn't already a person with zero faces. This will ensure that we can always check the value of m_latestFaces[m_numPersons-1] to see if a face has been collected for every person. This is done as follows:
if (pt.inside(m_btnAddPerson)) {
// Ensure there isn't a person without collected faces.
if ((m_numPersons==0) ||
(m_latestFaces[m_numPersons-1] >= 0)) {
// Add a new person.
m_numPersons++;
m_latestFaces.push_back(-1);
}
m_selectedPerson = m_numPersons - 1;
m_mode = MODE_COLLECT_FACES;
}
This method can be used to test for other button clicks, such as toggling the debug flag as follows:
else if (pt.inside(m_btnDebug)) {
m_debug = !m_debug;
}
To handle the Delete All button, we need to empty various data structures that are local to our main loop (that is, not accessible from the mouse event callback function), so we change to the Delete All mode and then we can delete everything from inside the main loop. We must also deal with the user clicking the main window (that is, not a button). If they clicked on one of the people on the right-hand side, then we want to select that person and change to the Collection mode. Or, if they clicked in the main window while in the Collection mode, then we want to change to the Training mode. This is done as follows:
else {
// Check if the user clicked on a face from the list.
int clickedPerson = -1;
for (int i=0; i<m_numPersons; i++) {
if (m_gui_faces_top >= 0) {
Rect rcFace = Rect(m_gui_faces_left,
m_gui_faces_top + i * faceHeight, faceWidth, faceHeight);
if (pt.inside(rcFace)) {
clickedPerson = i;
break;
}
}
}
// Change the selected person, if the user clicked a face.
if (clickedPerson >= 0) {
// Change the current person & collect more photos.
m_selectedPerson = clickedPerson;
m_mode = MODE_COLLECT_FACES;
}
// Otherwise they clicked in the center.
else {
// Change to training mode if it was collecting faces.
if (m_mode == MODE_COLLECT_FACES) {
m_mode = MODE_TRAINING;
}
}
}