Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

579
LINES

< > BotCompany Repo | #1033924 // Gazelle Screen Cam / Gazelle 22 Module [backup before FlexibleRateTimer]

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

Uses 1405K of libraries. Click here for Pure Java version (21004L/117K).

1  
!7
2  
3  
// Note: Don't use db_mainConcepts(), only the module's concepts field
4  
5  
!include early #1033884 // Compact Module Include Gazelle V [dev version]
6  
7  
module GazelleScreenCam {
8  
  !include early #1025212 // +Enabled without visualization
9  
  
10  
  int pixelRows = 128, colors = 8;
11  
  S script, testScreenScript;
12  
  bool animate = true;
13  
  bool horizontalLayout; // flat layout
14  
  
15  
  WatchTarget watchTarget;
16  
  
17  
  transient ImageSurface isPosterized, isRegions, isTestScreen;
18  
  transient new ScreenCamStream imageStream;
19  
  transient new BWIntegralImageStream integralImages;
20  
  transient new SourceTriggeredStream<BWImage> scaledAndPosterizedImages;
21  
  transient new DoubleFPSCounter fpsCounter;
22  
  transient int fps;
23  
  //transient ScreenSelectorRadioButtons screenSelector;
24  
  transient WatchTargetSelector watchTargetSelector;
25  
  transient new RollingAverage remainingMSPerFrame;
26  
  transient int remainingMS;
27  
  
28  
  transient new FunctionTimings<S> functionTimings;
29  
  
30  
  transient ReliableSingleThread rstRunScript = dm_rst(me(), r _runScript);
31  
  
32  
  transient JGazelleVScriptRunner scriptRunner;
33  
  transient JGazelleVScriptRunner testScreenScriptRunner;
34  
  
35  
  transient Animation animation;
36  
  
37  
  transient BWImage_FastRegions mainScreenRegions;
38  
  
39  
  transient UIURLSystem uiURLs;
40  
  
41  
  // set by host
42  
  transient Concepts concepts;
43  
  
44  
  S uiURL;
45  
  
46  
  transient FileWatchService fileWatcher;
47  
  
48  
  transient SimpleCRUD_v2<Label> labelCRUD;
49  
  transient SimpleCRUD_v2<GalleryImage> imageCRUD;
50  
51  
  transient JGallery gallery;
52  
53  
  start {
54  
    dm_onFieldChange horizontalLayout(
55  
      //r dm_revisualize // deh buggy
56  
      r dm_reload
57  
    );
58  
    
59  
    // non-standalone mode (doesn't work yet)
60  
    if (concepts == null) {
61  
      db();
62  
      concepts = db_mainConcepts();
63  
    }
64  
    
65  
    // update count in tab when tab isn't selected
66  
    onConceptChanges(concepts, -> {
67  
      labelCRUD?.updateEnclosingTabTitle();
68  
      imageCRUD?.updateEnclosingTabTitle();
69  
    });
70  
    
71  
    uiURLs = new UIURLSystem(me(), dm_fieldLiveValue uiURL());
72  
    
73  
    scriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue script(me()));
74  
    testScreenScriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue testScreenScript(me()));
75  
76  
    imageStream.directlyFeedInto(integralImages);
77  
    
78  
    integralImages.onNewElement(ii ->
79  
      scaledAndPosterizedImages.newElement(
80  
        scaleAndPosterize(ii, new SnPSettings(pixelRows, colors))));
81  
          
82  
    integralImages.onNewElement(r {
83  
      if (shouldRunScript()) rstRunScript.go();
84  
    });
85  
          
86  
    scaledAndPosterizedImages.onNewElement(img -> {
87  
      fpsCounter.inc();
88  
      setField(fps := iround(fpsCounter!));
89  
      
90  
      // display before analysis (old)
91  
      // isPosterized?.setImage_thisThread(img);
92  
      
93  
      // find regions
94  
      floodFill(img);
95  
      
96  
      // display after analysis so we can highlight a region
97  
      if (isPosterized != null) {
98  
        var img2 = highlightRegion(img, isPosterized, mainScreenRegions);
99  
        isPosterized.setImage_thisThread(img2);
100  
      }
101  
    });
