diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2019-01-04 23:37:34 +0100 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2019-01-04 23:37:34 +0100 |
| commit | 276c16e1055c23350abd3d9d071cfce9b4f1b27f (patch) | |
| tree | b85c3b3c8ff0f7bfb77323d3f77be0f88bb3086f | |
| parent | e5b6ef658e936c32d9500ff7f781171d9785315a (diff) | |
rm rotation on homepage, add dataset list
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | client/faceSearch/faceSearch.query.js | 2 | ||||
| -rw-r--r-- | client/faceSearch/faceSearch.result.js | 12 | ||||
| -rw-r--r-- | client/faceSearch/upload.js | 154 | ||||
| -rw-r--r-- | client/nameSearch/nameSearch.query.js | 8 | ||||
| -rw-r--r-- | client/tables.js | 6 | ||||
| -rw-r--r-- | megapixels/app/models/sql_factory.py | 3 | ||||
| -rw-r--r-- | megapixels/app/server/api.py | 8 | ||||
| -rw-r--r-- | megapixels/app/site/builder.py | 20 | ||||
| -rw-r--r-- | megapixels/app/site/parser.py | 16 | ||||
| -rw-r--r-- | site/assets/css/applets.css | 24 | ||||
| -rw-r--r-- | site/assets/css/css.css | 68 | ||||
| -rw-r--r-- | site/assets/js/app/face.js | 6 | ||||
| -rw-r--r-- | site/public/datasets/index.html | 25 | ||||
| -rw-r--r-- | site/public/datasets/lfw/index.html | 6 | ||||
| -rw-r--r-- | site/public/index.html | 25 | ||||
| -rw-r--r-- | site/templates/datasets.html | 24 | ||||
| -rw-r--r-- | site/templates/home.html | 17 |
18 files changed, 384 insertions, 41 deletions
@@ -41,5 +41,6 @@ cd megapixels python cli_faiss.py sync_metadata python cli_faiss.py build_faiss python cli_faiss.py build_db +python cli_site.py build python cli_flask.py run ``` diff --git a/client/faceSearch/faceSearch.query.js b/client/faceSearch/faceSearch.query.js index 20d200bb..9f778ca0 100644 --- a/client/faceSearch/faceSearch.query.js +++ b/client/faceSearch/faceSearch.query.js @@ -68,7 +68,7 @@ class FaceSearchQuery extends Component { } </div> <div className='cta'> - <h2>Search This Dataset</h2> + <h2>Search by Image</h2> <h3>Searching {13456} images</h3> <p> {'Use facial recognition to reverse search into the LFW dataset '} diff --git a/client/faceSearch/faceSearch.result.js b/client/faceSearch/faceSearch.result.js index 936bc8d2..95534830 100644 --- a/client/faceSearch/faceSearch.result.js +++ b/client/faceSearch/faceSearch.result.js @@ -26,6 +26,18 @@ const errors = { {"Sorry, an error occured."} </div> ), + bad_dataset: ( + <div> + <h2>{""}</h2> + {""} + </div> + ), + not_an_image: ( + <div> + <h2>{"Not an image"}</h2> + {"Sorry, the file you uploaded was not recognized as an image. Please upload a JPG or PNG image and try again."} + </div> + ), } class FaceSearchResult extends Component { diff --git a/client/faceSearch/upload.js b/client/faceSearch/upload.js new file mode 100644 index 00000000..f18bdce6 --- /dev/null +++ b/client/faceSearch/upload.js @@ -0,0 +1,154 @@ +const MAX_SIDE = 300 + +function render(img){ + var resized = renderToCanvas(img, { correctOrientation: true }) + var canvas = document.createElement('canvas') // document.querySelector('#user_photo_canvas') + ctx = canvas.getContext('2d') + ctx.fillStyle = 'black' + ctx.fillRect(0, 0, MAX_SIDE, MAX_SIDE) + var x_offset = (MAX_SIDE - resized.width) / 2 + var y_offset = (MAX_SIDE - resized.height) / 2 + ctx.drawImage(resized, x_offset, y_offset) + return canvas +} +function renderToCanvas(img, options) { + if (!img) return + options = options || {} + + // Canvas max size for any side + var maxSize = MAX_SIDE + var canvas = document.createElement('canvas') + var ctx = canvas.getContext('2d') + var initialScale = options.scale || 1 + // Scale to needed to constrain canvas to max size + var scale = getScale(img.width * initialScale, img.height * initialScale, maxSize, maxSize, true) + // Still need to apply the user defined scale + scale *= initialScale + var width = canvas.width = Math.round(img.width * scale) + var height = canvas.height = Math.round(img.height * scale) + var correctOrientation = options.correctOrientation + var jpeg = !!img.src.match(/data:image\/jpeg|\.jpeg$|\.jpg$/i) + var hasDataURI = !!img.src.match(/^data:/) + + ctx.save() + + // Can only correct orientation on JPEGs represented as dataURIs + // for the time being + if (correctOrientation && jpeg && hasDataURI) { + applyOrientationCorrection(canvas, ctx, img.src) + } + // Resize image if too large + if (scale !== 1) { + ctx.scale(scale, scale) + } + + ctx.drawImage(img, 0, 0) + ctx.restore() + + return canvas +} + +function getScale(width, height, viewportWidth, viewportHeight, fillViewport) { + fillViewport = !!fillViewport + var landscape = (width / height) > (viewportWidth / viewportHeight) + if (landscape) { + if (fillViewport) { + return fitVertical() + } else if (width > viewportWidth) { + return fitHorizontal() + } + } else { + if (fillViewport) { + return fitHorizontal() + } else if (height > viewportHeight) { + return fitVertical() + } + } + return 1 + + function fitHorizontal() { + return viewportWidth / width + } + + function fitVertical() { + return viewportHeight / height + } +} + +function applyOrientationCorrection(canvas, ctx, uri) { + var orientation = getOrientation(uri) + // Only apply transform if there is some non-normal orientation + if (orientation && orientation !== 1) { + var transform = orientationToTransform[orientation] + var rotation = transform.rotation + var mirror = transform.mirror + var flipAspect = rotation === 90 || rotation === 270 + if (flipAspect) { + // Fancy schmancy swap algo + canvas.width = canvas.height + canvas.width + canvas.height = canvas.width - canvas.height + canvas.width -= canvas.height + } + if (rotation > 0) { + applyRotation(canvas, ctx, rotation) + } + } +} + +function applyRotation(canvas, ctx, deg) { + var radians = deg * (Math.PI / 180) + if (deg === 90) { + ctx.translate(canvas.width, 0) + } else if (deg === 180) { + ctx.translate(canvas.width, canvas.height) + } else if (deg == 270) { + ctx.translate(0, canvas.height) + } + ctx.rotate(radians) +} + +function getOrientation (uri) { + var exif = new ExifReader + // Split off the base64 data + var base64String = uri.split(',')[1] + // Read off first 128KB, which is all we need to + // get the EXIF data + var arr = base64ToUint8Array(base64String, 0, Math.pow(2, 17)) + try { + exif.load(arr.buffer) + return exif.getTagValue('Orientation') + } catch (err) { + return 1 + } +} + +function base64ToUint8Array(string, start, finish) { + var start = start || 0 + var finish = finish || string.length + // atob that shit + var binary = atob(string) + var buffer = new Uint8Array(binary.length) + for (var i = start; i < finish; i++) { + buffer[i] = binary.charCodeAt(i) + } + return buffer +} + +/** + * Mapping from EXIF orientation values to data + * regarding the rotation and mirroring necessary to + * render the canvas correctly + * Derived from: + * http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/ + */ +var orientationToTransform = { + 1: { rotation: 0, mirror: false }, + 2: { rotation: 0, mirror: true }, + 3: { rotation: 180, mirror: false }, + 4: { rotation: 180, mirror: true }, + 5: { rotation: 90, mirror: true }, + 6: { rotation: 90, mirror: false }, + 7: { rotation: 270, mirror: true }, + 8: { rotation: 270, mirror: false } +} + diff --git a/client/nameSearch/nameSearch.query.js b/client/nameSearch/nameSearch.query.js index b82e324b..629b7b1d 100644 --- a/client/nameSearch/nameSearch.query.js +++ b/client/nameSearch/nameSearch.query.js @@ -11,22 +11,22 @@ class NameSearchQuery extends Component { handleInput(value) { this.setState({ q: value }) - if (value.length > 2) { - this.props.actions.search(this.props.payload, value) + if (value.strip().length > 1) { + this.props.actions.search(this.props.payload, value.strip()) } } render() { return ( <div className='query'> - <h2>Find Your Name</h2> + <h2>Search by Name</h2> <h3>Searching {13456} identities</h3> <p> {'Enter your name to see if you were included in this dataset..'} </p> <input type="text" - class="q" + className="q" placeholder="Enter your name" value={this.state.q} onInput={e => this.handleInput(e.target.value)} diff --git a/client/tables.js b/client/tables.js index b4c13887..9e134eb6 100644 --- a/client/tables.js +++ b/client/tables.js @@ -75,7 +75,7 @@ export default function append(el, payload) { }) } - if (fields.length > 1 && fields[1].indexOf('filter')) { - const filter = fields[1].split(' ') - } + // if (fields && fields.length > 1 && fields[1].indexOf('filter')) { + // const filter = fields[1].split(' ') + // } } diff --git a/megapixels/app/models/sql_factory.py b/megapixels/app/models/sql_factory.py index b270afd2..a580f28e 100644 --- a/megapixels/app/models/sql_factory.py +++ b/megapixels/app/models/sql_factory.py @@ -61,7 +61,8 @@ def load_sql_dataset(path, replace=False, engine=None, base_model=None): print('loading dataset {}'.format(fn)) df = pd.read_csv(fn) # fix columns that are named "index", a sql reserved word - df.columns = table.__table__.columns.keys() + df.reindex_axis(sorted(df.columns), axis=1) + df.columns = sorted(table.__table__.columns).keys() df.to_sql(name=table.__tablename__, con=engine, if_exists='replace', index=False) return dataset diff --git a/megapixels/app/server/api.py b/megapixels/app/server/api.py index 35862837..3683d5fd 100644 --- a/megapixels/app/server/api.py +++ b/megapixels/app/server/api.py @@ -45,18 +45,20 @@ def upload(dataset_name): dataset = get_dataset(dataset_name) if dataset_name not in faiss_datasets: return jsonify({ - 'error': 'invalid dataset' + 'error': 'bad_dataset' }) faiss_dataset = faiss_datasets[dataset_name] file = request.files['query_img'] fn = file.filename - if fn.endswith('blob'): + if fn.endswith('blob'): # FIX PNG IMAGES? fn = 'filename.jpg' basename, ext = os.path.splitext(fn) # print("got {}, type {}".format(basename, ext)) if ext.lower() not in valid_exts: - return jsonify({ 'error': 'not an image' }) + return jsonify({ + 'error': 'not_an_image' + }) im = Image.open(file.stream).convert('RGB') im_np = pil2np(im) diff --git a/megapixels/app/site/builder.py b/megapixels/app/site/builder.py index ff1a0c83..fac49c24 100644 --- a/megapixels/app/site/builder.py +++ b/megapixels/app/site/builder.py @@ -14,7 +14,7 @@ env = Environment( autoescape=select_autoescape([]) ) -def build_page(fn, research_posts): +def build_page(fn, research_posts, datasets): """ build a single page from markdown into the appropriate template - writes it to site/public/ @@ -40,6 +40,8 @@ def build_page(fn, research_posts): elif 'research/' in fn: skip_h1 = True template = env.get_template("research.html") + elif 'datasets/index' in fn: + template = env.get_template("datasets.html") else: template = env.get_template("page.html") @@ -60,17 +62,18 @@ def build_page(fn, research_posts): content=content, research_posts=research_posts, latest_research_post=research_posts[-1], + datasets=datasets, ) os.makedirs(output_path, exist_ok=True) with open(output_fn, "w") as file: file.write(html) -def build_research_index(research_posts): +def build_index(key, research_posts, datasets): """ build the index of research (blog) posts """ - metadata, sections = parser.read_metadata('../site/content/research/index.md') + metadata, sections = parser.read_metadata('../site/content/{}/index.md'.format(key)) template = env.get_template("page.html") s3_path = s3.make_s3_path(cfg.S3_SITE_PATH, metadata['path']) content = parser.parse_markdown(sections, s3_path, skip_h1=False) @@ -80,8 +83,9 @@ def build_research_index(research_posts): content=content, research_posts=research_posts, latest_research_post=research_posts[-1], + datasets=datasets, ) - output_fn = cfg.DIR_SITE_PUBLIC + '/research/index.html' + output_fn = '{}/{}/index.html'.format(cfg.DIR_SITE_PUBLIC, key) with open(output_fn, "w") as file: file.write(html) @@ -90,14 +94,16 @@ def build_site(): build the site! =^) """ research_posts = parser.read_research_post_index() + datasets = parser.read_datasets_index() for fn in glob.iglob(os.path.join(cfg.DIR_SITE_CONTENT, "**/*.md"), recursive=True): - build_page(fn, research_posts) - build_research_index(research_posts) + build_page(fn, research_posts, datasets) + build_index('research', research_posts, datasets) def build_file(fn): """ build just one page from a filename! =^) """ research_posts = parser.read_research_post_index() + datasets = parser.read_datasets_index() fn = os.path.join(cfg.DIR_SITE_CONTENT, fn) - build_page(fn, research_posts) + build_page(fn, research_posts, datasets) diff --git a/megapixels/app/site/parser.py b/megapixels/app/site/parser.py index b3d3a8c2..d3eccfca 100644 --- a/megapixels/app/site/parser.py +++ b/megapixels/app/site/parser.py @@ -66,6 +66,8 @@ def format_applet(section, s3_path): opt = None if command == 'python' or command == 'javascript' or command == 'code': return format_section([ section ], s3_path) + if command == '': + return '' applet['command'] = command if opt: @@ -221,8 +223,20 @@ def read_research_post_index(): """ Generate an index of the research (blog) posts """ + return read_post_index('research') + +def read_datasets_index(): + """ + Generate an index of the datasets + """ + return read_post_index('datasets') + +def read_post_index(basedir): + """ + Generate an index of posts + """ posts = [] - for fn in sorted(glob.glob('../site/content/research/*/index.md')): + for fn in sorted(glob.glob('../site/content/{}/*/index.md'.format(basedir))): metadata, valid_sections = read_metadata(fn) if metadata is None or metadata['status'] == 'private' or metadata['status'] == 'draft': continue diff --git a/site/assets/css/applets.css b/site/assets/css/applets.css index 315d72e0..9c37354a 100644 --- a/site/assets/css/applets.css +++ b/site/assets/css/applets.css @@ -65,12 +65,17 @@ } .cta { padding-left: 20px; - font-size: 11pt; + font-size: 10pt; } .cta ol { margin: 0; padding: 0 0 20px 20px; } + +.searchContainer { + padding-top: 20px; +} + .uploadContainer > div { position: relative; width: 300px; @@ -98,3 +103,20 @@ .uploadContainer img { max-width: 40px; } + + +/* tabulator */ + +.tabulator-row { + transition: background-color 100ms cubic-bezier(0,0,1,1); + background-color: rgba(255,255,255,0.0); +} +.desktop .tabulator-row:hover { + background-color: rgba(255,255,255,0.2); +} +.tabulator-row.tabulator-row-odd { + background-color: rgba(255,255,255,0.05); +} +.tabulator-row.tabulator-row-even { + background-color: rgba(255,255,255,0.1); +}
\ No newline at end of file diff --git a/site/assets/css/css.css b/site/assets/css/css.css index 003ac4a3..7e354a4c 100644 --- a/site/assets/css/css.css +++ b/site/assets/css/css.css @@ -1,4 +1,4 @@ -* { box-sizing: border-box; } +* { box-sizing: border-box; outline: 0; } html, body { margin: 0; padding: 0; @@ -27,7 +27,7 @@ header { left: 0; width: 100%; height: 70px; - z-index: 1; + z-index: 2; background: #1e1e1e; display: flex; flex-direction: row; @@ -44,11 +44,11 @@ header .slogan { } header .logo { background-image: url(../img/megapixels_logo_white.svg); - background-size: cover; + background-size: contain; background-repeat: no-repeat; margin-top: 7px; - margin-right: 14px; - width: 49px; + margin-right: 10px; + width: 39px; height: 30px; } header .site_name { @@ -175,13 +175,16 @@ th, .gray { line-height: 1.5; } section { - width: 640px; + width: 960px; margin: 0 auto; } .content .first_paragraph { font-weight: 300; - font-size: 18pt; - color: #ccc; + font-size: 16pt; + color: #ddd; + margin-bottom: 50px; + margin-top: 30px; + line-height: 36px; } p { margin: 0 0 20px 0; @@ -212,6 +215,16 @@ p { padding-bottom: 4px; } +/* lists */ + +ul { + list-style-type: none; + margin: 0 0 30px 0; + padding: 0; +} +ul li { + margin-bottom: 8px; +} /* misc formatting */ code { @@ -368,18 +381,19 @@ section.wide .image { } .intro .headline { font-family: 'Roboto Mono', monospace; - font-size: 16pt; + font-size: 28pt; + line-height: 40pt; } .intro .buttons { margin: 40px 0; } .intro button { font-family: 'Roboto', sans-serif; - padding: 8px 12px; - border-radius: 6px; + padding: 15px 20px; + border-radius: 8px; border: 1px solid transparent; cursor: pointer; - font-size: 11pt; + font-size: 12pt; margin-right: 10px; transition: color 0.1s cubic-bezier(0,0,1,1), background-color 0.1s cubic-bezier(0,0,1,1); } @@ -406,4 +420,32 @@ section.wide .image { } .desktop .intro .under a:hover { color: #fff; -}
\ No newline at end of file +} + +/* intro - list of datasets */ + +.dataset-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; +} +.dataset-list a { + text-decoration: none; + transition: background-color 0.1s cubic-bezier(0,0,1,1); + background: black; + margin: 0 20px 20px 0; +} +.dataset-list .dataset { + width: 220px; + height: 140px; + padding: 10px; + color: white; +} +.dataset-list a:nth-child(3n+1) { background-color: rgba(255, 0, 0, 0.1); } +.desktop .dataset-list a:nth-child(3n+1):hover { background-color: rgba(255, 0, 0, 0.2); } + +.dataset-list a:nth-child(3n+2) { background-color: rgba(255, 128, 0, 0.1); } +.desktop .dataset-list a:nth-child(3n+2):hover { background-color: rgba(255, 128, 0, 0.2); } + +.dataset-list .dataset:nth-child(3n+3) { background-color: rgba(255, 255, 0, 0.1); } +.desktop .dataset-list .dataset:nth-child(3n+3):hover { background-color: rgba(255, 255, 0, 0.2); }
\ No newline at end of file diff --git a/site/assets/js/app/face.js b/site/assets/js/app/face.js index bdaa0313..f3f1f2bf 100644 --- a/site/assets/js/app/face.js +++ b/site/assets/js/app/face.js @@ -216,12 +216,12 @@ var face = (function(){ requestAnimationFrame(animate) if (swapping) update_swap(t) renderer.render(scene, camera) - scene.rotation.y += 0.01 * Math.PI + // scene.rotation.y += 0.01 * Math.PI mouseTarget.x += (mouse.x - mouseTarget.x) * 0.1 mouseTarget.y += (mouse.y - mouseTarget.y) * 0.1 scene.rotation.x = (mouseTarget.y - 0.5) * Math.PI / 2 - // scene.rotation.y = (mouseTarget.x - 0.5) * Math.PI - scene.rotation.y += 0.01 + scene.rotation.y = (mouseTarget.x - 0.5) * Math.PI + // scene.rotation.y += 0.01 last_t = t } })() diff --git a/site/public/datasets/index.html b/site/public/datasets/index.html index bcc7c1ab..4d6f57b6 100644 --- a/site/public/datasets/index.html +++ b/site/public/datasets/index.html @@ -28,11 +28,36 @@ </header> <div class="content"> + <section><h1>Facial Recognition Datasets</h1> <p>Regular Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> <h3>Summary</h3> </section><section><div class='meta'><div><div class='gray'>Found</div><div>275 datasets</div></div><div><div class='gray'>Created between</div><div>1993-2018</div></div><div><div class='gray'>Smallest dataset</div><div>20 images</div></div><div><div class='gray'>Largest dataset</div><div>10,000,000 images</div></div></div></section><section><div class='meta'><div><div class='gray'>Highest resolution faces</div><div>450x500 (Unconstrained College Students)</div></div><div><div class='gray'>Lowest resolution faces</div><div>16x20 pixels (QMUL SurvFace)</div></div></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "load_file https://megapixels.nyc3.digitaloceanspaces.com/v1/citations/datasets.csv"}'></div></section> + <section> + <h2>Dataset Portraits</h2> + <p> + We have prepared detailed studies of some of the more noteworthy datasets. + </p> + + <div class="dataset-list"> + + <a href="/datasets/lfw/"> + <div class="dataset"> + Labeled Faces in The Wild + </div> + </a> + + <a href="/datasets/vgg_face2/"> + <div class="dataset"> + VGG Face2 + </div> + </a> + + </div> + </section> + + </div> <footer> <div> diff --git a/site/public/datasets/lfw/index.html b/site/public/datasets/lfw/index.html index ddb3f1d1..2ab9815f 100644 --- a/site/public/datasets/lfw/index.html +++ b/site/public/datasets/lfw/index.html @@ -29,10 +29,10 @@ <div class="content"> <section><h1>Labeled Faces in the Wild</h1> -</section><section><div class='meta'><div><div class='gray'>Created</div><div>2007</div></div><div><div class='gray'>Images</div><div>13,233</div></div><div><div class='gray'>People</div><div>5,749</div></div><div><div class='gray'>Created From</div><div>Yahoo News images</div></div><div><div class='gray'>Search available</div><div>Searchable</div></div></div></section><section><p>Labeled Faces in The Wild (LFW) is amongst the most widely used facial recognition training datasets in the world and is the first of its kind to be created entirely from images posted online. The LFW dataset includes 13,233 images of 5,749 people that were collected between 2002-2004. Use the tools below to check if you were included in this dataset or scroll down to read the analysis.</p> -</section><section class='applet_container'><div class='applet' data-payload='{"command": "face_search"}'></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "name_search"}'></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "load_file assets/lfw_names_gender_kg_min.csv", "fields": ["Name, Images, Gender, Description"]}'></div></section><section class='images'><div class='image'><img src='https://nyc3.digitaloceanspaces.com/megapixels/v1/datasets/lfw/assets/lfw_feature.jpg' alt='Eighteen of the 5,749 people in the Labeled Faces in the Wild Dataset. The most widely used face dataset for benchmarking commercial face recognition algorithms.'><div class='caption'>Eighteen of the 5,749 people in the Labeled Faces in the Wild Dataset. The most widely used face dataset for benchmarking commercial face recognition algorithms.</div></div></section><section><h3>Intro</h3> +</section><section><div class='meta'><div><div class='gray'>Created</div><div>2007</div></div><div><div class='gray'>Images</div><div>13,233</div></div><div><div class='gray'>People</div><div>5,749</div></div><div><div class='gray'>Created From</div><div>Yahoo News images</div></div><div><div class='gray'>Search available</div><div>Searchable</div></div></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "face_search"}'></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "name_search"}'></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "load_file assets/lfw_names_gender_kg_min.csv", "fields": ["Name, Images, Gender, Description"]}'></div></section><section class='wide'><div class='image'><img src='https://nyc3.digitaloceanspaces.com/megapixels/v1/datasets/lfw/assets/lfw_feature.jpg' alt='Eighteen of the 5,749 people in the Labeled Faces in the Wild Dataset. The most widely used face dataset for benchmarking commercial face recognition algorithms.'><div class='caption'>Eighteen of the 5,749 people in the Labeled Faces in the Wild Dataset. The most widely used face dataset for benchmarking commercial face recognition algorithms.</div></div></section><section><h3>Intro</h3> +<p>Labeled Faces in The Wild (LFW) is among the most widely used facial recognition training datasets in the world and is the first of its kind to be created entirely from images posted online. The LFW dataset includes 13,233 images of 5,749 people that were collected between 2002-2004. Use the tools below to check if you were included in this dataset or scroll down to read the analysis.</p> <p>Three paragraphs describing the LFW dataset in a format that can be easily replicated for the other datasets. Nothing too custom. An analysis of the initial research papers with context relative to all the other dataset papers.</p> -</section><section class='images'><div class='image'><img src='https://nyc3.digitaloceanspaces.com/megapixels/v1/datasets/lfw/assets/lfw_montage_everyone_nocrop_1920.jpg' alt=' all 5,749 people in the LFW Dataset sorted from most to least images collected.'><div class='caption'> all 5,749 people in the LFW Dataset sorted from most to least images collected.</div></div></section><section><h3>LFW by the Numbers</h3> +</section><section class='wide'><div class='image'><img src='https://nyc3.digitaloceanspaces.com/megapixels/v1/datasets/lfw/assets/lfw_montage_everyone_nocrop_1920.jpg' alt=' From George W. Bush to Jamie Lee Curtis: all 5,749 people in the LFW Dataset sorted from most to least images collected.'><div class='caption'> From George W. Bush to Jamie Lee Curtis: all 5,749 people in the LFW Dataset sorted from most to least images collected.</div></div></section><section><h3>LFW by the Numbers</h3> <ul> <li>Was first published in 2007</li> <li>Developed out of a prior dataset from Berkely called "Faces in the Wild" or "Names and Faces" [^lfw_original_paper]</li> diff --git a/site/public/index.html b/site/public/index.html index 6db6ccb7..017f3a4b 100644 --- a/site/public/index.html +++ b/site/public/index.html @@ -51,7 +51,30 @@ <section><h2>Facial Recognition Datasets</h2> <p>Regular Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> <h3>Summary</h3> -</section><section><div class='meta'><div><div class='gray'>Found</div><div>275 datasets</div></div><div><div class='gray'>Created between</div><div>1993-2018</div></div><div><div class='gray'>Smallest dataset</div><div>20 images</div></div><div><div class='gray'>Largest dataset</div><div>10,000,000 images</div></div></div></section><section><div class='meta'><div><div class='gray'>Highest resolution faces</div><div>450x500 (Unconstrained College Students)</div></div><div><div class='gray'>Lowest resolution faces</div><div>16x20 pixels (QMUL SurvFace)</div></div></div></section><section class='applet_container'><div class='applet' data-payload='{"command": "load_file https://megapixels.nyc3.digitaloceanspaces.com/v1/citations/datasets.csv"}'></div></section> +</section><section><div class='meta'><div><div class='gray'>Found</div><div>275 datasets</div></div><div><div class='gray'>Created between</div><div>1993-2018</div></div><div><div class='gray'>Smallest dataset</div><div>20 images</div></div><div><div class='gray'>Largest dataset</div><div>10,000,000 images</div></div></div></section><section><div class='meta'><div><div class='gray'>Highest resolution faces</div><div>450x500 (Unconstrained College Students)</div></div><div><div class='gray'>Lowest resolution faces</div><div>16x20 pixels (QMUL SurvFace)</div></div></div></section> + + <section> + <h2>Dataset Portraits</h2> + <p> + We have prepared detailed studies of some of the more noteworthy datasets. + </p> + + <div class="dataset-list"> + + <a href="/datasets/lfw/"> + <div class="dataset"> + Labeled Faces in The Wild + </div> + </a> + + <a href="/datasets/vgg_face2/"> + <div class="dataset"> + VGG Face2 + </div> + </a> + + </div> + </section> </div> diff --git a/site/templates/datasets.html b/site/templates/datasets.html new file mode 100644 index 00000000..ba230eee --- /dev/null +++ b/site/templates/datasets.html @@ -0,0 +1,24 @@ +{% extends 'layout.html' %} + +{% block content %} + + {{ content }} + + <section> + <h2>Dataset Portraits</h2> + <p> + We have prepared detailed studies of some of the more noteworthy datasets. + </p> + + <div class="dataset-list"> + {% for dataset in datasets %} + <a href="{{ dataset.url }}"> + <div class="dataset"> + {{ dataset.title }} + </div> + </a> + {% endfor %} + </div> + </section> + +{% endblock %} diff --git a/site/templates/home.html b/site/templates/home.html index 59f8cf76..c0965a15 100644 --- a/site/templates/home.html +++ b/site/templates/home.html @@ -23,6 +23,23 @@ {{ content }} + <section> + <h2>Dataset Portraits</h2> + <p> + We have prepared detailed studies of some of the more noteworthy datasets. + </p> + + <div class="dataset-list"> + {% for dataset in datasets %} + <a href="{{ dataset.url }}"> + <div class="dataset"> + {{ dataset.title }} + </div> + </a> + {% endfor %} + </div> + </section> + {% endblock %} {% block scripts %} |
