forked from hypar-io/ML
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add "input_generation" and "image_generation" scripts.
- Loading branch information
Showing
11 changed files
with
770 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Hypar ML utilities | ||
|
||
Tools for training and deploying models on [Hypar](https://hypar.io). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Image generation | ||
|
||
Renders a directory of .glb files into .png files using [Hypar's](https://hypar.io) renderer. | ||
|
||
This spins up a local static file server on port 8000 to expose the .glb files to the rendering sandbox. It then renders each .glb through the Hypar renderer in a headless Chromium context and saves a screenshot locally. | ||
|
||
## Setup | ||
|
||
Requirements: | ||
* [NodeJS](https://nodejs.org/) | ||
* Python 2 | ||
|
||
Run `npm install` inside this directory to fetch all remaining dependencies. | ||
|
||
## Usage | ||
|
||
Run the following command: | ||
``` | ||
npm run ts-node generateImages.ts [INPUT_DIRECTORY] [OUTPUT_DIRECTORY] | ||
``` | ||
|
||
Where: | ||
* `[INPUT_DIRECTORY]` is the path to a directory containing .glb files | ||
* `[OUTPUT_DIRECTORY]` is the path where output .png files will be written. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#! /usr/bin/env python | ||
|
||
from SimpleHTTPServer import SimpleHTTPRequestHandler, test | ||
|
||
class CORSHTTPRequestHandler(SimpleHTTPRequestHandler): | ||
def end_headers(self): | ||
self.send_header('Access-Control-Allow-Origin', '*') | ||
SimpleHTTPRequestHandler.end_headers(self) | ||
|
||
if __name__ == '__main__': | ||
test(HandlerClass=CORSHTTPRequestHandler) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
const { exec, execSync } = require('child_process') | ||
const fs = require('fs') | ||
const path = require('path') | ||
const puppeteer = require('puppeteer') | ||
|
||
const args = process.argv.slice(2) | ||
if (args.length != 2) { | ||
console.error('Must provide a directory of .glb files and an output directory') | ||
process.exit() | ||
} | ||
|
||
const inputDirectory = path.resolve(args[0]) | ||
if (!fs.existsSync(inputDirectory)) { | ||
console.error('Input directory does not exist: ', inputDirectory) | ||
process.exit() | ||
} | ||
const outputDirectory = path.resolve(args[1]) | ||
if (!fs.existsSync(outputDirectory)){ | ||
fs.mkdirSync(outputDirectory, { recursive: true }) | ||
} | ||
|
||
// Start a file server for the GLBs so that the web context can fetch them. | ||
const serverPath = path.resolve('cors_simple_server.py') | ||
process.chdir(inputDirectory) | ||
const glbServerPort = 8000 | ||
exec(`python ${serverPath} ${glbServerPort}`, (err, stdout, stderr) => { | ||
if (err) { | ||
console.error(err) | ||
return | ||
} | ||
|
||
// the *entire* stdout and stderr (buffered) | ||
console.log(`stdout: ${stdout}`) | ||
console.log(`stderr: ${stderr}`) | ||
}) | ||
console.log(`GLB server listening on port ${glbServerPort}`) | ||
|
||
// Use a headless web browser to render each GLB through Hypar's rendering engine and take a screenshot. | ||
const width = 256 | ||
const height = 256 | ||
let browser = null | ||
const screenshotGltf = async (glbName: string, targetName: string) => { | ||
return new Promise(async (resolve, reject) => { | ||
if (!browser) { | ||
browser = await puppeteer.launch({ | ||
ignoreHTTPSErrors: true, | ||
args: [ | ||
"--disable-dev-shm-usage", | ||
"--no-zygote", | ||
"--use-gl=swiftshader", | ||
"--enable-webgl", | ||
"--hide-scrollbars", | ||
"--mute-audio", | ||
"--no-sandbox", | ||
"--single-process", | ||
"--disable-breakpad", | ||
"--ignore-gpu-blacklist", | ||
"--headless" | ||
], | ||
}) | ||
} | ||
const page = await browser.newPage() | ||
await page.setViewport({ width: width, height: height }) | ||
await page.exposeFunction('onModelLoaded', e => { | ||
console.log('Capturing screenshot.') | ||
page.screenshot({ path: targetName }).then(async () => { | ||
await page.close() | ||
resolve() | ||
}) | ||
.catch(async () => { | ||
await page.close() | ||
reject() | ||
}) | ||
}) | ||
await page.evaluateOnNewDocument(() => { | ||
document.addEventListener('model-loaded', () => { | ||
(window as any).onModelLoaded() | ||
}) | ||
}) | ||
|
||
await page.goto(`https://hypar.io/render?url=http://localhost:${glbServerPort}/${glbName}`) | ||
}) | ||
} | ||
|
||
|
||
// Iterate over all .glb files and take a screenshot. | ||
const processFile = (filePath: string) => { | ||
return new Promise((resolve, reject) => { | ||
console.log('Processing', filePath) | ||
const inPath = path.basename(filePath) | ||
const outPath = path.join(outputDirectory, path.basename(filePath, '.glb') + '.png') | ||
if (fs.existsSync(outPath)) { | ||
console.log('Screenshot already exists. Skipping.') | ||
resolve() | ||
} else { | ||
screenshotGltf(inPath, outPath).then(resolve).catch(resolve) | ||
} | ||
}) | ||
} | ||
|
||
async function processAllFiles(files) { | ||
for (const file of files) { | ||
await processFile(file) | ||
} | ||
} | ||
const files = fs.readdirSync(inputDirectory).filter((fileInDir) => path.extname(fileInDir) == '.glb') | ||
processAllFiles(files) |
Oops, something went wrong.