102  
    
103  
    // 20 Hz is enough for everyone
104  
    dm_doEvery(1000/20, r {
105  
      if (enabled) {
106  
        watchTargetSelector?.updateScreenCount();
107  
        Timestamp deadline = tsNowPlusMS(1000/20);
108  
        if (watchTarget cast WatchScreen)
109  
          imageStream.useScreen(watchTarget.screenNr-1);
110  
        else if (watchTarget cast WatchMouse)
111  
          imageStream.area(mouseArea(watchTarget.width, watchTarget.height));
112  
        imageStream.step();
113  
        long remaining = deadline.minus(tsNow());
114  
        remainingMSPerFrame.add(remaining);
115  
        setField(remainingMS := iround(remainingMSPerFrame!));
116  
      }
117  
    });
118  
    
119  
    startDirWatcher();
120  
    for (f : allImageFiles(galleryDir()))
121  
      addToGallery(f);
122  
  }
123  
  
124  
  // convert to color & highlight region
125  
  BufferedImage highlightRegion(BWImage image, ImageSurface is, BWImage_FastRegions regions) {
126  
    var pixels = image.getRGBPixels();
127  
    
128  
    var mouse = is.mousePosition;
129  
    if (mouse != null && regions != null) {
130  
      int iHighlightedRegion = regions.regionAt(mouse);
131  
      //int marked = 0;
132  
      if (iHighlightedRegion > 0)
133  
        for i over pixels:
134  
          if (regions.regionAt(i) == iHighlightedRegion) {
135  
            pixels[i] = 0xFF008000;
136  
            //++marked;
137  
          }
138  
      //printVars(+mouse, +iHighlightedRegion, +marked);
139  
    }
140  
    
141  
    ret bufferedImage(pixels, image.getWidth(), image.getHeight());
142  
  }
143  
  
144  
  void startDirWatcher {
145  
    fileWatcher = new FileWatchService;
146  
    fileWatcher.addRecursiveListener(picturesDir(), file -> {
147  
      if (!isImageFile(file)) ret;
148  
      addToGallery(file);
149  
    });
150  
  }
151  
  
152  
  ImageSurface stdImageSurface() {
153  
    ret pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false);
154  
  }
155  
  
