Generate SSD detector from typed Kotlin
ober
c6dcf0f846fe91a03c5b49a3282d7a21374926fe
--- 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#fccc76e702602c0538c28935ef7b5e228947bded" + - "https://git.sr.ht/~lisp/jerboa#a62bac2471f691b7087ea3594db3d375b2097cfd" # 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)" = fccc76e702602c0538c28935ef7b5e228947bded - test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 041beddb9852658fbd7865cc1073272583513867 + test "$(git -C ../jerboa rev-parse HEAD)" = a62bac2471f691b7087ea3594db3d375b2097cfd + test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = a1e7cd426ed7957d29801409eb5e56207ea5e1a3 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": "fccc76e702602c0538c28935ef7b5e228947bded", - "tree": "041beddb9852658fbd7865cc1073272583513867" + "commit": "a62bac2471f691b7087ea3594db3d375b2097cfd", + "tree": "a1e7cd426ed7957d29801409eb5e56207ea5e1a3" }, "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=fccc76e702602c0538c28935ef7b5e228947bded # gitsafe:ignore -jerboa_tree=041beddb9852658fbd7865cc1073272583513867 # gitsafe:ignore +jerboa_commit=a62bac2471f691b7087ea3594db3d375b2097cfd # gitsafe:ignore +jerboa_tree=a1e7cd426ed7957d29801409eb5e56207ea5e1a3 # gitsafe:ignore gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331 --- a/templates/ssd-review.ss +++ b/templates/ssd-review.ss @@ -3422,7 +3422,7 @@ (float32 w) (float32 h) "android-contour"))))))))))))) - (def (detectorComponentCells (components : (List Component)) + (def (detectorComponentCells (components : (MutableList Component)) (detector : String)) : (MutableList SsdCell) (for/fold ((out (mutable-list-empty SsdCell))) ((i (in-range (int32 0) (list-size components)))) @@ -3432,7 +3432,7 @@ (begin (mutable-list-add! out (nullable-get cell)) out))))) - (def (detectorToneCells (components : (List Component)) + (def (detectorToneCells (components : (MutableList Component)) (gray : IntArray) (width : Int32) (height : Int32)) : (MutableList SsdCell) @@ -3444,7 +3444,7 @@ (begin (mutable-list-add! out (nullable-get cell)) out))))) - (def (detectorContourCells (components : (List Component)) + (def (detectorContourCells (components : (MutableList Component)) (edge : BooleanArray) (width : Int32) (height : Int32)) : (MutableList SsdCell) @@ -5102,7 +5102,7 @@ " detectorNote = \", rust detector\"" " detectorSource = if (forceDetect && existingTruthGroupCount > 0) \"forced-rust-plus-truth\" else \"rust-detector\"" " } else {" - " detectedCells = SsdDetector.detectCells(bitmap)" + " detectedCells = detectCells(bitmap)" " detectorSource = if (forceDetect && existingTruthGroupCount > 0) \"forced-android-plus-truth\" else \"android-fallback\"" " }" " ssdSessionAddDetectedCellsInsideArea(session, detectedCells)" @@ -6060,81 +6060,131 @@ " }" "}" )) - (kotlin-file-lines "com/sfb/ssdreview/SsdDetector.kt" - ( - "package com.sfb.ssdreview" - "" - "import android.graphics.Bitmap" - "object SsdDetector {" - " fun detectCells(bitmap: Bitmap): MutableList<SsdCell> {" - " val width = bitmap.width" - " val height = bitmap.height" - " val pixels = IntArray(width * height)" - " bitmap.getPixels(pixels, 0, width, 0, 0, width, height)" - " val gray = grayscale(pixels)" - " val cells = mutableListOf<SsdCell>()" - "" - " cells += detectorComponentCells(" - " detectColorComponents(width, height, pixels, \"android-color\")," - " \"android-color\"" - " )" - "" - " cells += detectorToneCells(" - " detectToneComponents(width, height, gray, \"android-tone\")," - " gray," - " width," - " height" - " )" - "" - " var merged = mergeDuplicateCells(cells)" - " if (merged.size < 50) {" - " merged += contourCells(width, height, gray)" - " merged = mergeDuplicateCells(merged)" - " }" - " return merged" - " }" - "" - " fun shrinkRectToInk(bitmap: Bitmap, rect: FloatArray): FloatArray? {" - " return shrinkRectByMaskKind(bitmap, rect, 0)" - " }" - "" - " fun shrinkRectToBoxFill(bitmap: Bitmap, rect: FloatArray): FloatArray? {" - " return shrinkRectByMaskKind(bitmap, rect, 1)" - " }" - "" - " private fun shrinkRectByMaskKind(" - " bitmap: Bitmap," - " rect: FloatArray," - " kind: Int" - " ): FloatArray? {" - " val x1 = rect[0].toInt().coerceIn(0, bitmap.width - 1)" - " val y1 = rect[1].toInt().coerceIn(0, bitmap.height - 1)" - " val x2 = rect[2].toInt().coerceIn(0, bitmap.width)" - " val y2 = rect[3].toInt().coerceIn(0, bitmap.height)" - " val w = x2 - x1" - " val h = y2 - y1" - " if (w < 4 || h < 4 || w * h > 1_200_000) return null" - " val pixels = IntArray(w * h)" - " bitmap.getPixels(pixels, 0, w, x1, y1, w, h)" - " return if (kind == 0) {" - " shrinkInkMaskBounds(pixels, w, h, x1, y1, bitmap.width, bitmap.height)" - " } else {" - " shrinkBoxFillMaskBounds(pixels, w, h, x1, y1, bitmap.width, bitmap.height)" - " }" - " }" - "" - " private fun contourCells(width: Int, height: Int, gray: IntArray): List<SsdCell> {" - " val edge = edgeMask(gray, width, height)" - " return detectorContourCells(" - " detectEdgeComponents(width, height, edge, \"android-contour\")," - " edge," - " width," - " height" - " )" - " }" - "" - "}" - )) + (typed-kotlin-file "com/sfb/ssdreview/SsdDetector.kt" + (kotlin-imports (android graphics Bitmap)) + (typed-library (com sfb ssdreview) + (export detectCells shrinkRectToInk shrinkRectToBoxFill) + (type Bitmap) + (type Int32) + (type IntArray) + (type Float32) + (type FloatArray) + (extern (bitmapWidth (bitmap : Bitmap)) : Int32 + (kotlin-member-get width)) + (extern (bitmapHeight (bitmap : Bitmap)) : Int32 + (kotlin-member-get height)) + (extern (bitmapGetPixels (bitmap : Bitmap) + (pixels : IntArray) + (offset : Int32) + (stride : Int32) + (x : Int32) + (y : Int32) + (width : Int32) + (height : Int32)) : Unit + (kotlin-member-call getPixels)) + (extern (float32ToInt32 (value : Float32)) : Int32 + (kotlin-member-call toInt)) + (def (clampDetectorInt32 (value : Int32) + (floor : Int32) + (ceiling : Int32)) : Int32 + (if (< value floor) + floor + (if (> value ceiling) ceiling value))) + (def (contourCells (width : Int32) (height : Int32) (gray : IntArray)) : (MutableList SsdCell) + (let ((edge (edgeMask gray width height))) + (detectorContourCells + (detectEdgeComponents width height edge "android-contour") + edge + width + height))) + (def (detectCells (bitmap : Bitmap)) : (MutableList SsdCell) + (let ((width (bitmapWidth bitmap)) + (height (bitmapHeight bitmap))) + (let ((pixels + (int-array-build + (* width height) + (index (int32 0))))) + (begin + (bitmapGetPixels + bitmap + pixels + (int32 0) + width + (int32 0) + (int32 0) + width + height) + (let ((gray (grayscale pixels)) + (cells (mutable-list-empty SsdCell))) + (begin + (mutable-list-add-all! + cells + (detectorComponentCells + (detectColorComponents width height pixels "android-color") + "android-color")) + (mutable-list-add-all! + cells + (detectorToneCells + (detectToneComponents width height gray "android-tone") + gray + width + height)) + (let ((merged (mergeDuplicateCells cells))) + (if (< (list-size merged) (int32 50)) + (begin + (mutable-list-add-all! merged (contourCells width height gray)) + (mergeDuplicateCells merged)) + merged)))))))) + (def (shrinkRectByMaskKind (bitmap : Bitmap) + (rect : FloatArray) + (kind : Int32)) : (Nullable FloatArray) + (let ((bitmapW (bitmapWidth bitmap)) + (bitmapH (bitmapHeight bitmap))) + (let ((x1 (clampDetectorInt32 + (float32ToInt32 (float-array-ref rect (int32 0))) + (int32 0) + (- bitmapW (int32 1)))) + (y1 (clampDetectorInt32 + (float32ToInt32 (float-array-ref rect (int32 1))) + (int32 0) + (- bitmapH (int32 1)))) + (x2 (clampDetectorInt32 + (float32ToInt32 (float-array-ref rect (int32 2))) + (int32 0) + bitmapW)) + (y2 (clampDetectorInt32 + (float32ToInt32 (float-array-ref rect (int32 3))) + (int32 0) + bitmapH))) + (let ((w (- x2 x1)) + (h (- y2 y1))) + (if (or (or (< w (int32 4)) + (< h (int32 4))) + (> (* w h) (int32 1200000))) + (nullable-none FloatArray) + (let ((pixels + (int-array-build + (* w h) + (index (int32 0))))) + (begin + (bitmapGetPixels + bitmap + pixels + (int32 0) + w + x1 + y1 + w + h) + (if (= kind (int32 0)) + (shrinkInkMaskBounds pixels w h x1 y1 bitmapW bitmapH) + (shrinkBoxFillMaskBounds pixels w h x1 y1 bitmapW bitmapH))))))))) + (def (shrinkRectToInk (bitmap : Bitmap) + (rect : FloatArray)) : (Nullable FloatArray) + (shrinkRectByMaskKind bitmap rect (int32 0))) + (def (shrinkRectToBoxFill (bitmap : Bitmap) + (rect : FloatArray)) : (Nullable FloatArray) + (shrinkRectByMaskKind bitmap rect (int32 1))))) (kotlin-file-lines "com/sfb/ssdreview/SsdVisionBridge.kt" ( "package com.sfb.ssdreview" @@ -6478,8 +6528,8 @@ " bboxForCells(matching)" " } else {" " bitmap?.let {" - " SsdDetector.shrinkRectToBoxFill(it, rect)" - " ?: SsdDetector.shrinkRectToInk(it, rect)" + " shrinkRectToBoxFill(it, rect)" + " ?: shrinkRectToInk(it, rect)" " } ?: rect" " }" " onStatus?.invoke("