diff --git a/app/src/main/java/org/fairscan/app/domain/ExportQuality.kt b/app/src/main/java/org/fairscan/app/domain/ExportQuality.kt index 8b0c534..050bc92 100644 --- a/app/src/main/java/org/fairscan/app/domain/ExportQuality.kt +++ b/app/src/main/java/org/fairscan/app/domain/ExportQuality.kt @@ -27,7 +27,7 @@ enum class ExportQuality( maxPixels = 2_000_000 ), HIGH( - jpegQuality = 90, - maxPixels = 5_000_000 + jpegQuality = 80, + maxPixels = 4_000_000 ) } diff --git a/evaluation/src/main/java/org/fairscan/evaluation/ExportQualityEvaluator.kt b/evaluation/src/main/java/org/fairscan/evaluation/ExportQualityEvaluator.kt new file mode 100644 index 0000000..10e6a41 --- /dev/null +++ b/evaluation/src/main/java/org/fairscan/evaluation/ExportQualityEvaluator.kt @@ -0,0 +1,220 @@ +/* + * Copyright 2025 Pierre-Yves Nicolas + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +package org.fairscan.evaluation + +import org.fairscan.imageprocessing.detectDocumentQuad +import org.fairscan.imageprocessing.extractDocument +import org.fairscan.imageprocessing.isColoredDocument +import org.fairscan.imageprocessing.scaledTo +import org.opencv.core.MatOfInt +import org.opencv.imgcodecs.Imgcodecs +import java.io.File + +fun main() { + nu.pattern.OpenCV.loadLocally() + ExportQualityEvaluator.runEvaluation() +} + +object ExportQualityEvaluator { + + fun runEvaluation() { + val root = File("evaluation") + val datasetDir = File(root, "dataset") + val imageDir = File(datasetDir, "images") + val outputDir = File("evaluation/reports/export_quality").apply { mkdirs() } + + val imgFiles = imageDir.listFiles { f -> f.extension.lowercase() == "jpg" } + ?.toList() ?: listOf() + + val qualities = listOf(60, 75, 80) + val maxPixelsList = listOf(1_500_000, 2_000_000, 4_000_000) + + for (imgFile in imgFiles) { + val imgName = imgFile.nameWithoutExtension + val maskFile = File(datasetDir, "masks/$imgName.png") + if (!maskFile.exists()) continue + + val sourceMat = Imgcodecs.imread(imgFile.absolutePath) + if (sourceMat.empty()) continue + + val maskMat = Imgcodecs.imread(maskFile.absolutePath, Imgcodecs.IMREAD_UNCHANGED) + if (maskMat.empty()) continue + + println("Processing ${imgName}...") + + val mask = MatMask(maskMat) + + val quad = detectDocumentQuad(mask, isLiveAnalysis = false) + ?.scaledTo(mask.width, mask.height, sourceMat.width(), sourceMat.height()) + if (quad == null) { + println("Failed to detect quad for $imgName") + continue + } + + val isColored = isColoredDocument(sourceMat, mask, quad) + + for (quality in qualities) { + + for (maxPixels in maxPixelsList) { + val outputMat = + extractDocument(sourceMat, quad, 0, isColored, maxPixels.toLong()) + + val outputFile = File(outputDir, "$imgName-$quality-$maxPixels.jpg") + val params = MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, quality) + if (!Imgcodecs.imwrite(outputFile.absolutePath, outputMat, params)) { + throw RuntimeException("Could not write image to ${outputFile.absolutePath}") + } + + params.release() + outputMat.release() + } + } + sourceMat.release() + generateHtmlReport(outputDir, imgName, qualities, maxPixelsList, crop = CropParams()) + } + } + + data class CropParams( + val centerX: Double = 0.5, + val centerY: Double = 0.5, + val size: Double = 0.5 + ) + + fun generateHtmlReport( + outputDir: File, + imgName: String, + qualities: List, + maxPixelsList: List, + crop: CropParams + ) { + val htmlFile = File(outputDir, "$imgName.html") + + htmlFile.writeText( + """ + + + + + $imgName – Export quality comparison + + + + +

$imgName

+ +
+ Center X + Center Y + Size +
+ + ${qualities.joinToString("") { q -> + """ +
+ ${ + maxPixelsList.joinToString("") { mp -> + val fileName = "$imgName-$q-$mp.jpg" + """ +
+
q$q - $mp px - ${File(outputDir, fileName).length() / 1024}kB
+
+ +
+
+ """ + } + } +
+ """ + }} + + + + + + """.trimIndent() + ) + } + +} \ No newline at end of file