Browse Source

working code

Dr-Swopt 2 weeks ago
parent
commit
0cf200184c

+ 43 - 5
frontend/src/app/components/analyzer/analyzer.component.ts

@@ -87,23 +87,48 @@ export class AnalyzerComponent implements OnInit {
       
       await this.localInference.loadModel(modelPath);
 
+      // Get original image dimensions to pass to the parser
+      const img = await this.loadImageDimensions(this.selectedFile);
+
       // 2. Preprocess the image to Float32Array [1, 3, 640, 640]
       const imageData = await this.imageProcessor.processImage(this.selectedFile);
 
       // 3. Run Inference locally
       const outputTensor = await this.localInference.runInference(imageData);
+      const rawData = outputTensor.data as Float32Array;
+
+      // 4. Decode Tensor -> Detections
+      // PASS img.width and img.height here
+      const detections = this.localInference.parseDetections(
+        rawData, 
+        this.confidence, 
+        img.width, 
+        img.height
+      );
+
+      // 5. Calculate Industrial Summary - Updated to match new categories
+      const summary: any = { 
+        'Empty_Bunch': 0, 
+        'Underripe': 0, 
+        'Abnormal': 0, 
+        'Ripe': 0, 
+        'Unripe': 0, 
+        'Overripe': 0 
+      };
+      
+      detections.forEach((d: any) => {
+        if (summary[d.class] !== undefined) summary[d.class]++;
+      });
       
-      // 4. Temporary Mock for Results (Post-processing math logic pending in Phase 5)
       this.results = {
-        industrial_summary: { 'Ripe': 0, 'Abnormal': 0, 'Underripe': 0 },
+        industrial_summary: summary,
         inference_ms: performance.now() - start,
-        detections: [] 
+        detections: detections
       };
 
-      console.log('Backend-less PoC: Inference Output Tensor:', outputTensor);
+      console.log('Backend-less PoC: Parsed Detections:', detections);
       
       this.loading = false;
-      // We still call drawDetections, but detections array is empty for now
       setTimeout(() => this.drawDetections(), 100);
     } catch (err) {
       console.error('Local Analysis Failed:', err);
@@ -111,6 +136,19 @@ export class AnalyzerComponent implements OnInit {
     }
   }
 
+  // Helper to get raw file dimensions
+  private loadImageDimensions(file: File): Promise<{width: number, height: number}> {
+    return new Promise((resolve) => {
+      const img = new Image();
+      img.onload = () => {
+        const dimensions = { width: img.width, height: img.height };
+        URL.revokeObjectURL(img.src);
+        resolve(dimensions);
+      };
+      img.src = URL.createObjectURL(file);
+    });
+  }
+
   drawDetections(): void {
     if (!this.results || !this.results.detections || !this.canvas) return;
 

+ 44 - 0
frontend/src/app/services/local-inference.service.ts

@@ -29,4 +29,48 @@ export class LocalInferenceService {
     
     return output[this.session.outputNames[0]];
   }
+
+  parseDetections(tensorData: Float32Array, threshold: number, imgWidth: number, imgHeight: number): any[] {
+    const detections = [];
+    const numBoxes = 300; // Based on your dims [1, 300, 6]
+    
+    for (let i = 0; i < numBoxes; i++) {
+        const offset = i * 6;
+        const confidence = tensorData[offset + 4];
+
+        if (confidence >= threshold) {
+            const classId = Math.round(tensorData[offset + 5]);
+            const className = this.getClassName(classId);
+
+            detections.push({
+                // Coordinate Scaling: Convert 0.0-1.0 normalized values to absolute pixels
+                // This matches your Python logic: abs_x1 = x1 * orig_w
+                box: [
+                    tensorData[offset + 0] * imgWidth,  // x1
+                    tensorData[offset + 1] * imgHeight, // y1
+                    tensorData[offset + 2] * imgWidth,  // x2
+                    tensorData[offset + 3] * imgHeight  // y2
+                ],
+                confidence: confidence,
+                class: className,
+                // Health Alert: Abnormal (2) and Empty_Bunch (0) per data.yaml
+                is_health_alert: className === 'Abnormal' || className === 'Empty_Bunch'
+            });
+        }
+    }
+    return detections;
+  }
+
+  private getClassName(id: number): string {
+    // STRICT ORDER matching your data.yaml
+    const classes = [
+      'Empty_Bunch', // 0
+      'Underripe',   // 1
+      'Abnormal',    // 2
+      'Ripe',        // 3
+      'Unripe',      // 4
+      'Overripe'     // 5
+    ];
+    return classes[id] || 'Unknown';
+  }
 }