I want to get some info from barcode using my camera.
It works when I use png image downloaded from site, but when I try to get it work with a photo I took, it outputs me the empty array. Seems like I need to make some preps with the image in order to make it work.
Here is my code:
fun getTheBarCode(bitmap: Bitmap) {
val options = FirebaseVisionBarcodeDetectorOptions.Builder()
.setBarcodeFormats(
FirebaseVisionBarcode.FORMAT_AZTEC)
.build()
val detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options)
val bm = BitmapFactory.decodeResource(getResources(), R.drawable.barcode) //this is the place where I can load my downloaded barcode to make everything work!
val newBitmap = Bitmap.createScaledBitmap(bitmap, 300, 500, false)
val image = FirebaseVisionImage.fromBitmap(newBitmap)
photoImage.setImageBitmap(newBitmap)
detector.detectInImage(image)
.addOnSuccessListener {
Log.d("Success", "Success")
//empty array here, when I take picture.
}
.addOnFailureListener {
Log.d("Failed", it.message)
}
}
This is how I get the image from the camera
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val photo = data.extras.get("data") as Bitmap
getTheBarCode(photo)
}
}
Edit:
I've take a picture with my phone, scale it down to 1500x1000px and put it inside my app directory, then loaded it as a bitmap.
Still not working.
The approach you're using will only give you back thumbnail of photo (as per https://developer.android.com/training/camera/photobasics) ...that may not be sufficient for what you're trying to do. That link also contains info on how to get access to full size photo.
Related
I am trying to learn Kotlin and I'm building a simple example as I go. I have 3 image buttons that open the camera and take a photo. The thumbnail is then set into an ImageView. I've used the examples from https://developer.android.com/training/camera/photobasics?hl=en to get the basics working (figuring if I can make it work for one, it'll work for all. It does indeed work for one, but I can't figure out how to make it one function that drops the thumbnail into the correct ImageView.
Inside my onCreate I have the listener for each of the buttons that will invoke the camera:
camRead1.setOnClickListener {dispatchTakePictureIntent() }
camRead2.setOnClickListener {dispatchTakePictureIntent() }
camRead3.setOnClickListener {dispatchTakePictureIntent() }
And I took the sample from the url above:
val REQUEST_IMAGE_CAPTURE = 1
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val thumb: ImageView = findViewById(R.id.thumbRead1)
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
val imageBitmap = data.extras.get("data") as Bitmap
thumb.setImageBitmap(imageBitmap)
}
}
and pasted it into my class MainActivity, and after I replaced imageView in the override function with a variable (thumb) and added the super, it worked perfectly for the first one.
However, I am trying to get 3 photos, read1, read2, and read3 which each need to display the thumb in thumbRead1, thumbRead2 and thumbRead3. I can't figure out how the onActivityResult is executed since the call inside dispatchTakePictureIntent is calling startActivityForResult (especially as Android Studio says that startActivityForResult is deprecated).
Obviously, once onActivityResult executes, I can see that thumb defines R.id.thumbRead1 and receives imageBitmap but I don't understand how I can make it aware of the button that was clicked.
Without understanding how onActivityResult is called, I'm thinking that if I can do something like:
findViewById(R.id("thumbRead" + imgID))
to define the specific ImageView that I want the photo pasted into. Am I on the right track here? If not, what is the recommended way of doing this?
Note they've recently added what's supposed to be a cleaner way of starting other activities for results and getting the results, explained here. But since you're already doing it the traditional way, I'll explain how to get that working.
I think the easiest thing to do in this situation is just make more request codes, so you can check which request it was.
val REQUEST_IMAGE_CAPTURE_SOURCE_1 = 1
val REQUEST_IMAGE_CAPTURE_SOURCE_2 = 2
val REQUEST_IMAGE_CAPTURE_SOURCE_3 = 3
//...
camRead1.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_1) }
camRead2.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_2) }
camRead3.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_3) }
//...
private fun dispatchTakePictureIntent(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestCode)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_OK) {
// possibly show message to user
return
}
val imageViewId = when (requestCode) {
REQUEST_IMAGE_CAPTURE_SOURCE_1 -> R.id.thumbRead1
REQUEST_IMAGE_CAPTURE_SOURCE_2 -> R.id.thumbRead2
REQUEST_IMAGE_CAPTURE_SOURCE_3 -> R.id.thumbRead3
}
val imageView = findViewById<ImageView>(imageViewId)
imageView.imageBitmap = data.extras.get("data") as Bitmap
}
By the way, if you want to get an ID for a view using the String like you were showing you were trying, you would do it like this:
val viewId = resources.getIdentifier("thumbRead$imgId", "id", packageName)
val imageView = findViewById<ImageView>(viewId)
You need to pass different request code for each call and pass it to the dispatchTakePictureIntent function. You do not need to get id by findviewbyid. You simply can add the image on the basis of the request code.
val REQUEST_IMAGE_CAPTURE_ONE = 1
val REQUEST_IMAGE_CAPTURE_TWO = 2
val REQUEST_IMAGE_CAPTURE_THREE = 3
private fun dispatchTakePictureIntent(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestCode)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
val imageBitmap = data.extras.get("data") as Bitmap
if (requestCode == REQUEST_IMAGE_CAPTURE_ONE ) {
thumbRead1.setImageBitmap(imageBitmap)
}else if (requestCode == REQUEST_IMAGE_CAPTURE_TWO ) {
thumbRead2.setImageBitmap(imageBitmap)
}else if (requestCode == REQUEST_IMAGE_CAPTURE_THREE ) {
thumbRead3.setImageBitmap(imageBitmap)
}
}
}
I am opening my phones camera, taking a photo, showing a 50px snippet then saving an image into FirebaseFireStore Storage.
The image is very pixelated when I download it from FireStore. Can someone have a look at my code to see were I am going wrong please?
Perhaps I am saving the 50px image, whereas I would like to save the image that was taken from the camera.
Variable
val REQUEST_CODECAM = 200
var bitmapPhoto: Bitmap? = null
Open the Camera
binding!!.galleryContainer.setOnClickListener { v: View? ->
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(cameraIntent, REQUEST_CODECAM)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODECAM && data != null){
bitmapPhoto = data.extras?.get("data") as Bitmap
// Image is shown in 50px ListView cell
binding!!.issueImage.setImageBitmap(data.extras?.get("data") as Bitmap)
//imageUri = data.data
//Picasso.get().load(imageUri).into(binding!!.issueImage)
}
}
Save Button Pressed...
fun saveImage(action: GenericAction?) {
val imageName = UUID.randomUUID().toString()
val imageReference = FirebaseStorage.getInstance().reference.child("partInfoImagesFolder").child(imageName)
val baos = ByteArrayOutputStream()
bitmapPhoto.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
var uploadTask = imageReference.putBytes(data)
uploadTask.addOnFailureListener {
// Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
// taskSnapshot.metadata contains file metadata such as size, content-type, etc.
// ...
imageReference.downloadUrl.addOnCompleteListener { task1: Task<Uri?>? ->
if (task1 != null) {
if (task1.isSuccessful()) {
saveCollOfURLString = task1.getResult().toString()
action?.onCallback()
}
}
}
}
}
I'm trying to use TensorImage.load() to load a bitmap of picture the user took with the camera app. When I pass in the bitmap I get this error:
java.lang.IllegalArgumentException: Only supports loading ARGB_8888 bitmaps
This is my code for when I call the load function. First, it starts with the onActivityResult:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CAMERA_REQUEST_CODE) {
if(Build.VERSION.SDK_INT < 28) {
val foodBitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, Uri.fromFile(photoFile))
// pass this bitmap to the classifier
val predictions = foodClassifier.recognizeImage(foodBitmap, 0)
} else {
val source = ImageDecoder.createSource(this.contentResolver, Uri.fromFile(photoFile))
val foodBitmap = ImageDecoder.decodeBitmap(source)
// pass this bitmap to the classifier
val predictions = foodClassifier.recognizeImage(foodBitmap, 0)
}
}
}
In the recognizeImage function, I call a variable named inputImageBuffer which is of type TensorImage. I call the load function and pass the bitmap. This is where the application crashes. Can someone tell me how do I fix this?
I solved the issue by changing the bitmap configuration in simplest way.
Bitmap bmp = imageBitmap.copy(Bitmap.Config.ARGB_8888,true) ;
Here
ii - Bitmap is immutable therefore I have make a copy with Bitmap.Config.ARGB_8888 configuration and a new Bitmap with refrence,
for further reference
https://developer.android.com/reference/android/graphics/Bitmap.Config
For anyone else this is how I solved the issue by changing the bitmap configuration.
// Convert the image to a Bitmap
var bitmap: Bitmap? = null
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val source = ImageDecoder.createSource(requireContext().contentResolver, uri!!)
bitmap = ImageDecoder.decodeBitmap(source)
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
} else {
bitmap = MediaStore.Images.Media.getBitmap(requireContext().contentResolver, uri!!)
}
} catch (e: Exception) {
println("Could not convert image to BitMap")
e.printStackTrace()
}
My old implementation to upload image to Firebase Storage in JPEG format without any compression
private fun sendToFirebase() {
if (imgUri != null) {
val fileRef = storageRef!!.child(username+ ".jpg")
....
// code to upload and read image url
}
}
Decided to write a image compression technique to compress image and then upload to Firebase Storage
Result : Achieved image compression technique, see below
Newly added code to compress image
URI to Bitmap
val bitmap = MediaStore.Images.Media.getBitmap(activity?.contentResolver, imgUri)
Method to compress Bitmap
private fun compressBitmap(bitmap: Bitmap, quality:Int):Bitmap{
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP, quality, stream)
val byteArray = stream.toByteArray()
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
Bitmap compression Implementation
compressBitmap(bitmap, 80)
Query: How to upload same compressed image to Firebase storage
private fun sendToFirebase() {
if (imgUri != null) {
// code to convert uri to bitmap <start>
val bitmap = MediaStore.Images.Media.getBitmap(activity?.contentResolver, imgUri)
compressBitmap(bitmap, 80)
// code to convert uri to bitmap <end>
// old implementation
.....
}
}
You don't seem to be passing anything into your function for sendtoFirebase. i am posting code i have done to successfully upload.
you looking at compressing first so you would need this;
private fun compressBitmap(bitmap: Bitmap, quality: Int): Bitmap {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP,quality,stream)
val byteArray = stream.toByteArray()
arrayByte = byteArray
uploadFile(arrayByte)
return BitmapFactory.decodeByteArray(byteArray,0,byteArray.size)
}
in the above, uploadFile is the call for the firebase upload. i am passing the compressed bitmap into the function. the functional for upload looks as follows:
in below mImageURI is a companion object which is part of the URI passed for compression. you can remove the if statement below if you dont want to do the check
private fun uploadFile(data:ByteArray) {
if (mImageUri != null){
val storageref = imageref.child("put your image id here")
storageref.putBytes(data).addOnSuccessListener {
Handler().postDelayed({
progressbar.setProgress(0)
Toast.makeText(activity, "Upload Successful", Toast.LENGTH_LONG).show()
}
, 1000)
}.addOnFailureListener{e->
Toast.makeText(activity,e.message,Toast.LENGTH_LONG).show()
}.addOnProgressListener {taskSnapshot ->
val progress = (100.0 * taskSnapshot.bytesTransferred/taskSnapshot.totalByteCount)
progressbar.setProgress(progress.toInt())
}
}
else if(mImageUri == null) {
Toast.makeText(activity,"No File Selected",Toast.LENGTH_LONG).show()
}
}
You do not need to have the progress bar above. its just a nice visual for the user to have to see the progress of the upload if the file is large.
your really only need to ensure that you passing data into .putbytes
Edit: For your onActivity result if your code is similar to mine then use;
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK
&& data != null && data.getData() != null) {
mImageUri = data.getData()!!
image1.setImageURI(data.getData())
}
}
in the above image1 is a imageView on the current page to show the image selected.
Hope this helps
I am writing an app that requires the Firebase ml kit to read text (FirebaseVisionImage) and i am using this Google Firebase Page for instructions.
However I am having issues using the MediaStore.ACTION_IMAGE_CAPTURE Intent. When i run the app, take a photo and then try and process the image i mostly get back null from the text recogniser. I believe this is due to the orientation not being provided or that on Android the ACTION_IMAGE_CAPTURE is only using the thumbnail?
When it does (kind of) work (not return null) the text recogniser is not recognising any of the text and instead may return just a few characters. It is probably worth noting that i have developed a prototype of this same app on iOS and it is working fine. My take away from this is that it is how the image is captured and returned between the two platforms. On iOS i call a function to get the image orientation and parse that in to the FirebaseVision function.
The documentation also uses CameraX in some of its examples however i am not using this as it seems to still be in alpha stage of development.
Have i missed something? How do i get the orientation?
private fun openCamera() {
val values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, R.string.app_name)
values.put(MediaStore.Images.Media.DESCRIPTION, "Capturing Photo!")
image_uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
//camera intent
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri)
startActivityForResult(cameraIntent, IMAGE_CAPTURE_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK) {
//process captured image
//image_uri
Log.d(TAG, "$image_uri")
val bmp = MediaStore.Images.Media.getBitmap(contentResolver, image_uri)
val image = FirebaseVisionImage.fromBitmap(bmp)
val detector = FirebaseVision.getInstance().onDeviceTextRecognizer
val result = detector.processImage(image)
.addOnSuccessListener { firebaseVisionText ->
// Task completed successfully
// ...
Log.d(TAG, "Process complete -> ${firebaseVisionText.text}")
val resultText = firebaseVisionText.text
Log.d(TAG, "$resultText")
}
.addOnFailureListener { e ->
Log.d(TAG, "Process failed $e")
}
} else {
Log.d(TAG, "onActivityResult -> resultCode: $resultCode")
}
}