summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2019-01-13 21:06:51 +0100
committerJules Laplace <julescarbon@gmail.com>2019-01-13 21:06:51 +0100
commitb4ed297a6dc73ec5f5cf2772ca1b754ea3f98cae (patch)
tree59798cf83e459a7f543515f54af2d7898257f44a
parent6710b9f7f223acd01ac82171d9f9f4eb577f5885 (diff)
basic blurring applet
-rw-r--r--.gitignore1
-rw-r--r--client/common/upload.helpers.js27
-rw-r--r--client/faceAnalysis/faceAnalysis.actions.js21
-rw-r--r--client/faceAnalysis/faceAnalysis.container.js2
-rw-r--r--client/faceAnalysis/faceAnalysis.query.js12
-rw-r--r--client/faceAnalysis/faceAnalysis.reducer.js8
-rw-r--r--client/faceAnalysis/faceAnalysis.result.js26
-rw-r--r--megapixels/app/server/api.py1
-rw-r--r--megapixels/app/server/api_task.py10
-rw-r--r--megapixels/app/server/tasks/blur.py67
-rw-r--r--megapixels/app/server/tasks/fullmonte.py6
-rw-r--r--megapixels/app/server/tasks/sleep.py2
-rw-r--r--megapixels/app/settings/app_cfg.py1
-rw-r--r--site/assets/css/applets.css17
14 files changed, 132 insertions, 69 deletions
diff --git a/.gitignore b/.gitignore
index 30c69fbe..b800c5b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -158,4 +158,5 @@ scraper/reports/papers/
.creds
site/assets/js/dist/
+site/public/user_content
diff --git a/client/common/upload.helpers.js b/client/common/upload.helpers.js
index eb42a993..4b38fb09 100644
--- a/client/common/upload.helpers.js
+++ b/client/common/upload.helpers.js
@@ -1,6 +1,6 @@
import ExifReader from 'exifreader'
-export const MAX_SIDE = 300
+export const MAX_SIDE = 256
function base64ToUint8Array(string, start, finish) {
start = start || 0
@@ -110,16 +110,17 @@ export function renderToCanvas(img, options) {
options = options || {}
// Canvas max size for any side
- const maxSize = MAX_SIDE
+ const maxSide = MAX_SIDE
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const initialScale = options.scale || 1
// Scale to needed to constrain canvas to max size
- let scale = getScale(img.width * initialScale, img.height * initialScale, maxSize, maxSize, true)
+ let scale = getScale(img.naturalWidth * initialScale, img.naturalHeight * initialScale, maxSide, maxSide, true)
+ console.log(scale)
// Still need to apply the user defined scale
scale *= initialScale
- canvas.width = Math.round(img.width * scale)
- canvas.height = Math.round(img.height * scale)
+ canvas.width = Math.round(img.naturalWidth * scale)
+ canvas.height = Math.round(img.naturalHeight * scale)
const { correctOrientation } = options
const jpeg = !!img.src.match(/data:image\/jpeg|\.jpeg$|\.jpg$/i)
const hasDataURI = !!img.src.match(/^data:/)
@@ -144,12 +145,12 @@ export function renderToCanvas(img, options) {
export function renderThumbnail(img) {
const resized = renderToCanvas(img, { correctOrientation: true })
- const canvas = document.createElement('canvas') // document.querySelector('#user_photo_canvas')
- const ctx = canvas.getContext('2d')
- ctx.fillStyle = 'black'
- ctx.fillRect(0, 0, MAX_SIDE, MAX_SIDE)
- const xOffset = (MAX_SIDE - resized.width) / 2
- const yOffset = (MAX_SIDE - resized.height) / 2
- ctx.drawImage(resized, xOffset, yOffset)
- return canvas
+ // const canvas = document.createElement('canvas') // document.querySelector('#user_photo_canvas')
+ // const ctx = canvas.getContext('2d')
+ // ctx.fillStyle = 'black'
+ // ctx.fillRect(0, 0, MAX_SIDE, MAX_SIDE)
+ // const xOffset = (MAX_SIDE - resized.width) / 2
+ // const yOffset = (MAX_SIDE - resized.height) / 2
+ // ctx.drawImage(resized, xOffset, yOffset, resized.width, resized.height)
+ return resized
}
diff --git a/client/faceAnalysis/faceAnalysis.actions.js b/client/faceAnalysis/faceAnalysis.actions.js
index 860d3292..f8d8973f 100644
--- a/client/faceAnalysis/faceAnalysis.actions.js
+++ b/client/faceAnalysis/faceAnalysis.actions.js
@@ -16,17 +16,20 @@ export const publicUrl = {
// standard loading events
const loading = (tag, offset) => ({
+ ts: Date.now(),
type: types.faceAnalysis.loading,
tag,
offset
})
const loaded = (tag, data, offset = 0) => ({
+ ts: Date.now(),
type: types.faceAnalysis.loaded,
tag,
data,
offset
})
const polled = (data, offset = 0) => ({
+ ts: Date.now(),
type: types.faceAnalysis.poll,
data,
offset
@@ -52,13 +55,19 @@ let pollTimeout = null
export const poll = (payload, taskURL) => dispatch => {
clearTimeout(pollTimeout)
- console.log('polling...')
+ // console.log('polling...')
get(taskURL)
.then(data => {
- console.log('poll', data)
+ // console.log('poll', data)
dispatch(polled(data))
- if (data.state !== 'error' && data.state !== 'complete') {
- pollTimeout = setTimeout(() => poll(payload, taskURL), POLL_DELAY)
+ // console.log(data.state)
+ if (data.state === 'COMPLETE' || data.state === 'SUCCESS') {
+ console.log('complete!')
+ } else if (data.state === 'ERROR' || data.state === 'FAILURE') {
+ console.log('errorr!')
+ dispatch(error(data))
+ } else {
+ pollTimeout = setTimeout(() => poll(payload, taskURL)(dispatch), POLL_DELAY)
}
})
.catch(err => dispatch(error('result', err)))
@@ -71,8 +80,8 @@ export const upload = (payload, file) => dispatch => {
dispatch(loading(tag))
post(url.upload(), fd)
.then(data => {
- console.log('loaded!', tag, data)
- dispatch(loaded(tag, data))
+ // console.log('loaded!', tag, data)
+ dispatch(polled(tag, data))
const { result, taskURL } = data
if (result && taskURL) {
poll(payload, taskURL)(dispatch)
diff --git a/client/faceAnalysis/faceAnalysis.container.js b/client/faceAnalysis/faceAnalysis.container.js
index a86bcaa4..24848455 100644
--- a/client/faceAnalysis/faceAnalysis.container.js
+++ b/client/faceAnalysis/faceAnalysis.container.js
@@ -12,7 +12,7 @@ class FaceAnalysisContainer extends Component {
const { payload } = this.props
// console.log(payload)
return (
- <div className='searchContainer'>
+ <div className='analysisContainer'>
<FaceAnalysisQuery payload={payload} />
<FaceAnalysisResult payload={payload} />
</div>
diff --git a/client/faceAnalysis/faceAnalysis.query.js b/client/faceAnalysis/faceAnalysis.query.js
index a79e3e78..33dd641f 100644
--- a/client/faceAnalysis/faceAnalysis.query.js
+++ b/client/faceAnalysis/faceAnalysis.query.js
@@ -19,13 +19,23 @@ class FaceAnalysisQuery extends Component {
}
upload(blob) {
+ if (this.state.image) {
+ URL.revokeObjectURL(this.state.image)
+ }
+ const url = URL.createObjectURL(blob)
+ this.setState({ image: url })
this.props.actions.upload(this.props.payload, blob)
}
+ componentWillUnmount() {
+ if (this.state.image) {
+ URL.revokeObjectURL(this.state.image)
+ }
+ }
+
render() {
const { result } = this.props
const { image } = this.state
- console.log(result)
const style = {}
if (image) {
style.backgroundImage = 'url(' + image + ')'
diff --git a/client/faceAnalysis/faceAnalysis.reducer.js b/client/faceAnalysis/faceAnalysis.reducer.js
index de6e5b0a..d9be7447 100644
--- a/client/faceAnalysis/faceAnalysis.reducer.js
+++ b/client/faceAnalysis/faceAnalysis.reducer.js
@@ -5,25 +5,32 @@ const initialState = () => ({
task: {},
result: {},
loading: false,
+ startTime: 0,
+ timing: 0,
})
export default function faceAnalysisReducer(state = initialState(), action) {
+ const { startTime } = state
switch (action.type) {
case types.faceAnalysis.loading:
return {
...state,
+ startTime: action.ts,
+ timing: 0,
[action.tag]: { loading: true },
}
case types.faceAnalysis.loaded:
return {
...state,
+ timing: action.ts - startTime,
[action.tag]: action.data,
}
case types.faceAnalysis.poll:
return {
...state,
+ timing: action.ts - startTime,
result: action.data,
}
@@ -31,6 +38,7 @@ export default function faceAnalysisReducer(state = initialState(), action) {
console.log('error', action)
return {
...state,
+ timing: action.ts - startTime,
[action.tag]: { error: action.err },
}
diff --git a/client/faceAnalysis/faceAnalysis.result.js b/client/faceAnalysis/faceAnalysis.result.js
index f9531eba..63a23d65 100644
--- a/client/faceAnalysis/faceAnalysis.result.js
+++ b/client/faceAnalysis/faceAnalysis.result.js
@@ -36,8 +36,10 @@ const errors = {
class FaceAnalysisResult extends Component {
render() {
- const { query, task, result, loading, error } = this.props.result
- console.log(this.props.result)
+ const { result, timing } = this.props
+ const { data, error, loading, message } = result
+ let { step, total } = data || {}
+ // console.log(step, total)
if (loading) {
return (
<div className='result'>
@@ -48,7 +50,6 @@ class FaceAnalysisResult extends Component {
</div>
)
}
- console.log(task, result)
if (error) {
// console.log(error)
let errorMessage = errors[error] || errors.error
@@ -56,12 +57,24 @@ class FaceAnalysisResult extends Component {
<div className='result'>{errorMessage}</div>
)
}
- if (!task && !result) return
-
+ // console.log(result)
+ if (!total) {
+ return (
+ <div className='result'></div>
+ )
+ }
+ let blurImg = data.data.blur_fn && (
+ <div>
+ <img src={data.data.blur_fn} />
+ <span>Blurred image</span>
+ </div>
+ )
return (
<div className='result'>
+ {!(step && total && message) ? '' : (<span>{step} / {total}: {message}</span>)}
+ {blurImg}
<div className="about">
- <small>Query took {query.timing.toFixed(2)} seconds</small>
+ <small>Query took {(timing / 1000).toFixed(2)} s.</small>
</div>
</div>
)
@@ -71,6 +84,7 @@ class FaceAnalysisResult extends Component {
const mapStateToProps = state => ({
query: state.faceAnalysis.query,
result: state.faceAnalysis.result,
+ timing: state.faceAnalysis.timing,
options: state.faceAnalysis.options,
})
diff --git a/megapixels/app/server/api.py b/megapixels/app/server/api.py
index 663f52cc..5ad454d8 100644
--- a/megapixels/app/server/api.py
+++ b/megapixels/app/server/api.py
@@ -39,7 +39,6 @@ def show(dataset_name):
else:
return jsonify({ 'status': 404 })
-
@api.route('/dataset/<dataset_name>/face', methods=['POST'])
def upload(dataset_name):
"""Query an image against FAISS and return the matching identities"""
diff --git a/megapixels/app/server/api_task.py b/megapixels/app/server/api_task.py
index fb24c154..c9bc19ed 100644
--- a/megapixels/app/server/api_task.py
+++ b/megapixels/app/server/api_task.py
@@ -31,22 +31,23 @@ def task_status(task_name, task_id):
return jsonify({
'state': 'error',
'percent': 100,
- 'message': 'Unknown task'
+ 'message': 'Unknown task',
})
-
# app.logger.info('task state: {}'.format(task.state))
if task.state == 'PENDING':
response = {
'state': task.state,
'percent': 0,
- 'message': 'Pending...'
+ 'message': 'Pending...',
+ 'data': task.info,
}
elif task.state != 'FAILURE':
response = {
'state': task.state,
'percent': task.info.get('percent', 0),
'uuid': task.info.get('uuid', 0),
- 'message': task.info.get('message', '')
+ 'message': task.info.get('message', ''),
+ 'data': task.info,
}
if 'result' in task.info:
response['result'] = task.info['result']
@@ -56,6 +57,7 @@ def task_status(task_name, task_id):
'state': task.state,
'percent': 100,
'message': str(task.info), # this is the exception raised
+ 'data': task.info,
}
return jsonify(response)
diff --git a/megapixels/app/server/tasks/blur.py b/megapixels/app/server/tasks/blur.py
index d1f67f54..42977097 100644
--- a/megapixels/app/server/tasks/blur.py
+++ b/megapixels/app/server/tasks/blur.py
@@ -9,6 +9,8 @@ import numpy as np
from app.utils.im_utils import ensure_np, ensure_pil
from flask import current_app as app
+import app.settings.app_cfg as cfg
+
from app.server.tasks import celery
from celery.utils.log import get_task_logger
@@ -19,57 +21,58 @@ import imutils
def blur_task(self, uuid_name, fn):
"""Process image and update during"""
celery_logger.debug('process_image_task, uuid: {}'.format(uuid_name))
+ celery_logger.debug('fn: {}'.format(fn))
files = []
+ meta = {
+ 'step': 0,
+ 'total': 3,
+ 'message': 'Starting',
+ 'uuid': uuid_name,
+ 'data': {},
+ }
+ self.update_state(state='PROCESSING', meta=meta)
+
im = Image.open(fn).convert('RGB')
+ os.remove(fn)
- self.update_state(
- state = 'PROCESSING',
- meta = {
- 'percent': 0.25,
- 'message': 'Applying blur',
- 'uuid': uuid_name
- })
+ meta['step'] += 1
+ meta['message'] = 'Applying blur'
+ self.update_state(state='PROCESSING', meta=meta)
im_np = ensure_np(im)
im_blur = cv.blur(im_np, (5,5), 1.0)
im_blur_pil = ensure_pil(im_blur)
fn = uuid_name + '_blur.jpg'
- # fpath = os.path.join(render_dir, fn)
- # im_blur_pil.save(fpath, 'JPEG', quality=95)
+ fpath = os.path.join(cfg.DIR_SITE_USER_CONTENT, fn)
+ im_blur_pil.save(fpath, 'JPEG', quality=80)
+ celery_logger.debug('fpath: {}'.format(fpath))
+ print('fpath: {}'.format(fpath))
# files.append({
# 'title': 'Blurred image',
# 'fn': render_uri + uuid_name + '_blur.jpg'
# })
+ meta['step'] += 1
+ meta['message'] = 'Applying blur'
+ meta['data']['blur_fn'] = os.path.join('/user_content/', fn)
+ self.update_state(state='PROCESSING', meta=meta)
time.sleep(3)
- self.update_state(
- state = 'PROCESSING',
- meta = {
- 'percent': 0.75,
- 'message': 'Sleeping some more',
- 'uuid': uuid_name
- })
- time.sleep(2)
+ if os.path.exists(fpath):
+ os.remove(fpath)
- data = {
- 'uuid': uuid_name,
- 'date': str(datetime.datetime.now()),
- 'files': files
- }
+ meta['step'] += 1
+ meta['message'] = 'Securely deleting user content'
+ self.update_state(state='PROCESSING', meta=meta)
+ time.sleep(2)
- # json_path = os.path.join(json_dir, uuid_name + '.json')
- # with open(json_path, 'w') as json_file:
- # json.dump(data, json_file)
+ celery_logger.debug('done!!')
+
+ meta['step'] = meta['total']
+ meta['state'] = 'complete'
+ return meta
- celery_logger.debug('ok')
-
- return {
- 'percent': 100,
- 'state': 'complete',
- 'uuid': uuid_name,
- }
diff --git a/megapixels/app/server/tasks/fullmonte.py b/megapixels/app/server/tasks/fullmonte.py
index 17ca9403..8215656a 100644
--- a/megapixels/app/server/tasks/fullmonte.py
+++ b/megapixels/app/server/tasks/fullmonte.py
@@ -17,15 +17,15 @@ from app.processors import face_detector, face_landmarks
from app.models.data_store import DataStore
@celery.task(bind=True)
-def fullmonte_task(self, uuid_name):
- return
-
+def fullmonte_task(self, uuid_name, fn):
# TOOD add selective testing
opt_run_pose = True
opt_run_2d_68 = True
opt_run_3d_68 = True
opt_run_3d_68 = True
+ return
+
# -------------------------------------------------
# init here
diff --git a/megapixels/app/server/tasks/sleep.py b/megapixels/app/server/tasks/sleep.py
index 9b91cc52..fa40b0e9 100644
--- a/megapixels/app/server/tasks/sleep.py
+++ b/megapixels/app/server/tasks/sleep.py
@@ -22,7 +22,7 @@ def sleep_task(self, uuid_name):
for i,m in enumerate(msgs):
percent = int(float(i)/float(len(msgs))*100.0)
self.update_state(
- state = 'PROCESSING',
+ state = 'processing',
meta = {
'percent': percent,
'message': m['msg'],
diff --git a/megapixels/app/settings/app_cfg.py b/megapixels/app/settings/app_cfg.py
index a8f41819..fea47572 100644
--- a/megapixels/app/settings/app_cfg.py
+++ b/megapixels/app/settings/app_cfg.py
@@ -148,6 +148,7 @@ S3_DATASETS_PATH = "v1" # datasets is already in the filename
DIR_SITE_PUBLIC = "../site/public"
DIR_SITE_CONTENT = "../site/content"
DIR_SITE_TEMPLATES = "../site/templates"
+DIR_SITE_USER_CONTENT = "../site/public/user_content"
# -----------------------------------------------------------------------------
# Celery
diff --git a/site/assets/css/applets.css b/site/assets/css/applets.css
index b64da4b7..e5b73562 100644
--- a/site/assets/css/applets.css
+++ b/site/assets/css/applets.css
@@ -25,6 +25,9 @@
font-size: 9pt;
padding-top: 10px;
}
+
+/* search results */
+
.results {
margin-top: 10px;
padding-bottom: 10px;
@@ -119,4 +122,16 @@
}
.tabulator-row.tabulator-row-even {
background-color: rgba(255,255,255,0.1);
-} \ No newline at end of file
+}
+
+/* analysis results */
+
+.analysisContainer .result div {
+ width: 256px;
+ text-align: center;
+ border: 1px solid white;
+ padding: 10px;
+}
+.analysisContainer .result div img {
+ max-width: 100%;
+}