Transpiled version (29124L) is out of date.
1 | sclass G22CriticalPixelSearch is Steppable { |
2 | // input |
3 | settable IG22MasksHolder<?> masksHolder; |
4 | settable bool keepAllEntries; |
5 | settable bool sortPixelsFirst = true; |
6 | |
7 | // internal |
8 | int w, h; |
9 | Iterator<Pt> pixelIterator; |
10 | |
11 | // output |
12 | new Best<Pt> bestPixel; |
13 | Entry bestEntry; |
14 | Pt lastPixelLookedAt; |
15 | Entry lastEntry; |
16 | Entry[] pixelEntries; |
17 | float[] pixelScores; |
18 | int nPixelsTested; |
19 | |
20 | // stores all subsets of masks found if not null |
21 | CompactHashSet<HashedByteArray> subSets; |
22 | |
23 | *() {} |
24 | *(IG22MasksHolder *masksHolder) {} |
25 | |
26 | class Entry { |
27 | Pt pixel; |
28 | // child mask holders for pixel dark or pixel bright |
29 | //IG22MasksHolder darkChild, brightChild; |
30 | gettable L<IG22Mask> darkMasks; |
31 | gettable L<IG22Mask> brightMasks; |
32 | G22GhostImage darkGhost; |
33 | G22GhostImage brightGhost; |
34 | |
35 | simplyCached IG22MasksHolder darkHolder() { |
36 | ret new G22HashedMasks(darkMasks, darkGhost); |
37 | } |
38 | |
39 | simplyCached IG22MasksHolder brightHolder() { |
40 | ret new G22HashedMasks(brightMasks, brightGhost); |
41 | } |
42 | |
43 | void calcGhosts { |
44 | if (l(darkMasks) < l(brightMasks)) { |
45 | darkGhost = new G22GhostImage(lmapMethod image(darkMasks)); |
46 | brightGhost = masksHolder().ghost().minus(darkGhost); |
47 | } else { |
48 | brightGhost = new G22GhostImage(lmapMethod image(brightMasks)); |
49 | darkGhost = masksHolder().ghost().minus(brightGhost); |
50 | } |
51 | } |
52 | |
53 | toString { |
54 | ret commaCombine( |
55 | "Split at " + pixel, |
56 | "dark=" + darkHolder().renderCountAndCertainty(), |
57 | "bright=" + brightHolder().renderCountAndCertainty()); |
58 | } |
59 | } |
60 | |
61 | public bool step() { |
62 | if (w == 0) { |
63 | if (!masksHolder.canSplit()) false; |
64 | |
65 | meta-for w also as h { w = masksHolder.maskSize().w(); } |
66 | pixelEntries = new Entry[w*h]; |
67 | pixelScores = new float[w*h]; |
68 | arrayfill(pixelScores, -1); |
69 | pixelIterator = makePixelIterator(); |
70 | } |
71 | |
72 | if (!pixelIterator.hasNext()) false; |
73 | lastPixelLookedAt = pixelIterator.next(); |
74 | testPixel(lastPixelLookedAt); |
75 | true; |
76 | } |
77 | |
78 | int idx(Pt p) { ret p.y*w+p.x; } |
79 | |
80 | void testPixel(Pt p) { |
81 | double score; |
82 | Entry e = null; |
83 | ++nPixelsTested; |
84 | |
85 | // Find out if pixel is the same in all masks |
86 | float ghostBrightness = masksHolder.ghost().getFloatPixel(p); |
87 | if (ghostBrightness == 0 || ghostBrightness == 1) |
88 | // Pixel is determined, not usable for splitting |
89 | score = -2; |
90 | else { |
91 | // Pixel is not determined - let's make the 2 subsets |
92 | |
93 | e = new Entry; |
94 | e.pixel = p; |
95 | lastEntry = e; |
96 | if (keepAllEntries) |
97 | pixelEntries[idx(p)] = e; |
98 | |
99 | L<IG22Mask> masks = wideningListCast(masksHolder.masks()); |
100 | int n = l(masks); |
101 | |
102 | // bit is 1 when pixel is bright |
103 | byte[] brightBits = byteArrayForNBits(n); |
104 | |
105 | // calculate the split |
106 | for i to n: |
107 | if (masks.get(i).image().getBoolPixel(p)) |
108 | setBit(brightBits, i); |
109 | |
110 | subSets?.add(new HashedByteArray(brightBits)); |
111 | |
112 | var splitMasks = filterAntiFilterByBitSet(masks, brightBits); |
113 | e.brightMasks = splitMasks.a; |
114 | e.darkMasks = splitMasks.b; |
115 | e.calcGhosts(); |
116 | |
117 | score = scoreEntry(e); |
118 | } |
119 | |
120 | pixelScores[idx(p)] = (float) score; |
121 | if (score > 0 && bestPixel.put(p, score)) |
122 | bestEntry = e; |
123 | } |
124 | |
125 | swappable double scoreEntry(Entry e) { |
126 | double c1 = e.darkGhost.certainty(); |
127 | double c2 = e.brightGhost.certainty(); |
128 | |
129 | // ret avg(c1, c2); |
130 | ret min(c1, c2); |
131 | } |
132 | |
133 | double bestScore() { |
134 | ret bestPixel.score(); |
135 | } |
136 | |
137 | BWImage scoreImage() { |
138 | double min = masksHolder.certainty(); |
139 | double max = bestPixel.score(); |
140 | ret bwImageFromFunction(w, h, |
141 | (x, y) -> transformToZeroToOne(pixelScores[y*w+x], max, min)); |
142 | } |
143 | |
144 | G22PixelSplitMasks<?> splitMasksHolder() { |
145 | if (!bestPixel.has()) null; |
146 | ret new G22PixelSplitMasks() |
147 | .splitPixel(bestPixel!) |
148 | .darkHolder(bestEntry.darkHolder()) |
149 | .brightHolder(bestEntry.brightHolder()); |
150 | } |
151 | |
152 | IG22MasksHolder makeBestTree aka bestTree aka get() { |
153 | stepAll(this); |
154 | G22PixelSplitMasks<?> split = splitMasksHolder(); |
155 | if (split == null) ret masksHolder; |
156 | split.transformSubHolders(subHolder |
157 | -> new G22CriticalPixelSearch(subHolder).makeBestTree()); |
158 | ret split; |
159 | } |
160 | |
161 | void collectSubSets { |
162 | subSets if null = new CompactHashSet; |
163 | } |
164 | |
165 | Iterator<Pt> makePixelIterator() { |
166 | if (sortPixelsFirst) |
167 | // try least certain pixels first |
168 | ret iterator(pixelsByBrightness(masksHolder().ghost().certaintyImage())); |
169 | else |
170 | ret new WeightlessShuffledIterator<Pt>(pixelsInImage(w, h)); |
171 | } |
172 | } |
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): elmgxqgtpvxh, mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1035858 |
Snippet name: | G22CriticalPixelSearch - find best pixel to split list of masks at |
Eternal ID of this version: | #1035858/61 |
Text MD5: | 2ca7213890235ca20d11062a4a943c7a |
Author: | stefan |
Category: | javax / gazelle 22 |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-02-13 22:43:02 |
Source code size: | 4836 bytes / 172 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 277 / 628 |
Version history: | 60 change(s) |
Referenced in: | [show references] |