first commit
This commit is contained in:
1
app/lib/face/.pydio
Normal file
1
app/lib/face/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
af6921d2-187d-4cc8-b5eb-2db957efd2f6
|
||||
125
app/lib/face/ImagePro.py
Executable file
125
app/lib/face/ImagePro.py
Executable file
@@ -0,0 +1,125 @@
|
||||
import base64
|
||||
import io
|
||||
import os
|
||||
from PIL import Image, ImageColor
|
||||
|
||||
|
||||
class ImageProCls:
|
||||
base64FilePath=None
|
||||
|
||||
@staticmethod
|
||||
def humanbody_blending_with_image(input_image, gray_image, bg_image):
|
||||
"""
|
||||
|
||||
:param input_image: the PIL.Image instance, the source humanbody image
|
||||
:param gray_image: the PIL.Image instance, it is created from api base64 result, a gray image
|
||||
:param bg_image: the PIL.Image instance, the background image you want to replace
|
||||
:return: the PIL.Image instance is blending with humanbody
|
||||
|
||||
notes: you should close the return object after you leave
|
||||
"""
|
||||
input_width, input_height = input_image.size
|
||||
bg_width, bg_height = bg_image.size
|
||||
|
||||
input_aspect_ratio = input_width / float(input_height)
|
||||
bg_aspect_ratio = bg_width / float(bg_height)
|
||||
|
||||
if bg_aspect_ratio > input_aspect_ratio:
|
||||
target_width, target_height = int(bg_height * input_aspect_ratio), bg_height
|
||||
else:
|
||||
target_width, target_height = bg_width, int(bg_width / input_aspect_ratio)
|
||||
|
||||
crop_image = bg_image.crop((0, 0, 0+target_width, 0+target_height))
|
||||
new_image = crop_image.resize((input_width, input_height))
|
||||
crop_image.close()
|
||||
|
||||
for x in range(0, input_width):
|
||||
for y in range(0, input_height):
|
||||
coord = (x, y)
|
||||
gray_pixel_value = gray_image.getpixel(coord)
|
||||
input_rgb_color = input_image.getpixel(coord)
|
||||
bg_rgb_color = new_image.getpixel(coord)
|
||||
|
||||
confidence = gray_pixel_value / 255.0
|
||||
alpha = confidence
|
||||
|
||||
R = input_rgb_color[0] * alpha + bg_rgb_color[0] * (1 - alpha)
|
||||
G = input_rgb_color[1] * alpha + bg_rgb_color[1] * (1 - alpha)
|
||||
B = input_rgb_color[2] * alpha + bg_rgb_color[2] * (1 - alpha)
|
||||
|
||||
R = max(0, min(int(R), 255))
|
||||
G = max(0, min(int(G), 255))
|
||||
B = max(0, min(int(B), 255))
|
||||
|
||||
new_image.putpixel(coord, (R, G, B))
|
||||
|
||||
return new_image
|
||||
|
||||
@staticmethod
|
||||
def humanbody_blending_with_color(input_image, gray_image, bg_color):
|
||||
"""
|
||||
:param input_image: the PIL.Image instance
|
||||
:param gray_image: the PIL.Image instance, it is created from api base64 result, it is a gray image
|
||||
:param bg_color: a color string value, such as '#FFFFFF'
|
||||
:return: PIL.Image instance
|
||||
|
||||
notes: you should close the return object after you leave
|
||||
"""
|
||||
input_width, input_height = input_image.size
|
||||
bg_rgb_color = ImageColor.getrgb(bg_color)
|
||||
|
||||
new_image = Image.new("RGB", input_image.size, bg_color)
|
||||
|
||||
for x in range(0, input_width):
|
||||
for y in range(0, input_height):
|
||||
coord = (x, y)
|
||||
gray_pixel_value = gray_image.getpixel(coord)
|
||||
input_rgb_color = input_image.getpixel(coord)
|
||||
|
||||
confidence = gray_pixel_value / 255.0
|
||||
alpha = confidence
|
||||
|
||||
R = input_rgb_color[0] * alpha + bg_rgb_color[0] * (1 - alpha)
|
||||
G = input_rgb_color[1] * alpha + bg_rgb_color[1] * (1 - alpha)
|
||||
B = input_rgb_color[2] * alpha + bg_rgb_color[2] * (1 - alpha)
|
||||
|
||||
R = max(0, min(int(R), 255))
|
||||
G = max(0, min(int(G), 255))
|
||||
B = max(0, min(int(B), 255))
|
||||
|
||||
new_image.putpixel(coord, (R, G, B))
|
||||
|
||||
return new_image
|
||||
|
||||
@staticmethod
|
||||
def getSegmentImg(filePath):
|
||||
input_file = ''
|
||||
with open(filePath, 'r') as f:
|
||||
input_file = f.read()
|
||||
input_file = base64.b64decode(input_file)
|
||||
|
||||
gray_image = Image.open(io.BytesIO(input_file))
|
||||
input_image = Image.open('./imgResource/segment.jpg', 'r')
|
||||
|
||||
new_image = ImageProCls.humanbody_blending_with_color(input_image, gray_image, '#FFFFFF')
|
||||
new_image.save('./imgResource/resultImg.jpg')
|
||||
print('-' * 60)
|
||||
print('结果已经生成,生成文件名:resultImg.jpg,请在imgResource/目录下查看')
|
||||
if os.path.exists(filePath):
|
||||
os.remove(filePath)
|
||||
f.close()
|
||||
new_image.close()
|
||||
input_image.close()
|
||||
gray_image.close()
|
||||
|
||||
@staticmethod
|
||||
def getMergeImg(base64Str):
|
||||
imgdata = base64.b64decode(base64Str)
|
||||
file = open('./imgResource/MergeResultImg.jpg', 'wb')
|
||||
file.write(imgdata)
|
||||
file.close()
|
||||
print('结果已经生成,生成文件名:MergeResultImg.jpg,请在imgResource/目录下查看')
|
||||
|
||||
|
||||
|
||||
|
||||
0
app/lib/face/__init__.py
Executable file
0
app/lib/face/__init__.py
Executable file
1
app/lib/face/__pycache__/.pydio
Normal file
1
app/lib/face/__pycache__/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2cd2cff3-ad8d-41e2-a0a8-ef9e540f2339
|
||||
BIN
app/lib/face/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
app/lib/face/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/lib/face/__pycache__/__init__.cpython-38.pyc
Executable file
BIN
app/lib/face/__pycache__/__init__.cpython-38.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/__init__.cpython-39.pyc
Executable file
BIN
app/lib/face/__pycache__/__init__.cpython-39.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/compat.cpython-311.pyc
Normal file
BIN
app/lib/face/__pycache__/compat.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/lib/face/__pycache__/compat.cpython-38.pyc
Executable file
BIN
app/lib/face/__pycache__/compat.cpython-38.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/compat.cpython-39.pyc
Executable file
BIN
app/lib/face/__pycache__/compat.cpython-39.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/facepp.cpython-311.pyc
Normal file
BIN
app/lib/face/__pycache__/facepp.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/lib/face/__pycache__/facepp.cpython-38.pyc
Executable file
BIN
app/lib/face/__pycache__/facepp.cpython-38.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/facepp.cpython-39.pyc
Executable file
BIN
app/lib/face/__pycache__/facepp.cpython-39.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/structures.cpython-311.pyc
Normal file
BIN
app/lib/face/__pycache__/structures.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/lib/face/__pycache__/structures.cpython-38.pyc
Executable file
BIN
app/lib/face/__pycache__/structures.cpython-38.pyc
Executable file
Binary file not shown.
BIN
app/lib/face/__pycache__/structures.cpython-39.pyc
Executable file
BIN
app/lib/face/__pycache__/structures.cpython-39.pyc
Executable file
Binary file not shown.
64
app/lib/face/compat.py
Executable file
64
app/lib/face/compat.py
Executable file
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This module handles import compatibility issues between Python 2 and
|
||||
Python 3.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import random
|
||||
import string
|
||||
|
||||
# -------
|
||||
# Pythons
|
||||
# -------
|
||||
|
||||
# Syntax sugar.
|
||||
_ver = sys.version_info
|
||||
|
||||
#: Python 2.x?
|
||||
is_py2 = (_ver[0] == 2)
|
||||
|
||||
#: Python 3.x?
|
||||
is_py3 = (_ver[0] == 3)
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
# ---------
|
||||
# Specifics
|
||||
# ---------
|
||||
|
||||
if is_py2:
|
||||
from urllib2 import Request, urlopen, HTTPError, URLError
|
||||
builtin_str = str
|
||||
bytes = str
|
||||
str = unicode
|
||||
basestring = basestring
|
||||
numeric_types = (int, long, float)
|
||||
integer_types = (int, long)
|
||||
|
||||
elif is_py3:
|
||||
from urllib.request import Request, urlopen
|
||||
from urllib.error import HTTPError, URLError
|
||||
builtin_str = str
|
||||
str = str
|
||||
bytes = bytes
|
||||
basestring = (str, bytes)
|
||||
numeric_types = (int, float)
|
||||
integer_types = (int,)
|
||||
|
||||
|
||||
def enc(x):
|
||||
if isinstance(x, str):
|
||||
return x.encode('utf-8')
|
||||
elif isinstance(x, numeric_types):
|
||||
return str(x).encode('utf-8')
|
||||
return x
|
||||
|
||||
|
||||
def choose_boundary():
|
||||
rand_letters = ''.join(random.sample(string.ascii_letters+string.digits, 15))
|
||||
return '{ch}{flag}{rand}'.format(ch='-'*6, flag='PylibFormBoundary', rand=rand_letters)
|
||||
320
app/lib/face/facepp.py
Executable file
320
app/lib/face/facepp.py
Executable file
@@ -0,0 +1,320 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""a simple facepp sdk
|
||||
usage:
|
||||
api = API(key, secret)
|
||||
api.detect(img = File('/tmp/test.jpg'))
|
||||
"""
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import json
|
||||
import os.path
|
||||
import itertools
|
||||
import mimetypes
|
||||
import time
|
||||
from collections.abc import Iterable
|
||||
from app.lib.face.structures import ObjectDict
|
||||
from app.lib.face.compat import (basestring, str, numeric_types, enc, choose_boundary,
|
||||
Request, urlopen, HTTPError, URLError)
|
||||
|
||||
import ssl
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
__all__ = ['File', 'APIError', 'API']
|
||||
|
||||
DEBUG_LEVEL = 1
|
||||
|
||||
# 添加API Key API Secret
|
||||
API_KEY = "xfXREfL_pXgnqK2GedOunNPN2MFYSsPR"
|
||||
API_SECRET = "x0PGyvHoVSjX19KlkjH1Ct7Md5wxz8aV"
|
||||
|
||||
|
||||
class File(object):
|
||||
|
||||
"""an object representing a local file"""
|
||||
path = None
|
||||
content = None
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self._get_content()
|
||||
|
||||
def _get_content(self):
|
||||
"""read image content"""
|
||||
|
||||
if os.path.getsize(self.path) > 2 * 1024 * 1024:
|
||||
raise APIError(-1, None, 'image file size too large')
|
||||
else:
|
||||
with open(self.path, 'rb') as f:
|
||||
self.content = f.read()
|
||||
|
||||
def get_filename(self):
|
||||
return os.path.basename(self.path)
|
||||
|
||||
|
||||
class APIError(Exception):
|
||||
code = None
|
||||
"""HTTP status code"""
|
||||
|
||||
url = None
|
||||
"""request URL"""
|
||||
|
||||
body = None
|
||||
"""server response body; or detailed error information"""
|
||||
|
||||
def __init__(self, code, url, body):
|
||||
self.code = code
|
||||
self.url = url
|
||||
self.body = body
|
||||
|
||||
def __str__(self):
|
||||
return 'code={s.code}\nurl={s.url}\n{s.body}'.format(s=self)
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
class API(object):
|
||||
key = None
|
||||
secret = None
|
||||
server = 'https://api-cn.faceplusplus.com'
|
||||
|
||||
decode_result = True
|
||||
timeout = None
|
||||
max_retries = None
|
||||
retry_delay = None
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
:param srv: The API server address
|
||||
:param decode_result: whether to json_decode the result
|
||||
:param timeout: HTTP request timeout in seconds
|
||||
:param max_retries: maximal number of retries after catching URL error
|
||||
or socket error
|
||||
:param retry_delay: time to sleep before retrying
|
||||
"""
|
||||
if len(API_KEY)==0 or len(API_SECRET)==0:
|
||||
print('\n'+'请在'+os.path.realpath(__file__)+'文件中填写正确的API_KEY和API_SECRET'+'\n')
|
||||
exit(1)
|
||||
|
||||
self.key = API_KEY
|
||||
self.secret = API_SECRET
|
||||
|
||||
srv = None
|
||||
decode_result = True
|
||||
timeout = 30
|
||||
max_retries = 10
|
||||
retry_delay = 5
|
||||
if srv:
|
||||
self.server = srv
|
||||
self.decode_result = decode_result
|
||||
assert timeout >= 0 or timeout is None
|
||||
assert max_retries >= 0
|
||||
self.timeout = timeout
|
||||
self.max_retries = max_retries
|
||||
self.retry_delay = retry_delay
|
||||
|
||||
_setup_apiobj(self, self, '', [])
|
||||
|
||||
def update_request(self, request):
|
||||
"""overwrite this function to update the request before sending it to
|
||||
server"""
|
||||
pass
|
||||
|
||||
|
||||
def _setup_apiobj(self, api, prefix, path):
|
||||
if self is not api:
|
||||
self._api = api
|
||||
self._urlbase = '{server}/{prefix}/{path}'.format(server=api.server, prefix=prefix, path='/'.join(path))
|
||||
|
||||
lvl = len(path)
|
||||
done = set()
|
||||
for prefix, paths in _APIS:
|
||||
for i in paths:
|
||||
if len(i) <= lvl:
|
||||
continue
|
||||
cur = i[lvl]
|
||||
if i[:lvl] == path and cur not in done:
|
||||
done.add(cur)
|
||||
setattr(self, cur, _APIProxy(api, prefix, i[:lvl + 1]))
|
||||
|
||||
|
||||
class _APIProxy(object):
|
||||
_api = None
|
||||
"""underlying :class:`API` object"""
|
||||
|
||||
_urlbase = None
|
||||
|
||||
def __init__(self, api, prefix, path):
|
||||
_setup_apiobj(self, api, prefix, path)
|
||||
|
||||
def __call__(self, *args, **kargs):
|
||||
if len(args):
|
||||
raise TypeError('Only keyword arguments are allowed')
|
||||
form = _MultiPartForm()
|
||||
|
||||
for (k, v) in kargs.items():
|
||||
if isinstance(v, File):
|
||||
form.add_file(k, v.get_filename(), v.content)
|
||||
|
||||
url = self._urlbase
|
||||
for k, v in self._mkarg(kargs).items():
|
||||
form.add_field(k, v)
|
||||
|
||||
body = form.bytes
|
||||
request = Request(url, data=body)
|
||||
request.add_header('Content-type', form.get_content_type())
|
||||
request.add_header('Content-length', str(len(body)))
|
||||
|
||||
self._api.update_request(request)
|
||||
|
||||
retry = self._api.max_retries
|
||||
while True:
|
||||
retry -= 1
|
||||
try:
|
||||
ret = urlopen(request, timeout=self._api.timeout).read()
|
||||
break
|
||||
except HTTPError as e:
|
||||
raise APIError(e.code, url, e.read())
|
||||
except (socket.error, URLError) as e:
|
||||
if retry < 0:
|
||||
raise e
|
||||
_print_debug('caught error: {}; retrying'.format(e))
|
||||
time.sleep(self._api.retry_delay)
|
||||
|
||||
if self._api.decode_result:
|
||||
try:
|
||||
ret = json.loads(ret, object_hook=ObjectDict)
|
||||
except:
|
||||
raise APIError(-1, url, 'json decode error, value={0!r}'.format(ret))
|
||||
return ret
|
||||
|
||||
def _mkarg(self, kargs):
|
||||
"""change the argument list (encode value, add api key/secret)
|
||||
:return: the new argument list"""
|
||||
|
||||
kargs = kargs.copy()
|
||||
kargs['api_key'] = self._api.key
|
||||
kargs['api_secret'] = self._api.secret
|
||||
for k, v in list(kargs.items()):
|
||||
if isinstance(v, Iterable) and not isinstance(v, basestring):
|
||||
kargs[k] = ','.join(v)
|
||||
elif isinstance(v, File) or v is None:
|
||||
del kargs[k]
|
||||
elif isinstance(v, numeric_types):
|
||||
kargs[k] = str(v)
|
||||
else:
|
||||
kargs[k] = v
|
||||
|
||||
return kargs
|
||||
|
||||
|
||||
class _MultiPartForm(object):
|
||||
|
||||
"""Accumulate the data to be used when posting a form."""
|
||||
|
||||
def __init__(self):
|
||||
self.form_fields = []
|
||||
self.files = []
|
||||
self.boundary = choose_boundary()
|
||||
|
||||
def get_content_type(self):
|
||||
return 'multipart/form-data; boundary={}'.format(self.boundary)
|
||||
|
||||
def add_field(self, name, value):
|
||||
"""Add a simple field to the form data."""
|
||||
self.form_fields.append((name, value))
|
||||
|
||||
def add_file(self, fieldname, filename, content, mimetype=None):
|
||||
"""Add a file to be uploaded."""
|
||||
if mimetype is None:
|
||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
self.files.append((fieldname, filename, mimetype, content))
|
||||
|
||||
@property
|
||||
def bytes(self):
|
||||
"""Return a string(2.x) or bytes(3.x) representing the form data, including attached files."""
|
||||
# Build a list of lists, each containing "lines" of the
|
||||
# request. Each part is separated by a boundary string.
|
||||
# Once the list is built, return a string where each
|
||||
# line is separated by '\r\n'.
|
||||
parts = []
|
||||
part_boundary = "--" + self.boundary
|
||||
|
||||
# Add the form fields
|
||||
parts.extend(
|
||||
[part_boundary,
|
||||
'Content-Disposition: form-data; name="{}"'.format(name), '', value]
|
||||
for name, value in self.form_fields
|
||||
)
|
||||
|
||||
# Add the files to upload
|
||||
parts.extend(
|
||||
[part_boundary,
|
||||
'Content-Disposition: form-data; name="{}"; filename="{}"'.format(field_name, filename),
|
||||
'Content-Type: {}'.format(content_type),
|
||||
'',
|
||||
body,
|
||||
]
|
||||
for field_name, filename, content_type, body in self.files
|
||||
)
|
||||
|
||||
# Flatten the list and add closing boundary marker,
|
||||
# then return CR+LF separated data
|
||||
flattened = list(itertools.chain(*parts))
|
||||
flattened.append(part_boundary + '--')
|
||||
flattened.append('')
|
||||
return b'\r\n'.join(enc(x) for x in flattened)
|
||||
|
||||
|
||||
def _print_debug(msg):
|
||||
if DEBUG_LEVEL:
|
||||
sys.stderr.write(str(msg) + '\n')
|
||||
|
||||
|
||||
_APIS = [
|
||||
{
|
||||
'prefix': 'facepp/v3',
|
||||
'paths': [
|
||||
'/detect',
|
||||
'/compare',
|
||||
'/search',
|
||||
'/faceset/create',
|
||||
'/faceset/addface',
|
||||
'/faceset/removeface',
|
||||
'/faceset/update',
|
||||
'/faceset/getdetail',
|
||||
'/faceset/delete',
|
||||
'/faceset/getfacesets',
|
||||
'/face/analyze',
|
||||
'/face/getdetail',
|
||||
'/face/setuserid',
|
||||
],
|
||||
},
|
||||
{
|
||||
'prefix': 'humanbodypp/v1',
|
||||
'paths': [
|
||||
'/detect',
|
||||
'/segment',
|
||||
]
|
||||
},
|
||||
{
|
||||
'prefix': 'cardpp/v1',
|
||||
'paths': [
|
||||
'/ocridcard',
|
||||
'/ocrdriverlicense',
|
||||
'/ocrvehiclelicense',
|
||||
'/ocrbankcard',
|
||||
]
|
||||
},
|
||||
{
|
||||
'prefix': 'imagepp/v1',
|
||||
'paths': [
|
||||
'/licenseplate',
|
||||
'/recognizetext',
|
||||
'/mergeface'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
_APIS = [(i['prefix'], [p.split('/')[1:] for p in i['paths']]) for i in _APIS]
|
||||
19
app/lib/face/structures.py
Executable file
19
app/lib/face/structures.py
Executable file
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
class ObjectDict(dict):
|
||||
"""Dictionary object for json decode"""
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name in self:
|
||||
return self[name]
|
||||
else:
|
||||
raise AttributeError("No such attribute: " + name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
self[name] = value
|
||||
|
||||
def __delattr__(self, name):
|
||||
if name in self:
|
||||
del self[name]
|
||||
else:
|
||||
raise AttributeError("No such attribute: " + name)
|
||||
Reference in New Issue
Block a user