Explorar o código

feat: implement palm oil analysis service with Jimp image processing and ONNX scanner provider

Dr-Swopt hai 5 días
pai
achega
cc11781de3
Modificáronse 4 ficheiros con 944 adicións e 1048 borrados
  1. 929 1028
      package-lock.json
  2. 1 1
      package.json
  3. 4 4
      src/palm-oil/palm-oil.service.ts
  4. 10 15
      src/palm-oil/providers/scanner.provider.ts

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 929 - 1028
package-lock.json


+ 1 - 1
package.json

@@ -29,11 +29,11 @@
     "class-transformer": "^0.5.1",
     "class-validator": "^0.15.1",
     "find-process": "^2.1.1",
+    "jimp": "^1.6.1",
     "onnxruntime-node": "^1.24.3",
     "pidusage": "^4.0.1",
     "reflect-metadata": "^0.2.2",
     "rxjs": "^7.8.1",
-    "sharp": "^0.34.5",
     "socket.io": "^4.8.3",
     "sqlite3": "^5.1.7",
     "systeminformation": "^5.31.5",

+ 4 - 4
src/palm-oil/palm-oil.service.ts

@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
 import { InjectRepository } from '@nestjs/typeorm';
 import { Repository } from 'typeorm';
 import { ScannerProvider } from './providers/scanner.provider';
-import sharp from 'sharp';
+import { Jimp } from 'jimp';
 import { performance } from 'perf_hooks';
 import { AnalysisResponse, IndustrialSummary } from './interfaces/palm-analysis.interface';
 import { History } from './entities/history.entity';
@@ -29,9 +29,9 @@ export class PalmOilService {
     const processingStart = performance.now();
 
     // 1. Get original image dimensions
-    const metadata = await sharp(imageBuffer).metadata();
-    const originalWidth = metadata.width || 640;
-    const originalHeight = metadata.height || 640;
+    const imgMeta = await Jimp.read(imageBuffer);
+    const originalWidth = imgMeta.width || 640;
+    const originalHeight = imgMeta.height || 640;
 
     // 2. Preprocess
     const tensor = await this.scanner.preprocess(imageBuffer);

+ 10 - 15
src/palm-oil/providers/scanner.provider.ts

@@ -1,6 +1,6 @@
 import { Injectable, OnModuleInit } from '@nestjs/common';
 import * as onnx from 'onnxruntime-node';
-import sharp from 'sharp';
+import { Jimp } from 'jimp';
 import * as path from 'path';
 import { MPOB_CLASSES, HEALTH_ALERT_CLASSES } from '../constants/mpob-standards';
 import { DetectionResult } from '../interfaces/palm-analysis.interface';
@@ -29,26 +29,21 @@ export class ScannerProvider implements OnModuleInit {
    * Preprocesses the image buffer: resize to 640x640, transpose HWC to CHW, and normalize.
    */
   async preprocess(imageBuffer: Buffer): Promise<onnx.Tensor> {
-    // Proper Sharp RGB extraction
-    const resized = await sharp(imageBuffer)
-      .resize(640, 640, { fit: 'fill' })
-      .removeAlpha()
-      .raw()
-      .toBuffer({ resolveWithObject: true });
-
-    const { width, height, channels } = resized.info;
-    const pixels = resized.data; // Uint8Array [R, G, B, R, G, B...]
+    const img = await Jimp.read(imageBuffer);
+    img.resize({ w: 640, h: 640 });
 
+    const pixels = img.bitmap.data; // RGBA: [R, G, B, A, R, G, B, A, ...]
+    const width = img.width;
+    const height = img.height;
     const imageSize = width * height;
     const floatData = new Float32Array(3 * imageSize);
 
-    // HWC to CHW Transposition
-    // pixels: [R1, G1, B1, R2, G2, B2...]
+    // HWC (RGBA) to CHW (RGB) transposition — stride 4, skip alpha
     // floatData: [R1, R2, ..., G1, G2, ..., B1, B2, ...]
     for (let i = 0; i < imageSize; i++) {
-      floatData[i] = pixels[i * 3] / 255.0; // R
-      floatData[i + imageSize] = pixels[i * 3 + 1] / 255.0; // G
-      floatData[i + 2 * imageSize] = pixels[i * 3 + 2] / 255.0; // B
+      floatData[i] = pixels[i * 4] / 255.0;               // R
+      floatData[i + imageSize] = pixels[i * 4 + 1] / 255.0; // G
+      floatData[i + 2 * imageSize] = pixels[i * 4 + 2] / 255.0; // B
     }
 
     return new onnx.Tensor('float32', floatData, [1, 3, 640, 640]);

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio