so basically I’m learning on an app From the MLKit sample apps and others to detect an object with MLKit object detection and draw boundingBox with a custom, view. At first, I does work and I can detect the object and draw the boundingBox, but yet I forget to commit the project and just modified my code then it was can’t detect the object, I just wondering what’s going on
Here’s my 4 code that I potentially focus on the problem on
- ScanFragment (Here’s the portion of the Fragment code)
private fun startCamera() {
binding.cameraPreviewGraphicOverlay.clear()
val rotation = binding.previewView.display.rotation
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get()
preview = Preview.Builder()
.setTargetRotation(rotation)
.build()
preview?.setSurfaceProvider(binding.previewView.surfaceProvider)
imageAnalyser = ImageAnalysis.Builder()
.setTargetRotation(rotation)
.build()
.apply {
setAnalyzer(Executors.newSingleThreadExecutor()) {
ObjectDetectorProcessor(multiObjectMode) { it1, it2 ->
createOverlay(it1, it2)
}
}
}
cameraProvider.unbindAll()
try {
camera = cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageAnalyser
)
} catch (e: Exception) {
Log.e(TAG, "Use case binding failed", e)
}
}, ContextCompat.getMainExecutor(requireContext()))
}
private fun createOverlay(objectList: MutableList<DetectedObject>, rect: Rect) {
binding.cameraPreviewGraphicOverlay.clear()
objectList.forEach { detectedObject ->
val overlayView = ObjectDetectorGraphic(binding.cameraPreviewGraphicOverlay, detectedObject, rect)
binding.cameraPreviewGraphicOverlay.add(overlayView)
}
}
}
- ObjectDetectorProcessor
class ObjectDetectorProcessor(
private val listener: (MutableList<DetectedObject>, image: Rect) -> Unit
) : ImageAnalysis.Analyzer {
private val options = ObjectDetectorOptions.Builder()
.apply {
setDetectorMode(ObjectDetectorOptions.STREAM_MODE)
}.build()
private val detector = ObjectDetection.getClient(options)
@SuppressLint("UnsafeOptInUsageError")
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: kotlin.run {
Log.e(TAG, "Error: imageProxy null")
imageProxy.close()
return
}
// If this correct then I'll KMS
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
detector.process(image)
.addOnSuccessListener {objectList ->
listener(objectList, image.mediaImage?.cropRect!!)
}
.addOnFailureListener {
Log.e(TAG, "Error: ${it.message}", it)
}
}
companion object {
private const val TAG = "ObjectAnalyser"
}
}
- GraphicOverlay (as the custom View)
class GraphicOverlay(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val lock = Any()
var mScale: Float? = null
var mOffsetX: Float? = null
var mOffsetY: Float? = null
private val graphics = ArrayList<Graphics>()
/**
* Base class for a custom graphics objects to be rendered within the graphic overlay.
* The subclass of this can implement the [Graphic.draw] method to define the graphics element,
* and to add the instances of graphic to the overlay using the [GraphicOverlay.add]
* */
abstract class Graphics protected constructor(protected val overlay: GraphicOverlay) {
protected val context: Context = overlay.context
/** Draws the graphic on the supplied canvas. */
abstract fun draw(canvas: Canvas)
fun calculateRect(height: Float, width: Float, boundingBoxT: Rect): RectF {
// for land scape
fun isLandScapeMode(): Boolean {
return overlay.context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
}
fun whenLandScapeModeWidth(): Float {
return when(isLandScapeMode()) {
true -> width
false -> height
}
}
fun whenLandScapeModeHeight(): Float {
return when(isLandScapeMode()) {
true -> height
false -> width
}
}
val scaleX = overlay.width.toFloat() / whenLandScapeModeWidth()
val scaleY = overlay.height.toFloat() / whenLandScapeModeHeight()
val scale = scaleX.coerceAtLeast(scaleY)
overlay.mScale = scale
// Calculate offset (we need to center the overlay on the target)
val offsetX = (overlay.width.toFloat() - ceil(whenLandScapeModeWidth() * scale)) / 2.0f
val offsetY = (overlay.height.toFloat() - ceil(whenLandScapeModeHeight() * scale)) / 2.0f
overlay.mOffsetX = offsetX
overlay.mOffsetY = offsetY
val mappedBox = RectF().apply {
left = boundingBoxT.right * scale + offsetX
top = boundingBoxT.top * scale + offsetY
right = boundingBoxT.left * scale + offsetX
bottom = boundingBoxT.bottom * scale + offsetY
}
return mappedBox
}
}
fun clear() {
synchronized(lock) {
graphics.clear()
}
postInvalidate()
}
fun add(graphic: Graphics) {
synchronized(lock) {
graphics.add(graphic)
}
}
/** Draws the overlay with its associated graphic objects. */
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
synchronized(lock) {
graphics.forEach { it.draw(canvas) }
}
}
}
- And lastly the ObjectDetectorGraphic
class ObjectDetectorGraphic(overlay: GraphicOverlay, private val detectedObject : DetectedObject, private val rect: Rect) : Graphics(overlay) {
private val paintFill = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = Color.argb(70, 255, 255, 255)
style = Paint.Style.FILL
}
private val paintStroke = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = Color.GRAY
style = Paint.Style.STROKE
strokeWidth = 3f
}
override fun draw(canvas: Canvas) {
// val rect = overlay.translateRect(detectedObject.boundingBox)
val rect = calculateRect(
rect.height().toFloat(),
rect.width().toFloat(),
detectedObject.boundingBox
)
canvas.drawRect(rect, paintFill)
canvas.drawRect(rect, paintStroke)
}
}
At this rate, I don’t know what’s wrong and yet don’t know how to debug for that since on the logcat it seems I can’t find anything useful for my case.
I’m already looking at this case
(MLKit Object Detection is not detecting objects), but still not found working
archisei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.