react-native-yolo 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,9 +121,9 @@ public class HybridYoloModel: HybridYoloModelSpec {
121
121
 
122
122
  detections.append(
123
123
  Detection(
124
- boundingBox: box,
124
+ classId: Double(outputArray[offset + 5]),
125
125
  score: Double(score),
126
- classId: Double(outputArray[offset + 5])
126
+ boundingBox: box
127
127
  )
128
128
  )
129
129
  }
@@ -143,8 +143,13 @@ public class HybridYoloModel: HybridYoloModelSpec {
143
143
 
144
144
  // Extraction du CVPixelBuffer matériel pour un accès direct ultra-rapide
145
145
  let nativeBuffer = try frame.getNativeBuffer()
146
- guard let rawPointer = nativeBuffer.pointer else { return }
147
- let pixelBuffer = Unmanaged<CVPixelBuffer>.fromOpaque(rawPointer).takeUnretainedValue()
146
+ guard let rawPointer = UnsafeRawPointer(bitPattern: UInt(nativeBuffer.pointer)) else {
147
+ return
148
+ }
149
+
150
+ let pixelBuffer = Unmanaged<CVPixelBuffer>
151
+ .fromOpaque(rawPointer)
152
+ .takeUnretainedValue()
148
153
 
149
154
  CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
150
155
  defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly) }
@@ -184,13 +189,17 @@ public class HybridYoloModel: HybridYoloModelSpec {
184
189
  let v = Int(uvPtr[uvIndex + 1]) // V se trouve juste à côté
185
190
 
186
191
  // Formule standard de conversion YUV en RGB
187
- let rFloat = Float(y) + 1.402 * Float(v - 128)
188
- let gFloat = Float(y) - 0.344136 * Float(u - 128) - 0.714136 * Float(v - 128)
189
- let bFloat = Float(y) + 1.772 * Float(u - 128)
192
+ let yf = Float(y)
193
+ let uf = Float(u - 128)
194
+ let vf = Float(v - 128)
195
+
196
+ let rFloat = yf + (1.402 * vf)
197
+ let gFloat = yf - (0.344136 * uf) - (0.714136 * vf)
198
+ let bFloat = yf + (1.772 * uf)
190
199
 
191
- let r = Int(rFloat.rounded()).clamped(to: 0...255)
192
- let g = Int(gFloat.rounded()).clamped(to: 0...255)
193
- let b = Int(bFloat.rounded()).clamped(to: 0...255)
200
+ let r = clampInt(Int(rFloat.rounded()), 0, 255)
201
+ let g = clampInt(Int(gFloat.rounded()), 0, 255)
202
+ let b = clampInt(Int(bFloat.rounded()), 0, 255)
194
203
 
195
204
  if dataType == .float32 {
196
205
  let rNorm = Float(r) / 255.0
@@ -229,22 +238,26 @@ public class HybridYoloModel: HybridYoloModelSpec {
229
238
  case .up:
230
239
  let sx = Int(nx * Float(srcWidth))
231
240
  let sy = Int(ny * Float(srcHeight))
232
- return (sx.clamped(to: 0...(srcWidth - 1)), sy.clamped(to: 0...(srcHeight - 1)))
241
+ return (clampInt(sx, 0, srcWidth - 1), clampInt(sy, 0, srcHeight - 1))
233
242
  case .down:
234
243
  let sx = Int((1.0 - nx) * Float(srcWidth))
235
244
  let sy = Int((1.0 - ny) * Float(srcHeight))
236
- return (sx.clamped(to: 0...(srcWidth - 1)), sy.clamped(to: 0...(srcHeight - 1)))
245
+ return (clampInt(sx, 0, srcWidth - 1), clampInt(sy, 0, srcHeight - 1))
237
246
  case .left:
238
247
  let sx = Int(ny * Float(srcWidth))
239
248
  let sy = Int((1.0 - nx) * Float(srcHeight))
240
- return (sx.clamped(to: 0...(srcWidth - 1)), sy.clamped(to: 0...(srcHeight - 1)))
249
+ return (clampInt(sx, 0, srcWidth - 1), clampInt(sy, 0, srcHeight - 1))
241
250
  case .right:
242
251
  let sx = Int((1.0 - ny) * Float(srcWidth))
243
252
  let sy = Int(nx * Float(srcHeight))
244
- return (sx.clamped(to: 0...(srcWidth - 1)), sy.clamped(to: 0...(srcHeight - 1)))
253
+ return (clampInt(sx, 0, srcWidth - 1), clampInt(sy, 0, srcHeight - 1))
245
254
  @unknown default:
246
255
  return (0, 0)
247
256
  }
248
257
  }
258
+
259
+ private func clampInt(_ value: Int, _ minValue: Int, _ maxValue: Int) -> Int {
260
+ return min(max(value, minValue), maxValue)
261
+ }
249
262
  }
250
263
 
@@ -1,41 +1,42 @@
1
1
  import Foundation
2
2
  import NitroModules
3
3
  import VisionCamera
4
+ import CoreVideo
4
5
 