156  
  visualize {
157  
    gallery = new JGallery;
158  
    var galleryComponent = gallery.visualize();
159  
160  
    new AWTOnConceptChanges(concepts, galleryComponent, -> {
161  
      gallery.setImageFiles(map(list(concepts, GalleryImage), i -> i.path));
162  
    }).install();
163  
    
164  
    /*screenSelector = new ScreenSelectorRadioButtons(dm_fieldLiveValue screenNr());
165  
    screenSelector.compactLayout(true);
166  
    screenSelector.hideIfOnlyOne(true);
167  
    screenSelector.screenLabel("");*/
168  
    isPosterized = stdImageSurface();
169  
    
170  
    isRegions = stdImageSurface();
171  
    isTestScreen = stdImageSurface();
172  
    
173  
    // when test screen is visible, do the animation
174  
    awtEvery(isTestScreen, 1000/20, r stepAnimation);
175  
    
176  
    JTextArea taTimings = jTextArea_noUndo();
177  
    awtEveryAndNow(taTimings, .5, r {
178  
      setText(taTimings, renderFunctionTimings())
179  
    });
180  
    
181  
    var jSpeedInfo = dm_transientCalculatedToolTip speedInfo_long(rightAlignLabel(dm_transientCalculatedLabel speedInfo()));
182  
    
183  
    //print("Labels: " + list(concepts, Label));
184  
    labelCRUD = new SimpleCRUD_v2(concepts, Label);
185  
    labelCRUD.hideFields("globalID");
186  
    labelCRUD.addCountToEnclosingTab(true);
187  
    
188  
    imageCRUD = new SimpleCRUD_v2(concepts, GalleryImage);
189  
    imageCRUD.addCountToEnclosingTab(true);
190  
    imageCRUD.itemToMap_inner2 = img
191  
      -> litorderedmap(
192  
        "File" := fileName(img.path),
193  
        "Folder" := dirPath(img.path));
194  
    
195  
    // main visual
196  
197  
    var studyPanel = new StudyPanel;
198  
199  
    var tabs = scrollingTabs(jTopOrLeftTabs(horizontalLayout,
200  
      "Screen Cam" := withTools(isPosterized),
201  
      WithToolTip("Regions", "Visualize regions detected on screen")
202  
        := jscroll_centered_borderless(isRegions),
203  
      WithToolTip("Study", "Here you can analyze gallery images")
204  
        := withTopMargin(studyPanel.visualize()),
205  
      WithToolTip("Pretty Gallery", "Gallery view with preview images")
206  
        := galleryComponent,
207  
      WithToolTip("Powerful Gallery", "Gallery view with more functions (delete etc)")
208  
        := wrapCRUD(imageCRUD),
209  
      WithToolTip("Labels", "Manage labels (image markers)")
210  
        := wrapCRUD(labelCRUD),
211  
      WithToolTip("Script", "Run a Gazelle V script")
212  
        := scriptRunner.scriptAndResultPanel(),
213  
      "Test Screen" := testScreenPanel(),
214  
      Timings := withRightAlignedButtons(taTimings,
215  
        Reset := r resetTimings)
216  
    ));
217  
218  
    var cbEnabled = toolTip("Switch screen cam on or off", dm_checkBox enabled(""));
219  
    var lblScreenCam = setToolTip("Show scaled down and color-reduced screen image",
220  
      jlabel("Screen Cam"));
221  
    tabComponentClickFixer(lblScreenCam);
222  
    var screenCamTab = hstackWithSpacing(cbEnabled, lblScreenCam);
223  
    
224  
    replaceTabTitleComponent(tabs, "Screen Cam", screenCamTab);
225  
    
226  
    // for tab titles
227  
    labelCRUD.update();
228  
    imageCRUD.update();
229  
    
230  
    watchTargetSelector = new WatchTargetSelector;
231  
232  
    var urlBar = uiURLs.urlBar();
233  
    setToolTip(uiURLs.comboBox, "UI navigation system (currently unused)");
234  
    
235  
    var vis = northAndCenter(
236  
      withSideAndTopMargin(urlBar),
237  
      centerAndSouthOrEast(horizontalLayout,
238  
        horizontalLayout ? withMargin(tabs) : withSideMargin(tabs),
239  
        /*withMargin*/(borderlessScrollPane(jHigherScrollPane(
240  
        jfullcenter(vstack(
241  
          withLeftAndRightMargin(hstack(
242  
            dm_rcheckBox enabled("Watch"),
243  
            watchTargetSelector.visualize(),
244  
            jlabel(" in "),
245  
            withLabelToTheRight("colors @ ", dm_spinner colors(2, 256)),
246  
            withLabelToTheRight("p", dm_powersOfTwoSpinner pixelRows(512)),
247  
            , /* speed info can also go here */
248  
          )),
249  
          verticalStrut(2),
250  
          withRightMargin(jSpeedInfo)
251  
        ))))),
252  
    ));
253  
    setHorizontalMarginForAllButtons(vis, 4);
254  
    ret vis;
255  
  }
256  
  
257  
  S speedInfo() {
258  
    ret "FPS " + fps + " idle " + remainingMS + " ms";
259  
  }
260  
  
261  
  S speedInfo_long() {
262  
    ret "Screen cam running at " + nFrames(fps) + "/second. " + n2(remainingMS) + " ms remaining per frame in first core.";
263  
  }
264  
  
265  
  void floodFill(BWImage img) {
266  
    BWImage_FastRegions ff = new(img);
267  
    //ff.tolerance(0);
268  
    ff.collectBounds();
269  
    functionTimings.time("Regions", ff);
270  
    mainScreenRegions = ff;
271  
    if (isRegions != null && isRegions.isShowing_quick()) {
272  
      //print("Showing regions image");
273  
      isRegions.setImage_thisThread(ff.regionsImage());
274  
    }
275  
    setEnclosingTabTitle(isRegions, nRegions(ff.regionCount()));
276  
  }
