!7 !include early #1033506 // Compact Module Include Gazelle V module GazelleScreenCam { !include early #1025212 // +Enabled without visualization int screenNr; int pixelRows = 128, colors = 8; S script, testScreenScript; bool animate = true; bool horizontalLayout; // flat layout transient ImageSurface isPosterized, isRegions, isTestScreen; transient new ScreenCamStream images; transient new BWIntegralImageStream integralImages; transient new SourceTriggeredStream scaledAndPosterizedImages; transient new DoubleFPSCounter fpsCounter; transient int fps; transient ScreenSelectorRadioButtons screenSelector; 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; S uiURL; start { dm_onFieldChange horizontalLayout( //r dm_revisualize // deh buggy r dm_reload ); uiURLs = new UIURLSystem(me(), dm_fieldLiveValue uiURL()); scriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue script(me())); testScreenScriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue testScreenScript(me())); images.directlyFeedInto(integralImages); integralImages.onNewElement(ii -> scaledAndPosterizedImages.newElement( posterizeBWImage_withMeta(colors, scaledBWImageFromBWIntegralImage_withMeta_height(pixelRows, ii)))); integralImages.onNewElement(r { if (shouldRunScript()) rstRunScript.go(); }); scaledAndPosterizedImages.onNewElement(img -> { fpsCounter.inc(); setField(fps := iround(fpsCounter!)); isPosterized?.setImage_thisThread(img); floodFill(img); }); // 20 Hz is enough for everyone dm_doEvery(1000/20, r { if (enabled) { screenSelector?.updateScreenCount(); Timestamp deadline = tsNowPlusMS(1000/20); images.useScreen(screenNr); images.step(); long remaining = deadline.minus(tsNow()); remainingMSPerFrame.add(remaining); setField(remainingMS := iround(remainingMSPerFrame!)); } }); } ImageSurface stdImageSurface() { ret pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false); } visualize { 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())); // main visual var tabs = scrollingTabs(jTopOrLeftTabs(horizontalLayout, Posterized := withTools(isPosterized), Regions := jscroll_centered_borderless(isRegions), Script := scriptRunner.scriptAndResultPanel(), "Test Screen" := testScreenPanel(), Timings := withRightAlignedButtons(taTimings, "Reset" := r resetTimings) )); 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"), screenSelector.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(5, jbutton("A"), jbutton("B"), jbutton("C"), )); } } // end of module