5
6
  public enum FrameJpegConverter {
6
7
  private static let tag = "YOLO_TAG_FrameJpegConverter"
7
-
8
+
8
9
  public static func toJpegBytes(frame: any HybridFrameSpec, quality: Int = 80) -> [UInt8] {
9
- // 1. Extraction et arrondi propre des dimensions du frame
10
- let width = Int(frame.width.rounded())
11
- let height = Int(frame.height.rounded())
12
-
13
- // 2. Conversion ultra-rapide via memcpy vers le format matériel NV12
14
- let nv12 = Yuv420ToNv12Converter.convert(frame: frame, width: width, height: height)
15
-
16
- if nv12.isEmpty {
17
- NSLog("[%@]: Failed to convert frame to NV12 array", tag)
18
- return []
19
- }
20
-
21
- // 3. Encodage matériel en JPEG via le GPU (CoreImage / CIContext)
22
- let jpegBytes = Nv12JpegEncoder.encode(
23
- nv12: nv12,
24
- width: width,
25
- height: height,
26
- quality: quality
27
- )
28
-
29
- if jpegBytes.isEmpty {
30
- NSLog("[%@]: ❌ Failed to encode NV12 data to JPEG bytes", tag)
10
+ do {
11
+ let nativeBuffer = try frame.getNativeBuffer()
12
+
13
+ guard let rawPointer = UnsafeRawPointer(bitPattern: UInt(nativeBuffer.pointer)) else {
14
+ NSLog("[%@]: Failed to get native buffer pointer", tag)
15
+ return []
16
+ }
17
+
18
+ let pixelBuffer = Unmanaged<CVPixelBuffer>
19
+ .fromOpaque(rawPointer)
20
+ .takeUnretainedValue()
21
+
22
+ let jpegBytes = Nv12JpegEncoder.encode(
23
+ pixelBuffer: pixelBuffer,
24
+ quality: quality
25
+ )
26
+
27
+ if jpegBytes.isEmpty {
28
+ NSLog("[%@]: ❌ Failed to encode pixelBuffer to JPEG bytes", tag)
29
+ return []
30
+ }
31
+
32
+ return BitmapOrientationFixer.fix(
33
+ jpegBytes: jpegBytes,
34
+ frame: frame,
35
+ quality: quality
36
+ )
37
+ } catch {
38
+ NSLog("[%@]: ❌ Failed to convert frame to JPEG: %@", tag, "\(error)")
31
39
  return []
32
40
  }
33
-
34
- // 4. Redessin de sécurité via UIGraphicsImageRenderer pour fixer définitivement les pixels
35
- return BitmapOrientationFixer.fix(
36
- jpegBytes: jpegBytes,
37
- frame: frame,
38
- quality: quality
39
- )
40
41
  }
41
- }
42
+ }
@@ -1,58 +1,32 @@
1
1
  import Foundation
2
2
  import CoreImage
3
- import UIKit
3
+ import CoreVideo
4
+ import ImageIO
4
5
 
5
6
  public enum Nv12JpegEncoder {
6
- // Réutiliser le CIContext permet d'éviter des fuites de mémoire massives à chaque frame
7
- private static let ciContext = CIContext(options: [CIContextOption.useSoftwareRenderer: false])
8
-
7
+ private static let ciContext = CIContext(options: [
8
+ CIContextOption.useSoftwareRenderer: false
9
+ ])
10
+
9
11
  public static func encode(
10
- nv12: [UInt8],
11
- width: Int,
12
- height: Int,
12
+ pixelBuffer: CVPixelBuffer,
13
13
  quality: Int
14
14
  ) -> [UInt8] {
15
-
16
- // 1. Convertir la qualité (0-100 sur Android) en CGFloat (0.0-1.0 sur iOS)
17
15
  let compressionQuality = CGFloat(max(0, min(quality, 100))) / 100.0
18
-
19
- let ySize = width * height
20
- let uvSize = ySize / 2
21
-
22
- // Sécurité : s'assurer que la taille du tableau correspond bien aux dimensions fournies
23
- guard nv12.count >= (ySize + uvSize) else { return [] }
24
-
25
- // 2. Transformer le tableau d'octets [UInt8] en objet Data Swift
26
- let rawData = Data(bytes: nv12, count: ySize + uvSize)
27
-
28
- // 3. Spécifier le format de couleur NV12 pour CoreImage (kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
29
- let imageOptions: [CIImageOption: Any] = [
30
- .colorSpace: CGColorSpaceCreateDeviceRGB()
31
- ]
32
-
33
- // On indique à CoreImage la structure exacte du NV12 (Plan 0: Y, Plan 1: UV entrelacé)
34
- guard let ciImage = CIImage(
35
- imageWithFormat: Int32(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange),
36
- size: CGSize(width: width, height: height),
37
- data: rawData,
38
- rowBytes: width,
39
- options: imageOptions
16
+
17
+ let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
18
+ let colorSpace = CGColorSpaceCreateDeviceRGB()
19
+
20
+ guard let jpegData = ciContext.jpegRepresentation(
21
+ of: ciImage,
22
+ colorSpace: colorSpace,
23
+ options: [
24
+ kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: compressionQuality
25
+ ]
40
26
  ) else {
41
27
  return []
42
28
  }
43
-
44
- // 4. Rendu de l'image GPU vers une structure d'image CoreGraphics
45
- guard let cgImage = ciContext.createCGImage(ciImage, from: ciImage.extent) else {
46
- return []
47
- }
48
-
49
- // 5. Conversion en UIImage puis compression matérielle en JPEG
50
- let uiImage = UIImage(cgImage: cgImage)
51
- guard let jpegData = uiImage.jpegData(compressionQuality: compressionQuality) else {
52
- return []
53
- }
54
-
55
- // 6. Retourner le tableau d'octets natif [UInt8] requis par votre modèle
29
+
56
30
  return [UInt8](jpegData)
57
31
  }
58
- }
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-yolo",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "react-native-yolo is a react native package built with Nitro",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",