277  
  
278  
  bool useErrorHandling() { false; }
279  
  
280  
  S renderFunctionTimings() {
281  
    ret lines(ciSorted(map(functionTimings!, (f, avg) ->
282  
      firstToUpper(f) + ": " + n2(iround(nsToMicroseconds(avg!))) + " " + microSymbol() + "s (" + n2(iround(avg.n())) + ")")));
283  
  }
284  
  
285  
  transient long _runScript_idx;
286  
287  
  void _runScript() {
288  
    long n = integralImages.elementCount();
289  
    if (n > _runScript_idx) {
290  
      _runScript_idx = n;
291  
292  
      scriptRunner.parseAndRunOn(integralImages!);
293  
    }
294  
  }
295  
  
296  
  bool shouldRunScript() {
297  
    ret isShowing(scriptRunner.scpScriptResult);
298  
  }
299  
  
300  
  void stepAnimation {
301  
    if (!animate) ret;
302  
    if (animation == null) {
303  
      animation = new AnimatedLine;
304  
      animation.start();
305  
    }
306  
    animation.nextFrame();
307  
    var img = whiteImage(animation.w, animation.h);
308  
    animation.setGraphics(createGraphics(img));
309  
    animation.paint();
310  
    isTestScreen?.setImage(img);
311  
    
312  
    var ii = bwIntegralImage_withMeta(img);
313  
    testScreenScriptRunner.parseAndRunOn(ii);
314  
  }
315  
  
316  
  JComponent testScreenPanel() {
317  
    ret centerAndSouthWithMargin(
318  
      hsplit(
319  
        northAndCenterWithMargin(centerAndEastWithMargin(
320  
          jlabel("Input"), dm_fieldCheckBox animate()),
321  
        jscroll_centered_borderless(isTestScreen)),
322  
        
323  
        northAndCenterWithMargin(centerAndEastWithMargin(
324  
          jlabel("Output"), testScreenScriptRunner.lblScore),
325  
        testScreenScriptRunner.scpScriptResult)
326  
      ),
327  
        
328  
      testScreenScriptRunner.scriptInputField()
329  
    );
330  
  }
331  
  
332  
  L popDownItems() {
333  
    ret ll(jCheckBoxMenuItem_dyn("Horizontal Layout",
334  
      -> horizontalLayout,
335  
      b -> setField(horizontalLayout := b)));
336  
  }
337  
  
338  
  void unvisualize {} // don't zero transient component fields
339  
  
340  
  void resetTimings { functionTimings.reset(); }
341  
  
342  
  // add tool side bar to image surface
