FaceRecognizer.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. using OpenCVForUnity.CoreModule;
  2. using OpenCVForUnity.UtilsModule;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;
  6. namespace OpenCVForUnity.FaceModule
  7. {
  8. // C++: class FaceRecognizer
  9. /**
  10. * Abstract base class for all face recognition models
  11. *
  12. * All face recognition models in OpenCV are derived from the abstract base class FaceRecognizer, which
  13. * provides a unified access to all face recongition algorithms in OpenCV.
  14. *
  15. * ### Description
  16. *
  17. * I'll go a bit more into detail explaining FaceRecognizer, because it doesn't look like a powerful
  18. * interface at first sight. But: Every FaceRecognizer is an Algorithm, so you can easily get/set all
  19. * model internals (if allowed by the implementation). Algorithm is a relatively new OpenCV concept,
  20. * which is available since the 2.4 release. I suggest you take a look at its description.
  21. *
  22. * Algorithm provides the following features for all derived classes:
  23. *
  24. * <ul>
  25. * <li>
  26. * So called "virtual constructor". That is, each Algorithm derivative is registered at program
  27. * start and you can get the list of registered algorithms and create instance of a particular
  28. * algorithm by its name (see Algorithm::create). If you plan to add your own algorithms, it is
  29. * good practice to add a unique prefix to your algorithms to distinguish them from other
  30. * algorithms.
  31. * </li>
  32. * <li>
  33. * Setting/Retrieving algorithm parameters by name. If you used video capturing functionality from
  34. * OpenCV highgui module, you are probably familar with cv::cvSetCaptureProperty,
  35. * ocvcvGetCaptureProperty, VideoCapture::set and VideoCapture::get. Algorithm provides similar
  36. * method where instead of integer id's you specify the parameter names as text Strings. See
  37. * Algorithm::set and Algorithm::get for details.
  38. * </li>
  39. * <li>
  40. * Reading and writing parameters from/to XML or YAML files. Every Algorithm derivative can store
  41. * all its parameters and then read them back. There is no need to re-implement it each time.
  42. * </li>
  43. * </ul>
  44. *
  45. * Moreover every FaceRecognizer supports the:
  46. *
  47. * <ul>
  48. * <li>
  49. * <b>Training</b> of a FaceRecognizer with FaceRecognizer::train on a given set of images (your face
  50. * database!).
  51. * </li>
  52. * <li>
  53. * <b>Prediction</b> of a given sample image, that means a face. The image is given as a Mat.
  54. * </li>
  55. * <li>
  56. * <b>Loading/Saving</b> the model state from/to a given XML or YAML.
  57. * </li>
  58. * <li>
  59. * <b>Setting/Getting labels info</b>, that is stored as a string. String labels info is useful for
  60. * keeping names of the recognized people.
  61. * </li>
  62. * </ul>
  63. *
  64. * <b>Note:</b> When using the FaceRecognizer interface in combination with Python, please stick to Python 2.
  65. * Some underlying scripts like create_csv will not work in other versions, like Python 3. Setting the
  66. * Thresholds +++++++++++++++++++++++
  67. *
  68. * Sometimes you run into the situation, when you want to apply a threshold on the prediction. A common
  69. * scenario in face recognition is to tell, whether a face belongs to the training dataset or if it is
  70. * unknown. You might wonder, why there's no public API in FaceRecognizer to set the threshold for the
  71. * prediction, but rest assured: It's supported. It just means there's no generic way in an abstract
  72. * class to provide an interface for setting/getting the thresholds of *every possible* FaceRecognizer
  73. * algorithm. The appropriate place to set the thresholds is in the constructor of the specific
  74. * FaceRecognizer and since every FaceRecognizer is a Algorithm (see above), you can get/set the
  75. * thresholds at runtime!
  76. *
  77. * Here is an example of setting a threshold for the Eigenfaces method, when creating the model:
  78. *
  79. * <code>
  80. * // Let's say we want to keep 10 Eigenfaces and have a threshold value of 10.0
  81. * int num_components = 10;
  82. * double threshold = 10.0;
  83. * // Then if you want to have a cv::FaceRecognizer with a confidence threshold,
  84. * // create the concrete implementation with the appropriate parameters:
  85. * Ptr&lt;FaceRecognizer&gt; model = EigenFaceRecognizer::create(num_components, threshold);
  86. * </code>
  87. *
  88. * Sometimes it's impossible to train the model, just to experiment with threshold values. Thanks to
  89. * Algorithm it's possible to set internal model thresholds during runtime. Let's see how we would
  90. * set/get the prediction for the Eigenface model, we've created above:
  91. *
  92. * <code>
  93. * // The following line reads the threshold from the Eigenfaces model:
  94. * double current_threshold = model-&gt;getDouble("threshold");
  95. * // And this line sets the threshold to 0.0:
  96. * model-&gt;set("threshold", 0.0);
  97. * </code>
  98. *
  99. * If you've set the threshold to 0.0 as we did above, then:
  100. *
  101. * <code>
  102. * //
  103. * Mat img = imread("person1/3.jpg", IMREAD_GRAYSCALE);
  104. * // Get a prediction from the model. Note: We've set a threshold of 0.0 above,
  105. * // since the distance is almost always larger than 0.0, you'll get -1 as
  106. * // label, which indicates, this face is unknown
  107. * int predicted_label = model-&gt;predict(img);
  108. * // ...
  109. * </code>
  110. *
  111. * is going to yield -1 as predicted label, which states this face is unknown.
  112. *
  113. * ### Getting the name of a FaceRecognizer
  114. *
  115. * Since every FaceRecognizer is a Algorithm, you can use Algorithm::name to get the name of a
  116. * FaceRecognizer:
  117. *
  118. * <code>
  119. * // Create a FaceRecognizer:
  120. * Ptr&lt;FaceRecognizer&gt; model = EigenFaceRecognizer::create();
  121. * // And here's how to get its name:
  122. * String name = model-&gt;name();
  123. * </code>
  124. */
  125. public class FaceRecognizer : Algorithm
  126. {
  127. protected override void Dispose(bool disposing)
  128. {
  129. try
  130. {
  131. if (disposing)
  132. {
  133. }
  134. if (IsEnabledDispose)
  135. {
  136. if (nativeObj != IntPtr.Zero)
  137. face_FaceRecognizer_delete(nativeObj);
  138. nativeObj = IntPtr.Zero;
  139. }
  140. }
  141. finally
  142. {
  143. base.Dispose(disposing);
  144. }
  145. }
  146. protected internal FaceRecognizer(IntPtr addr) : base(addr) { }
  147. // internal usage only
  148. public static new FaceRecognizer __fromPtr__(IntPtr addr) { return new FaceRecognizer(addr); }
  149. //
  150. // C++: void cv::face::FaceRecognizer::train(vector_Mat src, Mat labels)
  151. //
  152. /**
  153. * Trains a FaceRecognizer with given data and associated labels.
  154. *
  155. * param src The training images, that means the faces you want to learn. The data has to be
  156. * given as a vector&lt;Mat&gt;.
  157. * param labels The labels corresponding to the images have to be given either as a vector&lt;int&gt;
  158. * or a Mat of type CV_32SC1.
  159. *
  160. * The following source code snippet shows you how to learn a Fisherfaces model on a given set of
  161. * images. The images are read with imread and pushed into a std::vector&lt;Mat&gt;. The labels of each
  162. * image are stored within a std::vector&lt;int&gt; (you could also use a Mat of type CV_32SC1). Think of
  163. * the label as the subject (the person) this image belongs to, so same subjects (persons) should have
  164. * the same label. For the available FaceRecognizer you don't have to pay any attention to the order of
  165. * the labels, just make sure same persons have the same label:
  166. *
  167. * <code>
  168. * // holds images and labels
  169. * vector&lt;Mat&gt; images;
  170. * vector&lt;int&gt; labels;
  171. * // using Mat of type CV_32SC1
  172. * // Mat labels(number_of_samples, 1, CV_32SC1);
  173. * // images for first person
  174. * images.push_back(imread("person0/0.jpg", IMREAD_GRAYSCALE)); labels.push_back(0);
  175. * images.push_back(imread("person0/1.jpg", IMREAD_GRAYSCALE)); labels.push_back(0);
  176. * images.push_back(imread("person0/2.jpg", IMREAD_GRAYSCALE)); labels.push_back(0);
  177. * // images for second person
  178. * images.push_back(imread("person1/0.jpg", IMREAD_GRAYSCALE)); labels.push_back(1);
  179. * images.push_back(imread("person1/1.jpg", IMREAD_GRAYSCALE)); labels.push_back(1);
  180. * images.push_back(imread("person1/2.jpg", IMREAD_GRAYSCALE)); labels.push_back(1);
  181. * </code>
  182. *
  183. * Now that you have read some images, we can create a new FaceRecognizer. In this example I'll create
  184. * a Fisherfaces model and decide to keep all of the possible Fisherfaces:
  185. *
  186. * <code>
  187. * // Create a new Fisherfaces model and retain all available Fisherfaces,
  188. * // this is the most common usage of this specific FaceRecognizer:
  189. * //
  190. * Ptr&lt;FaceRecognizer&gt; model = FisherFaceRecognizer::create();
  191. * </code>
  192. *
  193. * And finally train it on the given dataset (the face images and labels):
  194. *
  195. * <code>
  196. * // This is the common interface to train all of the available cv::FaceRecognizer
  197. * // implementations:
  198. * //
  199. * model-&gt;train(images, labels);
  200. * </code>
  201. */
  202. public void train(List<Mat> src, Mat labels)
  203. {
  204. ThrowIfDisposed();
  205. if (labels != null) labels.ThrowIfDisposed();
  206. Mat src_mat = Converters.vector_Mat_to_Mat(src);
  207. face_FaceRecognizer_train_10(nativeObj, src_mat.nativeObj, labels.nativeObj);
  208. }
  209. //
  210. // C++: void cv::face::FaceRecognizer::update(vector_Mat src, Mat labels)
  211. //
  212. /**
  213. * Updates a FaceRecognizer with given data and associated labels.
  214. *
  215. * param src The training images, that means the faces you want to learn. The data has to be given
  216. * as a vector&lt;Mat&gt;.
  217. * param labels The labels corresponding to the images have to be given either as a vector&lt;int&gt; or
  218. * a Mat of type CV_32SC1.
  219. *
  220. * This method updates a (probably trained) FaceRecognizer, but only if the algorithm supports it. The
  221. * Local Binary Patterns Histograms (LBPH) recognizer (see createLBPHFaceRecognizer) can be updated.
  222. * For the Eigenfaces and Fisherfaces method, this is algorithmically not possible and you have to
  223. * re-estimate the model with FaceRecognizer::train. In any case, a call to train empties the existing
  224. * model and learns a new model, while update does not delete any model data.
  225. *
  226. * <code>
  227. * // Create a new LBPH model (it can be updated) and use the default parameters,
  228. * // this is the most common usage of this specific FaceRecognizer:
  229. * //
  230. * Ptr&lt;FaceRecognizer&gt; model = LBPHFaceRecognizer::create();
  231. * // This is the common interface to train all of the available cv::FaceRecognizer
  232. * // implementations:
  233. * //
  234. * model-&gt;train(images, labels);
  235. * // Some containers to hold new image:
  236. * vector&lt;Mat&gt; newImages;
  237. * vector&lt;int&gt; newLabels;
  238. * // You should add some images to the containers:
  239. * //
  240. * // ...
  241. * //
  242. * // Now updating the model is as easy as calling:
  243. * model-&gt;update(newImages,newLabels);
  244. * // This will preserve the old model data and extend the existing model
  245. * // with the new features extracted from newImages!
  246. * </code>
  247. *
  248. * Calling update on an Eigenfaces model (see EigenFaceRecognizer::create), which doesn't support
  249. * updating, will throw an error similar to:
  250. *
  251. * <code>
  252. * OpenCV Error: The function/feature is not implemented (This FaceRecognizer (FaceRecognizer.Eigenfaces) does not support updating, you have to use FaceRecognizer::train to update it.) in update, file /home/philipp/git/opencv/modules/contrib/src/facerec.cpp, line 305
  253. * terminate called after throwing an instance of 'cv::Exception'
  254. * </code>
  255. *
  256. * <b>Note:</b> The FaceRecognizer does not store your training images, because this would be very
  257. * memory intense and it's not the responsibility of te FaceRecognizer to do so. The caller is
  258. * responsible for maintaining the dataset, he want to work with.
  259. */
  260. public void update(List<Mat> src, Mat labels)
  261. {
  262. ThrowIfDisposed();
  263. if (labels != null) labels.ThrowIfDisposed();
  264. Mat src_mat = Converters.vector_Mat_to_Mat(src);
  265. face_FaceRecognizer_update_10(nativeObj, src_mat.nativeObj, labels.nativeObj);
  266. }
  267. //
  268. // C++: int cv::face::FaceRecognizer::predict(Mat src)
  269. //
  270. public int predict_label(Mat src)
  271. {
  272. ThrowIfDisposed();
  273. if (src != null) src.ThrowIfDisposed();
  274. return face_FaceRecognizer_predict_1label_10(nativeObj, src.nativeObj);
  275. }
  276. //
  277. // C++: void cv::face::FaceRecognizer::predict(Mat src, int& label, double& confidence)
  278. //
  279. /**
  280. * Predicts a label and associated confidence (e.g. distance) for a given input image.
  281. *
  282. * param src Sample image to get a prediction from.
  283. * param label The predicted label for the given image.
  284. * param confidence Associated confidence (e.g. distance) for the predicted label.
  285. *
  286. * The suffix const means that prediction does not affect the internal model state, so the method can
  287. * be safely called from within different threads.
  288. *
  289. * The following example shows how to get a prediction from a trained model:
  290. *
  291. * <code>
  292. * using namespace cv;
  293. * // Do your initialization here (create the cv::FaceRecognizer model) ...
  294. * // ...
  295. * // Read in a sample image:
  296. * Mat img = imread("person1/3.jpg", IMREAD_GRAYSCALE);
  297. * // And get a prediction from the cv::FaceRecognizer:
  298. * int predicted = model-&gt;predict(img);
  299. * </code>
  300. *
  301. * Or to get a prediction and the associated confidence (e.g. distance):
  302. *
  303. * <code>
  304. * using namespace cv;
  305. * // Do your initialization here (create the cv::FaceRecognizer model) ...
  306. * // ...
  307. * Mat img = imread("person1/3.jpg", IMREAD_GRAYSCALE);
  308. * // Some variables for the predicted label and associated confidence (e.g. distance):
  309. * int predicted_label = -1;
  310. * double predicted_confidence = 0.0;
  311. * // Get the prediction and associated confidence from the model
  312. * model-&gt;predict(img, predicted_label, predicted_confidence);
  313. * </code>
  314. */
  315. public void predict(Mat src, int[] label, double[] confidence)
  316. {
  317. ThrowIfDisposed();
  318. if (src != null) src.ThrowIfDisposed();
  319. double[] label_out = new double[1];
  320. double[] confidence_out = new double[1];
  321. face_FaceRecognizer_predict_10(nativeObj, src.nativeObj, label_out, confidence_out);
  322. if (label != null) label[0] = (int)label_out[0];
  323. if (confidence != null) confidence[0] = (double)confidence_out[0];
  324. }
  325. //
  326. // C++: void cv::face::FaceRecognizer::predict(Mat src, Ptr_PredictCollector collector)
  327. //
  328. /**
  329. * <ul>
  330. * <li>
  331. * if implemented - send all result of prediction to collector that can be used for somehow custom result handling
  332. * </li>
  333. * </ul>
  334. * param src Sample image to get a prediction from.
  335. * param collector User-defined collector object that accepts all results
  336. *
  337. * To implement this method u just have to do same internal cycle as in predict(InputArray src, CV_OUT int &amp;label, CV_OUT double &amp;confidence) but
  338. * not try to get "best result, just resend it to caller side with given collector
  339. */
  340. public void predict_collect(Mat src, PredictCollector collector)
  341. {
  342. ThrowIfDisposed();
  343. if (src != null) src.ThrowIfDisposed();
  344. if (collector != null) collector.ThrowIfDisposed();
  345. face_FaceRecognizer_predict_1collect_10(nativeObj, src.nativeObj, collector.getNativeObjAddr());
  346. }
  347. //
  348. // C++: void cv::face::FaceRecognizer::write(String filename)
  349. //
  350. /**
  351. * Saves a FaceRecognizer and its model state.
  352. *
  353. * Saves this model to a given filename, either as XML or YAML.
  354. * param filename The filename to store this FaceRecognizer to (either XML/YAML).
  355. *
  356. * Every FaceRecognizer overwrites FaceRecognizer::save(FileStorage&amp; fs) to save the internal model
  357. * state. FaceRecognizer::save(const String&amp; filename) saves the state of a model to the given
  358. * filename.
  359. *
  360. * The suffix const means that prediction does not affect the internal model state, so the method can
  361. * be safely called from within different threads.
  362. */
  363. public void write(string filename)
  364. {
  365. ThrowIfDisposed();
  366. face_FaceRecognizer_write_10(nativeObj, filename);
  367. }
  368. //
  369. // C++: void cv::face::FaceRecognizer::read(String filename)
  370. //
  371. /**
  372. * Loads a FaceRecognizer and its model state.
  373. *
  374. * Loads a persisted model and state from a given XML or YAML file . Every FaceRecognizer has to
  375. * overwrite FaceRecognizer::load(FileStorage&amp; fs) to enable loading the model state.
  376. * FaceRecognizer::load(FileStorage&amp; fs) in turn gets called by
  377. * FaceRecognizer::load(const String&amp; filename), to ease saving a model.
  378. * param filename automatically generated
  379. */
  380. public void read(string filename)
  381. {
  382. ThrowIfDisposed();
  383. face_FaceRecognizer_read_10(nativeObj, filename);
  384. }
  385. //
  386. // C++: void cv::face::FaceRecognizer::setLabelInfo(int label, String strInfo)
  387. //
  388. /**
  389. * Sets string info for the specified model's label.
  390. *
  391. * The string info is replaced by the provided value if it was set before for the specified label.
  392. * param label automatically generated
  393. * param strInfo automatically generated
  394. */
  395. public void setLabelInfo(int label, string strInfo)
  396. {
  397. ThrowIfDisposed();
  398. face_FaceRecognizer_setLabelInfo_10(nativeObj, label, strInfo);
  399. }
  400. //
  401. // C++: String cv::face::FaceRecognizer::getLabelInfo(int label)
  402. //
  403. /**
  404. * Gets string information by label.
  405. *
  406. * If an unknown label id is provided or there is no label information associated with the specified
  407. * label id the method returns an empty string.
  408. * param label automatically generated
  409. * return automatically generated
  410. */
  411. public string getLabelInfo(int label)
  412. {
  413. ThrowIfDisposed();
  414. string retVal = Marshal.PtrToStringAnsi(DisposableObject.ThrowIfNullIntPtr(face_FaceRecognizer_getLabelInfo_10(nativeObj, label)));
  415. return retVal;
  416. }
  417. //
  418. // C++: vector_int cv::face::FaceRecognizer::getLabelsByString(String str)
  419. //
  420. /**
  421. * Gets vector of labels by string.
  422. *
  423. * The function searches for the labels containing the specified sub-string in the associated string
  424. * info.
  425. * param str automatically generated
  426. * return automatically generated
  427. */
  428. public MatOfInt getLabelsByString(string str)
  429. {
  430. ThrowIfDisposed();
  431. return MatOfInt.fromNativeAddr(DisposableObject.ThrowIfNullIntPtr(face_FaceRecognizer_getLabelsByString_10(nativeObj, str)));
  432. }
  433. #if (UNITY_IOS || UNITY_WEBGL) && !UNITY_EDITOR
  434. const string LIBNAME = "__Internal";
  435. #else
  436. const string LIBNAME = "opencvforunity";
  437. #endif
  438. // C++: void cv::face::FaceRecognizer::train(vector_Mat src, Mat labels)
  439. [DllImport(LIBNAME)]
  440. private static extern void face_FaceRecognizer_train_10(IntPtr nativeObj, IntPtr src_mat_nativeObj, IntPtr labels_nativeObj);
  441. // C++: void cv::face::FaceRecognizer::update(vector_Mat src, Mat labels)
  442. [DllImport(LIBNAME)]
  443. private static extern void face_FaceRecognizer_update_10(IntPtr nativeObj, IntPtr src_mat_nativeObj, IntPtr labels_nativeObj);
  444. // C++: int cv::face::FaceRecognizer::predict(Mat src)
  445. [DllImport(LIBNAME)]
  446. private static extern int face_FaceRecognizer_predict_1label_10(IntPtr nativeObj, IntPtr src_nativeObj);
  447. // C++: void cv::face::FaceRecognizer::predict(Mat src, int& label, double& confidence)
  448. [DllImport(LIBNAME)]
  449. private static extern void face_FaceRecognizer_predict_10(IntPtr nativeObj, IntPtr src_nativeObj, double[] label_out, double[] confidence_out);
  450. // C++: void cv::face::FaceRecognizer::predict(Mat src, Ptr_PredictCollector collector)
  451. [DllImport(LIBNAME)]
  452. private static extern void face_FaceRecognizer_predict_1collect_10(IntPtr nativeObj, IntPtr src_nativeObj, IntPtr collector_nativeObj);
  453. // C++: void cv::face::FaceRecognizer::write(String filename)
  454. [DllImport(LIBNAME)]
  455. private static extern void face_FaceRecognizer_write_10(IntPtr nativeObj, string filename);
  456. // C++: void cv::face::FaceRecognizer::read(String filename)
  457. [DllImport(LIBNAME)]
  458. private static extern void face_FaceRecognizer_read_10(IntPtr nativeObj, string filename);
  459. // C++: void cv::face::FaceRecognizer::setLabelInfo(int label, String strInfo)
  460. [DllImport(LIBNAME)]
  461. private static extern void face_FaceRecognizer_setLabelInfo_10(IntPtr nativeObj, int label, string strInfo);
  462. // C++: String cv::face::FaceRecognizer::getLabelInfo(int label)
  463. [DllImport(LIBNAME)]
  464. private static extern IntPtr face_FaceRecognizer_getLabelInfo_10(IntPtr nativeObj, int label);
  465. // C++: vector_int cv::face::FaceRecognizer::getLabelsByString(String str)
  466. [DllImport(LIBNAME)]
  467. private static extern IntPtr face_FaceRecognizer_getLabelsByString_10(IntPtr nativeObj, string str);
  468. // native support for java finalize()
  469. [DllImport(LIBNAME)]
  470. private static extern void face_FaceRecognizer_delete(IntPtr nativeObj);
  471. }
  472. }