Android Question Crop CameraEx Preview

josejad

Expert
Licensed User
Longtime User
Hi all:

I'm trying to move the code in this sample to read barcodes into a class, and let scan whole screen, or just the part inside a rectangle.

I'm trying to achieve what Erel says in the post:
Try this:
Convert the preview data to a jpeg data (there is such a method in CameraEx) and then load it to a bitmap.
Crop the bitmap and pass it to frameBuilder with:
frameBuilder.RunMethod("setBitmap", Array(YourBitmap)) 'instead of the setImageData line

B4X:
Sub Camera1_Preview (data() As Byte)
    If SearchForBarcodes Then
        If DateTime.Now > LastPreview + IntervalBetweenPreviewsMs Then
            'Dim n As Long = DateTime.Now
            cvs.ClearRect(cvs.TargetRect)
            Dim frameBuilder As JavaObject
            Dim bb As JavaObject
            bb = bb.InitializeStatic("java.nio.ByteBuffer").RunMethod("wrap", Array(data))
            frameBuilder.InitializeNewInstance("com/google/android/gms/vision/Frame.Builder".Replace("/", "."), Null)
            Dim cs As CameraSize = camEx.GetPreviewSize
            frameBuilder.RunMethod("setImageData", Array(bb, cs.Width, cs.Height,  842094169))
            Dim frame As JavaObject = frameBuilder.RunMethod("build", Null)
            Dim SparseArray As JavaObject = detector.RunMethod("detect", Array(frame))
            LastPreview = DateTime.Now
            Dim Matches As Int = SparseArray.RunMethod("size", Null)
            For i = 0 To Matches - 1
                Dim barcode As JavaObject = SparseArray.RunMethod("valueAt", Array(i))
                Dim raw As String = barcode.GetField("rawValue")
                Log(raw)
                ToastMessageShow("Found: " & raw, True)
                Dim points() As Object = barcode.GetField("cornerPoints")
                Dim tl As JavaObject = points(0)
'                Dim tr As JavaObject = points(1)
                Dim br As JavaObject = points(2)
'                Dim bl As JavaObject = points(3)
                Dim r As B4XRect
               
                Dim size As CameraSize = camEx.GetPreviewSize
                Dim xscale, yscale As Float
                If camEx.PreviewOrientation Mod 180 = 0 Then
                    xscale = Panel1.Width / size.Width
                    yscale = Panel1.Height / size.Height
                    r.Initialize(tl.GetField("x"), tl.GetField("y"), br.GetField("x"), br.GetField("y"))
                Else
                    xscale = Panel1.Width / size.Height
                    yscale = Panel1.Height / size.Width
                    r.Initialize(br.GetField("y"), br.GetField("x"), tl.GetField("y"),tl.GetField("x"))
                End If
               
                Select camEx.PreviewOrientation
                    Case 180
                        r.Initialize(size.Width - r.Right, size.Height - r.Bottom, size.Width - r.Left, size.Height - r.Top)
                    Case 90
                        r.Initialize(size.Height - r.Right, r.Top, size.Height - r.Left, r.Bottom)
                End Select
                r.Left = r.Left * xscale
                r.Right = r.Right * xscale
                r.Top = r.Top * yscale
                r.Bottom = r.Bottom * yscale
                cvs.DrawRect(r, Colors.Red, False, 5dip)
            Next
            If Matches = 0 Then
                cvs.ClearRect(cvs.TargetRect)
            End If
            cvs.Invalidate
            'Log(DateTime.Now - n)
        End If
    End If
End Sub

So, first of all I'm trying to crop the area inside my rectangle. I've made several test, and I think I've misunderstood the relationship between GetPreviewSize and the Panel size. But we will see this later, because maybe the problem is I'm not getting the image I want.

I've tried first of all, just to show the image I have to crop, with this code
B4X:
            'Draw rectangle to detect inside. Ignore it for now
            Dim rect As B4XRect 'To draw the detection rectangle
            rect.Initialize((Panel1.Width / 2) - 100dip, (Panel1.Height / 2) - 100dip, (Panel1.Width / 2) + 100dip, (Panel1.Height / 2) + 100dip)
            cvs.DrawRect(rect, Colors.White, False, 5dip)

           'Lets capture the image preview, to crop it later
            Dim jpeg() As Byte = camEx.PreviewImageToJpeg(data, 70)
            Dim bmp As Bitmap
            Dim ins As InputStream
            ins.InitializeFromBytesArray(jpeg, 0, jpeg.Length)
            bmp.Initialize2(ins)
            ins.Close
            Dim iv As ImageView
            iv.Initialize("")
            iv.Bitmap = bmp
            Panel1.AddView(iv, 0%x, 0%y, 100%x, 100%y)
            'END ADDED

The image I get is a zoomed and rotated image (the original preview to the left, what I get showed in the imageview, to the right)

Original.jpg
Captured.jpg

So when I crop my image with the same coordinates than the rectangle, I get another part of the image.

I've searched and it seems that in the CCTV example, Erel sends the preview image as it, but I think it's made the same way I'm doing.

I hope I've explained it right.

Thanks in advance¡¡
 
Last edited:

JordiCP

Expert
Licensed User
Longtime User
Hi,

Even if your image appears in portrait, the preview data always comes in the original camera orientation (in most phones, landscape).

CameraEx applies some orientation transformations to the displayed image. In these calculations, it takes into account the reference camera orientation, the reference device orientation, and current device orientation. In most cases (if we are talking of a phone and using the back camera), the default camera position will be landscape, the reference display orientation will be portrait (not for tablets) and also your app is now in portrait. --> As a result of these calculations, it tells us that the image to be given to the displaying surfaceView will have to be rotated +90 or -90 degrees, and it is configured this way in the class.

