Spaces:
Paused
Paused
File size: 4,243 Bytes
b66d95a 5b3c62d b66d95a 5b3c62d b66d95a 5b3c62d b66d95a 5b3c62d e24e4d2 b66d95a 5b3c62d b66d95a 5b3c62d df346d9 b66d95a df346d9 b66d95a e24e4d2 b66d95a 5b3c62d b66d95a 5b3c62d b66d95a 5b3c62d b66d95a df346d9 b66d95a df346d9 b66d95a df346d9 b66d95a 5b3c62d b66d95a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
import express, { Request, Response, NextFunction } from "express";
import path from "path";
import os from "os";
import fs from "fs";
import axios from "axios";
import fileUpload from "express-fileupload";
import archiver from "archiver";
import ffmpeg from "fluent-ffmpeg";
import { ColmapOptions, runColmap } from "./colmap.mts";
declare module 'express-serve-static-core' {
interface Request {
files: any;
}
}
const app = express();
const port = 7860;
const maxActiveRequests = 4;
let activeRequests = 0;
app.use(express.json({limit: '50mb'}));
app.use(express.urlencoded({limit: '50mb', extended: true}));
app.use(fileUpload());
app.post("/", async (req: Request, res: Response, _next: NextFunction) => {
if (activeRequests++ >= maxActiveRequests) {
return res.status(503).send("Service Unavailable");
}
const options: ColmapOptions = req.body;
let dataFile: fileUpload.UploadedFile | string = "";
try {
// we accept either JSON requests
if (req.is("json")) {
const { data } = await axios.get(req.body.assetUrl, {
responseType: "arraybuffer",
});
dataFile = Buffer.from(data, "binary");
}
// or file uploads
else {
if (!req.files || !req.files.data || req.files.data.mimetype !== 'video/mp4') {
return res.status(400).send("Missing or invalid data file in request");
}
dataFile = req.files.data;
}
const { projectTempDir, outputTempDir, imageFolder } = setupDirectories();
await handleFileStorage(dataFile, projectTempDir);
await generateImagesFromData(projectTempDir, imageFolder);
options.projectPath = projectTempDir;
options.workspacePath = projectTempDir;
options.imagePath = imageFolder;
// note: we don't need to read the result since this is a function having side effects on the file system
const result = await runColmap(options);
console.log("result:", result);
await createOutputArchive(outputTempDir);
res.download(path.join(outputTempDir, 'output.zip'), 'output.zip', (error) => {
if (!error) fs.rmSync(projectTempDir, {recursive: true, force: true});
fs.rmSync(outputTempDir, {recursive: true, force: true});
});
} catch (error) {
res.status(500).send(`Couldn't generate pose data. Error: ${error}`);
} finally {
activeRequests--;
}
});
app.get("/", async (req: Request, res: Response) => {
res.send("Campose API is a micro-service used to generate camera pose data from a set of images.");
});
app.listen(port, () => console.log(`Listening at http://localhost:${port}`));
function setupDirectories() {
const projectTempDir = path.join(os.tmpdir(), Math.random().toString().slice(2));
const outputTempDir = path.join(os.tmpdir(), Math.random().toString().slice(2));
const imageFolder = path.join(projectTempDir, 'images');
fs.mkdirSync(projectTempDir);
fs.mkdirSync(outputTempDir);
fs.mkdirSync(imageFolder);
return { projectTempDir, outputTempDir, imageFolder };
}
async function handleFileStorage(dataFile: fileUpload.UploadedFile | string, projectTempDir: string) {
if (dataFile instanceof Buffer) {
fs.writeFile(path.join(projectTempDir, "data.mp4"), dataFile, (err) => {
if (err) throw err;
});
} else if (typeof dataFile === "object" && dataFile.mv) {
try {
await dataFile.mv(path.join(projectTempDir, dataFile.name));
} catch (error) {
throw new Error(`File can't be moved: ${error}`);
}
} else {
throw new Error("Invalid File");
}
}
function generateImagesFromData(projectTempDir: string, imageFolder: string) {
return new Promise<void>((resolve, reject) => {
ffmpeg(path.join(projectTempDir, 'data.mp4'))
.outputOptions('-vf', 'fps=1')
.output(path.join(imageFolder, 'image-%03d.png'))
.on('end', resolve)
.on('error', reject)
.run()
});
}
function createOutputArchive(outputTempDir: string) {
return new Promise<void>((resolve, reject) => {
const archive = archiver('zip', { zlib: { level: 9 } });
const output = fs.createWriteStream(path.join(outputTempDir, 'output.zip'));
archive.pipe(output);
archive.directory(path.join(outputTempDir, '/'), '');
archive.finalize();
resolve();
});
} |