| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- // server/utils/imagePreprocessor.js
- import sharp from 'sharp';
- class ImagePreprocessor {
- constructor() {
- this.tempDir = './temp/processed';
- this.logger = {
- info: (msg, ...args) => console.log(`🖼️ [预处理] ${msg}`, ...args),
- error: (msg, ...args) => console.error(`❌ [预处理] ${msg}`, ...args),
- debug: (msg, ...args) => console.debug(`❌ [预处理] ${msg}`, ...args)
- };
- }
- async preprocessWithPadding(imagePath, config) {
- const startTime = Date.now();
- this.logger.info(`开始预处理: ${imagePath}`);
- try {
- const metadata = await sharp(imagePath).metadata();
- this.logger.info(`原始尺寸: ${metadata.width}x${metadata.height}`);
- // 智能填充策略
- const { paddingX, paddingY } = this.calculateSmartPadding(metadata);
- const paddedWidth = metadata.width + paddingX * 2;
- const paddedHeight = metadata.height + paddingY * 2;
- this.logger.debug(`添加填充: ${paddingX}x${paddingY}, 新尺寸: ${paddedWidth}x${paddedHeight}`);
- const paddedBuffer = await sharp(imagePath)
- .extend({
- top: paddingY,
- bottom: paddingY,
- left: paddingX,
- right: paddingX,
- background: { r: 255, g: 255, b: 255 }
- })
- .png()
- .toBuffer();
- const { width, height } = this.resizeForDetection({
- width: paddedWidth,
- height: paddedHeight
- }, config);
- const resizedBuffer = await sharp(paddedBuffer)
- .resize(width, height)
- .png()
- .toBuffer();
- const processingTime = Date.now() - startTime;
- this.logger.info(`预处理完成: ${width}x${height}, 耗时${processingTime}ms`);
- return {
- processedImage: {
- buffer: resizedBuffer,
- width, height,
- originalWidth: metadata.width,
- originalHeight: metadata.height,
- paddedWidth, paddedHeight,
- paddingX, paddingY,
- scaleX: paddedWidth / width,
- scaleY: paddedHeight / height
- }
- };
- } catch (error) {
- this.logger.error('预处理错误', error);
- throw error;
- }
- }
- calculateSmartPadding(metadata) {
- const basePadding = 20;
- const minPadding = 15;
- // 根据图像尺寸动态调整填充
- const widthRatio = Math.max(0.02, Math.min(0.08, 100 / metadata.width));
- const heightRatio = Math.max(0.02, Math.min(0.08, 100 / metadata.height));
- return {
- paddingX: Math.max(minPadding, Math.floor(metadata.width * widthRatio)),
- paddingY: Math.max(minPadding, Math.floor(metadata.height * heightRatio))
- };
- }
- resizeForDetection(metadata, config) {
- const { width, height } = metadata;
- const limitSideLen = config.detLimitSideLen || 960;
- let ratio = 1;
- if (Math.max(width, height) > limitSideLen) {
- ratio = limitSideLen / Math.max(width, height);
- this.logger.debug(`缩放比例: ${ratio.toFixed(4)}`);
- }
- const newWidth = Math.floor(width * ratio);
- const newHeight = Math.floor(height * ratio);
- // 确保尺寸是32的倍数
- const finalWidth = Math.max(32, Math.floor(newWidth / 32) * 32);
- const finalHeight = Math.max(32, Math.floor(newHeight / 32) * 32);
- this.logger.debug(`调整后尺寸: ${finalWidth}x${finalHeight}`);
- return { width: finalWidth, height: finalHeight };
- }
- async getImageInfo(imagePath) {
- try {
- const metadata = await sharp(imagePath).metadata();
- return {
- width: metadata.width || 0,
- height: metadata.height || 0,
- format: metadata.format || 'unknown',
- processed: false
- };
- } catch (error) {
- this.logger.error('获取图像信息失败', error);
- return {
- width: 0, height: 0, format: 'unknown', processed: false
- };
- }
- }
- }
- export default ImagePreprocessor;
|