Warning: session_start(): open(/var/lib/php/sessions/sess_g1ra8dmtgs6m01fgb9enm2c5ks, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
!7
cmodule ChessBoardRecognizer {
S segmenterPreset;
ParameterizedSegmenter segmenter;
S status;
S selectedSquare;
S piece;
LPair recognized;
transient int recreatedSquareSize = 32;
transient ReliableSingleThread rst = dm_rst(module(), r recognize);
transient BufferedImage img, board, square, recreated;
transient LL squareImages;
transient ImageSurface isInput, isBoard, isSquare, isRecreated;
transient LS pieces = ai_chessPieces();
transient Map> recreateStock; // false = dark, true = light
visualize {
isBoard = jImageSurface();
imageSurfaceOnHover(isBoard, voidfunc(Pt p) {
if (board == null || p == null) ret with noToolTip(isBoard);
setToolTip(isBoard, toolTipForSquare(boardPointToSquare(p));
});
imageSurfaceOnLeftClick(isBoard, voidfunc(Pt p) {
selectSquare(boardPointToSquare(p))
});
ret withCalc(rst, jvsplit(
jCenteredSection("Input image", jscroll_center(isInput = jImageSurface(img))),
northCenterAndSouthWithMargins(
centerAndEastWithMargin(withLabel("Segmenter preset: ", main.onChange(rst, dm_comboBox segmenterPreset(agiBlue_segmenterPresetNames()))), jbutton("Recognize", rst)),
hgridWithSpacing(
jCenteredSection("Recreated", jscroll_center(isRecreated = jImageSurface(recreated))),
jCenteredSection("Chess board", jscroll_center(isBoard)),
jCenteredLiveValueSection(dm_calculatedLiveValue(S, () -> "Selected square" + (empty(selectedSquare) ? "" : " (" + selectedSquare + ")")), centerAndSouthWithMargin(
jscroll_center(isSquare = jImageSurface(square)),
rightAlignedLine(
withLabel("Piece: ", dm_comboBox('piece, pieces)),
jbutton("Save & upload", rThread saveAndUploadPiece))
))),
dm_label('status)
)));
}
void recognize {
segmenter = parameterizedSegmenterFromAGIBlue(segmenterPreset);
if (segmenter == null) ret with infoBox(status("No segmenter"));
//img = dm_shootScreenHidingOS();
if (isInput != null) img = isInput.getImage();
L rects = segmenter.get(img);
if (empty(rects)) ret with status("No chess board found");
Rect r = first(rects);
if (l(rects) > 1) status("More than one chess board found, choosing one");
else status("Chess board found at: " + r);
board = clipBufferedImage(img, r);
squareImages = bufferedImageMNGrid(board, 8, 8);
if (isBoard != null)
isBoard.setImageAndZoomToDisplay(
mergeBufferedImagesVertically(
map(bufferedImageNVerticalSlices(8, board), i ->
mergeBufferedImagesHorizontally(bufferedImageNHorizontalSlices(8, i)))));
new ChessPieceRecognizer pieceRecognizer;
pieceRecognizer.load();
recognized = new L;
for (BufferedImage img : concatLists(squareImages))
recognized.add(pieceRecognizer.recognize(img));
change();
print(recognized);
recreate();
}
S status(S status) { setField(+status); ret status; }
O _getReloadData() { ret img; }
void _setReloadData(BufferedImage img) { this.img = img; }
void setImage(BufferedImage img) {
this.img = img;
if (isInput != null) isInput.setImageAndZoomToDisplay(img);
rst.trigger();
}
S boardPointToSquare(Pt p) {
double space = imageMergeSpacing();
double squareW = board.getWidth()/8.0+space;
double squareH = board.getHeight()/8.0+space;
int x = clamp(iratio_floor(p.x+space/2, squareW), 0, 7);
int y = clamp(iratio_floor(p.y+space/2, squareH), 0, 7);
ret strCharPlus('A', x) + (8-y);
}
void saveAndUploadPiece enter {
if (square == null || empty(piece)) ret;
temp tempInfoBox_noHide("Uploading...");
S imageURL = uploadToImageServer("Chess square: " + piece, square);
agiBlue_postInSlice(agiBlue_chessPieceImagesSlice(), imageURL, "is", piece);
agiBlue_postInSlice(agiBlue_chessPieceImagesSlice(), imageURL, "was on square", selectedSquare);
infoBox("Uploaded!");
if (mapGet(mapGet(recreateStock, chess_isLightSquare(selectedSquare)), piece) == null) recreateStock = null;
rst.trigger();
}
void recreate {
if (recognized == null) ret;
if (recreateStock == null)
recreateStock = mapToValues(ll(false, true), light ->
mapValues(pairsToMap(reversePairs(chessPieceImagesFromAGIBlue(light))), imageID -> resizeImage(loadImage2(imageID), recreatedSquareSize, recreatedSquareSize)));
new L out;
int i = 0;
for (S piece : pairsA(recognized)) {
bool light = even(i/8+i%8);
out.add(or_func(mapGet(mapGet(recreateStock, light), piece), () -> whiteImage(recreatedSquareSize, recreatedSquareSize)));
++i;
}
new L rows;
for (L row : listToChunks(out, 8))
rows.add(mergeBufferedImagesHorizontally(row, spacing := 0));
recreated = mergeBufferedImagesVertically(rows, spacing := 0);
if (isRecreated != null) isRecreated.setImageAndZoomToDisplay(recreated);
}
Pair recognitionForSquare(S square) {
int x, y = unpair chess_squareToPos(square);
ret _get(recognized, y*8+x);
}
S toolTipForSquare(S square) {
Pair rec = recognitionForSquare(square);
ret square + " - " + (rec == null ? "?" : rec.a + " [" + iround(rec.b*100) + "%]");
}
void selectSquare(S square) {
setField(selectedSquare := square);
S rec = pairA(recognitionForSquare(selectedSquare));
if (rec != null) setField(piece := rec);
int x, y = unpair chess_squareToPos(selectedSquare);
square = _get(_get(squareImages, y), x);
//printVars_str("leftClick", +p, +selectedSquare, +x, +y, +square);
isSquare.setImage(square);
}
}