!7 !include early #1033506 // Compact Module Include Gazelle V module GazelleScreenCam { !include early #1025212 // +Enabled without visualization int screenNr; int pixelRows = 100, colors = 8; transient ImageSurface isPosterized, isRegions; 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 SingleComponentPanel scpScriptResult; transient ReliableSingleThread rstRunScript = dm_rst(me(), r runScript); start { images.directlyFeedInto(integralImages); integralImages.onNewElement(ii -> scaledAndPosterizedImages.newElement( posterizeBWImage_withMeta(colors, scaledBWImageFromBWIntegralImage_withMeta(pixelRows, ii)))); scaledAndPosterizedImages.onNewElement(img -> { fpsCounter.inc(); setField(fps := iround(fpsCounter!)); isPosterized?.setImage(img); floodFill(img); }); // 20 Hz is enough for everyone dm_doEvery(1000/20, r { if (enabled) { Timestamp deadline = tsNowPlusMS(1000/20); images.useScreen(screenNr); images.step(); long remaining = deadline.minus(tsNow()); remainingMSPerFrame.add(remaining); setField(remainingMS := iround(remainingMSPerFrame!)); } }); } visualize { screenSelector = new ScreenSelectorRadioButtons(dm_fieldLiveValue screenNr()); screenSelector.compactLayout(true); screenSelector.screenLabel(""); isPosterized = pixelatedImageSurface().setAutoZoomToDisplay(true); isRegions = pixelatedImageSurface().setAutoZoomToDisplay(true); JTextArea taTimings = jTextArea_noUndo(); awtEveryAndNow(taTimings, .5, r { setText(taTimings, renderFunctionTimings()) }); var vis = centerAndSouth( withMargin(jscroll(jtabs( Posterized := jscroll_centered(isPosterized), Regions := jscroll_centered(isRegions), Script := northAndCenter( withMargin(withLabel("Gazelle V Script:", dm_textField script())), scpScriptResult = singleComponentPanel() ), Timings := taTimings, ))), withMargin(jHigherScrollPane(jfullcenter(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)), dm_calculatedToolTip speedInfo_long(dm_calculatedLabel speedInfo()), ))))), ); 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); isRegions?.setImage(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())) + ")"))); } }