!7 need latest dm_fieldLiveValue. !include early #1033506 // Compact Module Include Gazelle V module GazelleScreenCam { !include early #1025212 // +Enabled without visualization int screenNr; int pixelRows = 100, colors = 8; S script, testScreenScript; bool animate = true; 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; start { 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(); 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_calculatedToolTip speedInfo_long(rightAlignLabel(dm_calculatedLabel speedInfo())); var vis = centerAndSouth( withMargin(jtabs( Posterized := jscroll_centered(isPosterized), Regions := jscroll_centered(isRegions), Script := scriptRunner.scriptAndResultPanel(), "Test Screen" := testScreenPanel(), Timings := taTimings, )), withMargin(jHigherScrollPane(jfullcenter( vstackWithSpacing( 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 */ )), jSpeedInfo )))), ); 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); functionTimings.time("Regions", ff); if (isRegions != null && isRegions.isShowing_quick()) { print("Showing regions image"); isRegions.setImage_thisThread(ff.regionsImage()); } setEnclosingTabTitle(isRegions, nRegions(ff.regionCount())); } // old "lightning" version /*void floodFill(BWImage img) { FloodFillBWImage ff = new(img); ff.tolerance(0); ff.startAt(randomPt(img)); stepAll(ff); isRegions?.setImage(bitMatrixToBufferedImage(ff.visited); }*/ 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(img); testScreenScriptRunner.parseAndRunOn(ii); } JComponent testScreenPanel() { ret centerAndSouthWithMargin( hsplit( northAndCenterWithMargin(centerAndEastWithMargin( jlabel("Input"), dm_fieldChekBox animate()), jscroll_center(isTestScreen)), withTitle("Output", testScreenScriptRunner.scpScriptResult)), testScreenScriptRunner.scriptInputField() ); } }