!7 static int topTenSize = 1000, maxImages = 1000; static MultiSetAndTopTen mstt; // holds md5 p { mstt = new MultiSetAndTopTen( l_persistentTreeMap("Images + count"), l_persistentList("Top Ten")); mstt.maxEntries = maxImages; if (l(mstt.topTen()) != topTenSize) mstt.newTopTen(topTenSize); thread "Collect" { deleteUnusedImages(); repeat with sleep 10 { collectIt(); } } showButtons("Top " + topTenSize, f showTopTen); } svoid collectIt { print("Collecting..."); BWImage img = shootScreenBW(); L segments = autoSegment(img); for (Rect r : segments) { RGBImage clip = img.clip(r).toRGB(); S md5 = rgbMD5(clip); mstt.add(md5); File f = imgFile(md5); if (!f.exists()) savePNG(f, clip); } print(n(segments, "segment") + " on screen. " + n(mstt.numEntries(), "image") + " in DB. " + n(mstt.numOccurrences(), "occurrence") + ". DB size: " + toM(guessClusteredDirSize(programDir())) + " MB"); } static File imgFile(S md5) { ret getProgramFile(md5 + ".png"); } svoid showTopTen { L data = map(mstt.topTen(), func(S md5) { litorderedmap("Image" := loadBufferedImageOpt(imgFile(md5)), "MD5" := md5, "Occurrences" := mstt.get(md5)) }); showTable(data, "Top " + l(data)); } svoid deleteUnusedImages { Set set = caseInsensitiveSet(); set.addAll(mstt.entries()); for (File f : filesEndingWith(programDir(), ".png")) if (!mstt.contains(toLower(dropSuffix(".png", f.getName())))) { print("Deleting " + f); f.delete(); } }