I have an android app in Kotlin which depends on CameraX to analyze images and pass them to tensorflow lite image detection model ( not classification ). The problem is we get YUV or RGBA Output images and we need an argb bitmap to pass to tflite model to detect objects we have been struggling for weeks and we have a deadline soon help please.
ImageAnalysis.Analyzer {
private val supportedImages = listOf(ImageFormat.FLEX_RGBA_8888, ImageFormat.FLEX_RGB_888)
private var data = ""
#SuppressLint("UnsafeOptInUsageError")
override fun analyze(image: ImageProxy) {
if (image.format in supportedImages) {
val options = ObjectDetector.ObjectDetectorOptions.builder()
.setScoreThreshold(0.2F)
.setBaseOptions(BaseOptions.builder().build())
.build()
val objectDetector =
ObjectDetector.createFromFileAndOptions(
context, Model.createModel(context, "model.tflite").path, options
)
val bitmap = toBitmap(image)
val tfImage = TensorImage.fromBitmap(bitmap)
val results: List<Detection> = objectDetector.detect(tfImage)
for (result in results) {
val categories = result.categories
for (category in categories) {
val label = category.label
val boundingBox = result.boundingBox
data += "label : $label | bounding : $boundingBox"
}
}
listener(data)
image.close()
}
}
private fun toBitmap(image: ImageProxy): Bitmap {
val r = image.planes[0].buffer.int
val g = image.planes[1].buffer.int
val b = image.planes[2].buffer.int
val a = image.planes[3].buffer.int
var color = Color.argb(a, r, g, b)
val rect = Rect(0, 0, 1, 1)
color = ColorUtils.compositeColors(color, Color.WHITE)
val bitmap = Bitmap.createBitmap(rect.width(), rect.height(), Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint()
paint.color = color
canvas.drawRect(rect, paint)
savePic(bitmap = bitmap!!, display_name = Random(100000L).toString())
return bitmap
}
private fun savePic(bitmap: Bitmap, display_name: String): Boolean {
val mediaCollection = latest {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} ?: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "${display_name}.jpg")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.WIDTH, bitmap.width)
put(MediaStore.Images.Media.HEIGHT, bitmap.height)
}
return try {
context.contentResolver.insert(mediaCollection, contentValues)?.also { uri ->
context.contentResolver.openOutputStream(uri).use { outputStream ->
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)) {
throw IOException("could not save bitmap!")
}
}
} ?: throw IOException("could not create media store entry")
return true
} catch (e: IOException) {
e.printStackTrace()
false
}
}
}```
Here is the function that converts YUV_420_888 imageproxy into argb format bitmap.
I know a late answer but providing for others.
fun imageToBitmap(image: Image): Bitmap {
val planes: Array<Image.Plane> = image.planes
val yBuffer: ByteBuffer = planes[0].buffer
val uBuffer: ByteBuffer = planes[1].buffer
val vBuffer: ByteBuffer = planes[2].buffer
val ySize = yBuffer.remaining()
val uSize = uBuffer.remaining()
val vSize = vBuffer.remaining()
val nv21 = ByteArray(ySize + uSize + vSize)
//U and V are swapped
yBuffer[nv21, 0, ySize]
vBuffer[nv21, ySize, vSize]
uBuffer[nv21, ySize + vSize, uSize]
val yuvImage = YuvImage(nv21, ImageFormat.NV21, image.width, image.height, null)
val out = ByteArrayOutputStream()
yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 75, out)
val imageBytes: ByteArray = out.toByteArray()
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
}
Provide imageproxy from cameraX analyser to this function and it will provide the bitmap.
Related
I have managed to export my recyclerview in a PDF file but I am realizing that the image that is as a header is not showing in the pdf, I only know the questions and the answers that are the check boxes
I have tried the following code to show the recyclerview in pdf.
This is my activity
`
fun getScreenshotFromRecyclerView(view: RecyclerView): Bitmap? {
val adapter = view.adapter
var bigBitmap: Bitmap? = null
if (adapter != null) {
val size = listado2.size
var height = 0
val paint = Paint()
var iHeight = 0
val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
// Use 1/8th of the available memory for this memory cache.
val cacheSize = maxMemory / 8
val bitmaCache =
LruCache<String, Bitmap>(cacheSize)
for (i in 0 until size) {
val holder =
adapter.createViewHolder(view, adapter.getItemViewType(i))
adapter.onBindViewHolder(holder, i)
holder.itemView.measure(
View.MeasureSpec.makeMeasureSpec(
view.width,
View.MeasureSpec.EXACTLY
),
View.MeasureSpec.makeMeasureSpec(
0,
View.MeasureSpec.UNSPECIFIED
)
)
holder.itemView.layout(
0,
0,
holder.itemView.measuredWidth,
holder.itemView.measuredHeight
)
holder.itemView.isDrawingCacheEnabled = true
holder.itemView.buildDrawingCache()
val drawingCache = holder.itemView.drawingCache
if (drawingCache != null) {
bitmaCache.put(i.toString(), drawingCache)
}
// holder.itemView.setDrawingCacheEnabled(false);
// holder.itemView.destroyDrawingCache();
height += holder.itemView.measuredHeight
}
bigBitmap =
Bitmap.createBitmap(view.measuredWidth, height, Bitmap.Config.ARGB_8888)
val bigCanvas = Canvas(bigBitmap)
bigCanvas.drawColor(Color.WHITE)
for (i in 0 until size) {
val bitmap = bitmaCache[i.toString()]
bigCanvas.drawBitmap(bitmap!!, 0f, iHeight.toFloat(), paint)
iHeight += bitmap.height
bitmap.recycle()
}
}
return bigBitmap
}
`
This is my CreateFile.kt class
`
open fun salvarPDF(bitmap: Bitmap, nombreDeArchivo : String): String?{
archivo = File(pasta, "$nombreDeArchivo.pdf")
val archivoPDF = PdfDocument()
val pageInfo: PdfDocument.PageInfo = PageInfo.Builder(bitmap.width, bitmap.height, 1).create()
val pagina : PdfDocument.Page = archivoPDF.startPage(pageInfo)
val canvas : Canvas = pagina.canvas
canvas.drawBitmap(bitmap,null, Rect(0,0,bitmap.width, bitmap.height),null)
archivoPDF.finishPage(pagina)
try {
archivo!!.createNewFile()
val streamDeSalidad: OutputStream = FileOutputStream(archivo)
archivoPDF.writeTo(streamDeSalidad)
streamDeSalidad.close()
archivoPDF.close()
}catch (e: IOException){
return "error en crear$e"
}
return "creado"
}
`
This is the result in PDF
But it should come out as follows.
Any idea where in the code I am failing.
I was doing the simple feature that I am taking the photo with Camerax and uploading the photo to Imagga to do the face detection by using this API, and here is the API result [Face(confidence=100.0, coordinates=Coordinates(height=1243, width=1243, xmax=2660, xmin=1417, ymax=3359, ymin=2116), face_id=)]
And base on the API document, the Coordinates are parameters that I needed to input to drawRect(xmin, ymin, xmax, ymax, paint), but the rectangle is always in the wrong position on the screen.
I've tried total 64 combinations of those four points but non is correct.
What have I done wrong? here's my code
take and upload photo to Imagga:
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
Log.e(TAG, "onImageSaved: " + output.savedUri)
savedUri = output.savedUri
val file = File(getPath(savedUri, applicationContext) ?: "")
val mFile = RequestBody.create(MediaType.parse("image/*"), file)
val fileToUpload = MultipartBody.Part.createFormData("image", file.name, mFile)
photoJob?.cancel()
photoJob = lifecycleScope.launch {
binding.isLoading = true
mainViewMode.startFaceDetection(fileToUpload)
}
}
fun getPath(contentUri: Uri?, context: Context): String? {
var res: String? = null
val proj = arrayOf(MediaStore.Images.Media.DATA)
val cursor: Cursor = context.contentResolver.query(contentUri!!, proj, null, null, null)!!
if (cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
res = cursor.getString(index)
}
cursor.close()
return res
}
receive face detection results from Imagga:
mainViewMode.apply {
faceResult.observe(this#MainActivity) {
showDetectionResult(it, savedUri)
}
}
private fun showDetectionResult(it: FaceDetectionResp, savedUri: Uri?) {
Log.e(TAG, "startFaceDetection: ${it.result.faces}")
val originBitmap = MediaStore.Images.Media.getBitmap(contentResolver, savedUri)
val bmp = originBitmap!!.copy(originBitmap.config, true)
val canvas = Canvas(bmp)
val paint = Paint().apply {
color = Color.GREEN
style = Paint.Style.STROKE
strokeWidth = 5f
}
val left = it.result.faces[0].coordinates.xmin.toFloat()
val top = it.result.faces[0].coordinates.ymin.toFloat()
val right = it.result.faces[0].coordinates.xmax.toFloat()
val bottom = it.result.faces[0].coordinates.ymax.toFloat()
// it did draw the rectangle but never in the right position that I expected
canvas.drawRect(left, top, right, bottom, paint)
//because I got landscape photo, so I rotate the bitmap to portrait
binding.ivFace.setImageBitmap(rotateImage(bmp, -90f))
}
fun rotateImage(source: Bitmap, angle: Float): Bitmap? {
val matrix = Matrix()
matrix.postRotate(angle)
return Bitmap.createBitmap(
source, 0, 0, source.width, source.height,
matrix, true
)
}
I've been stuck in this for a week, can anyone help me?
I am using camerax so I am able to get bitmap from camerax imageanalysyis usecase
private val analysis = object : ImageAnalysis.Analyzer {
override fun analyze(image: ImageProxy) {
showLogD("hello rotation before","${image.imageInfo.rotationDegrees}")
val yBuffer = image.planes[0].buffer // Y
val vuBuffer = image.planes[2].buffer // VU
val ySize = yBuffer.remaining()
val vuSize = vuBuffer.remaining()
val nv21 = ByteArray(ySize + vuSize)
yBuffer.get(nv21, 0, ySize)
vuBuffer.get(nv21, ySize, vuSize)
val yuvImage = YuvImage(nv21, ImageFormat.NV21, image.width, image.height, null)
val out = ByteArrayOutputStream()
yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 100, out)
val imageBytes = out.toByteArray()
var myBitmap= BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
val matrix = Matrix()
matrix.postRotate(90f)
myBitmap= Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.width, myBitmap.height, matrix, true);
}
I want to do video recording. but I dont know how to convert bitmap to video files
So I have implement CameraX in my new application but the pictures when saving are looking very bad with distorsion. Like the image is blurry and with lines everywhere. I tried multipile converters from imageProxy to Bitmap but the result is the same. I tested on 2 devices: Samsung A72 and Samsung S20 FE.
// Camera Provider Future ------------
cameraProviderFuture.addListener({
imagePreview = Preview.Builder().apply {
setTargetAspectRatio(AspectRatio.RATIO_16_9)
}.build()
imageCapture = ImageCapture.Builder().apply {
setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
setTargetAspectRatio(AspectRatio.RATIO_16_9)
setFlashMode(ImageCapture.FLASH_MODE_AUTO)
}.build()
val cameraProvider = cameraProviderFuture.get()
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, cameraSelector, imagePreview, imageCapture)
binding.dtcCameraPreview.implementationMode = PreviewView.ImplementationMode.COMPATIBLE
imagePreview?.setSurfaceProvider(binding.dtcCameraPreview.surfaceProvider)
}, ContextCompat.getMainExecutor(this))
// Function to convert ImageProxy.image to Bitmap -----------
private fun Image.toBitmap(rotationDegrees: Int): Bitmap {
val buffer = planes[0].buffer
val bytes = ByteArray(buffer.remaining())
buffer.get(bytes)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size, null)
val matrix = Matrix()
matrix.postRotate(rotationDegrees.toFloat())
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
// imageCapture ---------------
imageCapture?.takePicture(ContextCompat.getMainExecutor(this), object :
ImageCapture.OnImageCapturedCallback() {
#SuppressLint("UnsafeOptInUsageError")
override fun onCaptureSuccess(imageProxy: ImageProxy) {
val stream = ByteArrayOutputStream()
imageProxy.image?.toBitmap(90)?.compress(
Bitmap.CompressFormat.JPEG,
100,
stream
)
IntentHelper.addObject(stream.toByteArray(), "dtc_camera_data")
val result = Intent().putExtra(
DTCCameraContract.DTC_CAMERA_ACTION,
DTCCameraAction(false, isPictureTaken = true)
)
setResult(Activity.RESULT_OK, result)
imageProxy.close()
finish()
}
I Want to like this with renderscript filters a example gif is given below
My problem
In my code my code all renderscript filters running well but problem is when i am changing filter then resest the bitmap then update the filter value with bitmap .
class Filters(private val context: Context) {
private val TAG = BrightnessFilter::class.java.simpleName
private var rs: RenderScript = RenderScript.create(context)
private var brightnessScript: ScriptC_brightness = ScriptC_brightness(rs)
private var contrastScript: ScriptC_contrast = ScriptC_contrast(rs)
private var saturationFilter: ScriptC_saturation = ScriptC_saturation(rs)
private var convolution: ScriptIntrinsicConvolve3x3 =
ScriptIntrinsicConvolve3x3.create(rs, Element.U8_4(rs))
private var vignetteFilter: ScriptC_vignette = ScriptC_vignette(rs)
fun setBrightnessX(values: Float, inputImage: Bitmap): Bitmap {
val outBitmap = Bitmap.createBitmap(inputImage)
val tempIn = Allocation.createFromBitmap(rs, inputImage)
val tempOut = Allocation.createFromBitmap(rs, outBitmap)
brightnessScript.invoke_setBright(values)
brightnessScript.forEach_brightness(tempIn, tempOut)
tempOut.copyTo(outBitmap)
return outBitmap
}
fun setContrastX(contrast: Float, inputImage: Bitmap): Bitmap {
val outBitmap = Bitmap.createBitmap(inputImage)
val tempIn = Allocation.createFromBitmap(rs, inputImage)
val tempOut = Allocation.createFromBitmap(rs, outBitmap)
contrastScript._contrast = contrast
contrastScript.forEach_contrastness(tempIn, tempOut)
tempOut.copyTo(outBitmap)
tempIn.destroy()
tempOut.destroy()
return outBitmap
}
fun setSaturationX(saturation: Float, inputImage: Bitmap): Bitmap {
val outBitmap = Bitmap.createBitmap(inputImage)
val tempIn = Allocation.createFromBitmap(rs, inputImage)
val tempOut = Allocation.createFromBitmap(rs, outBitmap)
saturationFilter._saturationValue = saturation
saturationFilter.forEach_saturation(tempIn, tempOut)
tempOut.copyTo(outBitmap)
tempIn.destroy()
tempOut.destroy()
return outBitmap
}
fun sharpenX(sharpen: Float, bitmap: Bitmap): Bitmap {
val matrix = floatArrayOf(
0f, -sharpen, 0f,
-sharpen, 1 + 4 * sharpen, -sharpen,
0f, -sharpen, 0f
)
return applySharpenConvolveX(bitmap, matrix)
}
private fun applySharpenConvolveX(inputImage: Bitmap, coefficients: FloatArray): Bitmap {
val outBitmap = Bitmap.createBitmap(inputImage)
val tempIn = Allocation.createFromBitmap(rs, inputImage)
val tempOut = Allocation.createFromBitmap(rs, outBitmap)
convolution.setInput(tempIn)
convolution.setCoefficients(coefficients)
convolution.forEach(tempOut)
tempOut.copyTo(outBitmap)
return outBitmap
}
fun vignetteX(values: Float, inputImage: Bitmap): Bitmap {
vignetteFilter.setScale(values)
return vignetteFilter.x(inputImage)
}
}
For Slider Value change currentFilter is called and update the output Bitmap with ImageView
private fun currentFilter(values: Float): Bitmap {
return when (_recentTab.value!!) {
FilterName.BRIGHTNESS -> _filter.value!!.setBrightnessX(values, mInputImage)
FilterName.CONTRAST -> _filter.value!!.setContrastX(values, mInputImage)
FilterName.SATURATION -> _filter.value!!.setSaturationX(values, mInputImage)
FilterName.SHARPEN -> _filter.value!!.sharpenX(values, mInputImage)
FilterName.VIGNETTE -> _filter.value!!.vignetteX(values, mInputImage)
}
}