code changs for multiple protobuf models
[face-privacy-filter.git] / face_privacy_filter / filter_image.py
1 #! python
2 # -*- coding: utf-8 -*-
3 # ================================================================================
4 # ACUMOS
5 # ================================================================================
6 # Copyright © 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
7 # ================================================================================
8 # This Acumos software file is distributed by AT&T and Tech Mahindra
9 # under the Apache License, Version 2.0 (the "License");
10 # you may not use this file except in compliance with the License.
11 # You may obtain a copy of the License at
12 #
13 #      http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # This file is distributed on an "AS IS" BASIS,
16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 # See the License for the specific language governing permissions and
18 # limitations under the License.
19 # ================================================================================
20 """
21 Wrapper for face privacy transform task
22 """
23
24 import os.path
25 import sys
26
27 import numpy as np
28 import pandas as pd
29
30
31 def model_create_pipeline(transformer, funcName):
32     from acumos.session import Requirements
33     from acumos.modeling import Model, List, create_namedtuple
34     import sklearn
35     import cv2
36     from os import path
37
38     # derive the input type from the transformer
39     type_list, type_name = transformer._type_in  # it looked like this {'test': int, 'tag': str}
40     input_type = [(k, List[type_list[k]]) for k in type_list]
41     type_in = create_namedtuple(type_name, input_type)
42
43     # derive the output type from the transformer
44     type_list, type_name = transformer._type_out
45     output_type = [(k, List[type_list[k]]) for k in type_list]
46     type_out = create_namedtuple(type_name, output_type)
47
48     def predict_class(val_wrapped: type_in) -> type_out:
49         '''Returns an array of float predictions'''
50         df = pd.DataFrame(list(zip(*val_wrapped)), columns=val_wrapped._fields)
51         # df = pd.DataFrame(np.column_stack(val_wrapped), columns=val_wrapped._fields)  # numpy doesn't like binary
52         tags_df = transformer.predict(df)
53         tags_list = type_out(*(col for col in tags_df.values.T))  # flatten to tag set
54         return tags_list
55
56     # compute path of this package to add it as a dependency
57     package_path = path.dirname(path.realpath(__file__))
58     objModelDeclare = {}
59     objModelDeclare[funcName] = predict_class
60     return Model(**objModelDeclare), Requirements(packages=[package_path], reqs=[pd, np, sklearn],
61                                                         req_map={cv2: 'opencv-python'})
62
63
64 def main(config={}):
65     from face_privacy_filter.transform_detect import FaceDetectTransform
66     from face_privacy_filter.transform_region import RegionTransform
67     from face_privacy_filter._version import MODEL_NAME
68     import argparse
69     parser = argparse.ArgumentParser()
70     parser.add_argument('-p', '--predict_path', type=str, default='', help="save detections from model (model must be provided via 'dump_model')")
71     parser.add_argument('-i', '--input', type=str, default='', help='absolute path to input data (image or csv, only during prediction / dump)')
72     parser.add_argument('-c', '--csv_input', dest='csv_input', action='store_true', default=False, help='input as CSV format not an image')
73     parser.add_argument('-s', '--suppress_image', dest='suppress_image', action='store_true', default=False, help='do not create an extra row for a returned image')
74     parser.add_argument('-f', '--function', type=str, default='detect', help='which type of model to generate', choices=['detect', 'pixelate'])
75     parser.add_argument('-a', '--push_address', help='server address to push the model (e.g. http://localhost:8887/v2/models)', default='')
76     parser.add_argument('-A', '--auth_address', help='server address for login and push of the model (e.g. http://localhost:8887/v2/auth)', default='')
77     parser.add_argument('-d', '--dump_model', help='dump model to a pickle directory for local running', default='')
78     config.update(vars(parser.parse_args()))     # pargs, unparsed = parser.parse_known_args()
79
80     if not config['predict_path']:
81         print("Attempting to create new model for dump or push...")
82
83         # refactor the raw samples from upstream image classifier
84         if config['function'] == "detect":
85             transform = FaceDetectTransform(include_image=not config['suppress_image'])
86         elif config['function'] == "pixelate":
87             transform = RegionTransform()
88         else:
89             print("Error: Functional mode '{:}' unknown, aborting create".format(config['function']))
90         inputDf = transform.generate_in_df()
91         pipeline, reqs = model_create_pipeline(transform, config['function'])
92
93         # formulate the pipeline to be used
94         model_name = MODEL_NAME + "_" + config['function']
95         if config['push_address']:
96             from acumos.session import AcumosSession
97             print("Pushing new model to '{:}'...".format(config['push_address']))
98             session = AcumosSession(push_api=config['push_address'], auth_api=config['auth_address'])
99             session.push(pipeline, model_name, reqs)  # creates ./my-iris.zip
100
101         if config['dump_model']:
102             from acumos.session import AcumosSession
103             from os import makedirs
104             if not os.path.exists(config['dump_model']):
105                 makedirs(config['dump_model'])
106             print("Dumping new model to '{:}'...".format(config['dump_model']))
107             session = AcumosSession()
108             session.dump(pipeline, model_name, config['dump_model'], reqs)  # creates ./my-iris.zip
109
110     else:
111         if not config['dump_model'] or not os.path.exists(config['dump_model']):
112             print("Attempting to predict from a dumped model, but model not found.".format(config['dump_model']))
113             sys.exit(-1)
114         if not os.path.exists(config['input']):
115             print("Predictino requested but target input '{:}' was not found, please check input arguments.".format(config['input']))
116             sys.exit(-1)
117
118         print("Attempting predict/transform on input sample...")
119         from acumos.wrapped import load_model
120         model = load_model(config['dump_model'])
121         if not config['csv_input']:
122             inputDf = FaceDetectTransform.generate_in_df(config['input'])
123         else:
124             inputDf = pd.read_csv(config['input'], converters={FaceDetectTransform.COL_IMAGE_DATA: FaceDetectTransform.read_byte_arrays})
125
126         type_in = model.transform._input_type
127         transform_in = type_in(*tuple(col for col in inputDf.values.T))
128         transform_out = model.transform.from_wrapped(transform_in).as_wrapped()
129         dfPred = pd.DataFrame(list(zip(*transform_out)), columns=transform_out._fields)
130
131         if not config['csv_input']:
132             dfPred = FaceDetectTransform.suppress_image(dfPred)
133         print("ALMOST DONE")
134         print(dfPred)
135
136         if config['predict_path']:
137             print("Writing prediction to file '{:}'...".format(config['predict_path']))
138             if not config['csv_input']:
139                 dfPred.to_csv(config['predict_path'], sep=",", index=False)
140             else:
141                 FaceDetectTransform.generate_out_image(dfPred, config['predict_path'])
142
143         if dfPred is not None:
144             print("Predictions:\n{:}".format(dfPred))
145
146
147 if __name__ == '__main__':
148     # patch the path to include this object
149     pathRoot = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
150     if pathRoot not in sys.path:
151         sys.path.append(pathRoot)
152     main()