Capture/import image even when no document is detected
This commit is contained in:
@@ -27,9 +27,13 @@ import org.fairscan.app.domain.Rotation
|
||||
import org.fairscan.app.ui.screens.settings.DefaultColorMode
|
||||
import org.fairscan.imageprocessing.ColorMode
|
||||
import org.fairscan.imageprocessing.Mask
|
||||
import org.fairscan.imageprocessing.Point
|
||||
import org.fairscan.imageprocessing.Quad
|
||||
import org.fairscan.imageprocessing.autoColorMode
|
||||
import org.fairscan.imageprocessing.createQuad
|
||||
import org.fairscan.imageprocessing.extractDocument
|
||||
import org.fairscan.imageprocessing.resizeForMaxPixels
|
||||
import org.fairscan.imageprocessing.rotate
|
||||
import org.fairscan.imageprocessing.scaledTo
|
||||
import org.opencv.android.Utils
|
||||
import org.opencv.core.Mat
|
||||
@@ -106,28 +110,43 @@ fun processedImage(
|
||||
|
||||
fun extractDocumentFromBitmap(
|
||||
source: Bitmap,
|
||||
quadInMask: Quad,
|
||||
quadInMask: Quad?,
|
||||
rotationDegrees: Int,
|
||||
mask: Mask,
|
||||
mask: Mask?,
|
||||
viewModelScope: CoroutineScope,
|
||||
defaultColorMode: DefaultColorMode = DefaultColorMode.AUTO
|
||||
): CapturedPage {
|
||||
val exportQuality = ExportQuality.BALANCED
|
||||
val quad = quadInMask.scaledTo(mask.width, mask.height, source.width, source.height)
|
||||
var colorMode = ColorMode.COLOR
|
||||
var autoColorMode = colorMode
|
||||
var normalizedQuad = createQuad(listOf(
|
||||
Point(0.0, 0.0), Point(0.0, 1.0), Point(1.0, 1.0), Point(1.0, 0.0))
|
||||
)
|
||||
var page: Mat
|
||||
|
||||
val rgba = Mat()
|
||||
Utils.bitmapToMat(source, rgba)
|
||||
val bgr = Mat()
|
||||
Imgproc.cvtColor(rgba, bgr, Imgproc.COLOR_RGBA2BGR)
|
||||
rgba.release()
|
||||
val autoColorMode = autoColorMode(bgr, mask, quad)
|
||||
val colorMode = defaultColorMode.colorMode ?: autoColorMode
|
||||
val page = extractDocument(bgr, quad, rotationDegrees, colorMode, exportQuality.maxPixels)
|
||||
|
||||
if (mask == null || quadInMask == null) {
|
||||
// No document detected
|
||||
val resized = resizeForMaxPixels(bgr, exportQuality.maxPixels.toDouble())
|
||||
page = rotate(resized, rotationDegrees)
|
||||
resized.release()
|
||||
} else {
|
||||
val quad = quadInMask.scaledTo(mask.width, mask.height, source.width, source.height)
|
||||
normalizedQuad = quad.scaledTo(source.width, source.height, 1, 1)
|
||||
autoColorMode = autoColorMode(bgr, mask, quad)
|
||||
colorMode = defaultColorMode.colorMode ?: autoColorMode
|
||||
page = extractDocument(bgr, quad, rotationDegrees, colorMode, exportQuality.maxPixels)
|
||||
}
|
||||
|
||||
val pageJpeg = Jpeg.fromMat(page, exportQuality.jpegQuality)
|
||||
bgr.release()
|
||||
page.release()
|
||||
|
||||
val normalizedQuad = quad.scaledTo(source.width, source.height, 1, 1)
|
||||
val baseRotation = Rotation.fromDegrees(rotationDegrees)
|
||||
val metadata = PageMetadata(normalizedQuad, baseRotation, autoColorMode)
|
||||
val sourceJpegDeferred = viewModelScope.async(Dispatchers.IO) {
|
||||
|
||||
@@ -16,7 +16,6 @@ package org.fairscan.app.ui.screens.camera
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.camera.core.ImageProxy
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
@@ -526,7 +525,7 @@ private fun CameraPreviewWithOverlay(
|
||||
.background(Color.Black.copy(alpha = 0.6f))
|
||||
)
|
||||
}
|
||||
if (cameraUiState.showDetectionError) {
|
||||
if (cameraUiState.showCaptureError) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
@@ -534,7 +533,7 @@ private fun CameraPreviewWithOverlay(
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.error_no_document),
|
||||
text = stringResource(R.string.error_occurred),
|
||||
color = Color.White,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
|
||||
@@ -38,7 +38,7 @@ data class CameraUiState(
|
||||
val liveAnalysisState: LiveAnalysisState,
|
||||
val captureState: CaptureState,
|
||||
val importState: ImportState,
|
||||
val showDetectionError: Boolean,
|
||||
val showCaptureError: Boolean,
|
||||
val isLandscape: Boolean,
|
||||
val isDebugMode: Boolean,
|
||||
val isTorchEnabled: Boolean,
|
||||
|
||||
@@ -154,19 +154,14 @@ class CameraViewModel(appContainer: AppContainer): ViewModel() {
|
||||
private suspend fun processCapturedImage(
|
||||
source: Bitmap,
|
||||
rotationDegrees: Int,
|
||||
): CapturedPage? = withContext(Dispatchers.IO) {
|
||||
var result: CapturedPage? = null
|
||||
): CapturedPage = withContext(Dispatchers.IO) {
|
||||
val segmentation = imageSegmentationService.runSegmentationAndReturn(source)
|
||||
if (segmentation != null) {
|
||||
val mask = segmentation.segmentation
|
||||
val originalSize = ImageSize(source.width, source.height)
|
||||
val quad = detectDocumentQuad(mask, originalSize, isLiveAnalysis = false)
|
||||
if (quad != null) {
|
||||
val defaultColorMode = settingsRepository.defaultColorMode.first()
|
||||
result = extractDocumentFromBitmap(
|
||||
source, quad, rotationDegrees, mask, viewModelScope, defaultColorMode)
|
||||
}
|
||||
}
|
||||
val mask = segmentation?.segmentation
|
||||
val originalSize = ImageSize(source.width, source.height)
|
||||
val quad = mask?.let { detectDocumentQuad(mask, originalSize, isLiveAnalysis = false) }
|
||||
val defaultColorMode = settingsRepository.defaultColorMode.first()
|
||||
val result = extractDocumentFromBitmap(
|
||||
source, quad, rotationDegrees, mask, viewModelScope, defaultColorMode)
|
||||
return@withContext result
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">المزود: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">لم يعد من الممكن الوصول إلى مجلد التصدير المحدّد. يُرجى اختيار مجلد آخر.</string>
|
||||
<string name="error_no_app">لم يُعثر على تطبيق لفتح هذا الملف</string>
|
||||
<string name="error_no_document">لم يكتشف أي مستند</string>
|
||||
<string name="error_occurred">حدث خطأ</string>
|
||||
<string name="error_save">فشل حفظ الملف</string>
|
||||
<string name="export">صدِّر</string>
|
||||
<string name="export_as">صدِّر ك %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Poskytovatel: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">Vybraná složka pro export již není dostupná. Vyberte prosím jinou složku.</string>
|
||||
<string name="error_no_app">Nebyla nalezena žádná aplikace pro otevření tohoto souboru</string>
|
||||
<string name="error_no_document">Nebyl rozpoznán žádná dokument</string>
|
||||
<string name="error_occurred">Došlo k chybě</string>
|
||||
<string name="error_save">Soubor se nepodařilo uložit</string>
|
||||
<string name="export">Exportovat</string>
|
||||
<string name="export_as">Exportovat jako %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Anbieter: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">Der ausgewählte Exportordner ist nicht mehr zugänglich. Bitte wählen Sie einen anderen Ordner.</string>
|
||||
<string name="error_no_app">Keine App zum Öffnen dieser Datei gefunden</string>
|
||||
<string name="error_no_document">Kein Dokument erkannt</string>
|
||||
<string name="error_occurred">Ein Fehler ist aufgetreten</string>
|
||||
<string name="error_save">Datei konnte nicht gespeichert werden</string>
|
||||
<string name="export">Exportieren</string>
|
||||
<string name="export_as">Als %1$s exportieren</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Proveedor: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">La carpeta de exportación seleccionada ya no es accesible. Por favor, elija otra carpeta.</string>
|
||||
<string name="error_no_app">No se encontró ninguna aplicación para abrir este archivo</string>
|
||||
<string name="error_no_document">No se detectó ningún documento</string>
|
||||
<string name="error_occurred">Se produjo un error</string>
|
||||
<string name="error_save">No se pudo guardar el archivo</string>
|
||||
<string name="export">Exportar</string>
|
||||
<string name="export_as">Exportar como %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Fournisseur : %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">Le dossier d’export sélectionné n’est plus accessible. Veuillez choisir un autre dossier.</string>
|
||||
<string name="error_no_app">Aucune application trouvée pour ouvrir ce fichier</string>
|
||||
<string name="error_no_document">Aucun document détecté</string>
|
||||
<string name="error_occurred">Une erreur s’est produite</string>
|
||||
<string name="error_save">Échec de l\'enregistrement du fichier</string>
|
||||
<string name="export">Exporter</string>
|
||||
<string name="export_as">Exporter en %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Provedor: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">O cartafol de exportación seleccionado xa non é accesible. Escolle outro cartafol.</string>
|
||||
<string name="error_no_app">Non se atopou ningunha aplicación para abrir este ficheiro</string>
|
||||
<string name="error_no_document">Non se detectou ningún documento</string>
|
||||
<string name="error_occurred">Produciuse un erro</string>
|
||||
<string name="error_save">Produciuse un erro ao gardar o ficheiro</string>
|
||||
<string name="export">Exportar</string>
|
||||
<string name="export_as">Exportar como %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Provider: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">La cartella di esportazione selezionata non è più accessibile. Scegli un’altra cartella.</string>
|
||||
<string name="error_no_app">Nessuna app trovata per aprire questo file</string>
|
||||
<string name="error_no_document">Nessun documento rilevato</string>
|
||||
<string name="error_occurred">Si è verificato un errore</string>
|
||||
<string name="error_save">Impossibile salvare il file</string>
|
||||
<string name="export">Esporta</string>
|
||||
<string name="export_as">Esporta come %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Provedor: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">A pasta de exportação selecionada não está mais acessível. Escolha outra pasta.</string>
|
||||
<string name="error_no_app">Nenhum app encontrado para abrir este arquivo</string>
|
||||
<string name="error_no_document">Nenhum documento detectado</string>
|
||||
<string name="error_occurred">Ocorreu um erro</string>
|
||||
<string name="error_save">Falha ao salvar o arquivo</string>
|
||||
<string name="export">Exportar</string>
|
||||
<string name="export_as">Exportar como %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Провайдер: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">Выбранная папка экспорта больше недоступна. Пожалуйста, выберите другую папку.</string>
|
||||
<string name="error_no_app">Не найдено приложение для открытия этого файла</string>
|
||||
<string name="error_no_document">Документ не обнаружен</string>
|
||||
<string name="error_occurred">Произошла ошибка</string>
|
||||
<string name="error_save">Не удалось сохранить файл</string>
|
||||
<string name="export">Экспорт</string>
|
||||
<string name="export_as">Экспортировать как %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">Sağlayıcı: %1$s</string>
|
||||
<string name="error_export_dir_permission_lost">Seçilen dışa aktarma dizini artık erişilebilir değil. Lütfen başka bir dizin seçin.</string>
|
||||
<string name="error_no_app">No app found to open this file</string>
|
||||
<string name="error_no_document">No document detected</string>
|
||||
<string name="error_occurred">Bir hata oluştu</string>
|
||||
<string name="error_save">Failed to save file</string>
|
||||
<string name="export">Dışa aktar</string>
|
||||
<string name="export_as">%1$s olarak dışa aktar</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">提供者:%1$s</string>
|
||||
<string name="error_export_dir_permission_lost">所選的匯出目錄已無法存取。請選擇其他目錄。</string>
|
||||
<string name="error_no_app">找不到可開啟此檔案的應用程式</string>
|
||||
<string name="error_no_document">未偵測到文件</string>
|
||||
<string name="error_occurred">發生錯誤</string>
|
||||
<string name="error_save">儲存檔案失敗</string>
|
||||
<string name="export">匯出</string>
|
||||
<string name="export_as">匯出為 %1$s</string>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="error_context_provider">提供方:%1$s</string>
|
||||
<string name="error_export_dir_permission_lost">所选的导出目录已无法访问。请选择其他目录。</string>
|
||||
<string name="error_no_app">未找到可打开此文件的应用</string>
|
||||
<string name="error_no_document">未检测到任何文档</string>
|
||||
<string name="error_occurred">发生错误</string>
|
||||
<string name="error_save">无法保存文件</string>
|
||||
<string name="export">导出</string>
|
||||
<string name="export_as">导出为 %1$s</string>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="error_file_picker_launch" translatable="false">Failed to launch system file picker on this device</string>
|
||||
<string name="error_file_picker_result" translatable="false">Failed to set export directory</string>
|
||||
<string name="error_no_app">No app found to open this file</string>
|
||||
<string name="error_no_document">No document detected</string>
|
||||
<string name="error_occurred">An error occurred</string>
|
||||
<string name="error_save">Failed to save file</string>
|
||||
<string name="export">Export</string>
|
||||
<string name="export_as">Export as %1$s</string>
|
||||
|
||||
Reference in New Issue
Block a user