Warning: session_start(): open(/var/lib/php/sessions/sess_l8i0qvdnb3fnketu6erqa6se8l, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
sclass G22CriticalPixelSearch is Steppable {
// input
settable IG22MasksHolder> masksHolder;
settable bool keepAllEntries;
settable bool sortPixelsFirst = true;
// internal
int w, h;
Iterator pixelIterator;
// output
new Best bestPixel;
Entry bestEntry;
Pt lastPixelLookedAt;
Entry lastEntry;
Entry[] pixelEntries;
float[] pixelScores;
int nPixelsTested;
// stores all subsets of masks found if not null
CompactHashSet subSets;
*() {}
*(IG22MasksHolder *masksHolder) {}
class Entry {
Pt pixel;
// child mask holders for pixel dark or pixel bright
//IG22MasksHolder darkChild, brightChild;
gettable L darkMasks;
gettable L brightMasks;
G22GhostImage darkGhost;
G22GhostImage brightGhost;
simplyCached IG22MasksHolder darkHolder() {
ret new G22HashedMasks(darkMasks, darkGhost);
}
simplyCached IG22MasksHolder brightHolder() {
ret new G22HashedMasks(brightMasks, brightGhost);
}
void calcGhosts {
if (l(darkMasks) < l(brightMasks)) {
darkGhost = new G22GhostImage(lmapMethod image(darkMasks));
brightGhost = masksHolder().ghost().minus(darkGhost);
} else {
brightGhost = new G22GhostImage(lmapMethod image(brightMasks));
darkGhost = masksHolder().ghost().minus(brightGhost);
}
}
toString {
ret commaCombine(
"Split at " + pixel,
"dark=" + darkHolder().renderCountAndCertainty(),
"bright=" + brightHolder().renderCountAndCertainty());
}
}
public bool step() {
if (w == 0) {
if (!masksHolder.canSplit()) false;
meta-for w also as h { w = masksHolder.maskSize().w(); }
pixelEntries = new Entry[w*h];
pixelScores = new float[w*h];
arrayfill(pixelScores, -1);
pixelIterator = makePixelIterator();
}
if (!pixelIterator.hasNext()) false;
lastPixelLookedAt = pixelIterator.next();
testPixel(lastPixelLookedAt);
true;
}
int idx(Pt p) { ret p.y*w+p.x; }
void testPixel(Pt p) {
double score;
Entry e = null;
++nPixelsTested;
// Find out if pixel is the same in all masks
float ghostBrightness = masksHolder.ghost().getFloatPixel(p);
if (ghostBrightness == 0 || ghostBrightness == 1)
// Pixel is determined, not usable for splitting
score = -2;
else {
// Pixel is not determined - let's make the 2 subsets
e = new Entry;
e.pixel = p;
lastEntry = e;
if (keepAllEntries)
pixelEntries[idx(p)] = e;
L masks = wideningListCast(masksHolder.masks());
int n = l(masks);
// bit is 1 when pixel is bright
byte[] brightBits = byteArrayForNBits(n);
// calculate the split
for i to n:
if (masks.get(i).image().getBoolPixel(p))
setBit(brightBits, i);
subSets?.add(new HashedByteArray(brightBits));
e.darkMasks = filterListByPredicateOnIndex(masks, i -> !getBit(brightBits, i));
e.brightMasks = filterListByPredicateOnIndex(masks, i -> getBit(brightBits, i));
e.calcGhosts();
score = scoreEntry(e);
}
pixelScores[idx(p)] = (float) score;
if (score > 0 && bestPixel.put(p, score))
bestEntry = e;
}
swappable double scoreEntry(Entry e) {
double c1 = e.darkGhost.certainty();
double c2 = e.brightGhost.certainty();
// ret avg(c1, c2);
ret min(c1, c2);
}
double bestScore() {
ret bestPixel.score();
}
BWImage scoreImage() {
double min = masksHolder.certainty();
double max = bestPixel.score();
ret bwImageFromFunction(w, h,
(x, y) -> transformToZeroToOne(pixelScores[y*w+x], max, min));
}
G22PixelSplitMasks> splitMasksHolder() {
if (!bestPixel.has()) null;
ret new G22PixelSplitMasks()
.splitPixel(bestPixel!)
.darkHolder(bestEntry.darkHolder())
.brightHolder(bestEntry.brightHolder());
}
IG22MasksHolder makeBestTree() {
stepAll(this);
var split = splitMasksHolder();
if (split == null) ret masksHolder;
split.transformSubHolders(subHolder
-> new G22CriticalPixelSearch(subHolder).makeBestTree());
ret split;
}
void collectSubSets {
subSets if null = new CompactHashSet;
}
Iterator makePixelIterator() {
if (sortPixelsFirst)
// try least certain pixels first
ret iterator(pixelsByBrightness(masksHolder().ghost().certaintyImage()));
else
ret new WeightlessShuffledIterator(pixelsInImage(w, h));
}
}