!752 concepts. // Note: Don't reset idCounter in #1005389 if this program has // imported data already. !include #1005530 // PIF Classes (Clip, Found, FullySearched) + Screenshot + MarkedClip static int searchBack = 5; // search back in how many screenshots (must be at least 1 to include current screenshot) static float similarity = 0.999f; static int maxCopiesPerClip = 100; static int screenshotDelay = 3000; static new LinkedBlockingDeque queue; // contains Screenshot or TRUE (stands for please cancel current job) static JButton btnMark; static JTextField tfDesc; static JList list; p { mainConcepts.useGZIP = true; mainConcepts.persist(30000); dbBot(); importClips(); /*for (Clip clip : mainConcepts.list(Clip)) { print("My Clip: " + clip.description); }*/ if (countConcepts(Screenshot) == 0) new Screenshot(shootScreen2()); awt { showControls(jCenteredLine( jbutton("New screenshot", "newScreenshot"), jbutton("Import new clips", "importClips") )); lowerPriorityThread("run"); // caveat: priorities don't work on Linux is = new ImageSurface { public void setSelection(Rectangle r) { super.setSelection(r); btnMark.setEnabled(r != null); } }; /*is.addMouseMotionListener(new MouseAdapter { public void mouseMoved(MouseEvent e) { //is.setToolTipText(str(e.getPoint())); } });*/ list = showRegularlyUpdatedList("Currently seen things", "makeList", 1000); addToWindowSplitRight(list, new JScrollPane(is)); addToWindow(list, jcenteredLine( jMinWidth(300, onEnter(tfDesc = new JTextField, "mark")), btnMark = jdisabledButton("Mark", "mark"))); tfDesc.requestFocus(); moveToRightScreenEdge(getFrame(list)); onDoubleClick(list, voidfunc(S item) { long foundID = parseFirstLong(item); Found found = cast getConcept(foundID); Rect r = found.fi.r; moveMouse(r.x+r.w/2, r.y+r.h/2); }); // Make our own timer so it's not paused on pauseAll bindTimerToComponent(new Timer(250, actionListener { pcall { //print("calculating=" + calculating); consoleIcon_mem(allPaused() ? "#1005543" : calculating ? "#1005541" : null); } }), consoleFrame()); } } static ImageSurface is; static Screenshot lastShown; static L shownRects; static L makeList() { Screenshot screenshot = last(list(Screenshot)); if (screenshot != lastShown) { is.setImage(loadImage2(screenshot.pngFile())); if (lastShown == null) is.zoomToDisplaySize(); lastShown = screenshot; } new L l; final L lFound = findBackRefs(screenshot, Found); for (Found found : lFound) pcall { l.add("[\* found.id */] \* found.clip->description */"); } final L rects = map(func(Found f) { f.fi.r.getRectangle() }, lFound); if (neq(shownRects, rects)) { shownRects = rects; is.overlay = voidfunc(Graphics2D g) { for (Rectangle r : rects) is.drawSelectionRect(g, r, Color.blue, Color.white); }; is.repaint(); } setFrameTitle(list, "Seeing " + n(l(l), "things")); ret l; } static volatile bool calculating; svoid run { for (O o : grabFromQueueIterator(queue)) { if (o << Screenshot) { calculating = true; searchScreenshot(o/Screenshot); calculating = false; } } } svoid searchScreenshot(Screenshot screenshot) { print("Searching screenshot " + screenshot.id); BWImage screen = null; // Order clips by last found new LinkedHashSet clips; for (Found found : reversed(list(Found))) addIfNotNull(clips, found.clip!); addAll(clips, reversed(list(Clip))); quickSearch(screenshot); for (Clip clip : clips) { if (queue.peekFirst() instanceof Bool) ret; // signal to canel if (findConcept(FullySearched, +screenshot, +clip) != null) continue; print(" Searching " + clip.description); if (screen == null) screen = new BWImage(loadImage2(screenshot.pngFile())); bwRawImageSearch_verbose = true; bwRawImageSearch_maxEntries = maxCopiesPerClip; for (FoundImg fi : bwRawImageSearch(screen, clip.img, similarity)) uniq(Found, +screenshot, +clip, +fi); uniq(FullySearched, +screenshot, +clip); } print("Done searching screenshot"); } svoid quickSearch(Screenshot screenshot) { new HashMap lastPosition; for (Found found : reversed(list(Found))) if (!lastPosition.containsKey(found.clip!)) lastPosition.put(found.clip!, found.fi.r); BWImage screen = null; for (Clip clip : keys(lastPosition)) pcall { if (findConcept(FullySearched, +screenshot, +clip) != null) continue; Rect pos = lastPosition.get(clip); print(" Quick-Searching " + clip.description + " at " + struct(pos)); if (screen == null) screen = new BWImage(loadImage2(screenshot.pngFile())); BWImage pat = clip.img; int wp = pat.getWidth(), hp = pat.getHeight(); float maxError = (1f-similarity)*wp*hp; float diff = bwImageSectionsSimilarity(screen, pat, pos.x, pos.y, maxError); if (diff <= maxError) { float sim = 1-diff/(wp*hp); FoundImg fi = new FoundImg(pos, sim); print(" Found!"); uniq(Found, +screenshot, +clip, +fi); } } } svoid importClips { Concepts inConcepts = new Concepts("#1005389").load(); for (MarkedClip clip : inConcepts.list(MarkedClip)) { //print("Foreign Clip: " + clip.description); Clip cl = conceptWhere(Clip, originalID := clip.id); if (cl == null) { cl = cnew(Clip, originalID := clip.id, img := clip.img, description := clip.description); print(clip.description + " => Imported as " + cl.id); } } reScan(); } svoid reScan { for (Screenshot s : takeLast(searchBack, list(Screenshot))) queue.addFirst(s); queue.addFirst(true); // signal to cancel current activity } svoid newScreenshot { consoleFrame().toBack(); swingLater(screenshotDelay, r { Screenshot screenshot; queue.addFirst(screenshot = new Screenshot(shootScreen2())); Screenshot last = last(list(Screenshot)); print("Screenshot id: " + screenshot.id + ", latest id: " + last.id); assertSame(screenshot, last); queue.addFirst(true); // signal to cancel current activity consoleFrame().toFront(); getFrame(list).toFront(); }); } svoid mark { Rectangle r = is.getSelection(); if (r == null) ret; S desc = tfDesc.getText().trim(); cnew(MarkedClip, screenshot := lastShown, positionInScreenshot := new Rect(r), img := new BWImage(is.getImage()).clip(r), description := desc); showAnimation("#1005392", quote(desc), 1); print("Marked clip! " + quote(desc) + " (" + r + ")"); tfDesc.selectAll(); tfDesc.requestFocus(); reScan(); }