Warning : session_start(): open(/var/lib/php/sessions/sess_0p3c19qb9lhvo3b9jfuc0k30rc, 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
!7
// Note: Don't use db_mainConcepts(), only the module's concepts field
!include early #1033884 // Compact Module Include Gazelle V [dev version]
module GazelleScreenCam {
!include early #1025212 // +Enabled without visualization
int pixelRows = 128, colors = 8;
S script, testScreenScript;
bool animate = true;
bool horizontalLayout; // flat layout
WatchTarget watchTarget;
transient ImageSurface isPosterized, isRegions, isTestScreen;
transient new ScreenCamStream imageStream;
transient new BWIntegralImageStream integralImages;
transient new SourceTriggeredStream scaledAndPosterizedImages;
transient new DoubleFPSCounter fpsCounter;
transient int fps;
//transient ScreenSelectorRadioButtons screenSelector;
transient WatchTargetSelector watchTargetSelector;
transient new RollingAverage remainingMSPerFrame;
transient int remainingMS;
transient new FunctionTimings functionTimings;
transient ReliableSingleThread rstRunScript = dm_rst(me(), r _runScript);
transient JGazelleVScriptRunner scriptRunner;
transient JGazelleVScriptRunner testScreenScriptRunner;
transient Animation animation;
transient BWImage_FastRegions mainScreenRegions;
//transient ImageSurface_HighlightRegion regionHighlighter;
transient UIURLSystem uiURLs;
// set by host
transient Concepts concepts;
S uiURL;
transient FileWatchService fileWatcher;
transient SimpleCRUD_v2 labelCRUD;
transient SimpleCRUD_v2 imageCRUD;
transient JGallery gallery;
start {
dm_onFieldChange horizontalLayout(
//r dm_revisualize // deh buggy
r dm_reload
);
// non-standalone mode (doesn't work yet)
if (concepts == null) {
db();
concepts = db_mainConcepts();
}
// update count in tab when tab isn't selected
onConceptChanges(concepts, -> {
labelCRUD?.updateEnclosingTabTitle();
imageCRUD?.updateEnclosingTabTitle();
});
uiURLs = new UIURLSystem(me(), dm_fieldLiveValue uiURL());
scriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue script(me()));
testScreenScriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue testScreenScript(me()));
imageStream.directlyFeedInto(integralImages);
integralImages.onNewElement(ii ->
scaledAndPosterizedImages.newElement(
scaleAndPosterize(ii, new SnPSettings(pixelRows, colors))));
integralImages.onNewElement(r {
if (shouldRunScript()) rstRunScript.go();
});
scaledAndPosterizedImages.onNewElement(img -> {
fpsCounter.inc();
setField(fps := iround(fpsCounter!));
// display before analysis (old)
// isPosterized?.setImage_thisThread(img);
// find regions
floodFill(img);
// display after analysis so we can highlight a region
if (isPosterized != null) {
var img2 = modifyForDisplay(img);
isPosterized.setImage_thisThread(img2);
}
});
// 20 Hz is enough for everyone
dm_doEvery(1000/20, r {
if (enabled) {
watchTargetSelector?.updateScreenCount();
Timestamp deadline = tsNowPlusMS(1000/20);
if (watchTarget cast WatchScreen)
imageStream.useScreen(watchTarget.screenNr-1);
else if (watchTarget cast WatchMouse)
imageStream.area(mouseArea(watchTarget.width, watchTarget.height));
imageStream.step();
long remaining = deadline.minus(tsNow());
remainingMSPerFrame.add(remaining);
setField(remainingMS := iround(remainingMSPerFrame!));
}
});
startDirWatcher();
for (f : allImageFiles(galleryDir()))
addToGallery(f);
}
// convert to color & highlight region (TODO)
BufferedImage modifyForDisplay(BWImage image) {
var pixels = image.getRGBPixels();
var mouse = isPosterized.mousePosition;
if (mouse != null) {
var regions = mainScreenRegions;
int iHighlightedRegion = regions.regionAt(mouse);
int marked = 0;
if (iHighlightedRegion > 0)
for i over pixels:
if (regions.regionAt(i) == iHighlightedRegion) {
pixels[i] = 0xFF008000;
++marked;
}
//printVars(+mouse, +iHighlightedRegion, +marked);
}
ret bufferedImage(pixels, image.getWidth(), image.getHeight());
}
void startDirWatcher {
fileWatcher = new FileWatchService;
fileWatcher.addRecursiveListener(picturesDir(), file -> {
if (!isImageFile(file)) ret;
addToGallery(file);
});
}
ImageSurface stdImageSurface() {
ret pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false);
}
visualize {
gallery = new JGallery;
var galleryComponent = gallery.visualize();
new AWTOnConceptChanges(concepts, galleryComponent, -> {
gallery.setImageFiles(map(list(concepts, GalleryImage), i -> i.path));
}).install();
/*screenSelector = new ScreenSelectorRadioButtons(dm_fieldLiveValue screenNr());
screenSelector.compactLayout(true);
screenSelector.hideIfOnlyOne(true);
screenSelector.screenLabel("");*/
isPosterized = stdImageSurface();
/*regionHighlighter = new ImageSurface_HighlightRegion(isPosterized);
regionHighlighter.regionPainter(new RegionFillPainter);*/
isRegions = stdImageSurface();
isTestScreen = stdImageSurface();
// when test screen is visible, do the animation
awtEvery(isTestScreen, 1000/20, r stepAnimation);
JTextArea taTimings = jTextArea_noUndo();
awtEveryAndNow(taTimings, .5, r {
setText(taTimings, renderFunctionTimings())
});
var jSpeedInfo = dm_transientCalculatedToolTip speedInfo_long(rightAlignLabel(dm_transientCalculatedLabel speedInfo()));
//print("Labels: " + list(concepts, Label));
labelCRUD = new SimpleCRUD_v2(concepts, Label);
labelCRUD.hideFields("globalID");
labelCRUD.addCountToEnclosingTab(true);
imageCRUD = new SimpleCRUD_v2(concepts, GalleryImage);
imageCRUD.addCountToEnclosingTab(true);
imageCRUD.itemToMap_inner2 = img
-> litorderedmap(
"File" := fileName(img.path),
"Folder" := dirPath(img.path));
// main visual
var studyPanel = new StudyPanel;
var tabs = scrollingTabs(jTopOrLeftTabs(horizontalLayout,
WithToolTip("Posterized", "Show scaled down and color-reduced screen image")
:= withTools(isPosterized),
WithToolTip("Regions", "Visualize regions detected on screen")
:= jscroll_centered_borderless(isRegions),
WithToolTip("Study", "Here you can analyze gallery images")
:= withTopMargin(studyPanel.visualize()),
WithToolTip("Pretty Gallery", "Gallery view with preview images")
:= galleryComponent,
WithToolTip("Powerful Gallery", "Gallery view with more functions (delete etc)")
:= wrapCRUD(imageCRUD),
WithToolTip("Labels", "Manage labels (image markers)")
:= wrapCRUD(labelCRUD),
WithToolTip("Script", "Run a Gazelle V script")
:= scriptRunner.scriptAndResultPanel(),
"Test Screen" := testScreenPanel(),
Timings := withRightAlignedButtons(taTimings,
Reset := r resetTimings)
));
// for tab titles
labelCRUD.update();
imageCRUD.update();
watchTargetSelector = new WatchTargetSelector;
var vis = northAndCenter(
withSideAndTopMargin(uiURLs.urlBar()),
centerAndSouthOrEast(horizontalLayout,
horizontalLayout ? withMargin(tabs) : withSideMargin(tabs),
/*withMargin*/(borderlessScrollPane(jHigherScrollPane(
jfullcenter(vstack(
withLeftAndRightMargin(hstack(
//dm_rcheckBox enabled("Watch screen"),
dm_rcheckBox enabled("Watch"),
//screenSelector.visualize(),
watchTargetSelector.visualize(),
jlabel(" in "),
withLabelToTheRight("colors @ ", dm_spinner colors(2, 256)),
//withLabelToTheRight("p", dm_spinner pixelRows(1, 500)),
withLabelToTheRight("p", dm_powersOfTwoSpinner pixelRows(512)),
, /* speed info can also go here */
)),
verticalStrut(2),
withRightMargin(jSpeedInfo)
))))),
));
setHorizontalMarginForAllButtons(vis, 4);
ret vis;
}
S speedInfo() {
ret "FPS " + fps + " idle " + remainingMS + " ms";
}
S speedInfo_long() {
ret "Screen cam running at " + nFrames(fps) + "/second. " + n2(remainingMS) + " ms remaining per frame in first core.";
}
void floodFill(BWImage img) {
BWImage_FastRegions ff = new(img);
//ff.tolerance(0);
ff.collectBounds();
functionTimings.time("Regions", ff);
mainScreenRegions = ff;
//regionHighlighter?.setRegions(ff);
if (isRegions != null && isRegions.isShowing_quick()) {
//print("Showing regions image");
isRegions.setImage_thisThread(ff.regionsImage());
}
setEnclosingTabTitle(isRegions, nRegions(ff.regionCount()));
}
bool useErrorHandling() { false; }
S renderFunctionTimings() {
ret lines(ciSorted(map(functionTimings!, (f, avg) ->
firstToUpper(f) + ": " + n2(iround(nsToMicroseconds(avg!))) + " " + microSymbol() + "s (" + n2(iround(avg.n())) + ")")));
}
transient long _runScript_idx;
void _runScript() {
long n = integralImages.elementCount();
if (n > _runScript_idx) {
_runScript_idx = n;
scriptRunner.parseAndRunOn(integralImages!);
}
}
bool shouldRunScript() {
ret isShowing(scriptRunner.scpScriptResult);
}
void stepAnimation {
if (!animate) ret;
if (animation == null) {
animation = new AnimatedLine;
animation.start();
}
animation.nextFrame();
var img = whiteImage(animation.w, animation.h);
animation.setGraphics(createGraphics(img));
animation.paint();
isTestScreen?.setImage(img);
var ii = bwIntegralImage_withMeta(img);
testScreenScriptRunner.parseAndRunOn(ii);
}
JComponent testScreenPanel() {
ret centerAndSouthWithMargin(
hsplit(
northAndCenterWithMargin(centerAndEastWithMargin(
jlabel("Input"), dm_fieldCheckBox animate()),
jscroll_centered_borderless(isTestScreen)),
northAndCenterWithMargin(centerAndEastWithMargin(
jlabel("Output"), testScreenScriptRunner.lblScore),
testScreenScriptRunner.scpScriptResult)
),
testScreenScriptRunner.scriptInputField()
);
}
L popDownItems() {
ret ll(jCheckBoxMenuItem_dyn("Horizontal Layout",
-> horizontalLayout,
b -> setField(horizontalLayout := b)));
}
void unvisualize {} // don't zero transient component fields
void resetTimings { functionTimings.reset(); }
// add tool side bar to image surface
JComponent withTools(ImageSurface is) {
new ImageSurface_PositionToolTip(is);
ret centerAndEastWithMargin(jscroll_centered_borderless(is), vstackWithSpacing(3,
jimageButtonScaledToWidth(16, #1103054, "Save screenshot in gallery", rThread saveScreenshotToGallery),
));
}
class WatchTargetSelector {
JComboBox cb = jComboBox();
int screenCount;
visualize {
updateList();
print("Selecting watchTarget: " + watchTarget);
selectItem(cb, watchTarget);
main onChange(cb, watchTarget -> {
setField(+watchTarget);
print("Chose watchTarget: " + GazelleScreenCam.this.watchTarget);
});
ret cb;
}
void updateScreenCount() {
if (screenCount != screenCount())
updateList();
}
void updateList() swing {
setComboBoxItems(cb, makeWatchTargets());
}
L makeWatchTargets() {
ret flattenToList(
countIteratorAsList_incl(1, screenCount = screenCount(), i -> WatchScreen(i)),
new WatchMouse
);
}
}
class SnPSelector {
settable new SnPSettings settings;
event change;
visualize {
var colors = jspinner(settings.colors, 2, 256);
onChange(colors, -> {
settings.colors = intFromSpinner(colors);
change();
});
var pixelRows = jPowersOfTwoSpinner(512, settings.pixelRows);
onChange(pixelRows, -> {
settings.pixelRows = intFromSpinner(pixelRows);
change();
});
ret hstack(
colors,
jlabel(" colors @ "),
pixelRows,
jlabel(" p"));
}
}
JComponent wrapCRUD(SimpleCRUD_v2 crud) {
ret crud == null ?: withTopMargin(jRaisedSection(withMargin(crud.make_dontStartBots())));
}
File galleryDir() {
ret picturesDir(gazelle22_imagesSubDirName());
}
void saveScreenshotToGallery enter {
var img = imageStream!;
saveImageWithCounter(galleryDir(), "Screenshot", img);
}
void addToGallery(File imgFile) {
if (!isImageFile(imgFile)) ret;
var img = uniq(concepts, GalleryImage, path := imgFile);
//printVars("addToGallery", +imgFile, +img);
}
BWImage scaleAndPosterize(IBWIntegralImage ii, SnPSettings settings) {
ret posterizeBWImage_withMeta(settings.colors,
scaledBWImageFromBWIntegralImage_withMeta_height(settings.pixelRows, ii));
}
JComponent studyImagePanel(GalleryImage img) {
if (img == null) null;
print("studyImagePanel", img.path);
var i = loadImage2(img.path);
if (i == null) ret jcenteredlabel("Image not found");
//ret jlabel("found");
var is = stdImageSurface();
is.setImage_thisThread(i);
var scrollable = jscroll_centered_borderless(is);
ret hsplit(scrollable, jcenteredLabel("Analysis here"));
}
class StudyPanel {
new SnPSelector snpSelector;
new SingleComponentPanel scp;
ConceptsComboBox cbImage = new(concepts, GalleryImage);
*() {
cbImage.sortTheList = l -> sortConceptsByIDDesc(l);
main onChangeAndNow(cbImage, img -> dm_q(me(), r {
scp.setComponent(studyImagePanel(img));
}));
}
visual
jRaisedSection(northAndCenterWithMargins(
centerAndEast(withLabel("Study", cbImage),
hstack(jlabel(" in "), snpSelector.visualize())),
scp));
} // end of StudyPanel
} // end of module
concept Label > ConceptWithGlobalID {
S name;
//new RefL examples;
toString { ret "Label " + name; }
}
concept GalleryImage {
File path;
toString { ret /*"[" + id + "] " +*/ fileName(path); }
}
concept SavedRegion {
Concept image;
Rect area;
//new RefL labels;
}
concept ExampleForLabel {
new Ref label;
new Ref example;
double confidence = 1;
}
concept IfThenTheory {
new Ref if_;
new Ref then;
}
sclass WatchTarget {}
// screenNr: 1 = screen 1 etc
srecord WatchScreen(int screenNr) > WatchTarget {
toString { ret "Screen " + screenNr; }
}
srecord WatchMouse(int width, int height) > WatchTarget {
WatchMouse() {
height = 256;
width = iround(height*16.0/9);
}
toString { ret "Mouse"; }
}
// SnP = Scale and Posterize
persistable sclass SnPSettings {
int pixelRows = 128;
int colors = 8;
*(int *pixelRows, int *colors) {}
}