1+ using System . Runtime . InteropServices ;
2+ using OpenCvSharp ;
3+ using Sdcb . PaddleInference ;
4+
5+ namespace Sdcb . PaddleSeg
6+ {
7+ /// <summary>
8+ /// Handles image segmentation prediction using PaddlePaddle inference
9+ /// </summary>
10+ internal class PaddleSegPredictor : IDisposable
11+ {
12+ private readonly PaddlePredictor _p ;
13+
14+ /// <summary>
15+ /// Initializes a new instance of PaddleSegPredictor
16+ /// </summary>
17+ /// <param name="model">The segmentation model to use</param>
18+ /// <param name="configure">Optional configuration action for PaddleConfig</param>
19+ public PaddleSegPredictor ( SegModel model , Action < PaddleConfig > ? configure = null )
20+ {
21+ PaddleConfig c = model . CreateConfig ( ) ;
22+ model . ConfigureDevice ( c , configure ) ;
23+
24+ _p = c . CreatePredictor ( ) ;
25+ }
26+
27+ /// <summary>
28+ /// Performs segmentation on the input image
29+ /// </summary>
30+ /// <param name="img">Input image in BGR format</param>
31+ /// <returns>Array of segmentation labels where each element represents the class ID for a pixel</returns>
32+ public int [ ] Run ( Mat img )
33+ {
34+ // Convert BGR to RGB color space
35+ Cv2 . CvtColor ( img , img , ColorConversionCodes . BGR2RGB ) ;
36+
37+ // Normalize the image
38+ Mat mat = Normalize ( img ) ;
39+
40+ using PaddlePredictor predictor = _p . Clone ( ) ;
41+ using ( PaddleTensor input = predictor . GetInputTensor ( predictor . InputNames [ 0 ] ) )
42+ {
43+ // Set input shape: [batch_size=1, channels=3, height, width]
44+ input . Shape = new [ ] { 1 , 3 , mat . Rows , mat . Cols } ;
45+ float [ ] data = ExtractMat ( mat ) ;
46+ input . SetData ( data ) ;
47+ }
48+
49+ if ( ! predictor . Run ( ) )
50+ {
51+ throw new Exception ( "PaddlePredictor(Detector) run failed." ) ;
52+ }
53+
54+ using ( PaddleTensor output = predictor . GetOutputTensor ( predictor . OutputNames [ 0 ] ) )
55+ {
56+ int [ ] data = output . GetData < int > ( ) ;
57+ int [ ] shape = output . Shape ;
58+ return data ;
59+ }
60+ }
61+
62+ /// <summary>
63+ /// Normalizes the input image by:
64+ /// 1. Converting to float32 and scaling to [0,1]
65+ /// 2. Applying formula: (x - 0.5) / 0.5
66+ /// </summary>
67+ /// <param name="src">Source image</param>
68+ /// <returns>Normalized image</returns>
69+ private static Mat Normalize ( Mat src )
70+ {
71+ Mat imFloat = new Mat ( ) ;
72+ src . ConvertTo ( imFloat , MatType . CV_32FC3 , 1.0 / 255.0 ) ;
73+
74+ imFloat = ( imFloat - 0.5 ) / 0.5 ;
75+
76+ return imFloat ;
77+ }
78+
79+ /// <summary>
80+ /// Extracts image data into a float array in CHW (Channel, Height, Width) format
81+ /// required by PaddlePaddle
82+ /// </summary>
83+ /// <param name="src">Source image with 3 channels</param>
84+ /// <returns>Float array containing image data in CHW format</returns>
85+ private static float [ ] ExtractMat ( Mat src )
86+ {
87+ int rows = src . Rows ;
88+ int cols = src . Cols ;
89+ float [ ] result = new float [ rows * cols * 3 ] ;
90+ GCHandle resultHandle = default ;
91+ try
92+ {
93+ resultHandle = GCHandle . Alloc ( result , GCHandleType . Pinned ) ;
94+ IntPtr resultPtr = resultHandle . AddrOfPinnedObject ( ) ;
95+
96+ // Extract each channel and store in CHW format
97+ for ( int i = 0 ; i < src . Channels ( ) ; ++ i )
98+ {
99+ // Convert BGR to RGB order
100+ int rgb = 2 - i ;
101+ using Mat dest = new ( rows , cols , MatType . CV_32FC1 , resultPtr + i * rows * cols * sizeof ( float ) ) ;
102+ Cv2 . ExtractChannel ( src , dest , rgb ) ;
103+ }
104+ }
105+ finally
106+ {
107+ resultHandle . Free ( ) ;
108+ }
109+ return result ;
110+ }
111+
112+ /// <summary>
113+ /// Disposes the underlying PaddlePredictor
114+ /// </summary>
115+ public void Dispose ( )
116+ {
117+ _p . Dispose ( ) ;
118+ }
119+ }
120+ }
0 commit comments