!7 cmodule PipelinedRecognizer > DynImageSurface { transient ChessOCR_Pipeline activePipeline; transient JTable tblBoardsFound; transient ChessPieceRecognizer pieceRecognizer; transient ReliableSingleThread rst = dm_rst(module(), r newRecognition); transient S status; transient bool preparing; start { if (!hasImage()) setImage(whiteImage(100)); onNewImage = rst; rst.trigger(); doEvery(1.0, r updateStatus); } void updateStatus { ChessOCR_Pipeline pipeline = activePipeline; if (!preparing && (pipeline == null || pipeline.idle())) setField(status := "Idle"); else if (pipeline != null) setField(status := "Recognizing. Segmenters: " + pipeline.segmenters.stats() + ", possible board positions: " + pipeline.possibleBoardPositions.stats()); } void newRecognition { dispose activePipeline; if (!hasImage()) ret; temp dm_tempSetField(preparing := true); setField(status := "Recognizing..."); new ChessOCR_Pipeline pipeline; pipeline.inputImage = getImage(); if (pieceRecognizer == null) pieceRecognizer = chessOCR_pieceRecognizer(); pipeline.pieceRecognizer = pieceRecognizer; pipeline.boardsFound.onChange.add(r updateTable); pipeline.boardsFound.onImprovedScore.add(voidfunc(S fen, Rect r) { pipeline.possibleBoardPositions.addAll(wiggleRect(r)); }); activePipeline = pipeline; pipeline.addSegmenter(parameterizedSegmenterFromAGIBlue("GingerGM fullscreen find chess board #1")); } void updateTable { dataToTable(tblBoardsFound, sortedByMapElementDesc Score(map(activePipeline.boardsFound.byFEN, (fen, data) -> litorderedmap( "Score" := formatDouble(data.bestScore, 2), "FEN" := fen, "Best position" := strOrNull(data.bestPosition), "#" := l(data.boardPositions))))); } visual centerAndSouthWithMargins( jvsplit(super, jCenteredSection("Boards found", tblBoardsFound = sexyTable())), dm_label status()); L wiggleRect(Rect r) { new L out; Rect img = imageRect(getImage()); for y to 2: for x to 2: if (x > 0 || y > 0) out.add(intersectRects(img, growRectRightAndBottom(r, x, y))); ret out; } }