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

250
LINES

< > BotCompany Repo | #1024849 // Chess Board Recognizer backup

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

Uses 911K of libraries. Click here for Pure Java version (19060L/109K).

1  
!7
2  
3  
cmodule ChessBoardRecognizer {
4  
  S segmenterPreset;
5  
  ParameterizedSegmenter segmenter;
6  
  L<Rect> segments;
7  
  Rect boardLocation;
8  
  double recognitionScore;
9  
  S status;
10  
  S selectedSquare;
11  
  S piece;
12  
  LPair<S, Double> recognized;
13  
  S fen;
14  
15  
  switchable bool squareHeightAtBottom = true; // for YouTube videos
16  
  transient int recreatedSquareSize = 32;
17  
  transient ReliableSingleThread rst = dm_rst(module(), r recognize);
18  
  transient BufferedImage img, board, square, recreated;
19  
  transient LL<BufferedImage> squareImages;
20  
  transient ImageSurface isInput, isBoard, isSquare, isRecreated;
21  
  
22  
  transient LS pieces = ai_chessPieces();
23  
  transient Map<Bool, Map<S, BufferedImage>> recreateStock; // false = dark, true = light
24  
  
25  
  visualize {
26  
    isBoard = jImageSurface();
27  
    imageSurfaceOnHover(isBoard, voidfunc(Pt p) {
28  
      if (board == null || p == null) ret with noToolTip(isBoard);
29  
      setToolTip(isBoard, toolTipForSquare(boardPointToSquare(p));
30  
    });
31  
    imageSurfaceOnLeftClick(isBoard, voidfunc(Pt p) {
32  
      selectSquare(boardPointToSquare(p))
33  
    });
34  
    
35  
    isRecreated = jImageSurface(recreated);
36  
    imageSurfaceOnHover(isRecreated, voidfunc(Pt p) {
37  
      if (recreated == null || p == null) ret with noToolTip(isRecreated);
38  
      setToolTip(isRecreated, toolTipForSquare(recreatedPointToSquare(p));
39  
    });
40  
    imageSurfaceOnLeftClick(isRecreated, voidfunc(Pt p) {
41  
      selectSquare(recreatedPointToSquare(p))
42  
    });
43  
    
44  
    ret withCalc(rst, jvsplit(
45  
      jCenteredSection("Input image", jscroll_center(isInput = jImageSurface(or_func(img, () -> whiteImage(100))))),
46  
      northCenterAndSouthWithMargins(
47  
        centerAndEastWithMargin(withLabel("Segmenter preset: ", main.onChange(rst, dm_comboBox segmenterPreset(agiBlue_chessBoardSegmenterPresetNames()))),
48  
          hstackWithSpacing(
49  
            jbutton("Recognize", rst),
50  
            jPopDownButton_noText(
51  
              "Show possible chess boards found", rThread showSegments,
52  
              "Publish training image...", rThread publishImage,
53  
              "---", null,
54  
              "Screenshot (hiding OS)", rThread {
55  
                isInput.setImageAndZoomToDisplay(dm_shootScreenHidingOS());
56  
                rst.trigger();
57  
              })
58  
          )),
59  
        hgridWithSpacing(
60  
          jCenteredSection("Recreated", jscroll_center(isRecreated)),
61  
          jCenteredSection("Chess board in image",
62  
            centerAndSouthWithMargin(jscroll_center(isBoard),
63  
            dm_centeredCalculatedLabel(() -> "Recognition score: " + formatDouble(recognitionScore, 2))
64  
          )),
65  
          jCenteredLiveValueSection(dm_calculatedLiveValue(S, () -> "Selected square" + (empty(selectedSquare) ? "" : " (" + selectedSquare + ")")), centerAndSouthWithMargin(
66  
            jscroll_center(isSquare = jImageSurface(square)),
67  
            rightAlignedLine(
68  
              withLabel("Piece: ", dm_comboBox('piece, pieces)),
69  
              jbutton("Save & upload", rThread saveAndUploadPiece))
70  
        ))),
71  
        vstackWithSpacing(
72  
          dm_label('status),
73  
          withLabel("FEN:", dm_label('fen))
74  
        )
75  
      )));
76  
  }
77  
    
78  
  void recognize {
79  
    status("Recognizing...");
80  
    segmenter = parameterizedSegmenterFromAGIBlue(segmenterPreset);
81  
    if (segmenter == null) ret with infoBox(status("No segmenter"));
82  
    //img = dm_shootScreenHidingOS();
83  
    if (isInput != null) img = isInput.getImage();
84  
    L<Rect> rects = segmenter.get(img);
85  
    setField(segments := rects);
86  
    if (empty(rects)) {
87  
      clearImageSurfaces(isBoard, isRecreated);
88  
      setField(fen := "");
89  
      ret with status("No chess board found");
90  
    }
91  
    Rect r = first(rects);
92  
    bool corrected = squareHeightAtBottom && abs(r.w-r.h) > 3;
93  
    if (corrected) r.h = r.w;
94  
    new LS comments;
95  
    if (l(rects) > 1) comments.add("randomly choosing one from " + nBoards(rects));
96  
    if (corrected) comments.add("height-corrected");
97  
    status("Chess board found at: " + r + appendRoundBracketed(joinWithComma(comments)));
98  
    setField(boardLocation := r);
99  
    board = clipBufferedImage(img, r);
100  
    
101  
    squareImages = bufferedImageMNGrid(board, 8, 8);
102  
    
103  
    if (isBoard != null)
104  
      isBoard.setImageAndZoomToDisplay(
105  
        mergeBufferedImagesVertically(
106  
          map(bufferedImageNVerticalSlices(8, board), i ->
107  
            mergeBufferedImagesHorizontally(bufferedImageNHorizontalSlices(8, i)))));
108  
            
109  
    new ChessPieceRecognizer pieceRecognizer;
110  
    pieceRecognizer.load();
111  
    recognized = new L;
112  
    for (BufferedImage img : concatLists(squareImages))
113  
      recognized.add(pieceRecognizer.recognize(img));
114  
    setField(recognitionScore := doubleAvg(pairsB(recognized));
115  
    setField(fen := makeFEN());
116  
    print(recognized);
117  
    recreate();
118  
  }
119  
  
120  
  S status(S status) { setField(+status); ret status; }
121  
  
122  
  O _getReloadData() { ret img; }
123  
  void _setReloadData(BufferedImage img) { this.img = img; }
124  
 
125  
  void setImage(BufferedImage img) {
126  
    this.img = img;
127  
    if (isInput != null) isInput.setImageAndZoomToDisplay(img);
128  
    rst.trigger();
129  
  }
130  
131  
  S boardPointToSquare(Pt p) {
132  
    double space = imageMergeSpacing();
133  
    double squareW = board.getWidth()/8.0+space;
134  
    double squareH = board.getHeight()/8.0+space;
135  
    int x = clamp(iratio_floor(p.x+space/2, squareW), 0, 7);
136  
    int y = clamp(iratio_floor(p.y+space/2, squareH), 0, 7);
137  
    ret strCharPlus('A', x) + (8-y);
138  
  }
139  
  
140  
  S recreatedPointToSquare(Pt p) {
141  
    int x = clamp(iratio_floor(p.x, recreatedSquareSize), 0, 7);
142  
    int y = clamp(iratio_floor(p.y, recreatedSquareSize), 0, 7);
143  
    ret strCharPlus('A', x) + (8-y);
144  
  }
145  
  
146  
  void saveAndUploadPiece enter {
147  
    if (square == null || empty(piece)) ret;
148  
    chessOCR_uploadPieceImage(selectedSquare, piece, square);
149  
    if (mapGet(mapGet(recreateStock, chess_isLightSquare(selectedSquare)), piece) == null) recreateStock = null;
150  
    rst.trigger();
151  
  }
152  
  
153  
  void recreate {
154  
    if (recognized == null) ret;
155  
    if (recreateStock == null)
156  
      recreateStock = mapToValues(ll(false, true), light ->
157  
        mapValues(pairsToMap(reversePairs(chessPieceImagesFromAGIBlue(light))), imageID -> resizeImage(loadImage2(imageID), recreatedSquareSize, recreatedSquareSize)));
158  
159  
    new L<BufferedImage> out;
160  
    int i = 0;
161  
    for (S piece : pairsA(recognized)) {
162  
      bool light = even(i/8+i%8);
163  
      out.add(or_func(mapGet(mapGet(recreateStock, light), piece), () -> whiteImage(recreatedSquareSize, recreatedSquareSize)));
164  
      ++i;
165  
    }
166  
      
167  
    new L<BufferedImage> rows;
168  
    for (L<BufferedImage> row : listToChunks(out, 8))
169  
      rows.add(mergeBufferedImagesHorizontally(row, spacing := 0));
170  
    recreated = mergeBufferedImagesVertically(rows, spacing := 0);
171  
    if (isRecreated != null) isRecreated.setImageAndZoomToDisplay(recreated);
172  
  }
173  
  
174  
  Pair<S, Double> recognitionForSquare(S square) {
175  
    int x, y = unpair chess_squareToPos(square);
176  
    ret _get(recognized, y*8+x);
177  
  }
178  
  
179  
  S toolTipForSquare(S square) {
180  
    Pair<S, Double> rec = recognitionForSquare(square);
181  
    ret square + " - " + (rec == null ? "?" : rec.a + " [" + iround(clamp(rec.b, 0, 100)) + "%]");
182  
  }
183  
  
184  
  void selectSquare(S _square) {
185  
    setField(selectedSquare := _square);
186  
    S rec = pairA(recognitionForSquare(selectedSquare));
187  
    if (rec != null) setField(piece := rec);
188  
    int x, y = unpair chess_squareToPos(selectedSquare);
189  
    square = _get(_get(squareImages, y), x);
190  
    
191  
    ChessPieceProfile1 profile = chessOCR_pieceProfileFromRawImage_1(square, withPreprocessedImages := true);
192  
    isSquare.setImage(mergeBufferedImagesHorizontally(
193  
      itemPlusList(square, map toBufferedImage(profile.preprocessedImages))));
194  
    //printVars_str("leftClick", +p, +selectedSquare, +x, +y, +square);
195  
  }
196  
  
197  
  void showSegments {
198  
    L<Rect> segments = this.segments;
199  
    showImage_centered(n2(segments, "segment") + " found",
200  
      mergeBufferedImagesVertically(map(segments, r -> clipBufferedImage(img, r))));
201  
  }
202  
  
203  
  void publishImage enter {
204  
    BufferedImage img = this.img;
205  
    S segmenterPreset = this.segmenterPreset;
206  
    
207  
    JCheckBox cbFound = jcheckbox(true), cbHasBoard = jcheckbox(true);
208  
    JTextField tfFEN = jtextfield(fen), tfComments = jtextfield(),
209  
      tfImageCredits = jtextfield();
210  
    
211  
    showFormTitled("Publish training image",
212  
      "Image", jImageSurface(scaleImageToWidth(img, 500)),
213  
      "Segmenter used", jlabel(segmenterPreset),
214  
      "Is there a chess board in the image?", cbHasBoard,
215  
      "FEN (empty if no board in image)", tfFEN,
216  
      "Was the chess board found?", cbFound, // TODO: make clearer what this means if there is no board in image
217  
      "Image credits (optional)", tfImageCredits,
218  
      "Random comments", tfComments,
219  
      "NOTE:", jMultiLineLabel("By clicking 'publish', you PUBLISH this image (fair use/public domain)."),
220  
      "", jThreadedButton("Publish", r {
221  
        temp tempInfoBox_noHide("Uploading training image...");
222  
        S imageURL = uploadToImageServer("Chess board recognition training image", img);
223  
        S desc = "Chess board recognition training image " + assertNempty("Parseable image URL", parseSnippetImageURL(imageURL));
224  
        new LinkedHashMap<S> map;
225  
        map.put("Input image", imageURL);
226  
        mapPutIfNemptyValue(map, "Image credits", gtt(tfImageCredits));
227  
        S fen = gtt(tfFEN);
228  
        map.put("Image has chess board", yesNo_short_firstUpper(isChecked(cbHasBoard) || nempty(fen)));
229  
        mapPutIfNemptyValue(map, "FEN", fen);
230  
        map.put("Segmenter used", segmenterPreset);
231  
        map.put("Chess board found", yesNo_short_firstUpper(isChecked(cbFound)));
232  
        if (isChecked(cbFound))
233  
          map.put("Board location", struct(boardLocation));
234  
        S sliceID = agiBlue_chessBoardRecognitionTrainingImagesSliceID();
235  
        new L<Map> toPost;
236  
        S name = agiBlue_createUnusedNumberedPage(sliceID, desc + " #");
237  
        for (S key, value : map)
238  
          toPost.add(litmap(q := name, +key, +value));
239  
        agiBot_postMulti(keyPairForProgram(), toPost, slice := sliceID);
240  
        infoBox("Training image uploaded!");
241  
        openURLInBrowser(agiBlue_linkForPhrase(name, slice := sliceID));
242  
        disposeWindow(heldButton());
243  
      })
244  
    );
245  
  }
246  
  
247  
  S makeFEN() {
248  
    ret chess_makeFEN(listToChunks(pairsA(recognized), 8));
249  
  }
250  
}

Author comment

Began life as a copy of #1024674

download  show line numbers  debug dex  old transpilations   

Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1024849
Snippet name: Chess Board Recognizer backup
Eternal ID of this version: #1024849/1
Text MD5: cd3d7c3088fbd55d9a6ad9c4571144bc
Transpilation MD5: a754af502b229875faad6400537038de
Author: stefan
Category: javax / image recognition
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-08-27 01:30:59
Source code size: 10480 bytes / 250 lines
Pitched / IR pitched: No / No
Views / Downloads: 168 / 229
Referenced in: [show references]