diff --git a/app/src/androidTest/java/org/fairscan/app/domain/DocumentDetectionTest.kt b/app/src/androidTest/java/org/fairscan/app/domain/DocumentDetectionTest.kt index e15abbd..cadf1c2 100644 --- a/app/src/androidTest/java/org/fairscan/app/domain/DocumentDetectionTest.kt +++ b/app/src/androidTest/java/org/fairscan/app/domain/DocumentDetectionTest.kt @@ -23,6 +23,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import kotlinx.coroutines.runBlocking import org.fairscan.app.ui.screens.camera.extractDocumentFromBitmap +import org.fairscan.imageprocessing.ImageSize import org.fairscan.imageprocessing.detectDocumentQuad import org.fairscan.imageprocessing.scaledTo import org.junit.Assert.assertEquals @@ -48,26 +49,24 @@ class DocumentDetectionTest { listOf("img01.jpg", "img02.jpg", "img03.jpg").forEach { imageFileName -> val inputStream = context.assets.open("uncropped/$imageFileName") val bitmap = BitmapFactory.decodeStream(inputStream) - var outputBitmap: Bitmap? = null + var outputJpeg: ByteArray? = null val segmentationResult = runBlocking { - segmentationService.runSegmentationAndReturn(bitmap, 0) + segmentationService.runSegmentationAndReturn(bitmap) } if (segmentationResult != null) { val mask = segmentationResult.segmentation - val quad = detectDocumentQuad(mask, false) + val quad = detectDocumentQuad(mask, ImageSize(bitmap.width, bitmap.height),false) if (quad != null) { val resizedQuad = quad.scaledTo(mask.width, mask.height, bitmap.width, bitmap.height) - outputBitmap = extractDocumentFromBitmap(bitmap, resizedQuad, 0, mask).page + outputJpeg = extractDocumentFromBitmap(bitmap, resizedQuad, 0, mask).pageJpeg val file = File(context.getExternalFilesDir(null), imageFileName) - FileOutputStream(file).use { - outputBitmap.compress(Bitmap.CompressFormat.JPEG, 95, it) - } + file.writeBytes(outputJpeg) Log.i("DocumentDetectionTest", "Image saved to ${file.absolutePath}") } } - if (outputBitmap == null) { + if (outputJpeg == null) { fail("Failed to extract document from image $imageFileName") } } diff --git a/app/src/main/java/org/fairscan/app/MainViewModel.kt b/app/src/main/java/org/fairscan/app/MainViewModel.kt index a725c9c..96e09b8 100644 --- a/app/src/main/java/org/fairscan/app/MainViewModel.kt +++ b/app/src/main/java/org/fairscan/app/MainViewModel.kt @@ -109,7 +109,7 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode fun handleImageCaptured(capturedPage: CapturedPage) { viewModelScope.launch { imageRepository.add( - compressJpeg(capturedPage.page, 75), + capturedPage.pageJpeg, compressJpeg(capturedPage.source, 90), capturedPage.metadata, ) diff --git a/app/src/main/java/org/fairscan/app/domain/CapturedPage.kt b/app/src/main/java/org/fairscan/app/domain/CapturedPage.kt index 5aeb30c..2b67335 100644 --- a/app/src/main/java/org/fairscan/app/domain/CapturedPage.kt +++ b/app/src/main/java/org/fairscan/app/domain/CapturedPage.kt @@ -18,7 +18,7 @@ package org.fairscan.app.domain import android.graphics.Bitmap data class CapturedPage( - val page: Bitmap, + val pageJpeg: ByteArray, val source: Bitmap, val metadata: PageMetadata, ) diff --git a/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraScreen.kt b/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraScreen.kt index d0ee811..ca76038 100644 --- a/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraScreen.kt +++ b/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraScreen.kt @@ -285,7 +285,7 @@ private fun CameraScreenScaffold( ) } if (cameraUiState.captureState is CaptureState.CapturePreview) { - val page = cameraUiState.captureState.capturedPage.page + val page = bitmap(cameraUiState.captureState.capturedPage.pageJpeg) CapturedImage(page.asImageBitmap(), thumbnailCoords) } } @@ -533,10 +533,10 @@ fun CameraScreenPreviewWithProcessedImage() { val p = Point(0 , 0) val quad = Quad(p, p, p, p) ScreenPreview(CaptureState.CapturePreview( - debugImage("uncropped/img01.jpg"), + bitmap(debugImage("uncropped/img01.jpg")), CapturedPage( debugImage("gallica.bnf.fr-bpt6k5530456s-1.jpg"), - debugImage("gallica.bnf.fr-bpt6k5530456s-1.jpg"), + bitmap(debugImage("gallica.bnf.fr-bpt6k5530456s-1.jpg")), PageMetadata(quad, R0, false)))) } @@ -559,7 +559,7 @@ private fun ScreenPreview(captureState: CaptureState, rotationDegrees: Float = 0 contentAlignment = Alignment.TopCenter ) { Image( - debugImage("uncropped/img01.jpg").asImageBitmap(), + bitmap(debugImage("uncropped/img01.jpg")).asImageBitmap(), modifier=Modifier.rotate(rotationDegrees), contentDescription = null ) @@ -591,9 +591,9 @@ private fun ScreenPreview(captureState: CaptureState, rotationDegrees: Float = 0 } @Composable -private fun debugImage(imgName: String): Bitmap { +private fun debugImage(imgName: String): ByteArray { val context = LocalContext.current - return context.assets.open(imgName).use { input -> - BitmapFactory.decodeStream(input) - } + return context.assets.open(imgName).readBytes() } + +private fun bitmap(jpeg: ByteArray): Bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.size) diff --git a/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt b/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt index 545e452..66a960e 100644 --- a/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt +++ b/app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt @@ -37,6 +37,7 @@ import org.fairscan.imageprocessing.ImageSize import org.fairscan.imageprocessing.Mask import org.fairscan.imageprocessing.Quad import org.fairscan.imageprocessing.detectDocumentQuad +import org.fairscan.imageprocessing.encodeJpeg import org.fairscan.imageprocessing.extractDocument import org.fairscan.imageprocessing.isColoredDocument import org.fairscan.imageprocessing.scaledTo @@ -218,27 +219,14 @@ fun extractDocumentFromBitmap( val isColored = isColoredDocument(bgr, mask, quad) val maxPixels = ExportQuality.BALANCED.maxPixels val page = extractDocument(bgr, quad, rotationDegrees, isColored, maxPixels) - val outBgr = page + val pageJpeg = encodeJpeg(page, ExportQuality.BALANCED.jpegQuality) bgr.release() - val outBitmap = toBitmap(outBgr) - outBgr.release() + page.release() + val normalizedQuad = quad.scaledTo(source.width, source.height, 1, 1) val baseRotation = Rotation.fromDegrees(rotationDegrees) val metadata = PageMetadata(normalizedQuad, baseRotation, isColored) - return CapturedPage(outBitmap, source, metadata) -} - -fun toBitmap(bgr: Mat): Bitmap { - require(bgr.type() == CvType.CV_8UC3) - - val rgba = Mat() - Imgproc.cvtColor(bgr, rgba, Imgproc.COLOR_BGR2RGBA) - - val bmp = createBitmap(bgr.cols(), bgr.rows(), Bitmap.Config.ARGB_8888) - Utils.matToBitmap(rgba, bmp) - - rgba.release() - return bmp + return CapturedPage(pageJpeg, source, metadata) } fun rotateBitmap(source: Bitmap, angle: Float): Bitmap { diff --git a/imageprocessing/src/main/java/org/fairscan/imageprocessing/PostProcessing.kt b/imageprocessing/src/main/java/org/fairscan/imageprocessing/PostProcessing.kt index 6aedb86..76dd90d 100644 --- a/imageprocessing/src/main/java/org/fairscan/imageprocessing/PostProcessing.kt +++ b/imageprocessing/src/main/java/org/fairscan/imageprocessing/PostProcessing.kt @@ -316,14 +316,11 @@ fun enhanceGrayscaleImage(img: Mat): Mat { val denoised = Mat() Imgproc.bilateralFilter(stretched8u, denoised, 9, 20.0, 10.0) - val finalBgr = Mat() - Imgproc.cvtColor(denoised, finalBgr, Imgproc.COLOR_GRAY2BGR) - // -- Cleanup ----------- gray.release(); imgFloat.release(); logImg.release() blur.release(); logBlur.release(); diff.release() retinex.release(); result8u.release() - stretched8u.release(); denoised.release() + stretched8u.release(); - return finalBgr + return denoised }