Improve distinction between color and grayscale documents (#36)

This commit is contained in:
Pierre-Yves Nicolas
2025-09-18 19:01:17 +02:00
parent 41ff4e4cad
commit b03b2f98e2

View File

@@ -40,21 +40,63 @@ fun enhanceCapturedImage(img: Mat): Mat {
} }
} }
fun isColoredDocument(img: Mat, threshold: Double = 4.0): Boolean { fun isColoredDocument(
img: Mat,
chromaThreshold: Double = 20.0,
proportionThreshold: Double = 0.001
): Boolean {
val lab = Mat() val lab = Mat()
Imgproc.cvtColor(img, lab, Imgproc.COLOR_BGR2Lab) Imgproc.cvtColor(img, lab, Imgproc.COLOR_BGR2Lab)
val channels = ArrayList<Mat>() val channels = ArrayList<Mat>()
Core.split(lab, channels) Core.split(lab, channels)
val a = channels[1]
val b = channels[2]
val aStd = MatOfDouble() val aFloat = Mat()
val bStd = MatOfDouble() val bFloat = Mat()
Core.meanStdDev(channels[1], MatOfDouble(), aStd) a.convertTo(aFloat, CvType.CV_32F)
Core.meanStdDev(channels[2], MatOfDouble(), bStd) b.convertTo(bFloat, CvType.CV_32F)
val result = (aStd.toArray()[0] + bStd.toArray()[0]) / 2.0 val aShifted = Mat()
return result > threshold val bShifted = Mat()
Core.subtract(aFloat, Scalar(128.0), aShifted)
Core.subtract(bFloat, Scalar(128.0), bShifted)
val aSq = Mat()
val bSq = Mat()
Core.multiply(aShifted, aShifted, aSq)
Core.multiply(bShifted, bShifted, bSq)
val sumSq = Mat()
Core.add(aSq, bSq, sumSq)
val chroma = Mat()
Core.sqrt(sumSq, chroma)
val mask = Mat()
Imgproc.threshold(chroma, mask, chromaThreshold, 1.0, Imgproc.THRESH_BINARY)
val coloredPixels = Core.countNonZero(mask)
val totalPixels = chroma.rows() * chroma.cols()
val proportion = coloredPixels.toDouble() / totalPixels.toDouble()
lab.release()
channels.forEach { it.release() }
aFloat.release()
bFloat.release()
aShifted.release()
bShifted.release()
aSq.release()
bSq.release()
sumSq.release()
chroma.release()
mask.release()
return proportion > proportionThreshold
} }
private fun multiScaleRetinex(img: Mat, kernelSizes: List<Double> = listOf(30.0, 500.0)): Mat { private fun multiScaleRetinex(img: Mat, kernelSizes: List<Double> = listOf(30.0, 500.0)): Mat {
// Convert to grayscale (1 channel) // Convert to grayscale (1 channel)
val gray = Mat() val gray = Mat()