From db4ea3278b09e5c9b3a4a0a3070c8b6b537ef380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurant?= Date: Sun, 9 Mar 2025 12:56:13 +0100 Subject: [PATCH] feat: buffer to mat support --- cpp/react-native-fast-opencv.cpp | 64 +++++++++++++++++++ docs/pages/apidetails.md | 26 +++++++- example/ios/Podfile.lock | 4 +- example/src/examples/CameraPassthrough.tsx | 2 +- .../src/examples/CameraRealtimeDetection.tsx | 2 +- example/src/examples/DocumentDetection.tsx | 2 +- src/utils/UtilsFunctions.ts | 19 ++++++ 7 files changed, 111 insertions(+), 8 deletions(-) diff --git a/cpp/react-native-fast-opencv.cpp b/cpp/react-native-fast-opencv.cpp index 9b1bbd4..3785c93 100644 --- a/cpp/react-native-fast-opencv.cpp +++ b/cpp/react-native-fast-opencv.cpp @@ -71,6 +71,70 @@ jsi::Value OpenCVPlugin::get(jsi::Runtime& runtime, const jsi::PropNameID& propN memcpy(mat.data, vec.data(), (int)rows * (int)cols * (int)channels); auto id = FOCV_Storage::save(mat); + return FOCV_JsiObject::wrap(runtime, "mat", id); + }); + } else if (propName == "bufferToMat") { + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, "bufferToMat"), 4, + [=](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Object { + auto type = arguments[0].asString(runtime).utf8(runtime); + auto rows = arguments[1].asNumber(); + auto cols = arguments[2].asNumber(); + auto channels = arguments[3].asNumber(); + auto input = arguments[4].asObject(runtime); + + auto modeType = -1; + auto typeSize = 1; + + if(type == "uint8") { + typeSize = 1; + if (channels == 1) modeType = CV_8U; + if (channels == 3) modeType = CV_8UC3; + if (channels == 4) modeType = CV_8UC4; + } else if(type == "uint16") { + typeSize = 2; + if (channels == 1) modeType = CV_16U; + if (channels == 3) modeType = CV_16UC3; + if (channels == 4) modeType = CV_16UC4; + } else if(type == "int8") { + typeSize = 1; + if (channels == 1) modeType = CV_8S; + if (channels == 3) modeType = CV_8SC3; + if (channels == 4) modeType = CV_8SC4; + } else if(type == "int16") { + typeSize = 2; + if (channels == 1) modeType = CV_16S; + if (channels == 3) modeType = CV_16SC3; + if (channels == 4) modeType = CV_16SC4; + } else if(type == "int32") { + typeSize = 4; + if (channels == 1) modeType = CV_32S; + if (channels == 3) modeType = CV_32SC3; + if (channels == 4) modeType = CV_32SC4; + } else if(type == "float32") { + typeSize = 4; + if (channels == 1) modeType = CV_32F; + if (channels == 3) modeType = CV_32FC3; + if (channels == 4) modeType = CV_32FC4; + } else if(type == "float64") { + typeSize = 8; + if (channels == 1) modeType = CV_64F; + if (channels == 3) modeType = CV_64FC3; + if (channels == 4) modeType = CV_64FC4; + } + + if (channels == -1) { + throw std::runtime_error("Fast OpenCV Error: Invalid channel count passed to frameBufferToMat!"); + } + + auto inputBuffer = getTypedArray(runtime, std::move(input)); + auto vec = inputBuffer.toVector(runtime); + + cv::Mat mat(rows, cols, modeType); + memcpy(mat.data, vec.data(), (int)rows * (int)cols * (int)channels * typeSize); + auto id = FOCV_Storage::save(mat); + return FOCV_JsiObject::wrap(runtime, "mat", id); }); } diff --git a/docs/pages/apidetails.md b/docs/pages/apidetails.md index 4e51d9a..bea63ef 100644 --- a/docs/pages/apidetails.md +++ b/docs/pages/apidetails.md @@ -130,12 +130,32 @@ Clears stored objects from memory. clearBuffers(idsToKeep?: string[]): void; ``` -### Frame Buffer to Mat +### Buffer to Mat -Creates an object of type Mat based on an array of Uint8Array. +Creates an object of type Mat based on an array of Buffer Array. ```js -frameBufferToMat(rows: number, cols: number, channels: number, input: Uint8Array): Mat; +bufferToMat( + type: T, + rows: number, + cols: number, + channels: 1 | 3 | 4, + input: ImportBufferType[T] +): Mat; +``` + +where `ImportBufferType` is: + +```ts +type ImportBufferType = { + uint8: Uint8Array; + uint16: Uint16Array; + int8: Int8Array; + int16: Int16Array; + int32: Int32Array; + float32: Float32Array; + float64: Float64Array; +}; ``` ### Base64 to Mat diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6a7c6fb..75342f9 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -936,7 +936,7 @@ PODS: - React-Mapbuffer (0.74.4): - glog - React-debug - - react-native-fast-opencv (0.4.0): + - react-native-fast-opencv (0.4.1): - DoubleConversion - FastOpenCV-iOS (= 1.0.4) - glog @@ -1633,7 +1633,7 @@ SPEC CHECKSUMS: React-jsitracing: 7246bbdc12aa5ac7f25f5d14eb0e080038d75b00 React-logger: b4440a25b9c41b28042d289998d90b18c79ce2b0 React-Mapbuffer: fe1b4b0aa9c3fb49768dee7e322ee33d2dd6929e - react-native-fast-opencv: ec12ddebad1905298f63036fb9dfbfb5a1cfa502 + react-native-fast-opencv: 933f133ed6a319c8b18e105279f9f93efd39f92f react-native-image-picker: 6f7695f6e5aa43dc6275cbb3198cfa066a2f5be4 react-native-safe-area-context: b13be9714d9771fbde0120bc519c963484de3a71 react-native-skia: d0f075344d4e9333110c4f82dcf86d61105e90f9 diff --git a/example/src/examples/CameraPassthrough.tsx b/example/src/examples/CameraPassthrough.tsx index 591e3de..1786fc4 100644 --- a/example/src/examples/CameraPassthrough.tsx +++ b/example/src/examples/CameraPassthrough.tsx @@ -130,7 +130,7 @@ export function CameraPassthrough() { rotation: '90deg', }); - const frameMat = OpenCV.frameBufferToMat(HEIGHT, WIDTH, 4, resized); + const frameMat = OpenCV.bufferToMat('uint8', HEIGHT, WIDTH, 4, resized); const output = OpenCV.matToBuffer(frameMat, 'uint8'); const data = Skia.Data.fromBytes(output.buffer); diff --git a/example/src/examples/CameraRealtimeDetection.tsx b/example/src/examples/CameraRealtimeDetection.tsx index cbdb078..a3b5a8a 100644 --- a/example/src/examples/CameraRealtimeDetection.tsx +++ b/example/src/examples/CameraRealtimeDetection.tsx @@ -47,7 +47,7 @@ export function CameraRealtimeDetection() { dataType: 'uint8', }); - const src = OpenCV.frameBufferToMat(height, width, 3, resized); + const src = OpenCV.bufferToMat('uint8', height, width, 3, resized); const dst = OpenCV.createObject(ObjectType.Mat, 0, 0, DataTypes.CV_8U); const lowerBound = OpenCV.createObject(ObjectType.Scalar, 30, 60, 60); diff --git a/example/src/examples/DocumentDetection.tsx b/example/src/examples/DocumentDetection.tsx index 773972e..7f711b4 100644 --- a/example/src/examples/DocumentDetection.tsx +++ b/example/src/examples/DocumentDetection.tsx @@ -57,7 +57,7 @@ export function DocumentDetection() { }, }); - const source = OpenCV.frameBufferToMat(height, width, 3, resized); + const source = OpenCV.bufferToMat('uint8', height, width, 3, resized); OpenCV.invoke( 'cvtColor', diff --git a/src/utils/UtilsFunctions.ts b/src/utils/UtilsFunctions.ts index 2b92227..81bc71c 100644 --- a/src/utils/UtilsFunctions.ts +++ b/src/utils/UtilsFunctions.ts @@ -11,6 +11,8 @@ type BufferType = { float64: Float64Array; }; +type ImportBufferType = Omit; + export type UtilsFunctions = { /** * Clears any buffers that were allocate to back Mats on the native side. @@ -18,6 +20,9 @@ export type UtilsFunctions = { clearBuffers(idsToKeep?: string[]): void; /** * Converts a byte array to a Mat. + * + * @deprecated Use the new `bufferToMat` function instead. + * * @param rows - the number of rows in the Mat * @param cols - the number of columns in the Mat * @param channels - the number of channels in the Mat @@ -29,6 +34,20 @@ export type UtilsFunctions = { channels: number, input: Uint8Array ): Mat; + /** + * Converts a byte array to a Mat. + * @param rows - the number of rows in the Mat + * @param cols - the number of columns in the Mat + * @param channels - the number of channels in the Mat + * @param input - the byte array to convert + */ + bufferToMat( + type: T, + rows: number, + cols: number, + channels: 1 | 3 | 4, + input: ImportBufferType[T] + ): Mat; /** * Converts a base64 string to a Mat. * @param data - the base64 string to convert