From 30fa1635a5dbe6549fef74b7a5fdb8b2fba0a887 Mon Sep 17 00:00:00 2001 From: Shawn-Shan Date: Mon, 6 Jul 2020 16:52:46 -0500 Subject: [PATCH] endpoint api Former-commit-id: 101c0d4cfbfe62d873a289a1ba1ccb47bdbd66f5 [formerly 57e917cb08f4219a703fbdab6e782490077e8480] Former-commit-id: 6a0071b5ca45c7651f3aceb952a0eebddfcc6897 --- app/fawkes.py | 12 + app/setup.py | 12 + .../__pycache__/differentiator.cpython-36.pyc | Bin 9162 -> 9086 bytes fawkes/__pycache__/utils.cpython-36.pyc | Bin 13083 -> 16270 bytes fawkes/differentiator.py | 8 +- fawkes/protection.py | 31 ++- fawkes/utils.py | 167 +++++++++++++- fawkes_dev/azure.py | 212 ++++++++++-------- 8 files changed, 321 insertions(+), 121 deletions(-) create mode 100644 app/fawkes.py create mode 100644 app/setup.py diff --git a/app/fawkes.py b/app/fawkes.py new file mode 100644 index 0000000..a984dd6 --- /dev/null +++ b/app/fawkes.py @@ -0,0 +1,12 @@ +import sys + +if sys.version_info < (3, 0): + # Python 2 + import Tkinter as tk +else: + # Python 3 + import tkinter as tk +root = tk.Tk() +root.title("Sandwich") +tk.Button(root, text="Make me a Sandwich").pack() +tk.mainloop() diff --git a/app/setup.py b/app/setup.py new file mode 100644 index 0000000..5a6453b --- /dev/null +++ b/app/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup + +APP = ['Sandwich.py'] +DATA_FILES = [] +OPTIONS = {'argv_emulation': True} + +setup( + app=APP, + data_files=DATA_FILES, + options={'py2app': OPTIONS}, + setup_requires=['py2app'], +) diff --git a/fawkes/__pycache__/differentiator.cpython-36.pyc b/fawkes/__pycache__/differentiator.cpython-36.pyc index 0b8b35fb7ea23d16a7bdfb71f2dd54598db4f613..0e7916503f2aba6094099a39b154695534f4daeb 100644 GIT binary patch delta 291 zcmX@*{?Comn3tF9TRKzxpN*X5oQyr28#(0|8Rt%3z;%~#@#H%0#k^-27#NC~fCLLe zmBHkRoa&Q9d3t!Sz(m;?stm!RqP&U%JV4PRUJ$_tBG@;(@%~}q)dQ)01|%5Rd6*{$ z3dv2*72;%M-CQm-jgj&BWImCLj2|~Y5OHB<{5e@wBAap2=7|z^OpLoGUy#b>_bAb> zVaU>HW^`egz!+;W*+=>g8%Q99XL6j3H6!ojSu&cET#O7L7|D>w6u|(Ll}=&LW}3iK zR5Lk1N@bF)IwRj?4Ox9g{>c%tM>iYG9bjUUW(2zF(&V2C>loQKuTzX-WE7mtscgz< TI@w;?knz^!Lgg@KCIMyu9PLau delta 369 zcmez8cFLX8n3tE!k>_9BmyMj|oQz$Y8#(0|8D~#kz;%~#;p95*#k{8&7#NC~fCLLe zmBHkRoa&Q9d3ty+!9>{@stm!RqP&U%d_d76b`Ze}B6v2t@%~}q)di`21|%5Rd6*{$ z3dv2*72;%M*<3C(jgj%`WImCLjPEx;5OHB<{61M#BAfBh=7|z^OpLE4Uy#b>uPD*3 zVaU>HW^`egz!;k`*+=@0Sqft|^91IiLpAassT3Y51~CSp7!z2GC51(%~G^xa)6Y|d4_Oc_lke^xSNjGC;f9LCHjzzhH}qG53W diff --git a/fawkes/__pycache__/utils.cpython-36.pyc b/fawkes/__pycache__/utils.cpython-36.pyc index fba5d6fabab5f589cc1a256a5bf29f82cbaade7b..77639db2bb7185e2746c485fa2e088df0ffdcf39 100644 GIT binary patch literal 16270 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 LkXxi^_rU)Fj0GRk delta 5496 zcmZ`+eQX@X72nyr+uPea-5#^Jn6GV}hNOB!m#u1{T7x@vJX*xi4nd ziEYk3z=;rTfWQ=50;2E-Pzs_&h6({{XeAJ>Kv1h!d_HzS244?IL@<99clBuM-4&8 zM30ENCsUt|>QTWfnTBkm-Y9r)rYXBdUqedRNzJUyHtWrz!Ix>tw(70GYt)}<%dXSc zW!v?3sPCc`G?7ZKO?f4QOqmYiaWtsiep0m9&MnLQ@ajL)+*&;Cks*w1aj6*GIePdQk7D zG1?8~0Np@0LODn`(KwWw=?LwmeW1C8_R|574ADWl8Op763mt-T8y%(F=yuT9PWRFs zbSH2-D7jvW?fXoUT#|H%r{rN(O`3LMJeA>3$y@nDo(t}0C054^?$IW7ER!lEQrYAh z+%*-5L^KkFkJZoJq_mJaFd{kbe8J4=Y69$-lc{m$=I6a}qVkL0D;n!Sfe8{pRV|Y@ zC|ER-W;>6nvC<}xj={J1lYtwC&uRx^N;;vEE>l8fn2?LQs2fT*^-u*$5B0)iRL8T| z7&EOgbOwJx_|Vy_;Ir-^l4MIod6pEVgp`zk5O67Z9GfGjRuBbHQrQpvQspuV%pof~2W_*(r zYsYS$(QK`#rTtWiN}>e)B)Br;w*%>lqQB^;-tm$P1c9Pf3{cmC(ph<)hmOEQsGgO_ zT|1?s51a|0Gq>GwR00Q}eWrq{!U3Ofzy~h6(!rvNTENS|`{sE!@D=mC2Y6SK*r8+C zTm!y?(Lpc@UCtBhpdF^7n_Wp2Yy*$0uuUwaY*!;swOJV!6dVLv0~)m;g>{5l9hG2j z{D=5i?eI_lcH*F=L8V z^Irsd8-kA8GBe|jUj%rfVAv-t6j>JcRE&^rzQ3Yn*X0g6Y9f)!rR+pvCyZz927+fy zS^TRZDhZGSKT(bLq-vLT=^Xt19*1Dh3c+mM^fYp|)%;0^@??smVmLFpz-J*e zOC%txM25K56QUF#Y7T}#t9oJtAELi&?N`8c-_c9Wb;|xLpRN?}Wuq=1^2D!p={PCtp z{ex%*!Gw(faojnY%0i%?;qNvz)vWNCgT}A;f19o)eD0bxuMoQA4SJePzi#vTOE(S+ z50bZj`hMF-eaD7{AIX1Q_sZI{U)(YrUwsnasphp;EIP;@L05&-7l4DsK7)cs zk>rr9aQR`7{afO1HTNpWLWEpu9y(Z$EUrH|Bl=?mtmx`Qn0d-%mYFE9JYa>D5U66( zFs!rXh7NcP*%Q3fa$xin)Eu`#jVwD2EVwlZ1;Z1|rcvNwUgWO?YW6ES~28DN_ zf{UHyq1I;qGXMFu*2bP%91YWmL}~zaWgPPCR?|M@XI!}vTce&dToPspRmx?NP%l;QbwdKxsBgYa`&!#FE4IJrN(X2tD$&5K z%zi0q;i#0ZpcN;fZU<>_mbmXCMHe4$>*SBL9S-)Y@4y$(Zq8|#DR3P3EtA)aDbgf(X!RXPCsK*qy6WR{0s>W&W-|c+&GBH59|e~$6St= z8n$7XHk(5w1IY@$|P0PYGyU0&;?SZ@Ub6pJwu$QA^;>sD2L(zA* zEsYr&lXU~X(q&C#F>%#6fEF=EC0Qh{H@ScPy`}OM$?@9;Dxdk^I}kP|8gYWBEE zX)2erZsE^uXeA%;cQ+WLc(y?KH7q=ix4=xiN-SHE-=mp}*sM6Ul>rdJnmyTN4f!r@U0buuwxGY=f+nR91xP#3!D0TS1uOA^bd>Wh3jj= zn#itLvO9S=K9>7hr<=>2$nh2GcP#{{QqF=gFLQ8gKN1n}u52pjcp0l^reEB?^zBFYXEerGJgpXoVQ zBI!^O;Ldsr-y`XuT?x>tmCK@=`e{HwYZbgrKx-xhFLih!7DM7G6t)4HX;4VQC;^Qy zyj;RGG%EwA6vHT)Y_V&Q0}47PrSpWf7sJKykTetSI8Sa>5D~PU$`OpQP zIN?L=Y2MSfr(=Gu7`yBMlEw8FAthq>KK^hYy$J(Iw9be6H>%&iY$JeOh`QbZTUr+eCS`%L`A=IL$xLfgi*^Q{6JEcO%ZD6?mA(4PX~U-S=c5ze~A$u6Jgx64|> z``@DKD&9ZNZy4BBhLzpJe{$Jew%}lqWym97=6M`e1lkA4eIH2&k|mgd z2rNnL&me?n8%sj8J1%&P39Kxq0nANo0u|iJO#ZmIdWryb6nN#(eAZDcBU{Lru}a4c zXlAhwvBw{fe1Zg1gkF_rsU%{0V&V8svOi*LhXm;go`CqY)7_AAE!|fzQVd=ba2fxY zzckoIzQsQotiJ4Qe>GUI+>P_^=W8}Ml_1Swg41LL@=6VGDx|)k9472@7z3asR4xS2 z$cOgE2>c%s{|f;A255kgeN@&I#ZLAq)Y$t-FcFs5_jkzs4G26Jrr;@S*(C}Wqw@R7 zOU+ZciA+Z1diFS~{ul|~^c)YolM7Sj1FymR7tZ>4CV!eyVeIhL2bl|X@dWFElklRp z;^NX}F%Qb|G%v`@mk4o1)2qA6x`3PW7e4@45sA9L+%jRO03v<-U%MhD4XuPMfN_K6 z;_$p+sWD3+k*+~DP3FWyQ#{@oA}149&+@}Qe>`mhFvn4R3<*PWHQ0#VM8@2WXV>};5O~!t z{lWGFx&zgOEDQk BATCH_SIZE else len(image_X) + max_step=500, batch_size=1): + batch_size = batch_size if len(image_X) > batch_size else len(image_X) differentiator = FawkesMaskGeneration(sess, feature_extractors, batch_size=batch_size, @@ -50,11 +49,11 @@ def check_imgs(imgs): def main(*argv): + start_time = time.time() if not argv: argv = list(sys.argv) - # attach SIGPIPE handler to properly handle broken pipe - try: # sigpipe not available under windows. just ignore in this case + try: import signal signal.signal(signal.SIGPIPE, signal.SIG_DFL) except Exception as e: @@ -78,25 +77,34 @@ def main(*argv): parser.add_argument('--sd', type=int, default=1e9) parser.add_argument('--lr', type=float, default=2) + parser.add_argument('--batch-size', type=int, default=1) parser.add_argument('--separate_target', action='store_true') parser.add_argument('--format', type=str, help="final image format", - default="jpg") + default="png") args = parser.parse_args(argv[1:]) if args.mode == 'low': args.feature_extractor = "high_extract" args.th = 0.003 + args.max_step = 100 + args.lr = 15 elif args.mode == 'mid': args.feature_extractor = "high_extract" args.th = 0.005 + args.max_step = 100 + args.lr = 15 elif args.mode == 'high': args.feature_extractor = "high_extract" args.th = 0.007 + args.max_step = 100 + args.lr = 10 elif args.mode == 'ultra': args.feature_extractor = "high_extract" args.th = 0.01 + args.max_step = 1000 + args.lr = 5 elif args.mode == 'custom': pass else: @@ -116,7 +124,7 @@ def main(*argv): print("No images in the directory") exit(1) - faces = Faces(image_paths, sess) + faces = Faces(image_paths, sess, verbose=1) orginal_images = faces.cropped_faces orginal_images = np.array(orginal_images) @@ -133,7 +141,7 @@ def main(*argv): protected_images = generate_cloak_images(sess, feature_extractors_ls, orginal_images, target_emb=target_embedding, th=args.th, faces=faces, sd=args.sd, - lr=args.lr, max_step=args.max_step) + lr=args.lr, max_step=args.max_step, batch_size=args.batch_size) faces.cloaked_cropped_faces = protected_images @@ -141,9 +149,12 @@ def main(*argv): final_images = faces.merge_faces(cloak_perturbation) for p_img, cloaked_img, path in zip(final_images, protected_images, image_paths): - file_name = "{}_{}_{}_cloaked.{}".format(".".join(path.split(".")[:-1]), args.mode, args.th, args.format) + file_name = "{}_{}_cloaked.{}".format(".".join(path.split(".")[:-1]), args.mode, args.format) dump_image(p_img, file_name, format=args.format) + elapsed_time = time.time() - start_time + print('attack cost %f s' % (elapsed_time)) + if __name__ == '__main__': main(*sys.argv) diff --git a/fawkes/utils.py b/fawkes/utils.py index 6f8f590..c769e31 100644 --- a/fawkes/utils.py +++ b/fawkes/utils.py @@ -4,7 +4,13 @@ import json import os import pickle import random +import shutil import sys +import tarfile +import zipfile + +import six +from six.moves.urllib.error import HTTPError, URLError stderr = sys.stderr sys.stderr = open(os.devnull, 'w') @@ -15,15 +21,40 @@ import keras.backend as K import numpy as np import tensorflow as tf from PIL import Image, ExifTags -# from keras.applications.vgg16 import preprocess_input from keras.layers import Dense, Activation from keras.models import Model from keras.preprocessing import image -from keras.utils import get_file from skimage.transform import resize from sklearn.metrics import pairwise_distances + from .align_face import align, aligner +from six.moves.urllib.request import urlopen + +if sys.version_info[0] == 2: + def urlretrieve(url, filename, reporthook=None, data=None): + def chunk_read(response, chunk_size=8192, reporthook=None): + content_type = response.info().get('Content-Length') + total_size = -1 + if content_type is not None: + total_size = int(content_type.strip()) + count = 0 + while True: + chunk = response.read(chunk_size) + count += 1 + if reporthook is not None: + reporthook(count, chunk_size, total_size) + if chunk: + yield chunk + else: + break + + response = urlopen(url, data) + with open(filename, 'wb') as fd: + for chunk in chunk_read(response, reporthook=reporthook): + fd.write(chunk) +else: + from six.moves.urllib.request import urlretrieve def clip_img(X, preprocessing='raw'): @@ -57,13 +88,16 @@ def load_image(path): class Faces(object): - def __init__(self, image_paths, sess): + def __init__(self, image_paths, sess, verbose=1): + self.verbose = verbose self.aligner = aligner(sess) self.org_faces = [] self.cropped_faces = [] self.cropped_faces_shape = [] self.cropped_index = [] self.callback_idx = [] + if verbose: + print("Identify {} images".format(len(image_paths))) for i, p in enumerate(image_paths): cur_img = load_image(p) self.org_faces.append(cur_img) @@ -73,6 +107,9 @@ class Faces(object): cur_shapes = [f.shape[:-1] for f in cur_faces] cur_faces_square = [] + if verbose: + print("Find {} face(s) in {}".format(len(cur_faces), p.split("/")[-1])) + for img in cur_faces: long_size = max([img.shape[1], img.shape[0]]) base = np.zeros((long_size, long_size, 3)) @@ -270,7 +307,7 @@ def imagenet_reverse_preprocessing(x, data_format=None): def reverse_process_cloaked(x, preprocess='imagenet'): - x = clip_img(x, preprocess) + # x = clip_img(x, preprocess) return reverse_preprocess(x, preprocess) @@ -286,17 +323,18 @@ def load_extractor(name): model_dir = os.path.join(os.path.expanduser('~'), '.fawkes') os.makedirs(model_dir, exist_ok=True) model_file = os.path.join(model_dir, "{}.h5".format(name)) + emb_file = os.path.join(model_dir, "{}_emb.p.gz".format(name)) if os.path.exists(model_file): model = keras.models.load_model(model_file) else: get_file("{}.h5".format(name), "http://sandlab.cs.uchicago.edu/fawkes/files/{}.h5".format(name), cache_dir=model_dir, cache_subdir='') + model = keras.models.load_model(model_file) + if not os.path.exists(emb_file): get_file("{}_emb.p.gz".format(name), "http://sandlab.cs.uchicago.edu/fawkes/files/{}_emb.p.gz".format(name), cache_dir=model_dir, cache_subdir='') - model = keras.models.load_model(model_file) - if hasattr(model.layers[-1], "activation") and model.layers[-1].activation == "softmax": raise Exception( "Given extractor's last layer is softmax, need to remove the top layers to make it into a feature extractor") @@ -404,12 +442,18 @@ def select_target_label(imgs, feature_extractors_ls, feature_extractors_names, m max_id = np.argmax(max_sum) target_data_id = paths[int(max_id)] - image_dir = os.path.join(model_dir, "target_data/{}/*".format(target_data_id)) - if not os.path.exists(image_dir): - get_file("{}.h5".format(name), "http://sandlab.cs.uchicago.edu/fawkes/files/target_images".format(name), - cache_dir=model_dir, cache_subdir='') + image_dir = os.path.join(model_dir, "target_data/{}".format(target_data_id)) + # if not os.path.exists(image_dir): + os.makedirs(os.path.join(model_dir, "target_data"), exist_ok=True) + os.makedirs(image_dir, exist_ok=True) + for i in range(10): + if os.path.exists(os.path.join(model_dir, "target_data/{}/{}.jpg".format(target_data_id, i))): + continue + get_file("{}.jpg".format(i), + "http://sandlab.cs.uchicago.edu/fawkes/files/target_data/{}/{}.jpg".format(target_data_id, i), + cache_dir=model_dir, cache_subdir='target_data/{}/'.format(target_data_id)) - image_paths = glob.glob(image_dir) + image_paths = glob.glob(image_dir + "/*.jpg") target_images = [image.img_to_array(image.load_img(cur_path)) for cur_path in image_paths] @@ -424,6 +468,107 @@ def select_target_label(imgs, feature_extractors_ls, feature_extractors_names, m target_images = random.sample(target_images, len(imgs)) return np.array(target_images) + +def get_file(fname, + origin, + untar=False, + md5_hash=None, + file_hash=None, + cache_subdir='datasets', + hash_algorithm='auto', + extract=False, + archive_format='auto', + cache_dir=None): + if cache_dir is None: + cache_dir = os.path.join(os.path.expanduser('~'), '.keras') + if md5_hash is not None and file_hash is None: + file_hash = md5_hash + hash_algorithm = 'md5' + datadir_base = os.path.expanduser(cache_dir) + if not os.access(datadir_base, os.W_OK): + datadir_base = os.path.join('/tmp', '.keras') + datadir = os.path.join(datadir_base, cache_subdir) + _makedirs_exist_ok(datadir) + + if untar: + untar_fpath = os.path.join(datadir, fname) + fpath = untar_fpath + '.tar.gz' + else: + fpath = os.path.join(datadir, fname) + + download = False + if not os.path.exists(fpath): + download = True + + if download: + error_msg = 'URL fetch failure on {}: {} -- {}' + dl_progress = None + try: + try: + urlretrieve(origin, fpath, dl_progress) + except HTTPError as e: + raise Exception(error_msg.format(origin, e.code, e.msg)) + except URLError as e: + raise Exception(error_msg.format(origin, e.errno, e.reason)) + except (Exception, KeyboardInterrupt) as e: + if os.path.exists(fpath): + os.remove(fpath) + raise + # ProgressTracker.progbar = None + + if untar: + if not os.path.exists(untar_fpath): + _extract_archive(fpath, datadir, archive_format='tar') + return untar_fpath + + if extract: + _extract_archive(fpath, datadir, archive_format) + + return fpath + + +def _extract_archive(file_path, path='.', archive_format='auto'): + if archive_format is None: + return False + if archive_format == 'auto': + archive_format = ['tar', 'zip'] + if isinstance(archive_format, six.string_types): + archive_format = [archive_format] + + for archive_type in archive_format: + if archive_type == 'tar': + open_fn = tarfile.open + is_match_fn = tarfile.is_tarfile + if archive_type == 'zip': + open_fn = zipfile.ZipFile + is_match_fn = zipfile.is_zipfile + + if is_match_fn(file_path): + with open_fn(file_path) as archive: + try: + archive.extractall(path) + except (tarfile.TarError, RuntimeError, KeyboardInterrupt): + if os.path.exists(path): + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + raise + return True + return False + + +def _makedirs_exist_ok(datadir): + if six.PY2: + # Python 2 doesn't have the exist_ok arg, so we try-except here. + try: + os.makedirs(datadir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + else: + os.makedirs(datadir, exist_ok=True) # pylint: disable=unexpected-keyword-arg + # class CloakData(object): # def __init__(self, protect_directory=None, img_shape=(224, 224)): # diff --git a/fawkes_dev/azure.py b/fawkes_dev/azure.py index a0f3149..79312f7 100644 --- a/fawkes_dev/azure.py +++ b/fawkes_dev/azure.py @@ -1,14 +1,28 @@ - -import http.client, urllib.request, urllib.parse, urllib.error +import http.client import json +import random import time +import urllib.error +import urllib.parse +import urllib.request + +import requests + +# Face API Key and Endpoint +f = open('api_key.txt', 'r') +data = f.read().split("\n") +subscription_key = data[0] +uri_base = data[1] + +cloak_image_base = 'http://sandlab.cs.uchicago.edu/fawkes/files/cloak/{}_ultra_cloaked.png' +original_image_base = 'http://sandlab.cs.uchicago.edu/fawkes/files/cloak/{}.png' -#Face API Key and Endpoint -subscription_key = 'e127e26e4d534e2bad6fd9ca06145302' -uri_base = 'eastus.api.cognitive.microsoft.com' -# uri_base = 'https://shawn.cognitiveservices.azure.com/' def detect_face(image_url): + r = requests.get(image_url) + if r.status_code != 200: + return None + headers = { # Request headers 'Content-Type': 'application/json', @@ -32,6 +46,7 @@ def detect_face(image_url): conn.request("POST", "/face/v1.0/detect?%s" % params, body, headers) response = conn.getresponse() data = json.loads(response.read()) + print(data) conn.close() return data[0]["faceId"] @@ -102,12 +117,16 @@ def create_personId(personGroupId, personName): conn.request("POST", "/face/v1.0/persongroups/{}/persons?%s".format(personGroupId) % params, body, headers) response = conn.getresponse() data = json.loads(response.read()) - print(data) + # print(data) conn.close() return data["personId"] def add_persistedFaceId(personGroupId, personId, image_url): + r = requests.get(image_url) + if r.status_code != 200: + return None + headers = { 'Content-Type': 'application/json', 'Ocp-Apim-Subscription-Key': subscription_key, @@ -123,11 +142,14 @@ def add_persistedFaceId(personGroupId, personId, image_url): }) conn = http.client.HTTPSConnection(uri_base) - conn.request("POST", "/face/v1.0/persongroups/{}/persons/{}/persistedFaces?%s".format(personGroupId, personId) % params, body, headers) + conn.request("POST", + "/face/v1.0/persongroups/{}/persons/{}/persistedFaces?%s".format(personGroupId, personId) % params, + body, headers) response = conn.getresponse() data = json.loads(response.read()) - print(data) conn.close() + if "persistedFaceId" not in data: + return None return data["persistedFaceId"] @@ -161,7 +183,8 @@ def get_personGroupPerson(personGroupId, personId): body = json.dumps({}) conn = http.client.HTTPSConnection(uri_base) - conn.request("GET", "/face/v1.0/persongroups/{}/persons/{}?%s".format(personGroupId, personId) % params, body, headers) + conn.request("GET", "/face/v1.0/persongroups/{}/persons/{}?%s".format(personGroupId, personId) % params, body, + headers) response = conn.getresponse() data = json.loads(response.read()) print(data) @@ -208,6 +231,7 @@ def eval(original_faceIds, personGroupId, protect_personId): conn.close() face = data[0] + print(face) if len(face["candidates"]) and face["candidates"][0]["personId"] == protect_personId: return True else: @@ -225,48 +249,20 @@ def delete_personGroupPerson(personGroupId, personId): body = json.dumps({}) conn = http.client.HTTPSConnection(uri_base) - conn.request("DELETE", "/face/v1.0/persongroups/{}/persons/{}?%s".format(personGroupId, personId) % params, body, headers) + conn.request("DELETE", "/face/v1.0/persongroups/{}/persons/{}?%s".format(personGroupId, personId) % params, body, + headers) response = conn.getresponse() data = response.read() print(data) conn.close() -def add_protect_person(personGroupId, name): - personId = create_personId(personGroupId, name) - for idx in range(72): - cloaked_image_url = "https://super.cs.uchicago.edu/~shawn/cloaked/{}_c.png".format(idx) - add_persistedFaceId(personGroupId, personId, cloaked_image_url) - - -def add_sybil_person(personGroupId, name): - personId = create_personId(personGroupId, name) - for idx in range(82): - try: - cloaked_image_url = "https://super.cs.uchicago.edu/~shawn/sybils/{}_c.png".format(idx) - add_persistedFaceId(personGroupId, personId, cloaked_image_url) - except: - print(idx) - - -def add_other_person(personGroupId): - for idx_person in range(65): - personId = create_personId(personGroupId, str(idx_person)) - for idx_image in range(90): - try: - image_url = "https://super.cs.uchicago.edu/~shawn/train/{}/{}.png".format(idx_person, idx_image) - add_persistedFaceId(personGroupId, personId, image_url) - except: - print(idx_person, idx_image) - - def get_trainStatus(personGroupId): headers = { 'Ocp-Apim-Subscription-Key': subscription_key, } - params = urllib.parse.urlencode({ - }) + params = urllib.parse.urlencode({}) body = json.dumps({}) @@ -278,48 +274,75 @@ def get_trainStatus(personGroupId): conn.close() -def test_original(): - personGroupId = 'pubfig' - # create_personGroupId(personGroupId, 'pubfig') - # add protect person - protect_personId = 'd3df3012-6f3f-4c1b-b86d-55e91a352e01' - #protect_personId = create_personId(personGroupId, 'Emily') - #for idx in range(50): - # image_url = "https://super.cs.uchicago.edu/~shawn/cloaked/{}_o.png".format(idx) - # add_persistedFaceId(personGroupId, protect_personId, image_url) +def test_cloak(): + NUM_TRAIN = 10 + total_idx = range(0, 82) + TRAIN_RANGE = random.sample(total_idx, NUM_TRAIN) + + TEST_RANGE = TRAIN_RANGE + + personGroupId = 'all' + + # delete_personGroup(personGroupId) + create_personGroupId(personGroupId, personGroupId) + + with open("protect_personId.txt", 'r') as f: + protect_personId = f.read() + print(protect_personId) + delete_personGroupPerson(personGroupId, protect_personId) + + protect_personId = create_personId(personGroupId, 'Emily') + with open("protect_personId.txt", 'w') as f: + f.write(protect_personId) + + print("Created protect personId: {}".format(protect_personId)) + for idx in TRAIN_RANGE: + image_url = cloak_image_base.format(idx) + r = add_persistedFaceId(personGroupId, protect_personId, image_url) + if r is not None: + print("Added {}".format(idx)) + else: + print("Unable to add {}-th image of protect person".format(idx)) # add other people - #for idx_person in range(65): - # personId = create_personId(personGroupId, str(idx_person)) - # for idx_image in range(50): - # try: - # image_url = "https://super.cs.uchicago.edu/~shawn/train/{}/{}.png".format(idx_person, idx_image) - # add_persistedFaceId(personGroupId, personId, image_url) - # except: - # print(idx_person, idx_image) - + for idx_person in range(500): + personId = create_personId(personGroupId, str(idx_person)) + print("Created personId: {}".format(idx_person)) + for idx_image in range(10): + image_url = "http://sandlab.cs.uchicago.edu/fawkes/files/target_data/{}/{}.jpg".format( + idx_person, idx_image) + r = add_persistedFaceId(personGroupId, personId, image_url) + if r is not None: + print("Added {}".format(idx_image)) + else: + print("Unable to add {}-th image".format(idx_image)) # train model based on personGroup - #train_personGroup(personGroupId) - #time.sleep(3) - #get_trainStatus(personGroupId) - #list_personGroupPerson(personGroupId) + train_personGroup(personGroupId) + time.sleep(4) + get_trainStatus(personGroupId) + # list_personGroupPerson(personGroupId) - idx_range = range(50, 82) + # test original image + idx_range = TEST_RANGE acc = 0. - + tot = 0. for idx in idx_range: - original_image_url = "https://super.cs.uchicago.edu/~shawn/cloaked/{}_o.png".format(idx) + original_image_url = original_image_base.format(idx) faceId = detect_face(original_image_url) + if faceId is None: + print("{} does not exist".format(idx)) + continue original_faceIds = [faceId] # verify res = eval(original_faceIds, personGroupId, protect_personId) if res: acc += 1. + tot += 1. - acc /= len(idx_range) - print(acc) # 1.0 + acc /= tot + print(acc) # 1.0 def list_personGroups(): @@ -358,42 +381,37 @@ def delete_personGroup(personGroupId): conn.close() - def main(): + test_cloak() + # delete_personGroup('cloaking') # delete_personGroup('cloaking-emily') # delete_personGroup('pubfig') # list_personGroups() # exit() - personGroupId = 'cloaking' + # personGroupId = 'cloaking' # create_personGroupId(personGroupId, 'cloaking') - list_personGroups() - exit() - #delete_personGroupPerson(personGroupId, '0ac606cd-24b3-440f-866a-31adf2a1b446') - #add_protect_person(personGroupId, 'Emily') - #personId = create_personId(personGroupId, 'Emily') - #add_sybil_person(personGroupId, 'sybil') - protect_personId = '6c5a71eb-f39a-4570-b3f5-72cca3ab5a6b' - #delete_personGroupPerson(personGroupId, protect_personId) - #add_protect_person(personGroupId, 'Emily') - - # train model based on personGroup - #train_personGroup(personGroupId) - get_trainStatus(personGroupId) - #add_other_person(personGroupId) - #list_personGroupPerson(personGroupId) - #delete_personGroupPerson(personGroupId, '80e32c80-bc69-416a-9dff-c8d42d7a3301') - - idx_range = range(72, 82) - original_faceIds = [] - for idx in idx_range: - original_image_url = "https://super.cs.uchicago.edu/~shawn/cloaked/{}_o.png".format(idx) - faceId = detect_face(original_image_url) - original_faceIds.append(faceId) - - # verify - eval(original_faceIds, personGroupId, protect_personId) + # delete_personGroupPerson(personGroupId, '0ac606cd-24b3-440f-866a-31adf2a1b446') + # add_protect_person(personGroupId, 'Emily') + # protect_personId = create_personId(personGroupId, 'Emily') + # add_sybil_person(personGroupId, 'sybil') + # + # # train model based on personGroup + # train_personGroup(personGroupId) + # get_trainStatus(personGroupId) + # add_other_person(personGroupId) + # list_personGroupPerson(personGroupId) + # + # idx_range = range(72, 82) + # original_faceIds = [] + # for idx in idx_range: + # original_image_url = "https://super.cs.uchicago.edu/~shawn/cloaked/{}_o.png".format(idx) + # faceId = detect_face(original_image_url) + # original_faceIds.append(faceId) + # + # # verify + # eval(original_faceIds, personGroupId, protect_personId) if __name__ == '__main__': - main() \ No newline at end of file + test_cloak()