343  
  JComponent withTools(ImageSurface is) {
344  
    new ImageSurface_PositionToolTip(is);
345  
    ret centerAndEastWithMargin(jscroll_centered_borderless(is), vstackWithSpacing(3,
346  
      jimageButtonScaledToWidth(16, #1103054, "Save screenshot in gallery", rThread saveScreenshotToGallery),
347  
    ));
348  
  }
349  
  
350  
  class WatchTargetSelector {
351  
    JComboBox<WatchTarget> cb = jComboBox();
352  
    int screenCount;
353  
    
354  
    visualize {
355  
      updateList();
356  
      print("Selecting watchTarget: " + watchTarget);
357  
      selectItem(cb, watchTarget);
358  
      main onChange(cb, watchTarget -> {
359  
        setField(+watchTarget);
360  
        print("Chose watchTarget: " + GazelleScreenCam.this.watchTarget);
361  
      });
362  
      ret cb;
363  
    }
364  
    
365  
    void updateScreenCount() {
366  
      if (screenCount != screenCount())
367  
        updateList();
368  
    }
369  
    
370  
    void updateList() swing {
371  
      setComboBoxItems(cb, makeWatchTargets());
372  
    }
373  
    
374  
    L<WatchTarget> makeWatchTargets() {
375  
      ret flattenToList(
376  
        countIteratorAsList_incl(1, screenCount = screenCount(), i -> WatchScreen(i)),
377  
        new WatchMouse
378  
      );
379  
    }
380  
  }
381  
382  
  class SnPSelector {
383  
    settable new SnPSettings settings;
384  
    
385  
    event change;
386  
387  
    visualize {
388  
      var colors = jspinner(settings.colors, 2, 256);
389  
      main onChange(colors, -> {
390  
        settings.colors = intFromSpinner(colors);
391  
        change();
392  
      });
393  
      
394  
      var pixelRows = jPowersOfTwoSpinner(512, settings.pixelRows);
395  
      main onChange(pixelRows, -> {
396  
        settings.pixelRows = intFromSpinner(pixelRows);
397  
        change();
398  
      });
399  
      
400  
      ret hstack(
401  
        colors,
402  
        jlabel(" colors @ "),
403  
        pixelRows,
404  
        jlabel(" p"));
405  
    }
406  
  }
407  
  
408  
  JComponent wrapCRUD(SimpleCRUD_v2 crud) {
409  
    ret crud == null ?: withTopMargin(jRaisedSection(withMargin(crud.make_dontStartBots())));
410  
  }
411  
  
412  
  File galleryDir() {
413  
    ret picturesDir(gazelle22_imagesSubDirName());
414  
  }
415  
  
416  
  void saveScreenshotToGallery enter {
417  
    var img = imageStream!;
418  
    saveImageWithCounter(galleryDir(), "Screenshot", img);
419  
  }
420  
  
421  
  void addToGallery(File imgFile) {
422  
    if (!isImageFile(imgFile)) ret;
423  
    var img = uniq(concepts, GalleryImage, path := imgFile);
424  
    //printVars("addToGallery", +imgFile, +img);
425  
  }
426  
427  
  BWImage scaleAndPosterize(IBWIntegralImage ii, SnPSettings settings) {
428  
    ret posterizeBWImage_withMeta(settings.colors,
429  
      scaledBWImageFromBWIntegralImage_withMeta_height(settings.pixelRows, ii));
430  
  }
431  
432  
  class StudyPanel {
433  
    new SnPSelector snpSelector;
434  
    GalleryImage image;
435  
    ImageSurface is = stdImageSurface();
436  
    SingleComponentPanel scp = singleComponentPanel();
437  
    SingleComponentPanel analysisPanel = singleComponentPanel();
438  
    ConceptsComboBox<GalleryImage> cbImage = new(concepts, GalleryImage);
439  
    ImageToRegions itr;
440  
    int iSelectedRegion;
441  
442  
    *() {
443  
      cbImage.sortTheList = l -> sortConceptsByIDDesc(l);
444  
445  
      main onChangeAndNow(cbImage, img -> dm_q(me(), r {
446  
        image = img;
447  
        scp.setComponent(studyImagePanel());
448  
      }));
449  
450  
      is.removeAllTools();
451  
      is.onMousePositionChanged(r_dm_q(me(), l0 regionUpdate));
452  
453  
      imageSurfaceOnLeftMouseDown(is, pt -> dm_q(me(), r { chooseRegionAt(pt) }));
454  
455  
      snpSelector.onChange(r_dm_q(me(), l0 runSnP));
456  
    }
457  
458  
    void chooseRegionAt(Pt p) {
459  
      if (itr == null) ret;
460  
      iSelectedRegion = itr.regions.regionAt(p);
461  
      updateAnalysis();
462  
    }
463  
464  
    // load new image
465  
    JComponent studyImagePanel() { 
466  
      if (image == null) null;
467  
      var i = loadImage2(image.path);
468  
      if (i == null) ret jcenteredlabel("Image not found");
469  
470  
      iSelectedRegion = 0;
471  
      itr = new ImageToRegions(i, snpSelector.settings);
472  
      runSnP();
473  
      ret hsplit(jscroll_centered_borderless(is), analysisPanel);
474  
    }
475  
476  
    void runSnP {
477  
      if (itr == null) ret;
478  
      itr.run();
479  
      regionUpdate();
480  
    }
481  
482  
    void regionUpdate {
483  
      if (itr == null) ret;
484  
      var highlighted = highlightRegion(itr.posterized, is, itr.regions);
485  
      is.setImage(highlighted);
486  
      is.performAutoZoom(); // seems to be necessary for some reason
487  
488  
      updateAnalysis();
489  
    }
490  
491  
    void updateAnalysis {
492  
      new LS lines;
493  
      lines.add(nRegions(itr.regions.regionCount()));
494  
      lines.add("Selected region: " + iSelectedRegion);
495  
      S text = lines_rtrim(lines);
496  
      analysisPanel.setComponent(jscroll(jMultiLineLabel(text)));
497  
    }
498  
499  
    visual
500  
      jRaisedSection(northAndCenterWithMargins(
501  
        centerAndEast(withLabel("Study", cbImage),
502  
          hstack(jlabel(" in "), snpSelector.visualize())),
503  
        scp));
504  
  } // end of StudyPanel
505  
506  
  class ImageToRegions {
507  
    BufferedImage inputImage;
508  
    BWIntegralImage ii;
509  
    SnPSettings snpSettings;
510  
    BWImage posterized;
511  
    BWImage_FastRegions regions;
512  
513  
    *(BufferedImage *inputImage, SnPSettings *snpSettings) {}
514  
515  
    run {
516  
      ii = bwIntegralImage_withMeta(inputImage);
517  
      posterized = scaleAndPosterize(ii, snpSettings);
518  
      regions = new BWImage_FastRegions(posterized);
519  
      regions.collectBounds();
520  
      functionTimings.time("Regions", regions);
521  
    }
522  
  }
523  
} // end of module
524  
525  
concept Label > ConceptWithGlobalID {
526  
  S name;
527  
  //new RefL examples;
528  
  
529  
  toString { ret "Label " + name; }
530  
}
531  
532  
concept GalleryImage {
533  
  File path;
534  
535  
  toString { ret /*"[" + id + "] " +*/ fileName(path); }
536  
}
537  
538  
concept SavedRegion {
539  
  new Ref image; // e.g. a GalleryImage
540  
  SnPSettings snpSettings;
541  
  Rect bounds;
542  
  BitMatrix bitMatrix;
543  
  //new RefL<Label> labels;
544  
}
545  
546  
concept Example {
547  
  new Ref<Label> label;
548  
  new Ref item; // e.g. a SavedRegion
549  
  double confidence = 1;
550  
}
551  
552  
concept IfThenTheory {
553  
  new Ref if_;
554  
  new Ref then;
555  
}
556  
557  
sclass WatchTarget {}
558  
559  
// screenNr: 1 = screen 1 etc
560  
srecord WatchScreen(int screenNr) > WatchTarget {
561  
  toString { ret "Screen " + screenNr; }
562  
}
563  
564  
srecord WatchMouse(int width, int height) > WatchTarget {
565  
  WatchMouse() {
566  
    height = 256;
567  
    width = iround(height*16.0/9);
568  
  }
569  
  
570  
  toString { ret "Mouse"; }
571  
}
572  
573  
// SnP = Scale and Posterize
574  
persistable sclass SnPSettings {
575  
  int pixelRows = 128;
576  
  int colors = 8;
577  
578  
  *(int *pixelRows, int *colors) {}
579  
}

Author comment

Began life as a copy of #1033862

download  show line numbers  debug dex  old transpilations   

Travelled to 2 computer(s): bhatertpkbcr, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1033924
Snippet name: Gazelle Screen Cam / Gazelle 22 Module [backup before FlexibleRateTimer]
Eternal ID of this version: #1033924/1
Text MD5: 9db08d41b57d7d33177c3c184ab40fbd
Transpilation MD5: 588eea842591e146471f700b367242cc
Author: stefan
Category: javax / gazelle v
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-01-12 16:22:52
Source code size: 17597 bytes / 579 lines
Pitched / IR pitched: No / No
Views / Downloads: 114 / 165
Referenced in: [show references]