title: Fixing incorrect boundingBox coordinates?
body: <p>I'm working on an object detection application for Android (in Java) using Google ML and CameraX. I'm also using a Tensorflow model, which can be found <a href="https://tfhub.dev/tensorflow/lite-model/mobilenet_v1_0.75_192_quantized/1/metadata/1" rel="nofollow noreferrer">here</a>. My issue is that the coordinates of my boundingBox are so slightly misaligned, as demonstrated in the following image. Please ignore the fact that it's being detected as a spatula, my issue currently is focused on capturing the image within the graphic displayed on the screen.</p>
  <p><a href="https://i.stack.imgur.com/Fer3Hm.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Fer3Hm.jpg" alt="enter image description here" /></a></p>
  <p>This is the following class that was used to draw the graphicOverlay;</p>
  <h2>DrawGraphic.java;</h2>
  <pre><code>public class DrawGraphic extends View {
  
      Paint borderPaint, textPaint;
      Rect rect;
      String text;
  
      ImageProxy imageProxy;
      PreviewView previewView;
  
  
      public DrawGraphic(Context context, Rect rect, String text, ImageProxy imageProxy, PreviewView previewView) {
          super(context);
          this.rect = rect;
          this.text = text;
  
          borderPaint = new Paint();
          borderPaint.setColor(Color.WHITE);
          borderPaint.setStrokeWidth(10f);
          borderPaint.setStyle(Paint.Style.STROKE);
  
          textPaint = new Paint();
          textPaint.setColor(Color.WHITE);
          textPaint.setStrokeWidth(50f);
          textPaint.setTextSize(32f);
          textPaint.setStyle(Paint.Style.FILL);
      }
  
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
          canvas.setMatrix(getMappingMatrix(imageProxy, previewView));
          canvas.concat(getMappingMatrix(imageProxy, previewView));
          canvas.drawText(text, rect.centerX(), rect.centerY(), textPaint);
          canvas.drawRect(rect.left, rect.bottom, rect.right, rect.top, borderPaint);
  
          ImageProxy imageProxy;
          PreviewView previewView;
      }
  
      Matrix getMappingMatrix(ImageProxy imageProxy, PreviewView previewView) {
          Rect cropRect = imageProxy.getCropRect();
          int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
          Matrix matrix = new Matrix();
  
          float[] source = {
                  cropRect.left,
                  cropRect.top,
                  cropRect.right,
                  cropRect.top,
                  cropRect.right,
                  cropRect.bottom,
                  cropRect.left,
                  cropRect.bottom
          };
  
          float[] destination = {
                  0f,
                  0f,
                  previewView.getWidth(),
                  0f,
                  previewView.getWidth(),
                  previewView.getHeight(),
                  0f,
                  previewView.getHeight()
          };
  
          int vertexSize = 2;
  
          int shiftOffset = rotationDegrees / 90 * vertexSize;
          float[] tempArray = destination.clone();
          for (int toIndex = 0; toIndex &lt; source.length; toIndex++) {
              int fromIndex = (toIndex + shiftOffset) % source.length;
              destination[toIndex] = tempArray[fromIndex];
          }
          matrix.setPolyToPoly(source, 0, destination, 0, 4);
          return matrix;
      }
  }
  </code></pre>
  <h2>MainActivity.java</h2>
  <pre><code>public class MainActivity extends AppCompatActivity {
  
      private static final int PERMISSIONS_REQUEST = 1;
  
      private static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
  
      public static final Size DESIRED_PREVIEW_SIZE = new Size(640, 480);
  
      private PreviewView previewView;
  
      ActivityMainBinding binding;
  
      @Override
      protected void onCreate(@Nullable Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          binding = ActivityMainBinding.inflate(getLayoutInflater());
          setContentView(binding.getRoot());
  
          previewView = findViewById(R.id.previewView);
  
          if (hasPermission()) {
              // Start CameraX
              startCamera();
          } else {
              requestPermission();
          }
      }
  
      @SuppressLint(&quot;UnsafeOptInUsageError&quot;)
      private void startCamera() {
          ListenableFuture&lt;ProcessCameraProvider&gt; cameraProviderFuture = ProcessCameraProvider.getInstance(this);
  
          cameraProviderFuture.addListener(() -&gt; {
              // Camera provider is now guaranteed to be available
              try {
                  ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
  
                  // Set up the view finder use case to display camera preview
                  Preview preview = new Preview.Builder().build();
  
                  // Choose the camera by requiring a lens facing
                  CameraSelector cameraSelector = new CameraSelector.Builder()
                          .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                          .build();
  
                  // Image Analysis
                  ImageAnalysis imageAnalysis =
                          new ImageAnalysis.Builder()
                                  .setTargetResolution(DESIRED_PREVIEW_SIZE)
                                  .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                                  .build();
  
                  imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), imageProxy -&gt; {
                      // Define rotation Degrees of the imageProxy
                      int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
                      Log.v(&quot;ImageAnalysis_degrees&quot;, String.valueOf(rotationDegrees));
  
                      @SuppressLint(&quot;UnsafeExperimentalUsageError&quot;) Image mediaImage = imageProxy.getImage();
                      if (mediaImage != null) {
                          InputImage image =
                                  InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
                          //Pass image to an ML Kit Vision API
                          //...
  
                          LocalModel localModel =
                                  new LocalModel.Builder()
                                          .setAssetFilePath(&quot;mobilenet_v1_0.75_192_quantized_1_metadata_1.tflite&quot;)
                                          .build();
  
                          CustomObjectDetectorOptions customObjectDetectorOptions =
                                  new CustomObjectDetectorOptions.Builder(localModel)
                                          .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE)
                                          .enableClassification()
                                          .setClassificationConfidenceThreshold(0.5f)
                                          .setMaxPerObjectLabelCount(3)
                                          .build();
  
                          ObjectDetector objectDetector =
                                  ObjectDetection.getClient(customObjectDetectorOptions);
  
                          objectDetector.process(image)
                                  .addOnSuccessListener(detectedObjects -&gt; {
                                      getObjectResults(detectedObjects);
                                      Log.d(&quot;TAG&quot;, &quot;onSuccess&quot; + detectedObjects.size());
                                      for (DetectedObject detectedObject : detectedObjects) {
                                          Rect boundingBox = detectedObject.getBoundingBox();
  
                                          Integer trackingId = detectedObject.getTrackingId();
                                          for (DetectedObject.Label label : detectedObject.getLabels()) {
                                              String text = label.getText();
                                              int index = label.getIndex();
                                              float confidence = label.getConfidence();
                                          }
                                      }
                                  })
                                  .addOnFailureListener(e -&gt; Log.e(&quot;TAG&quot;, e.getLocalizedMessage()))
                                  .addOnCompleteListener(result -&gt; imageProxy.close());
                      }
  
                  });
  
                  // Connect the preview use case to the previewView
                  preview.setSurfaceProvider(
                          previewView.getSurfaceProvider());
  
                  // Attach use cases to the camera with the same lifecycle owner
                  if (cameraProvider != null) {
                      Camera camera = cameraProvider.bindToLifecycle(
                              this,
                              cameraSelector,
                              imageAnalysis,
                              preview);
                  }
  
              } catch (ExecutionException | InterruptedException e) {
                  e.printStackTrace();
              }
  
  
          }, ContextCompat.getMainExecutor(this));
      }
  
      private void getObjectResults(List&lt;DetectedObject&gt; detectedObjects) {
          for (DetectedObject object : detectedObjects) {
              if (binding.parentlayout.getChildCount() &gt; 1) {
                  binding.parentlayout.removeViewAt(1);
              }
              Rect rect = object.getBoundingBox();
              String text = &quot;Undefined&quot;;
              if (object.getLabels().size() != 0) {
                  text = object.getLabels().get(0).getText();
              }
  
              DrawGraphic drawGraphic = new DrawGraphic(this, rect, text);
              binding.parentlayout.addView(drawGraphic);
          }
      }
  
      private boolean hasPermission() {
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M) {
              return checkSelfPermission(PERMISSION_CAMERA) == PackageManager.PERMISSION_GRANTED;
          } else {
              return true;
          }
      }
  
      private void requestPermission() {
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M) {
              if (shouldShowRequestPermissionRationale(PERMISSION_CAMERA)) {
                  Toast.makeText(
                          this,
                          &quot;Camera permission is required for this demo&quot;,
                          Toast.LENGTH_LONG)
                          .show();
              }
              requestPermissions(new String[]{PERMISSION_CAMERA}, PERMISSIONS_REQUEST);
          }
      }
  
      @Override
      public void onRequestPermissionsResult(
              final int requestCode, final String[] permissions, final int[] grantResults) {
          super.onRequestPermissionsResult(requestCode, permissions, grantResults);
          if (requestCode == PERMISSIONS_REQUEST) {
              if (allPermissionsGranted(grantResults)) {
                  // Start CameraX
                  startCamera();
              } else {
                  requestPermission();
              }
          }
      }
  
      private static boolean allPermissionsGranted(final int[] grantResults) {
          for (int result : grantResults) {
              if (result != PackageManager.PERMISSION_GRANTED) {
                  return false;
              }
          }
          return true;
      }
  }
  </code></pre>
  <p>This all leads to my question on why the boundingBox is slightly &quot;off&quot;. Any further information required to supplement this question will be provided upon request.</p>