-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: first draft of object detection on android
- Loading branch information
Charles Parker
authored and
Charles Parker
committed
Mar 21, 2024
1 parent
e732e99
commit 61ae986
Showing
26 changed files
with
1,221 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="com.mediapipe"> | ||
package="com.reactnativemediapipe"> | ||
</manifest> |
This file was deleted.
Oops, something went wrong.
25 changes: 25 additions & 0 deletions
25
android/src/main/java/com/reactnativemediapipe/MediapipePackage.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.reactnativemediapipe | ||
|
||
import com.facebook.react.ReactPackage | ||
import com.facebook.react.bridge.NativeModule | ||
import com.facebook.react.bridge.ReactApplicationContext | ||
import com.facebook.react.uimanager.ViewManager | ||
import com.mrousavy.camera.frameprocessor.FrameProcessorPluginRegistry | ||
import com.reactnativemediapipe.objectdetection.ObjectDetectionFrameProcessorPlugin | ||
import com.reactnativemediapipe.objectdetection.ObjectDetectionModule | ||
|
||
class MediapipePackage : ReactPackage { | ||
companion object { | ||
init { | ||
FrameProcessorPluginRegistry.addFrameProcessorPlugin("objectDetection") { _, _ -> | ||
ObjectDetectionFrameProcessorPlugin() | ||
} | ||
} | ||
} override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> { | ||
return listOf(ObjectDetectionModule(reactContext)) | ||
} | ||
|
||
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> { | ||
return listOf(MediapipeViewManager()) | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...ava/com/mediapipe/MediapipeViewManager.kt → ...ctnativemediapipe/MediapipeViewManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package com.mediapipe | ||
package com.reactnativemediapipe | ||
|
||
import android.graphics.Color | ||
import android.view.View | ||
|
77 changes: 77 additions & 0 deletions
77
android/src/main/java/com/reactnativemediapipe/objectdetection/ConvertHelpers.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.reactnativemediapipe.objectdetection | ||
|
||
import android.graphics.RectF | ||
import com.facebook.react.bridge.Arguments | ||
import com.facebook.react.bridge.WritableArray | ||
import com.facebook.react.bridge.WritableMap | ||
import com.facebook.react.bridge.WritableNativeMap | ||
import com.google.mediapipe.tasks.components.containers.Category | ||
import com.google.mediapipe.tasks.components.containers.Detection | ||
import java.util.Optional | ||
|
||
// Assuming simplified representations based on your descriptions | ||
fun convertCategoryToWritableMap(category: Category): WritableMap { | ||
val map = Arguments.createMap() | ||
map.putDouble("score", category.score().toDouble()) | ||
map.putInt("index", category.index()) | ||
map.putString("categoryName", category.categoryName()) | ||
map.putString("displayName", category.displayName()) | ||
return map | ||
} | ||
|
||
fun convertDetectionToWritableMap(detection: Detection): WritableMap { | ||
val map = Arguments.createMap() | ||
val categoriesArray = Arguments.createArray() | ||
detection.categories().forEach { category -> | ||
categoriesArray.pushMap(convertCategoryToWritableMap(category)) | ||
} | ||
|
||
val keypointsArray = Arguments.createArray() | ||
detection.keypoints().ifPresent { keypoints -> | ||
keypoints.forEach { keypoint -> | ||
val keypointMap = Arguments.createMap() | ||
keypointMap.putDouble("x", keypoint.x().toDouble()) | ||
keypointMap.putDouble("y", keypoint.y().toDouble()) | ||
keypoint.label().ifPresent { keypointMap.putString("label", it) } | ||
keypoint.score().ifPresent{ keypointMap.putDouble("score",it.toDouble()) } | ||
keypointsArray.pushMap(keypointMap) | ||
} | ||
} | ||
|
||
map.putArray("categories", categoriesArray) | ||
map.putMap("boundingBox", convertRectFToWritableMap(detection.boundingBox())) | ||
map.putArray("keypoints", keypointsArray) | ||
return map | ||
} | ||
|
||
fun convertRectFToWritableMap(rectF: RectF): WritableMap { | ||
val map = Arguments.createMap() | ||
map.putDouble("left", rectF.left.toDouble()) | ||
map.putDouble("top", rectF.top.toDouble()) | ||
map.putDouble("right", rectF.right.toDouble()) | ||
map.putDouble("bottom", rectF.bottom.toDouble()) | ||
return map | ||
} | ||
|
||
fun convertResultBundleToWritableMap(resultBundle: ObjectDetectorHelper.ResultBundle): WritableMap { | ||
val map = Arguments.createMap() | ||
val resultsArray = Arguments.createArray() | ||
|
||
resultBundle.results.forEach { result -> | ||
val resultMap = Arguments.createMap() | ||
resultMap.putDouble("timestampMs", result.timestampMs().toDouble()) | ||
val detectionsArray = Arguments.createArray() | ||
result.detections().forEach { detection -> | ||
detectionsArray.pushMap(convertDetectionToWritableMap(detection)) | ||
} | ||
resultMap.putArray("detections", detectionsArray) | ||
resultsArray.pushMap(resultMap) | ||
} | ||
|
||
map.putArray("results", resultsArray) | ||
map.putInt("inputImageHeight", resultBundle.inputImageHeight) | ||
map.putInt("inputImageWidth", resultBundle.inputImageWidth) | ||
map.putInt("inputImageRotation", resultBundle.inputImageRotation) | ||
map.putDouble("inferenceTime", resultBundle.inferenceTime.toDouble()) | ||
return map | ||
} |
18 changes: 18 additions & 0 deletions
18
...main/java/com/reactnativemediapipe/objectdetection/ObjectDetectionFrameProcessorPlugin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.reactnativemediapipe.objectdetection | ||
|
||
import com.mrousavy.camera.frameprocessor.Frame | ||
import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin | ||
import com.mrousavy.camera.frameprocessor.VisionCameraProxy | ||
|
||
class ObjectDetectionFrameProcessorPlugin() : | ||
FrameProcessorPlugin() { | ||
|
||
override fun callback(frame: Frame, params: MutableMap<String, Any>?): Any? { | ||
val detectorHandle:Double = params!!["detectorHandle"] as Double | ||
val detector = ObjectDetectorMap.detectorMap[detectorHandle.toInt()] ?: return false | ||
|
||
val image = frame.image | ||
detector.detectLivestreamFrame(image) | ||
return true | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
android/src/main/java/com/reactnativemediapipe/objectdetection/ObjectDetectionModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package com.reactnativemediapipe.objectdetection | ||
|
||
import com.facebook.react.bridge.Arguments | ||
import com.facebook.react.bridge.Promise | ||
import com.facebook.react.bridge.ReactApplicationContext | ||
import com.facebook.react.bridge.ReactContextBaseJavaModule | ||
import com.facebook.react.bridge.ReactMethod | ||
import com.facebook.react.modules.core.DeviceEventManagerModule | ||
import com.google.mediapipe.tasks.vision.core.RunningMode | ||
|
||
object ObjectDetectorMap { | ||
internal val detectorMap = mutableMapOf<Int, ObjectDetectorHelper>() | ||
|
||
} | ||
class ObjectDetectionModule(reactContext: ReactApplicationContext) : | ||
ReactContextBaseJavaModule(reactContext) { | ||
|
||
private var nextId = 22 // just not zero | ||
|
||
override fun getName(): String { | ||
return "ObjectDetection" | ||
} | ||
|
||
private class ObjectDetectorListener( | ||
private val module: ObjectDetectionModule, | ||
private val handle: Int | ||
) : | ||
ObjectDetectorHelper.DetectorListener { | ||
override fun onError(error: String, errorCode: Int) { | ||
module.sendErrorEvent(handle, error, errorCode) | ||
} | ||
|
||
override fun onResults(resultBundle: ObjectDetectorHelper.ResultBundle) { | ||
module.sendResultsEvent(handle, resultBundle) | ||
} | ||
} | ||
|
||
@ReactMethod | ||
fun createDetector( | ||
threshold: Float, | ||
maxResults: Int, | ||
delegate: Int, | ||
model: String, | ||
runningMode: Int, | ||
promise: Promise | ||
) { | ||
val id = nextId++ | ||
val helper = ObjectDetectorHelper( | ||
threshold = threshold, | ||
maxResults = maxResults, | ||
currentDelegate = delegate, | ||
currentModel = model, | ||
runningMode = enumValues<RunningMode>().first { it.ordinal == runningMode }, | ||
context = reactApplicationContext.applicationContext, | ||
objectDetectorListener = ObjectDetectorListener(this,id) | ||
) | ||
ObjectDetectorMap.detectorMap[id] = helper | ||
promise.resolve(id) | ||
} | ||
|
||
@ReactMethod | ||
fun releaseDetector(handle: Int,promise: Promise) { | ||
val entry = ObjectDetectorMap.detectorMap[handle] | ||
if (entry != null) { | ||
entry.clearObjectDetector() | ||
ObjectDetectorMap.detectorMap.remove(handle) | ||
} | ||
promise.resolve(true) | ||
} | ||
|
||
@ReactMethod | ||
fun addListener(eventName: String?) { | ||
/* Required for RN built-in Event Emitter Calls. */ | ||
} | ||
|
||
@ReactMethod | ||
fun removeListeners(count: Int?) { | ||
/* Required for RN built-in Event Emitter Calls. */ | ||
} | ||
private fun sendErrorEvent(handle: Int, message: String, code: Int) { | ||
val errorArgs = | ||
Arguments.makeNativeMap(mapOf("handle" to handle, "message" to message, "code" to code)) | ||
|
||
reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) | ||
.emit("onError", errorArgs) | ||
} | ||
|
||
private fun sendResultsEvent(handle: Int, bundle: ObjectDetectorHelper.ResultBundle) { | ||
val resultArgs = convertResultBundleToWritableMap(bundle) | ||
resultArgs.putInt("handle", handle) | ||
reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) | ||
.emit("onResults", resultArgs) | ||
} | ||
} |
Oops, something went wrong.