Move SSD edge mask to typed Kotlin
ober
573e97fea4a03cb8b80c00afa0df5e9c06a9e8b5
--- a/.build.yml +++ b/.build.yml @@ -5,7 +5,7 @@ packages: - make=4.4.1-r4 sources: # Build dependency: full immutable commit, mirrored in dependencies.lock.json. - - "https://git.sr.ht/~lisp/jerboa#9dd139f6d61883e002be82dcdf923d357d09c1b0" + - "https://git.sr.ht/~lisp/jerboa#b0c66c1bb8042f3c48fcb3eae95222bc50d0a410" # The second source is the build subject selected by the SourceHut submitter. - https://git.sr.ht/~lisp/jerboa-android tasks: @@ -14,6 +14,6 @@ tasks: test "$(apk info -v chez-scheme)" = chez-scheme-10.3.0-r2 test "$(apk info -v git)" = git-2.54.0-r0 test "$(apk info -v make)" = make-4.4.1-r4 - test "$(git -C ../jerboa rev-parse HEAD)" = 9dd139f6d61883e002be82dcdf923d357d09c1b0 - test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = d9c0b1bd6f2c6c87bee6610e275b3997d29e53ac + test "$(git -C ../jerboa rev-parse HEAD)" = b0c66c1bb8042f3c48fcb3eae95222bc50d0a410 + test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = cde344bb6e2cda51bf460b54492ee3f42d953850 JERBOA="chez --libdirs .:../jerboa/lib --script" make test --- a/dependencies.lock.json +++ b/dependencies.lock.json @@ -11,8 +11,8 @@ "generator_runtime": { "name": "jerboa", "repository": "https://git.sr.ht/~lisp/jerboa", - "commit": "9dd139f6d61883e002be82dcdf923d357d09c1b0", - "tree": "d9c0b1bd6f2c6c87bee6610e275b3997d29e53ac" + "commit": "b0c66c1bb8042f3c48fcb3eae95222bc50d0a410", + "tree": "cde344bb6e2cda51bf460b54492ee3f42d953850" }, "assurance_tools": { "osv_scanner": { --- a/scripts/verify-supply-chain.sh +++ b/scripts/verify-supply-chain.sh @@ -3,8 +3,8 @@ set -eu repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) lock="$repo/dependencies.lock.json" -jerboa_commit=9dd139f6d61883e002be82dcdf923d357d09c1b0 # gitsafe:ignore -jerboa_tree=d9c0b1bd6f2c6c87bee6610e275b3997d29e53ac # gitsafe:ignore +jerboa_commit=b0c66c1bb8042f3c48fcb3eae95222bc50d0a410 # gitsafe:ignore +jerboa_tree=cde344bb6e2cda51bf460b54492ee3f42d953850 # gitsafe:ignore gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331 --- a/templates/ssd-review.ss +++ b/templates/ssd-review.ss @@ -789,7 +789,7 @@ (typed-kotlin-file "com/sfb/ssdreview/VisionArrays.kt" (typed-library (com sfb ssdreview) - (export grayAt edgeAt sideCoverage darkSideCoverage contourCell toneCell) + (export grayAt edgeAt edgeMask sideCoverage darkSideCoverage contourCell toneCell) (type Int32) (type IntArray) (type BooleanArray) @@ -799,6 +799,10 @@ (if (> a b) a b)) (def (array-min-int32 (a : Int32) (b : Int32)) : Int32 (if (< a b) a b)) + (def (array-abs-int32 (value : Int32)) : Int32 + (if (< value (int32 0)) + (- (int32 0) value) + value)) (def (coverage-count-at-least (coverage : FloatArray) (threshold : Float32)) : Int32 (for/fold ((count (int32 0))) ((index (in-range (int32 0) (float-array-length coverage)))) @@ -831,6 +835,122 @@ (>= y height)))) #f (boolean-array-ref edge (+ (* y width) x)))) + (def (sobelPixel (gray : IntArray) + (width : Int32) + (x : Int32) + (y : Int32) + (dx : Int32) + (dy : Int32)) : Int32 + (int-array-ref gray (+ (* (+ y dy) width) (+ x dx)))) + (def (edgeGradientAt (gray : IntArray) + (width : Int32) + (height : Int32) + (x : Int32) + (y : Int32)) : Int32 + (if (or (or (< x (int32 1)) + (< y (int32 1))) + (or (>= x (- width (int32 1))) + (>= y (- height (int32 1))))) + (int32 0) + (let ((nw (sobelPixel gray width x y (int32 -1) (int32 -1))) + (n (sobelPixel gray width x y (int32 0) (int32 -1))) + (ne (sobelPixel gray width x y (int32 1) (int32 -1))) + (w (sobelPixel gray width x y (int32 -1) (int32 0))) + (e (sobelPixel gray width x y (int32 1) (int32 0))) + (sw (sobelPixel gray width x y (int32 -1) (int32 1))) + (s (sobelPixel gray width x y (int32 0) (int32 1))) + (se (sobelPixel gray width x y (int32 1) (int32 1)))) + (let ((gx + (+ (+ (+ (+ (+ (- (int32 0) nw) + ne) + (- (int32 0) (* (int32 2) w))) + (* (int32 2) e)) + (- (int32 0) sw)) + se)) + (gy + (+ (+ (+ (+ (+ (- (int32 0) nw) + (- (int32 0) (* (int32 2) n))) + (- (int32 0) ne)) + sw) + (* (int32 2) s)) + se))) + (array-min-int32 + (int32 65535) + (+ (array-abs-int32 gx) (array-abs-int32 gy))))))) + (def (edgeGradientAtIndex (gray : IntArray) + (width : Int32) + (height : Int32) + (index : Int32)) : Int32 + (edgeGradientAt gray width height (mod index width) (/ index width))) + (def (edgeHistogram (gray : IntArray) + (width : Int32) + (height : Int32)) : IntArray + (let ((histogram + (int-array-build + (int32 221) + (index (int32 0))))) + (begin + (for/fold ((count (int32 0))) + ((index (in-range (int32 0) (* width height)))) + (let ((mag (edgeGradientAtIndex gray width height index))) + (if (> mag (int32 0)) + (let ((bin (array-min-int32 (int32 220) mag))) + (begin + (int-array-set! + histogram + bin + (+ (int-array-ref histogram bin) (int32 1))) + (+ count (int32 1)))) + count))) + histogram))) + (def (edgeHistogramSampleCount (histogram : IntArray)) : Int32 + (for/fold ((count (int32 0))) + ((bin (in-range (int32 1) (int-array-length histogram)))) + (+ count (int-array-ref histogram bin)))) + (def (edgeThresholdFromHistogram (histogram : IntArray) + (sampleCount : Int32)) : Int32 + (if (<= sampleCount (int32 0)) + (int32 120) + (let ((rank + (array-min-int32 + (- sampleCount (int32 1)) + (/ (+ (* sampleCount (int32 88)) (int32 50)) + (int32 100))))) + (let ((state + (for/fold ((state (int32 0))) + ((bin (in-range (int32 1) + (int-array-length histogram)))) + (if (< state (int32 0)) + state + (let ((next (+ state (int-array-ref histogram bin)))) + (if (> next rank) + (- (int32 0) (+ bin (int32 1))) + next)))))) + (let ((adaptive + (if (< state (int32 0)) + (- (int32 0) (+ state (int32 1))) + (int32 220)))) + (array-min-int32 + (array-max-int32 (int32 90) adaptive) + (int32 220))))))) + (def (edgeMask (gray : IntArray) + (width : Int32) + (height : Int32)) : BooleanArray + (if (or (< width (int32 3)) + (< height (int32 3))) + (boolean-array-build + (* width height) + (index #f)) + (let ((histogram (edgeHistogram gray width height))) + (let ((threshold + (edgeThresholdFromHistogram + histogram + (edgeHistogramSampleCount histogram)))) + (boolean-array-build + (* width height) + (index + (>= (edgeGradientAtIndex gray width height index) + threshold))))))) (def (edgeBandTop? (edge : BooleanArray) (width : Int32) (height : Int32) @@ -3250,10 +3370,8 @@ "" "import android.graphics.Bitmap" "import java.util.ArrayDeque" - "import kotlin.math.abs" "import kotlin.math.max" "import kotlin.math.min" - "import kotlin.math.roundToInt" "" "object SsdDetector {" " fun detectCells(bitmap: Bitmap): MutableList<SsdCell> {" @@ -3446,26 +3564,6 @@ " return merged.mapIndexed { index, cell -> cell.copy(id = \"c%04d\".format(index + 1)) }.toMutableList()" " }" "" - " private fun edgeMask(gray: IntArray, width: Int, height: Int): BooleanArray {" - " val gradients = IntArray(width * height)" - " val samples = mutableListOf<Int>()" - " if (width < 3 || height < 3) return BooleanArray(width * height)" - " for (y in 1 until height - 1) {" - " for (x in 1 until width - 1) {" - " fun p(dx: Int, dy: Int): Int = gray[(y + dy) * width + x + dx]" - " val gx = -p(-1, -1) + p(1, -1) - 2 * p(-1, 0) + 2 * p(1, 0) - p(-1, 1) + p(1, 1)" - " val gy = -p(-1, -1) - 2 * p(0, -1) - p(1, -1) + p(-1, 1) + 2 * p(0, 1) + p(1, 1)" - " val mag = min(65535, abs(gx) + abs(gy))" - " gradients[y * width + x] = mag" - " if (mag > 0) samples.add(mag)" - " }" - " }" - " samples.sort()" - " val adaptive = if (samples.isEmpty()) 120 else samples[(samples.size * 0.88f).roundToInt().coerceIn(0, samples.size - 1)].coerceAtLeast(90)" - " val threshold = min(adaptive, 220)" - " return BooleanArray(width * height) { gradients[it] >= threshold }" - " }" - "" "}" )) (kotlin-file-lines "com/sfb/ssdreview/SsdVisionBridge.kt"