From 88ec48e1c4d93ba9cd3aa186c068ef2aa4c27c56 Mon Sep 17 00:00:00 2001 From: adamhrv Date: Mon, 17 Dec 2018 01:37:31 +0100 Subject: fixing dataset procesosrs --- megapixels/commands/cv/face_vector.py | 125 ++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 megapixels/commands/cv/face_vector.py (limited to 'megapixels/commands/cv/face_vector.py') diff --git a/megapixels/commands/cv/face_vector.py b/megapixels/commands/cv/face_vector.py new file mode 100644 index 00000000..203f73eb --- /dev/null +++ b/megapixels/commands/cv/face_vector.py @@ -0,0 +1,125 @@ +""" +Converts ROIs to face vector +""" + +import click + +from app.settings import types +from app.utils import click_utils +from app.settings import app_cfg as cfg + +@click.command() +@click.option('-o', '--output', 'opt_fp_out', default=None, + help='Override enum output filename CSV') +@click.option('-m', '--media', 'opt_dir_media', default=None, + help='Override enum media directory') +@click.option('--data_store', 'opt_data_store', + type=cfg.DataStoreVar, + default=click_utils.get_default(types.DataStore.SSD), + show_default=True, + help=click_utils.show_help(types.Dataset)) +@click.option('--dataset', 'opt_dataset', + type=cfg.DatasetVar, + required=True, + show_default=True, + help=click_utils.show_help(types.Dataset)) +@click.option('--size', 'opt_size', + type=(int, int), default=(300, 300), + help='Output image size') +@click.option('-j', '--jitters', 'opt_jitters', default=cfg.DLIB_FACEREC_JITTERS, + help='Number of jitters') +@click.option('-p', '--padding', 'opt_padding', default=cfg.DLIB_FACEREC_PADDING, + help='Percentage padding') +@click.option('--slice', 'opt_slice', type=(int, int), default=(None, None), + help='Slice list of files') +@click.option('-f', '--force', 'opt_force', is_flag=True, + help='Force overwrite file') +@click.option('-g', '--gpu', 'opt_gpu', default=0, + help='GPU index') +@click.pass_context +def cli(ctx, opt_fp_out, opt_dir_media, opt_data_store, opt_dataset, opt_size, + opt_slice, opt_force, opt_gpu, opt_jitters, opt_padding): + """Converts face ROIs to vectors""" + + import sys + import os + from os.path import join + from pathlib import Path + from glob import glob + + from tqdm import tqdm + import numpy as np + import dlib # must keep a local reference for dlib + import cv2 as cv + import pandas as pd + + from app.models.bbox import BBox + from app.models.data_store import DataStore + from app.utils import logger_utils, file_utils, im_utils + from app.processors import face_recognition + + + # ------------------------------------------------- + # init here + + log = logger_utils.Logger.getLogger() + # set data_store + data_store = DataStore(opt_data_store, opt_dataset) + + # get filepath out + fp_out = data_store.metadata(types.Metadata.FACE_VECTOR) if opt_fp_out is None else opt_fp_out + if not opt_force and Path(fp_out).exists(): + log.error('File exists. Use "-f / --force" to overwite') + return + + # init face processors + facerec = face_recognition.RecognitionDLIB() + + # load data + fp_record = data_store.metadata(types.Metadata.FILE_RECORD) + df_record = pd.read_csv(fp_record).set_index('index') + fp_roi = data_store.metadata(types.Metadata.FACE_ROI) + df_roi = pd.read_csv(fp_roi).set_index('index') + + if opt_slice: + df_roi = df_roi[opt_slice[0]:opt_slice[1]] + + # ------------------------------------------------- + # process here + df_img_groups = df_roi.groupby('record_index') + log.debug('processing {:,} groups'.format(len(df_img_groups))) + + vecs = [] + + for image_index, df_img_group in tqdm(df_img_groups): + # make fp + roi_index = df_img_group.index.values[0] + # log.debug(f'roi_index: {roi_index}, image_index: {image_index}') + ds_file = df_record.loc[roi_index] # locate image meta + #ds_file = df_record.loc['index', image_index] # locate image meta + + fp_im = data_store.face_image(str(ds_file.subdir), str(ds_file.fn), str(ds_file.ext)) + im = cv.imread(fp_im) + # get bbox + x = df_img_group.x.values[0] + y = df_img_group.y.values[0] + w = df_img_group.w.values[0] + h = df_img_group.h.values[0] + imw = df_img_group.image_width.values[0] + imh = df_img_group.image_height.values[0] + dim = im.shape[:2][::-1] + # get face vector + dim = (imw, imh) + bbox_dim = BBox.from_xywh(x, y, w, h).to_dim(dim) # convert to int real dimensions + # compute vec + # padding=opt_padding not yet implemented in 19.16 but merged in master + vec = facerec.vec(im, bbox_dim, jitters=opt_jitters) + vec_str = ','.join([repr(x) for x in vec]) # convert to string for CSV + vecs.append( {'roi_index': roi_index, 'image_index': image_index, 'vec': vec_str}) + + + # save date + df = pd.DataFrame.from_dict(vecs) + df.index.name = 'index' + file_utils.mkdirs(fp_out) + df.to_csv(fp_out) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 994d74feae29f2577bc04e10dd4bafbfb3dc8e83 Mon Sep 17 00:00:00 2001 From: adamhrv Date: Tue, 18 Dec 2018 01:15:36 +0100 Subject: set jitter 25 --- megapixels/app/models/data_store.py | 2 +- megapixels/app/models/dataset.py | 18 ++++-- megapixels/app/settings/types.py | 3 +- megapixels/commands/cv/face_landmarks_3d.py | 96 +++++++++++++++++++++++++++++ megapixels/commands/cv/face_pose.py | 2 +- megapixels/commands/cv/face_vector.py | 2 +- megapixels/commands/cv/faces_to_3dlm.py | 96 ----------------------------- megapixels/commands/datasets/lookup.py | 4 +- megapixels/commands/datasets/s3_sync.py | 6 +- megapixels/commands/demo/face_search.py | 26 ++++---- 10 files changed, 135 insertions(+), 120 deletions(-) create mode 100644 megapixels/commands/cv/face_landmarks_3d.py delete mode 100644 megapixels/commands/cv/faces_to_3dlm.py (limited to 'megapixels/commands/cv/face_vector.py') diff --git a/megapixels/app/models/data_store.py b/megapixels/app/models/data_store.py index 244aba60..7b6bef21 100644 --- a/megapixels/app/models/data_store.py +++ b/megapixels/app/models/data_store.py @@ -21,7 +21,7 @@ class DataStore: def metadata(self, enum_type): return join(self.dir_metadata, f'{enum_type.name.lower()}.csv') - def metadata(self, enum_type): + def metadata_dir(self): return join(self.dir_metadata) def media_images_original(self): diff --git a/megapixels/app/models/dataset.py b/megapixels/app/models/dataset.py index 35e10465..eb0109a7 100644 --- a/megapixels/app/models/dataset.py +++ b/megapixels/app/models/dataset.py @@ -40,7 +40,7 @@ class Dataset: self._metadata[metadata_type] = pd.read_csv(fp_csv).set_index('index') # convert DataFrame to list of floats self._face_vectors = self.df_vecs_to_dict(self._metadata[metadata_type]) - self._face_vector_idxs = self.df_vec_idxs_to_dict(self._metadata[metadata_type]) + self._face_vector_roi_idxs = self.df_vec_roi_idxs_to_dict(self._metadata[metadata_type]) self.log.info(f'build face vector dict: {len(self._face_vectors)}') # remove the face vector column, it can be several GB of memory self._metadata[metadata_type].drop('vec', axis=1, inplace=True) @@ -81,8 +81,8 @@ class Dataset: # future datasets can have multiple identities per images ds_identities = df_identity.iloc[identity_index] # get filepath and S3 url - fp_im = self.data_store.face_image(ds_record.subdir, ds_record.fn, ds_record.ext) - s3_url = self.data_store_s3.face_image(ds_record.uuid) + fp_im = self.data_store.face(ds_record.subdir, ds_record.fn, ds_record.ext) + s3_url = self.data_store_s3.face(ds_record.uuid) image_record = ImageRecord(ds_record, fp_im, s3_url, ds_identities=ds_identities) return image_record @@ -147,8 +147,14 @@ class Dataset: for match_idx in match_idxs: # get the corresponding face vector row roi_index = self._face_vector_roi_idxs[match_idx] + df_record = self._metadata[types.Metadata.FILE_RECORD] + ds_record = df_record.iloc[roi_index] self.log.debug(f'find match index: {match_idx}, --> roi_index: {roi_index}') - image_record = self.roi_idx_to_record(roi_index) + fp_im = self.data_store.face(ds_record.subdir, ds_record.fn, ds_record.ext) + s3_url = self.data_store_s3.face(ds_record.uuid) + image_record = ImageRecord(ds_record, fp_im, s3_url) + #roi_index = self._face_vector_roi_idxs[match_idx] + #image_record = self.roi_idx_to_record(roi_index) image_records.append(image_record) return image_records @@ -159,10 +165,10 @@ class Dataset: # convert the DataFrame CSV to float list of vecs return [list(map(float,x.vec.split(','))) for x in df.itertuples()] - def df_vec_idxs_to_dict(self, df): + def df_vec_roi_idxs_to_dict(self, df): # convert the DataFrame CSV to float list of vecs #return [x.roi_index for x in df.itertuples()] - return [x.image_index for x in df.itertuples()] + return [x.roi_index for x in df.itertuples()] def similar(self, query_vec, n_results): '''Finds most similar N indices of query face vector diff --git a/megapixels/app/settings/types.py b/megapixels/app/settings/types.py index 754be618..ee6f8de5 100644 --- a/megapixels/app/settings/types.py +++ b/megapixels/app/settings/types.py @@ -45,7 +45,8 @@ class LogLevel(Enum): # -------------------------------------------------------------------- class Metadata(Enum): - IDENTITY, FILE_RECORD, FACE_VECTOR, FACE_POSE, FACE_ROI = range(5) + IDENTITY, FILE_RECORD, FACE_VECTOR, FACE_POSE, FACE_ROI, FACE_LANDMARKS_68, \ + FACE_LANDMARKS_3D = range(7) class Dataset(Enum): LFW, VGG_FACE2 = range(2) diff --git a/megapixels/commands/cv/face_landmarks_3d.py b/megapixels/commands/cv/face_landmarks_3d.py new file mode 100644 index 00000000..03ef8fc2 --- /dev/null +++ b/megapixels/commands/cv/face_landmarks_3d.py @@ -0,0 +1,96 @@ +""" + +""" + +import click + +from app.settings import types +from app.utils import click_utils +from app.settings import app_cfg as cfg + +color_filters = {'color': 1, 'gray': 2, 'all': 3} + +@click.command() +@click.option('-i', '--input', 'opt_dirs_in', required=True, multiple=True, + help='Input directory') +@click.option('-o', '--output', 'opt_fp_out', required=True, + help='Output CSV') +@click.option('-e', '--ext', 'opt_ext', + default='jpg', type=click.Choice(['jpg', 'png']), + help='File glob ext') +@click.option('--size', 'opt_size', + type=(int, int), default=(300, 300), + help='Output image size') +@click.option('-g', '--gpu', 'opt_gpu', default=0, + help='GPU index') +@click.option('--slice', 'opt_slice', type=(int, int), default=(None, None), + help='Slice list of files') +@click.option('--recursive/--no-recursive', 'opt_recursive', is_flag=True, default=False, + help='Use glob recursion (slower)') +@click.option('-f', '--force', 'opt_force', is_flag=True, + help='Force overwrite file') +@click.pass_context +def cli(ctx, opt_dirs_in, opt_fp_out, opt_ext, opt_size, opt_gpu, opt_slice, + opt_recursive, opt_force): + """Converts face imges to 3D landmarks""" + + import sys + import os + from os.path import join + from pathlib import Path + from glob import glob + + from tqdm import tqdm + import numpy as np + import dlib # must keep a local reference for dlib + import cv2 as cv + import pandas as pd + from face_alignment import FaceAlignment, LandmarksType + from skimage import io + + from app.utils import logger_utils, file_utils + from app.processors import face_detector + + # ------------------------------------------------- + # init here + + + log = logger_utils.Logger.getLogger() + + if not opt_force and Path(opt_fp_out).exists(): + log.error('File exists. Use "-f / --force" to overwite') + return + + device = 'cuda' if opt_gpu > -1 else 'cpu' + fa = FaceAlignment(LandmarksType._3D, flip_input=False, device=device) + + # get list of files to process + fp_ims = [] + for opt_dir_in in opt_dirs_in: + if opt_recursive: + fp_glob = join(opt_dir_in, '**/*.{}'.format(opt_ext)) + fp_ims += glob(fp_glob, recursive=True) + else: + fp_glob = join(opt_dir_in, '*.{}'.format(opt_ext)) + fp_ims += glob(fp_glob) + log.debug(fp_glob) + + + if opt_slice: + fp_ims = fp_ims[opt_slice[0]:opt_slice[1]] + log.debug('processing {:,} files'.format(len(fp_ims))) + + + data = {} + + for fp_im in tqdm(fp_ims): + fpp_im = Path(fp_im) + im = io.imread(fp_im) + preds = fa.get_landmarks(im) + if preds and len(preds) > 0: + data[fpp_im.name] = preds[0].tolist() + + # save date + file_utils.mkdirs(opt_fp_out) + + file_utils.write_json(data, opt_fp_out, verbose=True) \ No newline at end of file diff --git a/megapixels/commands/cv/face_pose.py b/megapixels/commands/cv/face_pose.py index e7ffb7ac..c37d006f 100644 --- a/megapixels/commands/cv/face_pose.py +++ b/megapixels/commands/cv/face_pose.py @@ -95,7 +95,7 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_dir_media, opt_data_store, opt_dataset, for record_index, df_img_group in tqdm(df_img_groups): # make fp ds_record = df_record.iloc[record_index] - fp_im = data_store.face_image(ds_record.subdir, ds_record.fn, ds_record.ext) + fp_im = data_store.face(ds_record.subdir, ds_record.fn, ds_record.ext) im = cv.imread(fp_im) # get bbox x = df_img_group.x.values[0] diff --git a/megapixels/commands/cv/face_vector.py b/megapixels/commands/cv/face_vector.py index 203f73eb..cd816f9f 100644 --- a/megapixels/commands/cv/face_vector.py +++ b/megapixels/commands/cv/face_vector.py @@ -98,7 +98,7 @@ def cli(ctx, opt_fp_out, opt_dir_media, opt_data_store, opt_dataset, opt_size, ds_file = df_record.loc[roi_index] # locate image meta #ds_file = df_record.loc['index', image_index] # locate image meta - fp_im = data_store.face_image(str(ds_file.subdir), str(ds_file.fn), str(ds_file.ext)) + fp_im = data_store.face(str(ds_file.subdir), str(ds_file.fn), str(ds_file.ext)) im = cv.imread(fp_im) # get bbox x = df_img_group.x.values[0] diff --git a/megapixels/commands/cv/faces_to_3dlm.py b/megapixels/commands/cv/faces_to_3dlm.py deleted file mode 100644 index 658d4484..00000000 --- a/megapixels/commands/cv/faces_to_3dlm.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -Crop images to prepare for training -""" - -import click -# from PIL import Image, ImageOps, ImageFilter, ImageDraw - -from app.settings import types -from app.utils import click_utils -from app.settings import app_cfg as cfg - -color_filters = {'color': 1, 'gray': 2, 'all': 3} - -@click.command() -@click.option('-i', '--input', 'opt_dirs_in', required=True, multiple=True, - help='Input directory') -@click.option('-o', '--output', 'opt_fp_out', required=True, - help='Output CSV') -@click.option('-e', '--ext', 'opt_ext', - default='jpg', type=click.Choice(['jpg', 'png']), - help='File glob ext') -@click.option('--size', 'opt_size', - type=(int, int), default=(300, 300), - help='Output image size') -@click.option('-g', '--gpu', 'opt_gpu', default=0, - help='GPU index') -@click.option('--slice', 'opt_slice', type=(int, int), default=(None, None), - help='Slice list of files') -@click.option('--recursive/--no-recursive', 'opt_recursive', is_flag=True, default=False, - help='Use glob recursion (slower)') -@click.option('-f', '--force', 'opt_force', is_flag=True, - help='Force overwrite file') -@click.pass_context -def cli(ctx, opt_dirs_in, opt_fp_out, opt_ext, opt_size, opt_gpu, opt_slice, - opt_recursive, opt_force): - """Converts face imges to 3D landmarks""" - - import sys - import os - from os.path import join - from pathlib import Path - from glob import glob - - from tqdm import tqdm - import numpy as np - import dlib # must keep a local reference for dlib - import cv2 as cv - import pandas as pd - from face_alignment import FaceAlignment, LandmarksType - from skimage import io - - from app.utils import logger_utils, file_utils - from app.processors import face_detector - - # ------------------------------------------------- - # init here - - log = logger_utils.Logger.getLogger() - - if not opt_force and Path(opt_fp_out).exists(): - log.error('File exists. Use "-f / --force" to overwite') - return - - device = 'cuda' if opt_gpu > -1 else 'cpu' - fa = FaceAlignment(LandmarksType._3D, flip_input=False, device=device) - - # get list of files to process - fp_ims = [] - for opt_dir_in in opt_dirs_in: - if opt_recursive: - fp_glob = join(opt_dir_in, '**/*.{}'.format(opt_ext)) - fp_ims += glob(fp_glob, recursive=True) - else: - fp_glob = join(opt_dir_in, '*.{}'.format(opt_ext)) - fp_ims += glob(fp_glob) - log.debug(fp_glob) - - - if opt_slice: - fp_ims = fp_ims[opt_slice[0]:opt_slice[1]] - log.debug('processing {:,} files'.format(len(fp_ims))) - - - data = {} - - for fp_im in tqdm(fp_ims): - fpp_im = Path(fp_im) - im = io.imread(fp_im) - preds = fa.get_landmarks(im) - if preds and len(preds) > 0: - data[fpp_im.name] = preds[0].tolist() - - # save date - file_utils.mkdirs(opt_fp_out) - - file_utils.write_json(data, opt_fp_out, verbose=True) \ No newline at end of file diff --git a/megapixels/commands/datasets/lookup.py b/megapixels/commands/datasets/lookup.py index c1c66c19..5ae4c3f5 100644 --- a/megapixels/commands/datasets/lookup.py +++ b/megapixels/commands/datasets/lookup.py @@ -10,7 +10,7 @@ log = Logger.getLogger() @click.command() @click.option('--index', 'opt_index', type=int, required=True, - help='Vector index to lookup') + help='File index to lookup') @click.option('--data_store', 'opt_data_store', type=cfg.DataStoreVar, default=click_utils.get_default(types.DataStore.SSD), @@ -45,7 +45,7 @@ def cli(ctx, opt_index, opt_data_store, opt_dataset): dataset.load_records() dataset.load_identities() # set data store and load files - # find image records + # get image record from file index image_record = dataset.index_to_record(opt_index) image_record.summarize() # load image diff --git a/megapixels/commands/datasets/s3_sync.py b/megapixels/commands/datasets/s3_sync.py index 3098d9be..17940c6d 100644 --- a/megapixels/commands/datasets/s3_sync.py +++ b/megapixels/commands/datasets/s3_sync.py @@ -54,4 +54,8 @@ def cli(ctx, opt_data_store, opt_dataset, opt_type, opt_dryrun): if not opt_dryrun: subprocess.call(cmd) - \ No newline at end of file + +''' +upload: '/data_store_ssd/datasets/people/vgg_face2/media/uuid/00418e0e-48e9-44f9-b6a0-b2ffd773802e.jpg' -> 's3://megapixels/v1/media/vgg_face2/00418e0e-48e9-44f9-b6a0-b2ffd773802e.jpg' [3202 of 3187313] +[2953 of 3187313] +''' \ No newline at end of file diff --git a/megapixels/commands/demo/face_search.py b/megapixels/commands/demo/face_search.py index 0452cc9d..34a25762 100644 --- a/megapixels/commands/demo/face_search.py +++ b/megapixels/commands/demo/face_search.py @@ -6,9 +6,11 @@ from app.utils import click_utils from app.settings import app_cfg as cfg from app.utils.logger_utils import Logger +log = Logger.getLogger() + @click.command() @click.option('-i', '--input', 'opt_fp_in', required=True, - help='Input face image') + help='File to lookup') @click.option('--data_store', 'opt_data_store', type=cfg.DataStoreVar, default=click_utils.get_default(types.DataStore.SSD), @@ -19,8 +21,8 @@ from app.utils.logger_utils import Logger required=True, show_default=True, help=click_utils.show_help(types.Dataset)) -@click.option('--gpu', 'opt_gpu', default=0, - help='GPU index (use -1 for CPU)') +@click.option('--gpu', 'opt_gpu', default=0, + help='GPU index (use -1 for CPU') @click.pass_context def cli(ctx, opt_fp_in, opt_data_store, opt_dataset, opt_gpu): """Display image info""" @@ -31,18 +33,22 @@ def cli(ctx, opt_fp_in, opt_data_store, opt_dataset, opt_gpu): from pathlib import Path import time - import imutils import pandas as pd import cv2 as cv - import dlib from tqdm import tqdm - + import imutils + from app.utils import file_utils, im_utils - from app.models.data_store import DataStore, DataStoreS3 + from app.models.data_store import DataStore from app.processors import face_detector from app.processors import face_recognition log = Logger.getLogger() + # init dataset + dataset = Dataset(opt_data_store, opt_dataset) + dataset.load_face_vectors() + dataset.load_records() + dataset.load_identities() # init face detection detector = face_detector.DetectorDLIBHOG() @@ -52,6 +58,7 @@ def cli(ctx, opt_fp_in, opt_data_store, opt_dataset, opt_gpu): # load query image im_query = cv.imread(opt_fp_in) + # get detection as BBox object bboxes = detector.detect(im_query, largest=True) bbox = bboxes[0] @@ -64,9 +71,6 @@ def cli(ctx, opt_fp_in, opt_data_store, opt_dataset, opt_gpu): # extract the face vectors vec_query = recognition.vec(im_query, bbox) - - # load dataset CSVs - dataset = Dataset(opt_data_store, opt_dataset) # find matches image_records = dataset.find_matches(vec_query, n_results=5) @@ -91,4 +95,4 @@ def cli(ctx, opt_fp_in, opt_data_store, opt_dataset, opt_gpu): sys.exit() elif k != 255: # any key to continue - break \ No newline at end of file + break -- cgit v1.2.3-70-g09d2 From 5340bee951c18910fd764241945f1f136b5a22b4 Mon Sep 17 00:00:00 2001 From: adamhrv Date: Sun, 23 Dec 2018 01:24:24 +0100 Subject: fixing face roi --- megapixels/app/settings/types.py | 2 +- megapixels/commands/cv/face_roi.py | 4 ++-- megapixels/commands/cv/face_vector.py | 2 +- megapixels/commands/datasets/records.py | 40 ++++++++++++++++++++------------- megapixels/commands/demo/face_search.py | 4 +++- 5 files changed, 31 insertions(+), 21 deletions(-) (limited to 'megapixels/commands/cv/face_vector.py') diff --git a/megapixels/app/settings/types.py b/megapixels/app/settings/types.py index ee6f8de5..0805c5bd 100644 --- a/megapixels/app/settings/types.py +++ b/megapixels/app/settings/types.py @@ -49,7 +49,7 @@ class Metadata(Enum): FACE_LANDMARKS_3D = range(7) class Dataset(Enum): - LFW, VGG_FACE2 = range(2) + LFW, VGG_FACE2, MSCELEB, UCCS, UMD_FACES = range(5) # --------------------------------------------------------------------- diff --git a/megapixels/commands/cv/face_roi.py b/megapixels/commands/cv/face_roi.py index d7248aee..a08566a8 100644 --- a/megapixels/commands/cv/face_roi.py +++ b/megapixels/commands/cv/face_roi.py @@ -115,7 +115,7 @@ def cli(ctx, opt_fp_in, opt_dir_media, opt_fp_out, opt_data_store, opt_dataset, data = [] for df_record in tqdm(df_records.itertuples(), total=len(df_records)): - fp_im = data_store.face_image(str(df_record.subdir), str(df_record.fn), str(df_record.ext)) + fp_im = data_store.face(str(df_record.subdir), str(df_record.fn), str(df_record.ext)) im = cv.imread(fp_im) # filter out color or grayscale iamges @@ -149,10 +149,10 @@ def cli(ctx, opt_fp_in, opt_dir_media, opt_fp_out, opt_data_store, opt_dataset, # debug display if opt_display and len(bboxes): - bbox_dim = bbox.to_dim(im.shape[:2][::-1]) # w,h im_md = im_utils.resize(im, width=min(1200, opt_size[0])) for bbox in bboxes: bbox_dim = bbox.to_dim(im_md.shape[:2][::-1]) + log.debug(f'bbox: {bbox_dim}') cv.rectangle(im_md, bbox_dim.pt_tl, bbox_dim.pt_br, (0,255,0), 3) cv.imshow('', im_md) while True: diff --git a/megapixels/commands/cv/face_vector.py b/megapixels/commands/cv/face_vector.py index cd816f9f..7200d73b 100644 --- a/megapixels/commands/cv/face_vector.py +++ b/megapixels/commands/cv/face_vector.py @@ -115,7 +115,7 @@ def cli(ctx, opt_fp_out, opt_dir_media, opt_data_store, opt_dataset, opt_size, # padding=opt_padding not yet implemented in 19.16 but merged in master vec = facerec.vec(im, bbox_dim, jitters=opt_jitters) vec_str = ','.join([repr(x) for x in vec]) # convert to string for CSV - vecs.append( {'roi_index': roi_index, 'image_index': image_index, 'vec': vec_str}) + vecs.append( {'roi_index': roi_index, 'record_index': image_index, 'vec': vec_str}) # save date diff --git a/megapixels/commands/datasets/records.py b/megapixels/commands/datasets/records.py index 80de5040..b6ef618b 100644 --- a/megapixels/commands/datasets/records.py +++ b/megapixels/commands/datasets/records.py @@ -107,10 +107,12 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_dataset, opt_data_store, opt_dir_media, # convert data to dict data = [] + indentity_count = 0 for sha256, fp_im in zip(sha256s, fp_ims): fpp_im = Path(fp_im) subdir = str(fpp_im.parent.relative_to(fp_in)) + if opt_identity: subdirs = subdir.split('/') if not len(subdirs) > 0: @@ -124,7 +126,8 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_dataset, opt_data_store, opt_dir_media, elif opt_identity == 'subdir_tail': identity = subdirs[-1] # use last part of subdir path else: - identity = '' + identity = indentity_count # use incrementing number + indentity_count += 1 data.append({ 'subdir': subdir, @@ -135,22 +138,27 @@ def cli(ctx, opt_fp_in, opt_fp_out, opt_dataset, opt_data_store, opt_dir_media, 'identity_key': identity }) - log.info(f'adding identity index using: "{opt_identity}". This may take a while...') - # convert dict to DataFrame df_records = pd.DataFrame.from_dict(data) - # sort based on identity_key - df_records = df_records.sort_values(by=['identity_key'], ascending=True) - # add new column for identity - df_records['identity_index'] = [-1] * len(df_records) - # populate the identity_index - df_records_identity_groups = df_records.groupby('identity_key') - # enumerate groups to create identity indices - for identity_index, df_records_identity_group_tuple in enumerate(df_records_identity_groups): - identity_key, df_records_identity_group = df_records_identity_group_tuple - for ds_record in df_records_identity_group.itertuples(): - df_records.at[ds_record.Index, 'identity_index'] = identity_index - # reset index after being sorted - df_records = df_records.reset_index(drop=True) + if opt_identity: + log.info(f'adding identity index using: "{opt_identity}". This may take a while...') + # convert dict to DataFrame + # sort based on identity_key + df_records = df_records.sort_values(by=['identity_key'], ascending=True) + # add new column for identity + df_records['identity_index'] = [-1] * len(df_records) + # populate the identity_index + df_records_identity_groups = df_records.groupby('identity_key') + # enumerate groups to create identity indices + for identity_index, df_records_identity_group_tuple in enumerate(df_records_identity_groups): + identity_key, df_records_identity_group = df_records_identity_group_tuple + for ds_record in df_records_identity_group.itertuples(): + df_records.at[ds_record.Index, 'identity_index'] = identity_index + # reset index after being sorted + df_records = df_records.reset_index(drop=True) + else: + # name everyone person 1, 2, 3... + pass + df_records.index.name = 'index' # reassign 'index' as primary key column # write to CSV file_utils.mkdirs(fp_out) diff --git a/megapixels/commands/demo/face_search.py b/megapixels/commands/demo/face_search.py index 34a25762..6e4bcdad 100644 --- a/megapixels/commands/demo/face_search.py +++ b/megapixels/commands/demo/face_search.py @@ -21,6 +21,8 @@ log = Logger.getLogger() required=True, show_default=True, help=click_utils.show_help(types.Dataset)) +@click.option('--results', 'opt_results', default=5, + help='Number of match results to display') @click.option('--gpu', 'opt_gpu', default=0, help='GPU index (use -1 for CPU') @click.pass_context @@ -73,7 +75,7 @@ def cli(ctx, opt_fp_in, opt_data_store, opt_dataset, opt_gpu): vec_query = recognition.vec(im_query, bbox) # find matches - image_records = dataset.find_matches(vec_query, n_results=5) + image_records = dataset.find_matches(vec_query, n_results=opt_results) # summary ims_match = [im_query] -- cgit v1.2.3-70-g09d2