diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4d309c0..fb39261f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.8.3)
project(opencv_apps)
-find_package(catkin REQUIRED COMPONENTS cv_bridge dynamic_reconfigure message_generation image_transport nodelet roscpp)
+find_package(catkin REQUIRED COMPONENTS cv_bridge dynamic_reconfigure message_generation image_transport nodelet roscpp sensor_msgs)
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV VERSION: ${OpenCV_VERSION}")
@@ -32,6 +32,7 @@ generate_dynamic_reconfigure_options(
cfg/EdgeDetection.cfg cfg/HoughLines.cfg cfg/HoughCircles.cfg
cfg/FindContours.cfg cfg/ConvexHull.cfg cfg/GeneralContours.cfg cfg/ContourMoments.cfg
cfg/FaceDetection.cfg
+ cfg/FaceRecognition.cfg
cfg/GoodfeatureTrack.cfg
cfg/CornerHarris.cfg
#
@@ -63,7 +64,6 @@ add_message_files(
FlowStamped.msg
FlowArray.msg
FlowArrayStamped.msg
- RectArrayStamped.msg
Size.msg
Face.msg
FaceArray.msg
@@ -86,9 +86,15 @@ add_message_files(
ContourArrayStamped.msg
)
+add_service_files(
+ FILES
+ FaceRecognitionTrain.srv
+)
+
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
+ sensor_msgs
std_msgs
)
@@ -253,6 +259,7 @@ opencv_apps_add_nodelet(camshift camshift/camshift src/nodelet/camshift_nodelet.
# ./em.cpp
# ./example_cmake/example.cpp
opencv_apps_add_nodelet(face_detection face_detection/face_detection src/nodelet/face_detection_nodelet.cpp) # ./facedetect.cpp
+opencv_apps_add_nodelet(face_recognition face_recognition/face_recognition src/nodelet/face_recognition_nodelet.cpp)
# ./facial_features.cpp
opencv_apps_add_nodelet(fback_flow fback_flow/fback_flow src/nodelet/fback_flow_nodelet.cpp) # ./fback.cpp
# ./ffilldemo.cpp
@@ -343,7 +350,7 @@ install(TARGETS ${_opencv_apps_nodelet_targets}
install(FILES nodelet_plugins.xml
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
-install(DIRECTORY launch test
+install(DIRECTORY launch test scripts
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
USE_SOURCE_PERMISSIONS)
diff --git a/cfg/FaceRecognition.cfg b/cfg/FaceRecognition.cfg
new file mode 100755
index 00000000..bdff7139
--- /dev/null
+++ b/cfg/FaceRecognition.cfg
@@ -0,0 +1,61 @@
+#! /usr/bin/env python
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2017, Yuki Furuta.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Kei Okada nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+PACKAGE='face_recognition'
+
+from dynamic_reconfigure.parameter_generator_catkin import *
+
+gen = ParameterGenerator()
+
+methods = gen.enum([gen.const("eigen", str_t, "eigen", "eigen"),
+ gen.const("fisher", str_t, "fisher", "fisher"),
+ gen.const("LBPH", str_t, "LBPH", "LBPH")],
+ "Method to recognize faces")
+
+# variable type level description default min max
+gen.add("model_method", str_t, 0, "Method to recognize faces", "eigen", edit_method=methods)
+gen.add("use_saved_data", bool_t, 0, "Use saved data", True)
+gen.add("save_train_data", bool_t, 0, "Save train data", True)
+gen.add("data_dir", str_t, 0, "Save directory for train data", "~/.ros/opencv_apps/face_data")
+gen.add("face_model_width", int_t, 0, "Width of training face image", 190, 30, 500)
+gen.add("face_model_height", int_t, 0, "Height of training face image", 90, 30, 500)
+gen.add("face_padding", double_t, 0, "Padding ratio of each face", 0.1, 0.0, 2.0)
+gen.add("model_num_components", int_t, 0, "Number of components for face recognizer model", 0, 0, 100)
+gen.add("model_threshold", double_t, 0, "Threshold for face recognizer model", 8000.0, 0.0, 10000.0)
+gen.add("lbph_radius", int_t, 0, "Radius parameter used only for LBPH model", 1, 1, 10)
+gen.add("lbph_neighbors", int_t, 0, "Neighbors parameter used only for LBPH model", 8, 1, 30)
+gen.add("lbph_grid_x", int_t, 0, "grid_x parameter used only for LBPH model", 8, 1, 30)
+gen.add("lbph_grid_y", int_t, 0, "grid_y parameter used only for LBPH model", 8, 1, 30)
+
+exit(gen.generate(PACKAGE, "face_recognition", "FaceRecognition"))
diff --git a/launch/face_recognition.launch b/launch/face_recognition.launch
new file mode 100644
index 00000000..b7dbca80
--- /dev/null
+++ b/launch/face_recognition.launch
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/msg/Face.msg b/msg/Face.msg
index 557556b6..789e0cfe 100644
--- a/msg/Face.msg
+++ b/msg/Face.msg
@@ -1,2 +1,4 @@
Rect face
Rect[] eyes
+string label
+float64 confidence
diff --git a/nodelet_plugins.xml b/nodelet_plugins.xml
index 74a7466b..1ab76dac 100644
--- a/nodelet_plugins.xml
+++ b/nodelet_plugins.xml
@@ -43,6 +43,10 @@
Nodelet to find faces
+
+ Nodelet to identify faces
+
+
Nodelet for detecting corners using Shi-Tomasi method
diff --git a/scripts/face_recognition_trainer.py b/scripts/face_recognition_trainer.py
new file mode 100755
index 00000000..b62c5e30
--- /dev/null
+++ b/scripts/face_recognition_trainer.py
@@ -0,0 +1,97 @@
+#! /usr/bin/env python
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2017, Yuki Furuta.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Kei Okada nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+from __future__ import print_function
+
+try:
+ input = raw_input
+except:
+ pass
+
+import rospy
+import message_filters
+from sensor_msgs.msg import Image
+from opencv_apps.msg import FaceArrayStamped
+from opencv_apps.srv import FaceRecognitionTrain, FaceRecognitionTrainRequest
+
+class FaceRecognitionTrainer(object):
+ def __init__(self):
+ self.queue_size = rospy.get_param("~queue_size", 100)
+
+ self.img_sub = message_filters.Subscriber("image", Image)
+ self.face_sub = message_filters.Subscriber("faces", FaceArrayStamped)
+
+ self.req = FaceRecognitionTrainRequest()
+ self.label = ""
+ self.ok = False
+
+ self.sync = message_filters.TimeSynchronizer([self.img_sub, self.face_sub],
+ self.queue_size)
+ self.sync.registerCallback(self.callback)
+ def callback(self, img, faces):
+ if len(faces.faces) <= 0:
+ return
+ if self.ok:
+ faces.faces.sort(key=lambda f: f.face.width * f.face.height)
+ self.req.images.append(img)
+ self.req.rects.append(faces.faces[0].face)
+ self.req.labels.append(self.label)
+ self.ok = False
+ def run(self):
+ rospy.wait_for_service("train")
+ train = rospy.ServiceProxy("train", FaceRecognitionTrain)
+ self.label = input("Please input your name and press Enter: ")
+ while len(self.label) <= 0 or input("Your name is %s. Correct? [y/n]: " % self.label) not in ["", "y", "Y"]:
+ self.label = input("Please input your name and press Enter: ")
+
+ input("Please stand at the center of the camera and press Enter: ")
+ while True:
+ self.ok = True
+ while self.ok:
+ print("taking picture...")
+ rospy.sleep(1)
+ if input("One more picture? [y/n]: ") not in ["", "y", "Y"]:
+ break
+ print("sending to trainer...")
+
+ res = train(self.req)
+ if res.ok:
+ print("OK. Trained successfully!")
+ else:
+ print("NG. Error: %s" % res.error)
+
+if __name__ == '__main__':
+ rospy.init_node("face_recognition_trainer")
+ t = FaceRecognitionTrainer()
+ t.run()
diff --git a/src/nodelet/face_recognition_nodelet.cpp b/src/nodelet/face_recognition_nodelet.cpp
new file mode 100644
index 00000000..24b8051e
--- /dev/null
+++ b/src/nodelet/face_recognition_nodelet.cpp
@@ -0,0 +1,559 @@
+/*********************************************************************
+* Software License Agreement (BSD License)
+*
+* Copyright (c) 2017, Yuki Furuta.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of the Kei Okada nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include