batch_represent.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. from __future__ import absolute_import
  4. from __future__ import division
  5. from __future__ import print_function
  6. """
  7. Allows you to generate embeddings from a directory of images in the format:
  8. Instructions:
  9. Image data directory should look like the following figure:
  10. person-1
  11. ├── image-1.jpg
  12. ├── image-2.png
  13. ...
  14. └── image-p.png
  15. ...
  16. person-m
  17. ├── image-1.png
  18. ├── image-2.jpg
  19. ...
  20. └── image-q.png
  21. Trained Model:
  22. - Both the trained model metagraph and the model parameters need to exist
  23. in the same directory, and the metagraph should have the extension '.meta'.
  24. ####
  25. USAGE:
  26. $ python batch_represent.py -d <YOUR IMAGE DATA DIRECTORY> -o <DIRECTORY TO STORE OUTPUT ARRAYS> --trained_model_dir <DIRECTORY CONTAINING PRETRAINED MODEL>
  27. ###
  28. """
  29. """
  30. Attributions:
  31. The code is heavily inspired by the code from by David Sandberg's ../src/validate_on_lfw.py
  32. The concept is inspired by Brandon Amos' github.com/cmusatyalab/openface/blob/master/batch-represent/batch-represent.lua
  33. """
  34. #----------------------------------------------------
  35. # MIT License
  36. #
  37. # Copyright (c) 2017 Rakshak Talwar
  38. #
  39. # Permission is hereby granted, free of charge, to any person obtaining a copy
  40. # of this software and associated documentation files (the "Software"), to deal
  41. # in the Software without restriction, including without limitation the rights
  42. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  43. # copies of the Software, and to permit persons to whom the Software is
  44. # furnished to do so, subject to the following conditions:
  45. #
  46. # The above copyright notice and this permission notice shall be included in all
  47. # copies or substantial portions of the Software.
  48. #
  49. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  50. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  51. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  52. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  53. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  54. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  55. # SOFTWARE.
  56. #----------------------------------------------------
  57. import os
  58. import sys
  59. import argparse
  60. import importlib
  61. import time
  62. sys.path.insert(1, "../src")
  63. import facenet
  64. import numpy as np
  65. from sklearn.datasets import load_files
  66. import tensorflow as tf
  67. from six.moves import xrange
  68. def main(args):
  69. with tf.Graph().as_default():
  70. with tf.Session() as sess:
  71. # create output directory if it doesn't exist
  72. output_dir = os.path.expanduser(args.output_dir)
  73. if not os.path.isdir(output_dir):
  74. os.makedirs(output_dir)
  75. # load the model
  76. print("Loading trained model...\n")
  77. meta_file, ckpt_file = facenet.get_model_filenames(os.path.expanduser(args.trained_model_dir))
  78. facenet.load_model(args.trained_model_dir, meta_file, ckpt_file)
  79. # grab all image paths and labels
  80. print("Finding image paths and targets...\n")
  81. data = load_files(args.data_dir, load_content=False, shuffle=False)
  82. labels_array = data['target']
  83. paths = data['filenames']
  84. # Get input and output tensors
  85. images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
  86. embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
  87. phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
  88. image_size = images_placeholder.get_shape()[1]
  89. embedding_size = embeddings.get_shape()[1]
  90. # Run forward pass to calculate embeddings
  91. print('Generating embeddings from images...\n')
  92. start_time = time.time()
  93. batch_size = args.batch_size
  94. nrof_images = len(paths)
  95. nrof_batches = int(np.ceil(1.0*nrof_images / batch_size))
  96. emb_array = np.zeros((nrof_images, embedding_size))
  97. for i in xrange(nrof_batches):
  98. start_index = i*batch_size
  99. end_index = min((i+1)*batch_size, nrof_images)
  100. paths_batch = paths[start_index:end_index]
  101. images = facenet.load_data(paths_batch, do_random_crop=False, do_random_flip=False, image_size=image_size, do_prewhiten=True)
  102. feed_dict = { images_placeholder:images, phase_train_placeholder:False}
  103. emb_array[start_index:end_index,:] = sess.run(embeddings, feed_dict=feed_dict)
  104. time_avg_forward_pass = (time.time() - start_time) / float(nrof_images)
  105. print("Forward pass took avg of %.3f[seconds/image] for %d images\n" % (time_avg_forward_pass, nrof_images))
  106. print("Finally saving embeddings and gallery to: %s" % (output_dir))
  107. # save the gallery and embeddings (signatures) as numpy arrays to disk
  108. np.save(os.path.join(output_dir, "gallery.npy"), labels_array)
  109. np.save(os.path.join(output_dir, "signatures.npy"), emb_array)
  110. def parse_arguments(argv):
  111. parser = argparse.ArgumentParser(description="Batch-represent face embeddings from a given data directory")
  112. parser.add_argument('-d', '--data_dir', type=str,
  113. help='directory of images with structure as seen at the top of this file.')
  114. parser.add_argument('-o', '--output_dir', type=str,
  115. help='directory containing aligned face patches with file structure as seen at the top of this file.')
  116. parser.add_argument('--trained_model_dir', type=str,
  117. help='Load a trained model before training starts.')
  118. parser.add_argument('--batch_size', type=int, help='Number of images to process in a batch.', default=50)
  119. return parser.parse_args(argv)
  120. if __name__ == "__main__":
  121. main(parse_arguments(sys.argv[1:]))