summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/common/upload.helpers.js6
-rw-r--r--client/common/uploadImage.component.js3
-rw-r--r--client/faceAnalysis/faceAnalysis.actions.js39
-rw-r--r--client/faceAnalysis/faceAnalysis.query.js10
-rw-r--r--client/faceAnalysis/faceAnalysis.reducer.js1
-rw-r--r--client/faceAnalysis/faceAnalysis.result.js54
-rw-r--r--megapixels/app/server/api_task.py48
-rw-r--r--megapixels/app/server/tasks/blur.py27
-rw-r--r--package-lock.json29
-rw-r--r--package.json1
10 files changed, 81 insertions, 137 deletions
diff --git a/client/common/upload.helpers.js b/client/common/upload.helpers.js
index 5a041fd4..eb42a993 100644
--- a/client/common/upload.helpers.js
+++ b/client/common/upload.helpers.js
@@ -15,15 +15,15 @@ function base64ToUint8Array(string, start, finish) {
}
function getOrientation(uri) {
- const exif = new ExifReader()
// Split off the base64 data
const base64String = uri.split(',')[1]
// Read off first 128KB, which is all we need to
// get the EXIF data
const arr = base64ToUint8Array(base64String, 0, 2 ** 17)
try {
- exif.load(arr.buffer)
- return exif.getTagValue('Orientation')
+ const tags = ExifReader.load(arr.buffer)
+ // console.log(tags)
+ return tags.Orientation
} catch (err) {
return 1
}
diff --git a/client/common/uploadImage.component.js b/client/common/uploadImage.component.js
index eb8cc60f..bc88828e 100644
--- a/client/common/uploadImage.component.js
+++ b/client/common/uploadImage.component.js
@@ -20,7 +20,7 @@ export default class UploadImageComponent extends Component {
img.onload = null
this.resizeAndUpload(img)
}
- img.src = fileReaderEvent.result
+ img.src = fileReaderEvent.target.result
}
fr.readAsDataURL(files[0])
}
@@ -28,6 +28,7 @@ export default class UploadImageComponent extends Component {
resizeAndUpload(img) {
const canvas = renderThumbnail(img)
canvas.toBlob(blob => {
+ // console.log(blob)
this.props.onUpload(blob)
}, 'image/jpeg', 80)
}
diff --git a/client/faceAnalysis/faceAnalysis.actions.js b/client/faceAnalysis/faceAnalysis.actions.js
index 6a318b5d..860d3292 100644
--- a/client/faceAnalysis/faceAnalysis.actions.js
+++ b/client/faceAnalysis/faceAnalysis.actions.js
@@ -8,7 +8,7 @@ import { get, post } from '../util'
// urls
const url = {
- upload: () => process.env.API_HOST + '/task/upload/sleep',
+ upload: () => process.env.API_HOST + '/task/upload/blur',
}
export const publicUrl = {
}
@@ -45,22 +45,6 @@ export const updateOptions = opt => dispatch => {
// API functions
-export const upload = (payload, file) => dispatch => {
- // const { options } = store.getState().faceAnalysis
- const tag = 'task'
- const fd = new FormData()
- fd.append('query_img', file)
- // fd.append('limit', options.perPage)
- // if (!query) {
- dispatch(loading(tag))
- // }
- post(url.upload(payload.dataset), fd)
- .then(data => {
- dispatch(loaded(tag, data))
- })
- .catch(err => dispatch(error(tag, err)))
-}
-
// task polling
const POLL_DELAY = 500
@@ -68,12 +52,31 @@ let pollTimeout = null
export const poll = (payload, taskURL) => dispatch => {
clearTimeout(pollTimeout)
+ console.log('polling...')
get(taskURL)
.then(data => {
+ console.log('poll', data)
dispatch(polled(data))
- if (!data.complete) {
+ if (data.state !== 'error' && data.state !== 'complete') {
pollTimeout = setTimeout(() => poll(payload, taskURL), POLL_DELAY)
}
})
.catch(err => dispatch(error('result', err)))
}
+
+export const upload = (payload, file) => dispatch => {
+ const tag = 'task'
+ const fd = new FormData()
+ fd.append('query_img', file)
+ dispatch(loading(tag))
+ post(url.upload(), fd)
+ .then(data => {
+ console.log('loaded!', tag, data)
+ dispatch(loaded(tag, data))
+ const { result, taskURL } = data
+ if (result && taskURL) {
+ poll(payload, taskURL)(dispatch)
+ }
+ })
+ .catch(err => dispatch(error(tag, err)))
+}
diff --git a/client/faceAnalysis/faceAnalysis.query.js b/client/faceAnalysis/faceAnalysis.query.js
index 6b92b70d..a79e3e78 100644
--- a/client/faceAnalysis/faceAnalysis.query.js
+++ b/client/faceAnalysis/faceAnalysis.query.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
-import { Loader } from '../common'
+import { Loader, UploadImage } from '../common'
import * as actions from './faceAnalysis.actions'
// function parse_bbox(s) {
@@ -37,13 +37,7 @@ class FaceAnalysisQuery extends Component {
<div className='uploadContainer'>
<div style={style}>
{image ? null : <img src="/assets/img/icon_camera.svg" />}
- <input
- type="file"
- name="img"
- accept="image/*"
- onChange={this.upload.bind(this)}
- required
- />
+ <UploadImage onUpload={this.upload.bind(this)} />
</div>
{result.loading && (
<div className='loading' style={style}>
diff --git a/client/faceAnalysis/faceAnalysis.reducer.js b/client/faceAnalysis/faceAnalysis.reducer.js
index 54a6d5eb..de6e5b0a 100644
--- a/client/faceAnalysis/faceAnalysis.reducer.js
+++ b/client/faceAnalysis/faceAnalysis.reducer.js
@@ -28,6 +28,7 @@ export default function faceAnalysisReducer(state = initialState(), action) {
}
case types.faceAnalysis.error:
+ console.log('error', action)
return {
...state,
[action.tag]: { error: action.err },
diff --git a/client/faceAnalysis/faceAnalysis.result.js b/client/faceAnalysis/faceAnalysis.result.js
index b825a0cb..f9531eba 100644
--- a/client/faceAnalysis/faceAnalysis.result.js
+++ b/client/faceAnalysis/faceAnalysis.result.js
@@ -26,12 +26,6 @@ const errors = {
{"Sorry, an error occured."}
</div>
),
- bad_dataset: (
- <div>
- <h2>{""}</h2>
- {""}
- </div>
- ),
not_an_image: (
<div>
<h2>{"Not an image"}</h2>
@@ -42,19 +36,19 @@ const errors = {
class FaceAnalysisResult extends Component {
render() {
- const { dataset } = this.props.payload
- const { query, distances, results, loading, error } = this.props.result
+ const { query, task, result, loading, error } = this.props.result
console.log(this.props.result)
if (loading) {
return (
<div className='result'>
<div>
<Loader /><br />
- <h2>Searching...</h2>
+ <h2>Uploading...</h2>
</div>
</div>
)
}
+ console.log(task, result)
if (error) {
// console.log(error)
let errorMessage = errors[error] || errors.error
@@ -62,53 +56,13 @@ class FaceAnalysisResult extends Component {
<div className='result'>{errorMessage}</div>
)
}
- if (!results) {
- return <div className='result'></div>
- }
- if (!results.length) {
- return (
- <div className='result'>{errors.nomatch}</div>
- )
- }
- const els = results.map((result, i) => {
- const distance = distances[i]
- const { uuid } = result.file_record
- const { x, y, w, h } = result.face_roi
- const { fullname, gender, description, images } = result.identity
- const bbox = {
- left: (100 * x) + '%',
- top: (100 * y) + '%',
- width: (100 * w) + '%',
- height: (100 * h) + '%',
- }
- // console.log(bbox)
- return (
- <div key={i}>
- <div className='img'>
- <img src={'https://megapixels.nyc3.digitaloceanspaces.com/v1/media/' + dataset + '/' + uuid + '.jpg'} />
- <div className='bbox' style={bbox} />
- </div>
- {fullname} {'('}{gender}{')'}<br/>
- {description}<br/>
- {courtesyS(images, 'image')}{' in dataset'}<br />
- {Math.round((1 - distance) * 100)}{'% match'}
- </div>
- )
- })
+ if (!task && !result) return
return (
<div className='result'>
<div className="about">
- <h2>Did we find you?</h2>
- {'These faces matched images in the '}
- <b><tt>{dataset}</tt></b>
- {' dataset with over 70% probability.'}
- <br />
<small>Query took {query.timing.toFixed(2)} seconds</small>
</div>
- <div className='results'>
- {els}
- </div>
</div>
)
}
diff --git a/megapixels/app/server/api_task.py b/megapixels/app/server/api_task.py
index 23e11454..fb24c154 100644
--- a/megapixels/app/server/api_task.py
+++ b/megapixels/app/server/api_task.py
@@ -3,6 +3,7 @@ import re
import uuid
import time
import dlib
+import tempfile
import simplejson as json
import numpy as np
from flask import Blueprint, request, jsonify
@@ -64,62 +65,51 @@ def sleep_test():
Test the Celery system using a task that sleeps.
"""
async_task = task_lookup['sleep']['task'].apply_async(args=['sleep_test'])
- task_url = '/task/{}/{}'.format('sleep', async_task.id)
+ task_url = '/task/status/{}/{}'.format('sleep', async_task.id)
return jsonify({
'result': True,
'task_url': task_url,
})
-@api_task.route('/upload/:style', methods=['POST'])
-def upload(style):
+@api_task.route('/upload/blur', methods=['POST'])
+def upload():
"""
Process a images in a particular style
"""
+ style = 'blur'
print('style: {}'.format(style))
if style in task_lookup:
task = task_lookup[style]['task']
- print('task',task)
+ print('task', task)
else:
return jsonify({
'result': False,
'error': 'Unknown task',
})
- file = request.files['user_image']
- ext = request.form['ext']
- if ext is None:
- ext = request.files['ext']
+ print('get file...')
+ file = request.files['query_img']
- uuid_name = str(uuid.uuid4())
+ uuid_str = str(uuid.uuid4())
- app.logger.info('[+] style: {}'.format(style))
- app.logger.info('[+] ext: {}'.format(ext))
- app.logger.info('[+] uuid_name: {}'.format(uuid_name))
-
- # convert PNG to JPG
- print('[+] Resizing image')
+ print('[+] style: {}'.format(style))
+ print('[+] uuid_name: {}'.format(uuid_str))
im = Image.open(file.stream).convert('RGB')
- im = ImageOps.fit(im, (256, 256))
-
- # # Save image to disk
- # print('[+] Save image to {}'.format(fpath))
- # im.save(fpath, 'JPEG', quality=100)
- # im_pil_256 = im.resize((256,256))
+ im = ImageOps.fit(im, (256, 256,))
- # print('[+] ensure_np...')
- # im_np = imx.ensure_np(im_pil_256)
+ tmpfile = tempfile.NamedTemporaryFile(delete=False)
- celery_result = {
- im: im,
- }
+ # Save image to disk
+ print('[+] Save image to temporary file')
+ im.save(tmpfile, 'JPEG', quality=80)
print('[+] Start celery')
- async_task = task.apply_async(args=[uuid_name, celery_result])
- task_url = '/task/{}/{}'.format(style, async_task.id)
+ async_task = task.apply_async(args=[uuid_str, tmpfile.name])
+ task_url = '/task/status/{}/{}'.format(style, async_task.id)
return jsonify({
'result': True,
'taskURL': task_url,
- 'uuid': uuid_name
+ 'uuid': uuid_str
})
diff --git a/megapixels/app/server/tasks/blur.py b/megapixels/app/server/tasks/blur.py
index 3b7e20be..d1f67f54 100644
--- a/megapixels/app/server/tasks/blur.py
+++ b/megapixels/app/server/tasks/blur.py
@@ -16,18 +16,13 @@ celery_logger = get_task_logger(__name__)
import imutils
@celery.task(bind=True)
-def blur_task(self, uuid_name, extra):
+def blur_task(self, uuid_name, fn):
"""Process image and update during"""
celery_logger.debug('process_image_task, uuid: {}'.format(uuid_name))
files = []
- im = Image.open(os.path.join(upload_dir, uuid_name + '.jpg')).convert('RGB')
- im = im.resize((256,256))
- files.append({
- 'title': 'Original image',
- 'fn': upload_uri + uuid_name + '.jpg'
- })
+ im = Image.open(fn).convert('RGB')
self.update_state(
state = 'PROCESSING',
@@ -42,13 +37,13 @@ def blur_task(self, uuid_name, extra):
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(render_dir, fn)
+ # im_blur_pil.save(fpath, 'JPEG', quality=95)
- files.append({
- 'title': 'Blurred image',
- 'fn': render_uri + uuid_name + '_blur.jpg'
- })
+ # files.append({
+ # 'title': 'Blurred image',
+ # 'fn': render_uri + uuid_name + '_blur.jpg'
+ # })
time.sleep(3)
@@ -67,9 +62,9 @@ def blur_task(self, uuid_name, extra):
'files': files
}
- json_path = os.path.join(json_dir, uuid_name + '.json')
- with open(json_path, 'w') as json_file:
- json.dump(data, json_file)
+ # 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('ok')
diff --git a/package-lock.json b/package-lock.json
index da0dfcae..60a74ece 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3427,6 +3427,11 @@
"strip-eof": "^1.0.0"
}
},
+ "exif-reader": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/exif-reader/-/exif-reader-1.0.2.tgz",
+ "integrity": "sha1-AkCLl7YQKOpPReW4k6g2+aoorE8="
+ },
"exifreader": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-2.5.0.tgz",
@@ -3498,7 +3503,7 @@
"dependencies": {
"array-flatten": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
"dev": true
}
@@ -3633,7 +3638,7 @@
},
"finalhandler": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
+ "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"dev": true,
"requires": {
@@ -4405,7 +4410,7 @@
},
"globby": {
"version": "6.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
"dev": true,
"requires": {
@@ -4418,7 +4423,7 @@
"dependencies": {
"pify": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
@@ -4720,7 +4725,7 @@
},
"http-errors": {
"version": "1.6.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"dev": true,
"requires": {
@@ -4749,7 +4754,7 @@
},
"http-proxy-middleware": {
"version": "0.18.0",
- "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz",
+ "resolved": "http://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz",
"integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==",
"dev": true,
"requires": {
@@ -4835,7 +4840,7 @@
},
"is-accessor-descriptor": {
"version": "0.1.6",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
"dev": true,
"requires": {
@@ -4855,7 +4860,7 @@
},
"is-data-descriptor": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
"dev": true,
"requires": {
@@ -5833,7 +5838,7 @@
},
"media-typer": {
"version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
@@ -6717,7 +6722,7 @@
"dependencies": {
"async": {
"version": "1.5.2",
- "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
"dev": true
}
@@ -10191,7 +10196,7 @@
},
"is-accessor-descriptor": {
"version": "0.1.6",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
"dev": true,
"requires": {
@@ -10211,7 +10216,7 @@
},
"is-data-descriptor": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
"dev": true,
"requires": {
diff --git a/package.json b/package.json
index 1848cc7c..fcabb7e1 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"data-uri-to-buffer": "^2.0.0",
"date-fns": "^1.29.0",
"dotenv": "^6.0.0",
+ "exif-reader": "^1.0.2",
"exifreader": "^2.5.0",
"fetch-jsonp": "^1.1.3",
"file-saver": "^2.0.0-rc.3",