Spaces:
Paused
Paused
File size: 5,511 Bytes
b66d95a 048dcb2 b66d95a 5b3c62d 048dcb2 5b3c62d b66d95a 5b3c62d b66d95a 5b3c62d b66d95a 5b3c62d e24e4d2 b66d95a 5b3c62d 9fb3a35 4e2728b 9fb3a35 50725ac 5b3c62d df346d9 b66d95a df346d9 b66d95a 2a3efb7 b66d95a 2a3efb7 b66d95a e24e4d2 b66d95a 5b3c62d b66d95a 5b3c62d b66d95a 5b3c62d b66d95a 54a13a6 b66d95a 50725ac fc983d4 df346d9 fc983d4 2a3efb7 df346d9 fc983d4 df346d9 50725ac 2a3efb7 df346d9 b66d95a fc983d4 df346d9 b66d95a 2a3efb7 b66d95a 2a3efb7 cca0a16 b66d95a 4e2728b 2a3efb7 cca0a16 4e2728b cca0a16 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
import express, { Request, Response, NextFunction } from "express";
import path from "path";
import os from "os";
import fs from "fs";
import util from "util";
import axios from "axios";
import fileUpload from "express-fileupload";
import archiver from "archiver";
import ffmpeg from "fluent-ffmpeg";
import { ColmapOptions, runColmap } from "./colmap.mts";
const writeFile = util.promisify(fs.writeFile);
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 { projectTempDir, outputTempDir, imageFolder } = setupDirectories();
const defaultOptions: ColmapOptions = {
command: 'automatic_reconstructor',
workspacePath: projectTempDir,
imagePath: imageFolder,
};
const requestBody = typeof req.body === "object" ? req.body : undefined;
const options: ColmapOptions = {...defaultOptions, ...requestBody};
console.log("options:", options);
let dataFile: fileUpload.UploadedFile | Buffer = Buffer.from("");
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 filePath = await handleFileStorage(dataFile, projectTempDir);
await generateImagesFromData(imageFolder, filePath);
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, { recursive: true });
fs.mkdirSync(outputTempDir, { recursive: true });
fs.mkdirSync(imageFolder, { recursive: true });
return { projectTempDir, outputTempDir, imageFolder };
}
async function handleFileStorage(dataFile: fileUpload.UploadedFile | Buffer, projectTempDir: string) {
console.log(`handleFileStorage called (projectTempDir: ${projectTempDir})`);
console.log("typeof dataFile: " + typeof dataFile);
if (dataFile instanceof Buffer) {
console.log("dataFile is a Buffer!");
const filePath = path.join(projectTempDir, "data.mp4");
await writeFile(filePath, dataFile);
return filePath;
} else if (typeof dataFile === "object" && dataFile.mv) {
console.log(`typeof dataFile === "object" && dataFile.mv`);
try {
console.log("dataFile.name = " + dataFile.name);
const filePath = path.join(projectTempDir, dataFile.name)
console.log("path.join(projectTempDir, dataFile.name) = " + filePath);
await dataFile.mv(filePath);
return filePath;
} catch (error) {
throw new Error(`File can't be moved: ${error}`);
}
} else {
console.log(`unrecognized dataFile format`);
throw new Error("Invalid File");
}
}
function generateImagesFromData(imageFolder: string, filePath: string) {
console.log(`generateImagesFromData("${imageFolder}", "${filePath}")`);
return new Promise<void>((resolve, reject) => {
console.log(`going to write to ${path.join(imageFolder, 'image%d.jpg')}`);
ffmpeg(filePath)
// .outputOptions('-vf', 'fps=1')
.outputOptions('-i')
.output(path.join(imageFolder, 'image%d.jpg'))
.on('end', () => {
console.log('Image generation finished successfully.');
resolve();
})
.on('error', (err) => {
console.log(`failed to generate the images: ${err}`)
reject(err);
})
.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();
});
} |