egg-api / egg-api.js
luoyutianyang's picture
Update egg-api.js
645e6ce verified
raw
history blame
4.41 kB
const express = require('express');
const fs = require('fs');
const path = require('path');
const cv = require('opencv4nodejs');
const Jimp = require('jimp');
const axios = require('axios');
const sharp = require('sharp');
const app = express();
const port = 7860; // 将端口改为 7860
const outputDir = './output';
// 确保输出目录存在
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir);
}
// 并行处理图片下载和处理
function processImage(url, inputImagePath, outputImagePath, classifiersFolder, replacementImagePath, callback) {
axios.get(url, { responseType: 'arraybuffer' })
.then(response => {
return sharp(response.data).toFile(inputImagePath);
})
.then(() => {
return replaceFaces(inputImagePath, outputImagePath, classifiersFolder, replacementImagePath);
})
.then(() => {
console.log('Image processed successfully.');
callback(null);
})
.catch(error => {
console.error('Error processing image:', error);
callback(error);
});
}
// 加载所有分类器
function loadClassifiersFromFolder(folderPath, callback) {
const classifiers = [];
fs.readdir(folderPath, (err, files) => {
if (err) {
callback(err);
return;
}
let completed = 0;
files.forEach(file => {
const filePath = path.join(folderPath, file);
const classifier = new cv.CascadeClassifier(filePath);
classifiers.push(classifier);
completed++;
if (completed === files.length) {
callback(null, classifiers);
}
});
});
}
// 人脸替换函数
function replaceFaces(inputImagePath, outputImagePath, classifiersFolder, replacementImagePath, callback) {
cv.imreadAsync(inputImagePath, (err, img) => {
if (err) {
callback(err);
return;
}
loadClassifiersFromFolder(classifiersFolder, (err, classifiers) => {
if (err) {
callback(err);
return;
}
Jimp.read(replacementImagePath, (err, replacementFace) => {
if (err) {
callback(err);
return;
}
const grayImg = img.bgrToGray();
const allFaces = [];
classifiers.forEach(classifier => {
const faces = classifier.detectMultiScale(grayImg).objects;
allFaces.push(...faces);
});
allFaces.forEach(faceRect => {
const resizedReplacementFace = replacementFace.resize(faceRect.width, faceRect.height);
const faceRegion = img.getRegion(faceRect);
const replacementBuffer = resizedReplacementFace.bitmap.data;
for (let y = 0; y < faceRect.height; y++) {
for (let x = 0; x < faceRect.width; x++) {
const idx = (y * faceRect.width + x) << 2;
const [r, g, b, a] = replacementBuffer.slice(idx, idx + 4);
if (a > 0) {
faceRegion.set(y, x, new cv.Vec3(b, g, r));
}
}
}
});
cv.imwrite(outputImagePath, img);
callback(null);
});
});
});
}
// Express接口
app.get('/process-image', (req, res) => {
const { imageUrl } = req.query;
if (!imageUrl) {
return res.status(400).send('Image URL is required');
}
const inputImagePath = path.join(outputDir, 'input.jpg'); // 使用jpg格式保存
const outputImagePath = path.join(outputDir, 'output.jpg');
const replacementImagePath = './replacement_face.png';
const classifiersFolder = './classifiers';
processImage(imageUrl, inputImagePath, outputImagePath, classifiersFolder, replacementImagePath, (err) => {
if (err) {
console.error('Error processing image:', err);
return res.status(500).send('Error processing image');
}
res.sendFile(outputImagePath, { root: '.' });
});
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});