So, you must apply something similar to the bitmap before cropping. Roughly:
  • Convert your preview to a bitmap.
  • Rotate accordingly.--> test with +90 and -90 to see which of them works, then you can improve with a general formula
  • Your 'drawn' rectangle comes in screen coordinates. Transform it to relative coordinates. Then apply these coordinates to the rotated image and crop it.

The right image comes rotated because you need the steps above. Also, I guess that it comes zoomed because you don't set the imageView gravity, try setting it to FILL
 
Upvote 0

pcicom

Member
Licensed User
Longtime User
Hi all:

I'm trying to move the code in this sample to read barcodes into a class, and let scan whole screen, or just the part inside a rectangle.

I'm trying to achieve what Erel says in the post:


B4X:
Sub Camera1_Preview (data() As Byte)
    If SearchForBarcodes Then
        If DateTime.Now > LastPreview + IntervalBetweenPreviewsMs Then
            'Dim n As Long = DateTime.Now
            cvs.ClearRect(cvs.TargetRect)
            Dim frameBuilder As JavaObject
            Dim bb As JavaObject
            bb = bb.InitializeStatic("java.nio.ByteBuffer").RunMethod("wrap", Array(data))
            frameBuilder.InitializeNewInstance("com/google/android/gms/vision/Frame.Builder".Replace("/", "."), Null)
            Dim cs As CameraSize = camEx.GetPreviewSize
            frameBuilder.RunMethod("setImageData", Array(bb, cs.Width, cs.Height,  842094169))
            Dim frame As JavaObject = frameBuilder.RunMethod("build", Null)
            Dim SparseArray As JavaObject = detector.RunMethod("detect", Array(frame))
            LastPreview = DateTime.Now
            Dim Matches As Int = SparseArray.RunMethod("size", Null)
            For i = 0 To Matches - 1
                Dim barcode As JavaObject = SparseArray.RunMethod("valueAt", Array(i))
                Dim raw As String = barcode.GetField("rawValue")
                Log(raw)
                ToastMessageShow("Found: " & raw, True)
                Dim points() As Object = barcode.GetField("cornerPoints")
                Dim tl As JavaObject = points(0)
'                Dim tr As JavaObject = points(1)
                Dim br As JavaObject = points(2)
'                Dim bl As JavaObject = points(3)
                Dim r As B4XRect
              
                Dim size As CameraSize = camEx.GetPreviewSize
                Dim xscale, yscale As Float
                If camEx.PreviewOrientation Mod 180 = 0 Then
                    xscale = Panel1.Width / size.Width
                    yscale = Panel1.Height / size.Height
                    r.Initialize(tl.GetField("x"), tl.GetField("y"), br.GetField("x"), br.GetField("y"))
                Else
                    xscale = Panel1.Width / size.Height
                    yscale = Panel1.Height / size.Width
                    r.Initialize(br.GetField("y"), br.GetField("x"), tl.GetField("y"),tl.GetField("x"))
                End If
              
                Select camEx.PreviewOrientation
                    Case 180
                        r.Initialize(size.Width - r.Right, size.Height - r.Bottom, size.Width - r.Left, size.Height - r.Top)
                    Case 90
                        r.Initialize(size.Height - r.Right, r.Top, size.Height - r.Left, r.Bottom)
                End Select
                r.Left = r.Left * xscale
                r.Right = r.Right * xscale
                r.Top = r.Top * yscale
                r.Bottom = r.Bottom * yscale
                cvs.DrawRect(r, Colors.Red, False, 5dip)
            Next
            If Matches = 0 Then
                cvs.ClearRect(cvs.TargetRect)
            End If
            cvs.Invalidate
            'Log(DateTime.Now - n)
        End If
    End If
End Sub

So, first of all I'm trying to crop the area inside my rectangle. I've made several test, and I think I've misunderstood the relationship between GetPreviewSize and the Panel size. But we will see this later, because maybe the problem is I'm not getting the image I want.

I've tried first of all, just to show the image I have to crop, with this code
B4X:
            'Draw rectangle to detect inside. Ignore it for now
            Dim rect As B4XRect 'To draw the detection rectangle
            rect.Initialize((Panel1.Width / 2) - 100dip, (Panel1.Height / 2) - 100dip, (Panel1.Width / 2) + 100dip, (Panel1.Height / 2) + 100dip)
            cvs.DrawRect(rect, Colors.White, False, 5dip)

           'Lets capture the image preview, to crop it later
            Dim jpeg() As Byte = camEx.PreviewImageToJpeg(data, 70)
            Dim bmp As Bitmap
            Dim ins As InputStream
            ins.InitializeFromBytesArray(jpeg, 0, jpeg.Length)
            bmp.Initialize2(ins)
            ins.Close
            Dim iv As ImageView
            iv.Initialize("")
            iv.Bitmap = bmp
            Panel1.AddView(iv, 0%x, 0%y, 100%x, 100%y)
            'END ADDED

The image I get is a zoomed and rotated image (the original preview to the left, what I get showed in the imageview, to the right)

View attachment 89529 View attachment 89530
So when I crop my image with the same coordinates than the rectangle, I get another part of the image.

I've searched and it seems that in the CCTV example, Erel sends the preview image as it, but I think it's made the same way I'm doing.

I hope I've explained it right.

Thanks in advance¡¡


Hi

I intented also equal to take picture, how do ?
 
Upvote 0

josejad

Expert
Licensed User
Longtime User
Sorry, I don’t understand the question. You want to take the picture from a class or crop the image?
 
Upvote 0
Top