Difference between revisions of "PlayChessWithAWebCam"

From BITPlan Wiki
Jump to navigation Jump to search
 
(98 intermediate revisions by the same user not shown)
Line 8: Line 8:
 
|storemode=property
 
|storemode=property
 
}}
 
}}
 +
[[File:PlayChessWithAWebCam2019-10-26.png|800px|link=https://github.com/WolfgangFahl/play-chess-with-a-webcam]]
 +
{{:PlayChessWithAWebCam/Links}}
 
= Motivation =
 
= Motivation =
 +
See {{Link|target=MagneticSensorChessBoard1987}} for the initial project of 1987.
 +
Time has moved on and the goals of the 1987 project can be achieved with less hardware and software in a more convenient manner these days.
 +
== Usecases ==
 +
=== [https://github.com/WolfgangFahl/play-chess-with-a-webcam/issues/26 Play Chess With A Webcam] ===
 +
As a chess player
 +
given a physical board and a starting position in FEN notation and a webcam observing the board in a proper angle (e.g. from above)
 +
i want to play moves against an opponent that
 +
# might sit directly in front of me
 +
# might sit with a similar setup remotely in front of a physical board
 +
# might play using some other remote means of communication
 +
 +
so that
 +
my moves are recorded and transmitted with the option to
 +
# later analyze
 +
# immediately analyze and if allowed by the oponent take back moves
 +
If the oponent is not at the board I'll have to do his moves manually or later might use some kind of robot to do that for me ...
 +
 +
=== [https://github.com/WolfgangFahl/play-chess-with-a-webcam/issues/19 Detecting Moves by a WebCAM] ===
 +
As a chess player given a logical chess board setting in {{Link|target=FEN}} notation (e.g. [https://lichess.org/editor/rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR_w_KQkq_- starting FEN] that I have setup on my physical board being observed by a webcam in HD at e.g. 25 FPS
 +
I want to use a webcam to detect my next valid move e.g. e2-e4
 +
so that the logical board changes to the new FEN e.g. (https://lichess.org/editor/rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR_w_KQkq_-) and the
 +
move is available in {{Link|target=Algebraic_Notation}} e.g. e2-e4 e.g. to be transferred via {{Link|target=UCI|title=Universal_Chess_Interface}} or e.g. [https://lichess.org/NqEY44Lg lichess.org]
 +
 +
=== [https://github.com/WolfgangFahl/play-chess-with-a-webcam/issues/22 Process Chessgame webcam movie recording to create PGN] ===
 +
As a chess player
 +
 +
I want to process a given movie of a chessgame
 +
so that I get a {{Link|target=PGN|title=Portable Game Notation}} of the game's moves
 +
 +
see
 +
 +
https://chess.stackexchange.com/questions/4695/tools-for-automated-notation-webcam-movie-to-pgn/4699
 +
 +
= State of Project =
 +
As of 2019-12-28 version 0.0.1 has not been released yet. The state of the project is alpha and will be in beta in a few days.
 +
 +
There is already a lof of stuff to try out and to participate in this open source project.
 +
 +
There is a web frontend which you can try out. Sample videos are available at
 +
https://github.com/SteinscheisserKarl/Chess-Testmedia/ which you can check out with:
 +
<source lang='bash' highlight="1-5">
 +
sudo apt-get install git-lfs
 +
git clone https://github.com/SteinscheisserKarl/Chess-Testmedia/
 +
cd Chess-Testmedia
 +
git lfs install
 +
git lfs pull
 +
</source>
 +
 +
<source lang='bash'>
 +
git clone https://github.com/WolfgangFahl/play-chess-with-a-webcam
 +
cd play-chess-with-a-webcam
 +
scripts/install
 +
scripts/run --input ../Chess-Testmedia/TK_scholarsmate30.avi --event 'PlayChessWithaWebCam' --site 'Stuttgart-Germany' --black OTB1 --white OTB2 --round 1 --warp '[[81,18],[271,15],[268,203],[85,203]]' --rotation 90 --nomoves
 +
</source>
 +
to tryout one of the Scholars Mate example video's in command line mode
 +
[[File:ScholarsMateDebug2019-10-29.png|400px]]
 +
or
 +
<source lang='bash'>
 +
scripts/runweb
 +
</source>
 +
for the default web cam or
 +
<source lang='bash'>
 +
scripts/runweb --input 1
 +
</source>
 +
if there is a second webcam installed.
 +
 +
You might want to click the corners of your chessboard to try out the warp function manually or click the .
 +
 +
 +
The scripts:
 +
* still
 +
* record
 +
are already useful for taking pictures and movie recordings of your chess match.
 +
The detection of the board and moves is not fully operational yet.
 +
 +
If you'd like to experiment a bit you can run the tests which will show some debug output.
  
 
= Installation =
 
= Installation =
 
Prerequisites: python3.7 (install script will check and try automatic installation in Ubuntu/MacOS)
 
Prerequisites: python3.7 (install script will check and try automatic installation in Ubuntu/MacOS)
<source lang='bash'>
+
<source lang='bash' highlight="1,9-10">
 
git clone https://github.com/WolfgangFahl/play-chess-with-a-webcam
 
git clone https://github.com/WolfgangFahl/play-chess-with-a-webcam
 +
Cloning into 'play-chess-with-a-webcam'...
 +
remote: Enumerating objects: 57, done.
 +
remote: Counting objects: 100% (57/57), done.
 +
remote: Compressing objects: 100% (40/40), done.
 +
remote: Total 385 (delta 29), reused 34 (delta 17), pack-reused 328
 +
Receiving objects: 100% (385/385), 1.79 MiB | 3.17 MiB/s, done.
 +
Resolving deltas: 100% (244/244), done
 
cd play-chess-with-a-webcam
 
cd play-chess-with-a-webcam
 
scripts/install
 
scripts/install
 +
checking that python3  is installed on os Linux ...
 +
/usr/bin/python3
 +
checking that pip3  is installed on os Linux ...
 +
installing pip3 from apt-package python3-pip
 +
Reading package lists... Done
 +
Building dependency tree     
 +
Reading state information... Done
 +
The following package was automatically installed and is no longer required:
 +
  libevent-core-2.1-6
 +
Use 'sudo apt autoremove' to remove it.
 +
The following additional packages will be installed:
 +
  libexpat1-dev libpython3-dev libpython3.6-dev python-pip-whl python3-dev
 +
  python3-setuptools python3-wheel python3.6-dev
 +
Suggested packages:
 +
  python-setuptools-doc
 +
The following NEW packages will be installed:
 +
  libexpat1-dev libpython3-dev libpython3.6-dev python-pip-whl python3-dev
 +
  python3-pip python3-setuptools python3-wheel python3.6-dev
 +
0 upgraded, 9 newly installed, 0 to remove and 40 not upgraded.
 +
Need to get 47,5 MB of archives.
 +
After this operation, 81,7 MB of additional disk space will be used.
 +
Do you want to continue? [Y/n] y
 +
</source>
 +
 +
== MacoS Macports ==
 +
You might want to set python3
 +
<source lang='bash'>
 +
sudo port select --list pip
 +
sudo port select --set pip3 pip37
 +
sudo port select --list python
 +
sudo port select --set python3 python37
 +
</source>
 +
 +
= Usage =
 +
== WebUI ==
 +
=== Menu ===
 +
<html><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"></html>
 +
{{MdiIcon|icon=home|color=blue|size=36}}
 +
{{MdiIcon|icon=description|color=blue|size=36|title=Play Chess With A WebCam Wiki Page}}
 +
{{MdiIcon|icon=save|color=blue|size=36}}
 +
{{MdiIcon|icon=folder|color=blue|size=36|title=Show games folder}}
 +
{{MdiIcon|icon=videocam|color=blue|size=36|title=record video}}
 +
{{MdiIcon|icon=camera_alt|color=blue|size=36|title=take still picture}}
 +
{{MdiIcon|icon=bug_report|color=blue|size=36|title=toggle debug mode}}
 +
{{MdiIcon|icon=crop|color=blue|size=36|title=auto find chess board}}
 +
{{MdiIcon|icon=keyboard_arrow_left|color=blue|size=36|title=take back move}}
 +
{{MdiIcon|icon=keyboard_arrow_right|color=blue|size=36|title=forward a move}}
 +
{{MdiIcon|icon=rotate_right|color=blue|size=36|title=rotate the video by 90 degrees}}
 +
{{MdiIcon|icon=play_arrow|color=blue|size=36|title=play/pause video}}
 +
 +
== Command line usage ==
 +
<source lang='bash' highlight="1">
 +
scripts/runweb -h
 +
[2019-10-29 09:27:14,631] INFO in webchesscam: python src folder is /Users/wf/source/python/play-chess-with-a-webcam/src
 +
[2019-10-29 09:27:14,646] INFO in webchesscam: Running on Darwin
 +
usage: webchesscam.py [-h] [--port PORT] [--input INPUT] [--host HOST]
 +
                      [--debug] [--rotation ROTATION] [--warp WARP]
 +
 +
WebChessCam
 +
 +
optional arguments:
 +
  -h, --help          show this help message and exit
 +
  --port PORT          port to run server at
 +
  --input INPUT        Manually set the input device.
 +
  --host HOST          host to allow access for
 +
  --debug              show debug output
 +
  --rotation ROTATION  rotation of chessboard
 +
  --warp WARP          warp points
 +
 +
</source>
 +
 +
== Recording ==
 +
=== Still images ===
 +
<source lang='bash'>
 +
scripts/still
 +
</source>
 +
=== Video of match ===
 +
<source lang='bash'>
 +
scripts/record
 +
</source>
 +
 +
= Example Sources =
 +
== OpenCV ==
 +
Also in the examples/opencv directory you'll find:
 +
* colorcluster.py 
 +
* histogramm.py
 +
* hough_lines.py
 +
* ...
 +
=== hough lines ===
 +
<source lang='bash'>
 +
python3 examples/opencv/hough_lines.py testMedia/chessBoard002.jpg
 +
</source>
 +
[[File:chessBoard002.jpg|300px]]
 +
[[File:detectedProbabilisticHough2019-10-21.png|300px]]
 +
[[File:detectedHough2019-10-21.png|300px]]
 +
=== histogramm / colorcluster ===
 +
[[File:chessBoard006.jpg|400px]]
 +
<source lang='bash'>
 +
python3 examples/opencv/histogramm.py testMedia/chessBoard006.jpg
 +
</source>
 +
[[File:hsvhistogramm2019-10-21.jpg|400px]]
 +
<source lang='bash' highlight="1">
 +
python3 examples/opencv/colorcluster.py testMedia/chessBoard006.jpg
 +
Clusterization took 2.8 s for 1 channels
 +
Clusterization took 4.5 s for 2 channels
 +
Clusterization took 6.7 s for 3 channels
 +
</source>
 +
[[File:colorCluster2019-10-21.jpg|800px]]
 +
 +
= Testing =
 +
<source lang='bash' hightlight="1">
 +
scripts/test
 +
---------- coverage: platform darwin, python 3.7.4-final-0 -----------
 +
Name                        Stmts  Miss  Cover
 +
------------------------------------------------
 +
src/Args.py                    10      7    30%
 +
src/Board.py                    79      5    94%
 +
src/BoardDetector.py            53      1    98%
 +
src/BoardFinder.py            185    12    94%
 +
src/Cell.py                    10      3    70%
 +
src/ChessCam.py                85    59    31%
 +
src/Environment.py              19      0  100%
 +
src/FPSCheck.py                17      0  100%
 +
src/Field.py                    98      1    99%
 +
src/Game.py                    80    11    86%
 +
src/Histogram.py                72      0  100%
 +
src/InputManager.py            41    29    29%
 +
src/JsonAbleMixin.py            32      7    78%
 +
src/MovementDetector.py        55    40    27%
 +
src/RunningStats.py            61      4    93%
 +
src/StateDetector.py          102      7    93%
 +
src/Video.py                  275    101    63%
 +
src/WebApp.py                  175    84    52%
 +
src/YamlAbleMixin.py            22      4    82%
 +
src/ciede2000.py                88      9    90%
 +
src/imutils/__init__.py          1      0  100%
 +
src/imutils/perspective.py      25      0  100%
 +
src/mathUtils.py                48      7    85%
 +
src/test_Args.py                16      0  100%
 +
src/test_Board.py              99      8    92%
 +
src/test_BoardDetector.py      87      0  100%
 +
src/test_ChessCam.py            4      0  100%
 +
src/test_Field.py              19      0  100%
 +
src/test_Game.py                48      0  100%
 +
src/test_Histogram.py          31      1    97%
 +
src/test_OpenCV_version.py      6      0  100%
 +
src/test_RunningStats.py        35      0  100%
 +
src/test_StateDetector.py      14      0  100%
 +
src/test_Video.py              68      1    99%
 +
src/test_Warp.py                46      2    96%
 +
src/test_findBoard.py          44      0  100%
 +
src/webchesscam.py              94    39    59%
 +
------------------------------------------------
 +
TOTAL                        2244    442    80%
 +
 +
================== 38 passed, 4 warnings in 94.81s (0:01:34)
 
</source>
 
</source>
 +
 
= Hardware =
 
= Hardware =
 
see e.g {{Link|target=Raspberry_PI_Chessboard_Camera}}
 
see e.g {{Link|target=Raspberry_PI_Chessboard_Camera}}
 +
 +
{{:WebCamBasedChess}}
  
 
= Source Code =
 
= Source Code =
 
== play-chess-with-a-webcam ==
 
== play-chess-with-a-webcam ==
* http://blogdugas.net/blog/2015/05/18/play-chess-with-a-webcam
 
 
see github fork at
 
see github fork at
 
* https://github.com/WolfgangFahl/play-chess-with-a-webcam
 
* https://github.com/WolfgangFahl/play-chess-with-a-webcam
  
Written in python2 migrated to python3.7.
+
Written in python using python3.7.
 
see https://unix.stackexchange.com/a/410851/38701 for selection your python version on Ubuntu
 
see https://unix.stackexchange.com/a/410851/38701 for selection your python version on Ubuntu
  
 
=== Code Structure ===
 
=== Code Structure ===
<uml>
+
click classes to see source code at [https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc Play Chess With A WebCam github repository]
hide circle
+
  <uml>
package Exceptions <<Rectangle>> {
+
    hide circle
   class ArenaQuit
+
    left to right direction
   Exception <|-- ArenaQuit
+
package Field {
 +
 
 +
  note top of SquareKind: kind of Square.
 +
  class SquareKind [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Field.py]] {
 +
    title(titles=["whitefield","blackfield","whitepiece","blackpiece"])
 +
  }
 +
 
 +
  class Channel [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Field.py]] {
 +
    title(titles=["green","blue","red"])
 +
  }
 +
 
 +
 
 +
  note top of FieldState: the state of a field is a combination of the field color with a piece color + two empty field color options.
 +
  class FieldState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Field.py]] {
 +
    title(titles=["whiteempty","whiteonwhite","blackonwhite","blackempty","whiteonblack","blackonblack"])
 +
  }
 +
 
 +
 
 +
  note top of Grid: Grid Info in the region of interest.
 +
   class Grid [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Field.py]] {
 +
    xstep(pXStep)
 +
    split(pStep,parts)
 +
    __init__(rois,xsteps,ysteps,safetyX=0,safetyY=0)
 +
    safeShift(value,safetyMargin)
 +
    dofs(roiIndex)
 +
    d()
 +
    shiftSafety(rx,ry)
 +
    ystep(pYStep)
 +
   }
 +
 
 +
 
 +
  note top of FieldROI: a region of interest within the square image area of pixels represented by some pixels.
 +
  class FieldROI [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Field.py]] {
 +
    __init__(field,grid,roiIndex,relPixelLambda)
 +
    pixelList()
 +
    analyze(image)
 +
    interPolate(rx,ry)
 +
  }
 +
 
  
   class BadImage
+
   note top of Field: a single Field of a chess board as observed from a WebCam.
   BadImage --|> Exception
+
   class Field [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Field.py]] {
 +
    getColor()
 +
    analyzeColor(image,hsv,distance=1,step=1)
 +
    hsv255_to_rgb255(h,s,v)
 +
    getFieldState()
 +
    __init__(board,row,col)
 +
    getRect()
 +
    drawDebug(video,image,detectedFieldState)
 +
    hsv_to_rgb(h,s,v)
 +
    getPiece()
 +
    divideInROIs(grid,roiLambda)
 +
  }
  
   class BadSegmentation
+
}
   BadSegmentation --|> Exception
+
package detectstate {
 +
   class DetectState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/detectstate.py]] {
 +
    invalidEnd()
 +
    validEnd()
 +
    check(validChanges,diffSum,diffSumDelta,meanFrameCount)
 +
    nextFrame()
 +
    __init__(validDiffSumTreshold,invalidDiffSumTreshold,diffSumDeltaTreshold,onPieceMoveDetected=None,onMoveDetected=None)
 +
   }
  
  class CannotBuildStateException
 
  CannotBuildStateException --|> Exception
 
  
   class RejectedMove
+
  note top of DetectColorState: detect state from Color Distribution.
 +
  class DetectColorState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/detectstate.py]] {
 +
    __init__(trapez)
 +
    squareState(fieldColorStats,tSquare,percent)
 +
    check(image,averageColors,drawDebug=False)
 +
    drawDebug()
 +
    inRange(stats,fs,percent)
 +
  }
 +
 
 +
}
 +
package ciede2000 {
 +
}
 +
package Board {
 +
   class RejectedMove [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Board.py]] {
 +
    __init__(value)
 +
    __str__()
 +
  }
 +
 
 
   RejectedMove --|> Exception
 
   RejectedMove --|> Exception
  
   class UserExit
+
   note top of Board: This class is used to hold the state of a chessboard with pieces positions and the current player's color which player needs to play. It uses the python-chess library by default
   UserExit --|> Exception
+
  class Board [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Board.py]] {
 +
    fen()
 +
    setFEN(fen)
 +
    piecesOfColor(color)
 +
    setPgn(pgn)
 +
    takeback()
 +
    GetCellName(col,row)
 +
    fieldStateCounts()
 +
    __init__(dominatorOffset=(0,-1))
 +
    performMove(move)
 +
    getPgn()
 +
    fieldAt(row,col)
 +
    unicode()
 +
    move(ucimove)
 +
  }
 +
 
 +
}
 +
package histogram {
 +
 
 +
  note top of Stats: Calculate Histogram statistics see https://math.stackexchange.com/questions/857566/how-to-get-the-standard-deviation-of-a-given-histogram-image
 +
   class Stats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/histogram.py]] {
 +
    __init__(histindexed)
 +
    range(relFactor=1.0,minValue=0,maxValue=255)
 +
  }
 +
 
 +
 
 +
  note top of Histogram: Image Histogram.
 +
  class Histogram [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/histogram.py]] {
 +
    savefig(fig,filepath)
 +
    colorRangeWithFactor(rangeFactor)
 +
    plot()
 +
    save(filepath)
 +
    plotRow(ax1,ax2)
 +
    fix(value)
 +
    preparePlot(rows,cols,title='colorhistogram',fontsize=20)
 +
    __init__(image,histSize=256,histRange=(0,256))
 +
    showDebug()
 +
    colorMask(image,rangeFactor)
 +
    range(relFactor=1.0)
 +
    show()
 +
  }
 +
 
 +
}
 +
package game {
 +
 
 +
  note top of Game: keeps track of a games state in a JavaScript compatible way to exchange game State information.
 +
  class Game [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/game.py]] {
 +
    showDebug()
 +
    __init__(gameid)
 +
  }
 +
 
 +
 
 +
  note top of WebCamGame: keeps track of a webcam games state in a JavaScript compatible way to exchange game and webcam/board State information.
 +
  class WebCamGame [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/game.py]] {
 +
    checkEnvironment(env)
 +
    getWebCamGames(path)
 +
    save(path="games")
 +
    __init__(gameid)
 +
  }
 +
 
 +
 
 +
  note top of Warp: holds the trapezoid points to be use for warping an image take from a peculiar angle.
 +
  class Warp [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/game.py]] {
 +
    updatePoints()
 +
    rotate(angle)
 +
    addPoint(px,py)
 +
    __init__(pointList=[],rotation=0,bgrColor=(0,255,0))
 +
  }
 +
 
 +
}
 +
package Environment4Test {
 +
 
 +
  note top of Environment4Test: Test Environment.
 +
  class Environment4Test [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Environment4Test.py]] {
 +
    loadFromImageInfo(webApp,imageInfo)
 +
    __init__()
 +
    getImage(num)
 +
    prepareFromImageInfo(imageInfo)
 +
    getImageWithVideo(num)
 +
  }
 +
 
 +
}
 +
package WebApp {
 +
 
 +
  note top of WebApp: actual Play Chess with a WebCam Application - Flask calls are routed here.
 +
  class WebApp [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/WebApp.py]] {
 +
    photo(path)
 +
    chessFEN(fen)
 +
    genVideo(video)
 +
    __init__(args,logger=None)
 +
    chessMove(move)
 +
    chessForward()
 +
    chessFindBoard()
 +
    log(msg)
 +
    videoFeed()
 +
    videoPause()
 +
    videoRecord(path)
 +
    chessWebCamClick(x,y,w,h)
 +
    chessPgn(pgn)
 +
    chessSave()
 +
    index(msg)
 +
    #genVideoStreamed(video)
 +
    indexException(e)
 +
    chessGameState(gameid)
 +
    timeStamp()
 +
    chessGameColors()
 +
    setDebug(debug)
 +
    createNewCame()
 +
    photoDownload(path,filename)
 +
    warpAndRotate(image)
 +
    chessTakeback()
 +
    chessDebug()
 +
    videoRotate90()
 +
    home()
 +
  }
 +
 
 +
}
 +
package YamlAbleMixin {
 +
 
 +
  note top of YamlAbleMixin: allow reading and writing derived objects from a yaml file.
 +
  class YamlAbleMixin [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/YamlAbleMixin.py]] {
 +
    writeYaml(name)
 +
    readYaml(name)
 +
  }
 +
 
 +
}
 +
package ChessTrapezoid {
 +
  Trapez2Square <|-- ChessTrapezoid
 +
  ChessTrapezoid -- ChessTSquare
 +
  ChessTSquare -- SquareChange
 +
  ChessTSquare -- FieldState
 +
 
 +
  note top of Transformation: Transformation kind.
 +
  class Transformation [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
  }
 +
 
 +
 
 +
  note top of Trapez2Square: transform a trapez to a square and back as needed.
 +
  class Trapez2Square [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    relativeTrapezToTrapezXY(rx1,ry1,rx2,ry2)
 +
    __init__(topLeft,topRight,bottomRight,bottomLeft)
 +
    relativeToTrapezXY(rx,ry)
 +
  }
 +
 
 +
 
 +
  note top of ChessTrapezoid: Chess board Trapezoid (UK) / Trapezium (US) / Trapez (DE)  as seen via a webcam image.
 +
  class ChessTrapezoid [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    tSquareAt(row,col,rotation=0)
 +
    analyzeColors(image)
 +
    checkColors(image,averageColors,rangeFactor=1.0)
 +
    relativeToIdealXY(rx,ry)
 +
    __init__(trapezPoints,idealSize=640,rotation=0,video=None)
 +
    preMoveBoard(w,h)
 +
    setup(idealSize=640,video=None)
 +
    detectChanges(image,diffImage,detectState)
 +
    diffSum(image,other)
 +
    updatePieces(fen)
 +
    drawRCenteredText(image,text,rx,ry,color=(255,255,255))
 +
    warpedBoardImage(image)
 +
    drawDebug(image,color=(255,255,255))
 +
    optimizeColorCheck(image,averageColors,debug=False)
 +
    genSquares()
 +
    idealColoredBoard(w,h,transformation=Transformation.IDEAL)
 +
    rotateIndices(row,col,rotation)
 +
    diffBoardImage(image,other)
 +
    byFieldState()
 +
    drawFieldStates(image,fieldStates,transformation=Transformation.ORIGINAL,channels=3)
 +
    drawRCircle(image,rcenter,rradius,color,thickness=-1)
 +
    drawCircle(image,center,radius,color,thickness=-1)
 +
  }
 +
 
 +
 
 +
  note top of FieldState: the state of a field is a combination of the field color with a piece color + two empty field color options.
 +
  class FieldState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    title(titles=["whiteempty","whiteonwhite","blackonwhite","blackempty","whiteonblack","blackonblack"])
 +
  }
 +
 
 +
 
 +
  note top of FieldColorStats: Color statistics for Fields.
 +
  class FieldColorStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    showStatsDebug(time)
 +
    analyzeStats(factor,time,debug=False)
 +
    __init__()
 +
    push(fieldState,an,percent)
 +
    showFieldStateDebug(fieldState)
 +
    showDebug(time)
 +
  }
 +
 
 +
 
 +
  note top of Color: Color definitions with maximum lightness difference and calculation of average color for a sample of square with a given fieldState.
 +
  class Color [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    colorRange(rangeFactor)
 +
    fixMeans(means,stds,pixels,nonzero)
 +
    __init__(image)
 +
    fix(value)
 +
    __str__()
 +
    countNonZero(image)
 +
  }
 +
 
 +
 
 +
  note top of SquareChange: keep track of changes of a square over time.
 +
  class SquareChange [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    push(stats,value)
 +
    __init__(value,stats)
 +
  }
 +
 
 +
 
 +
  note top of ChessTSquare: a chess square in it's trapezoidal perspective.
 +
  class ChessTSquare [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/ChessTrapezoid.py]] {
 +
    checkMoved(detectState)
 +
    squareChange(image,diffImage)
 +
    getFieldState()
 +
    rxy2xy(image)
 +
    drawState(image,transformation,channels)
 +
    setPolygons(trapez,rtl_x,rtl_y,rtr_x,rtr_y,rbr_x,rbr_y,rbl_x,rbl_y)
 +
    getSquareImage(image)
 +
    addPreMoveImage(image)
 +
    getPolygon(transformation)
 +
    drawDebug(image,color=(255,255,255))
 +
    rcenter()
 +
    __init__(trapez,square)
 +
  }
 +
 
 
}
 
}
 +
package boardfinder {
 +
BoardFinder -- Corners
  
package PlayChessWithAWebCam {
+
   note top of Corners: Chess board corners.
   note top of Args: This class parses command line arguments and generates a usage.
+
   class Corners [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/boardfinder.py]] {
   class Args {
+
    sortXY(xy)
    __init__(args)
+
    trapezColRows(cols,rows)
 +
    showDebug(image,title)
 +
    sort()
 +
    asPolygons(safetyMargin)
 +
    writeDebug(image,title,prefix)
 +
    showTrapezDebug(image,title,corners)
 +
    findPattern(image)
 +
    calcTrapez()
 +
    genChessPatterns()
 +
    calcPolygons(*safetyMargins)
 +
    safeXY(x,y,dx,dy)
 +
    __init__(pattern,video)
 
   }
 
   }
  
  class BoardFinder {
+
 
    getDominatorOffset()
+
  note top of BoardFinder: find a chess board in the given image.
    updateImage(inFrame)
+
  class BoardFinder [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/boardfinder.py]] {
    DetectBoardOrientation()
+
    drawPolygon(image,pos,polygon,whiteColor,blackColor)
    GetChessBoardCoordinates(rotation)
+
    findChessBoard(image,title)
    LineCrossingDetection()
+
    expand(image,title,histograms,corners)
    GetFullImageBoard(rectCoordinates=None, rotations=None)
+
    getColorFiltered(image,histograms,title,corners)
    _getBlackMaxSide(colorImage)
+
    maskPolygon(image,polygon)
    rotateImage(image)
+
    findCorners(image,limit=1,searchWidth=640)
 +
    showHistogramDebug(histograms,title,corners)
 +
    sortPoints(xylist)
 +
    centerXY(xylist)
 +
    showPolygonDebug(image,title,corners)
 +
    maskCornerPolygons(image,corners,filterColor)
 +
    __init__(image,video=None)
 +
    fieldColor(pos)
 +
    preparefindCorners(image,searchWidth=640)
 +
    getHistograms(image,title,corners)
 +
    findOuterCorners(searchWidth=640)
 
   }
 
   }
   class Cell {
+
 
 +
}
 +
package JsonAbleMixin {
 +
 
 +
  note top of JsonAbleMixin: allow reading and writing derived objects from a json file.
 +
   class JsonAbleMixin [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/JsonAbleMixin.py]] {
 +
    writeJson(name,postfix=".json")
 +
    readJson(name,postfix=".json")
 +
    asJson()
 
   }
 
   }
  note top of ChessCam: Chess Camera get next move by analyzing movements.
+
 
class ChessCam {
 
  prepare(args)
 
  __init__()
 
  playChessWithCam(args)
 
  getNextMove()
 
  getDominatorOffset()
 
  detectMovement()
 
  playChessWithCamMoves()
 
 
}
 
}
 +
package RunningStats {
 +
 +
  note top of MovingAverage: calculate a moving average.
 +
  class MovingAverage [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/RunningStats.py]] {
 +
    __init__(maxlen)
 +
    push(value)
 +
    mean()
 +
  }
 +
 +
  class MinMaxMixin    [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/RunningStats.py]] {
 +
    pushMinMax(value)
 +
    formatMinMax(formatM="%.1f-%.1f")
 +
    initMinMax()
 +
    __str__()
 +
  }
  
  
 +
  note top of RunningStats: calculate mean, variance and standard deviation in one pass using Welford's algorithm.
 +
  class RunningStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/RunningStats.py]] {
 +
    format(formatS="%d%.1f±%.1f")
 +
    variance()
 +
    __init__()
 +
    __str__()
 +
    standard_deviation()
 +
    clear()
 +
    mean()
 +
    push(xvalue)
 +
  }
  
   note top of GameEngine: This class is used to change the game state using StateClass.\nIt also communicates moves with the chess ai facade \\nand an observer to detect if a move have been played by an ai.
+
 
   class GameEngine {
+
   note top of MinMaxStats: running statistics with minimum and maximum.
     play()
+
  class MinMaxStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/RunningStats.py]] {
     mainLoop()
+
    formatMinMax(formatR="%d%.1f±%.1f",formatM="%.1f-%.1f")
 +
    __init__()
 +
    push(value)
 +
  }
 +
 
 +
 
 +
  note top of ColorStats: calculate the RunningStats for 3 color channels like RGB or HSV simultaneously.
 +
   class ColorStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/RunningStats.py]] {
 +
     push(c1,c2,c3)
 +
    colorKey()
 +
    variance()
 +
    __init__()
 +
    distance(this,other)
 +
    square(value)
 +
    standard_deviation()
 +
    clear()
 +
    rgbColorKey()
 +
     mean()
 
   }
 
   }
  class InputManager
+
 
  class MovementDetector
 
  note top of State: This class is used to remember the pieces positions and the current player's color which player needs to play).
 
class State {
 
  _move(fromCell,toCell)
 
  _validateMove(fromCell,toCell)
 
  _sameColor(c1,c2)
 
  _switchTurn()
 
  moveCam(move)
 
  _tryToPromote(c)
 
  _castle(fromCell,toCell)
 
  _eat(fromCell,toCell)
 
  _initBoard()
 
  __init__(dominatorOffset)
 
  _emptyCell(c)
 
  _partMoves(move)
 
 
}
 
}
 +
package webchesscam {
  
   class StateDetector {
+
   note top of WebChessCamArgs: This class parses command line arguments and generates a usage.
     _divideInCells()
+
  class WebChessCamArgs [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/webchesscam.py]] {
     detectState(colorImage)
+
     chessWebCamClick(width,height)
     _findIntersects()
+
    autoindex(path='.')
 +
    __init__(argv)
 +
    chessMove(move)
 +
    chessForward()
 +
    chessFindBoard()
 +
    photoDownload(filename)
 +
    chessSave()
 +
    chessUpdate()
 +
    video_pause()
 +
    video_feed()
 +
    chessGameState(gameid)
 +
    chessGameColors()
 +
    chessTakeback()
 +
    chessDebug()
 +
    root()
 +
    photo()
 +
    videoRotate90()
 +
     video_record()
 +
     home()
 
   }
 
   }
  
   note top of Uci: This class interacts with stdin and stdout with Arena in the UCI convention in order to communicate chess moves.
+
}
   class Uci {
+
package FPSCheck {
     sendMove(move)
+
 
     getResponse()
+
   note top of FPSCheck: Frame per second tracker.
     _setPosition(tokens)
+
   class FPSCheck [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/FPSCheck.py]] {
 +
     fps()
 +
    __init__()
 +
    start()
 +
     elapsed()
 +
     update()
 
   }
 
   }
  
   class Video {
+
}
 +
package Environment {
 +
 
 +
  note top of Environment: Runtime Environment.
 +
   class Environment [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Environment.py]] {
 
     __init__()
 
     __init__()
     record(prefix,printHints=True)
+
    checkDir(path)
     open(filePath)
+
  }
 +
 
 +
}
 +
package PlotLib {
 +
 
 +
  note top of PlotType: kind of Plot.
 +
  class PlotType [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/PlotLib.py]] {
 +
  }
 +
 
 +
  class PlotLib [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/PlotLib.py]] {
 +
    __init__(title,pagesize,imagesPerPage=4)
 +
    addPlot(image,imageTitle,xvalues=[],yvalues=[],isBGR=False)
 +
    addInfos(pdf,infos)
 +
    A4(turned=False)
 +
    plotImage(ax,image,imageTitle,thumbNailSize)
 +
    createHistogramPDF(path,plotType=PlotType.HISTOGRAMM,infos={})
 +
    finishPDF(pdf,infos={})
 +
    finishPDFPage(pdf)
 +
    fixPath(path)
 +
    plotHistogramm(image,axarr,rowIndex,colIndex)
 +
    plotChannel(img,ax,channel,prevAx=None)
 +
    startPDF(path)
 +
    pixel(fig,inch)
 +
  }
 +
 
 +
}
 +
package Video {
 +
 
 +
  note top of Video: Video handling e.g. recording/writing
 +
  class Video [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Video.py]] {
 +
    prepareRecording(filename,width,height,fps=None)
 +
    readImage(filePath)
 +
    drawText(frame,text,bottomLeftCornerOfText,font,fontScale,fontBGRColor,lineThickness)
 +
    still(prefix,imgformat="jpg",close=True,printHints=True,show=False,postProcess=None)
 +
    warp(image,pts,squared=True)
 +
    drawRectangle(image,pt1,pt2,color=(0,255,0),thickness=1)
 +
    play()
 +
    is_int(s)
 +
    getEmptyImage(image,channels=1)
 +
    imencode(frame,imgformat=".jpg")
 +
    showImage(image,title,keyCheck=True,keyWait=5)
 +
    drawPolygon(image,polygon,color)
 +
    createBlank(width,height,rgb_color=(0,0,0))
 +
    paused()
 +
     record(prefix,printHints=True,fps=None)
 +
    capture(device)
 +
    setup(cap)
 +
    readFrame(show=False,postProcess=None)
 +
    addTimeStamp(frame,withFrames=True,withFPS=True,fontBGRColor=(0,255,0),fontScale=1.0,font=cv2.FONT_HERSHEY_SIMPLEX,lineThickness=1)
 +
     houghTransform(image)
 
     drawLines(image,lines)
 
     drawLines(image,lines)
     houghTransform(image)
+
     drawTrapezoid(image,points,color)
 
     checkFilePath(filePath,raiseException=True)
 
     checkFilePath(filePath,raiseException=True)
 +
    open(filePath)
 
     sumIntensity(image)
 
     sumIntensity(image)
     readFrame(show=False)
+
     close()
 +
    drawCenteredText(frame,text,x,y,fontBGRColor=(0,255,0),fontScale=1.0,font=cv2.FONT_HERSHEY_SIMPLEX,lineThickness=1)
 +
    writeImage(image,filepath)
 +
    houghTransformP(image)
 +
    checkCap()
 +
    maskImage(image,mask)
 +
    __init__()
 +
    drawCircle(image,center,radius=10,color=(0,255,0),thickness=1)
 +
    timeStamp(separator='',timeseparator='')
 +
    readJpgImage(show=False,postProcess=None)
 +
    pause(ispaused)
 +
    fileTimeStamp()
 
     getSubRect(image,rect)
 
     getSubRect(image,rect)
     timeStamp()
+
     still2File(filename,format="jpg",close=True,printHints=True,show=False,postProcess=None)
     play()
+
     getEmptyImage4WidthAndHeight(w,h,channels)
     setup(cap)
+
     rotate(image,angle,center=None,scale=1.0)
     showImage(image,title,keyCheck=True,keyWait=5)
+
     showAndWriteImage(image,title,path="/tmp/",imageFormat=".jpg",keyCheck=True,keyWait=5)
     checkCap()
+
  }
     capture(device)
+
 
     createBlank(width,height,rgb_color)
+
 
     close()
+
  note top of VideoStream: run videograbbing in separate stream.
     readImage(filePath)
+
  class VideoStream [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/Video.py]] {
     still(prefix,format="jpg",printHints=True)
+
    stop()
 +
     read()
 +
     start()
 +
     __init__(video,show=False,postProcess=None,name='VideoStream')
 +
     update()
 +
  }
 +
 
 +
}
 +
package BoardDetector {
 +
 
 +
  note top of BoardDetector: detect a chess board's state from the given image.
 +
  class BoardDetector [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/pcwawc/BoardDetector.py]] {
 +
    divideInFields(image)
 +
    sortByFieldState()
 +
    genFields()
 +
     analyze(image,frameIndex,distance=3,step=1)
 +
     analyzeColors(image,distance=3,step=1)
 +
    analyzeFields(image,grid,roiLambda)
 +
    __init__(board,video,speedup=1)
 
   }
 
   }
  
 
}
 
}
GameEngine -- ChessCam
+
package perspective {
GameEngine -- State
+
}
GameEngine -- Uci
+
  skinparam titleFontSize 18
Uci -- ArenaQuit
+
  skinparam titleFontStyle bold
ChessCam -- BoardFinder
+
  skinparam titleFontName Arial
ChessCam -- MovementDetector
+
 
ChessCam -- InputManager
+
  skinparam classBackgroundColor white
ChessCam -- UserExit
+
  skinparam classBorderColor #FF8000
BoardFinder -- Video
+
  skinparam classFontColor black
MovementDetector -- StateDetector
+
  skinparam classFontSize 14
MovementDetector -- BadImage
+
  skinparam classFontStyle bold
StateDetector - Cell
+
  skinparam classFontName Arial
note top of State: This class is used to remember the pieces positions and the current player's color which player needs to play.
+
 
State -- RejectedMove
+
  skinparam classAttributeFontName Arial
InputManager - Args
+
  skinparam classAttributeFontSize 14
 +
 
 +
  skinparam classArrowFontName Arial
 +
  skinparam classArrowFontSize 14
 +
 
 +
  skinparam noteBackgroundColor #FFFFFF
 +
  skinparam noteBorderColor #000080
 +
  skinparam noteFontName Arial
 +
  skinparam noteFontSize 14
 
</uml>
 
</uml>
 
  
 
[[Category:Raspberry]]
 
[[Category:Raspberry]]
 
[[Category:Chess]]
 
[[Category:Chess]]
 +
 +
= Development Environment =
 +
https://www.liclipse.com/ is recommended since it alows interactive graphical debugging and editing with syntax and error hints.
 +
= OS-Support =
 +
== MacOS High Sierra 10.13.6 ==
 +
MacPorts: 2.6.2
 +
=== Install ===
 +
<source lang='bash' highlight="1">
 +
scripts/install
 +
checking that python3  is installed on os Darwin ...
 +
/opt/local/bin/python3
 +
checking that pip3  is installed on os Darwin ...
 +
/opt/local/bin/pip3
 +
Requirement already satisfied: opencv-python in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (4.1.1.26)
 +
Requirement already satisfied: pytest in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from -r requirements.txt (line 4)) (5.2.1)
 +
Collecting matplotlib (from -r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/c3/8b/af9e0984f5c0df06d3fab0bf396eb09cbf05f8452de4e9502b182f59c33b/matplotlib-3.1.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (14.4MB)
 +
    |████████████████████████████████| 14.4MB 7.4MB/s
 +
Collecting scipy (from -r requirements.txt (line 8))
 +
  Downloading https://files.pythonhosted.org/packages/d5/06/1a696649f4b2e706c509cb9333fdc6331fbe71251cede945f9e1fa13ea34/scipy-1.3.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (27.7MB)
 +
    |████████████████████████████████| 27.7MB 7.1MB/s
 +
Collecting pytest-cov (from -r requirements.txt (line 10))
 +
  Downloading https://files.pythonhosted.org/packages/b9/54/3673ee8be482f81527678ac894276223b9814bb7262e4f730469bb7bf70e/pytest_cov-2.8.1-py2.py3-none-any.whl
 +
Collecting python-chess (from -r requirements.txt (line 12))
 +
  Downloading https://files.pythonhosted.org/packages/58/70/72dc875a30ac7f26e0bec45714d67b19e0f498de920323b906995a741a88/python_chess-0.28.3-py3-none-any.whl (127kB)
 +
    |████████████████████████████████| 133kB 7.1MB/s
 +
Requirement already satisfied: numpy>=1.14.5 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from opencv-python->-r requirements.txt (line 2)) (1.16.4)
 +
Requirement already satisfied: attrs>=17.4.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (19.1.0)
 +
Requirement already satisfied: more-itertools>=4.0.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (7.2.0)
 +
Requirement already satisfied: py>=1.5.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (1.8.0)
 +
Requirement already satisfied: pluggy<1.0,>=0.12 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (0.13.0)
 +
Requirement already satisfied: atomicwrites>=1.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (1.3.0)
 +
Requirement already satisfied: wcwidth in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (0.1.7)
 +
Requirement already satisfied: importlib-metadata>=0.12; python_version < "3.8" in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (0.23)
 +
Requirement already satisfied: packaging in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (19.2)
 +
Collecting kiwisolver>=1.0.1 (from matplotlib->-r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/df/93/8bc9b52a8846be2b9572aa0a7c881930939b06e4abe1162da6a0430b794f/kiwisolver-1.1.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (113kB)
 +
    |████████████████████████████████| 122kB 8.3MB/s
 +
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from matplotlib->-r requirements.txt (line 6)) (2.4.2)
 +
Requirement already satisfied: python-dateutil>=2.1 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from matplotlib->-r requirements.txt (line 6)) (2.8.0)
 +
Collecting cycler>=0.10 (from matplotlib->-r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
 +
Collecting coverage>=4.4 (from pytest-cov->-r requirements.txt (line 10))
 +
  Downloading https://files.pythonhosted.org/packages/93/07/8302163cdbe2008441aa69f2119750110fde15ffd8a56a687311b143365a/coverage-4.5.4-cp37-cp37m-macosx_10_13_x86_64.whl (181kB)
 +
    |████████████████████████████████| 184kB 8.4MB/s
 +
Requirement already satisfied: zipp>=0.5 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from importlib-metadata>=0.12; python_version < "3.8"->pytest->-r requirements.txt (line 4)) (0.6.0)
 +
Requirement already satisfied: six in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from packaging->pytest->-r requirements.txt (line 4)) (1.12.0)
 +
Requirement already satisfied: setuptools in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib->-r requirements.txt (line 6)) (41.0.1)
 +
Installing collected packages: kiwisolver, cycler, matplotlib, scipy, coverage, pytest-cov, python-chess
 +
Successfully installed coverage-4.5.4 cycler-0.10.0 kiwisolver-1.1.0 matplotlib-3.1.1 pytest-cov-2.8.1 python-chess-0.28.3 scipy-1.3.1
 +
</source>
 +
 +
=== Test ===
 +
<source lang='bash' highlight="1">
 +
scripts/test
 +
=========================================== test session starts ===========================================
 +
platform darwin -- Python 3.7.3, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
 +
rootdir: /Users/wf/source/python/play-chess-with-a-webcam
 +
plugins: cov-2.8.1
 +
collected 11 items                                                                                       
 +
 +
src/test_Board.py .                                                                                [  9%]
 +
src/test_ChessCam.py .                                                                              [ 18%]
 +
src/test_OpenCV_version.py .                                                                        [ 27%]
 +
src/test_Video.py ...                                                                              [ 54%]
 +
src/test_findBoard.py .....                                                                        [100%]
 +
 +
---------- coverage: platform darwin, python 3.7.3-final-0 -----------
 +
Name                        Stmts  Miss  Cover
 +
------------------------------------------------
 +
src/Args.py                    10      7    30%
 +
src/Board.py                    33      3    91%
 +
src/BoardFinder.py            186    12    94%
 +
src/Cell.py                    10      4    60%
 +
src/ChessCam.py                86    59    31%
 +
src/InputManager.py            57    37    35%
 +
src/MovementDetector.py        55    40    27%
 +
src/StateDetector.py            92    75    18%
 +
src/Video.py                  133    48    64%
 +
src/mathUtils.py                49    25    49%
 +
src/test_Board.py              23      3    87%
 +
src/test_ChessCam.py            4      0  100%
 +
src/test_OpenCV_version.py      6      0  100%
 +
src/test_Video.py              28      0  100%
 +
src/test_findBoard.py          49      0  100%
 +
------------------------------------------------
 +
TOTAL                          821    313    62%
 +
 +
 +
=========================================== 11 passed in 37.60s ===========================================
 +
</source>
 +
 +
== Ubuntu 18.04.3 LTS bionic beaver ==
 +
=== Upgrade Python to 3.7 ===
 +
see https://linuxize.com/post/how-to-install-python-3-7-on-ubuntu-18-04/
 +
<source lang='bash'>
 +
sudo add-apt-repository ppa:deadsnakes/ppa
 +
sudo apt-install python3.7
 +
# install tkinter
 +
sudo apt-get install python3-tk
 +
</source>
 +
make python3.7 the default python3
 +
* https://unix.stackexchange.com/a/410851/38701
 +
 +
=== Install ===
 +
<source lang='bash' highlight="1,23">
 +
scripts/install
 +
scripts/install
 +
Bootstrap already downloaded
 +
Material Design Lite already downloaded
 +
Material Design Icons already downloaded
 +
chessboard.js already downloaded
 +
chessboard-1.0.0.css already downloaded
 +
chessboard-1.0.0.min.css already downloaded
 +
js/jquery-3.4.1.min.js already downloaded
 +
chess.js already downloaded
 +
checking that python3  is installed on os Linux ...
 +
/usr/bin/python3
 +
checking that pip3  is installed on os Linux ...
 +
/usr/bin/pip3
 +
Collecting opencv-python==4.1.2.30 (from -r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/d8/38/60de02a4c9013b14478a3f681a62e003c7489d207160a4d7df8705a682e7/opencv_python-4.1.2.30-cp37-cp37m-manylinux1_x86_64.whl (28.3MB)
 +
    100% |████████████████████████████████| 28.3MB 50kB/s
 +
Collecting python-chess==0.29.0 (from -r requirements.txt (line 9))
 +
  Using cached https://files.pythonhosted.org/packages/63/eb/003a6c069c0208e169165acd2d90665fa3901baab19b5fa26603d86b7193/python_chess-0.29.0-py3-none-any.whl
 +
Collecting berserk==0.3.1 (from -r requirements.txt (line 12))
 +
  Using cached https://files.pythonhosted.org/packages/bb/09/d25b49f70145e07a5ca7aa1a5ff9bf5499ba0754341a592a2e8d165ed621/berserk-0.3.1-py2.py3-none-any.whl
 +
Collecting python-lichess==0.9 (from -r requirements.txt (line 14))
 +
  Using cached https://files.pythonhosted.org/packages/23/07/6cfaa4ef2649d705defc3e7c8ff7ed3a3bb467400325d00ad9da3acedf39/python_lichess-0.9-py3-none-any.whl
 +
Collecting imutils==0.5.3 (from -r requirements.txt (line 16))
 +
  Using cached https://files.pythonhosted.org/packages/b5/94/46dcae8c061e28be31bcaa55c560cb30ee9403c9a4bb2659768ec1b9eb7d/imutils-0.5.3.tar.gz
 +
Collecting Flask==1.1.1 (from -r requirements.txt (line 21))
 +
  Using cached https://files.pythonhosted.org/packages/9b/93/628509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flask-1.1.1-py2.py3-none-any.whl
 +
Collecting Flask-RESTful==0.3.7 (from -r requirements.txt (line 22))
 +
  Using cached https://files.pythonhosted.org/packages/17/44/6e490150ee443ca81d5f88b61bb4bbb133d44d75b0b716ebe92489508da4/Flask_RESTful-0.3.7-py2.py3-none-any.whl
 +
Collecting Flask-AutoIndex==0.6.4 (from -r requirements.txt (line 23))
 +
  Using cached https://files.pythonhosted.org/packages/dc/43/26df9c0c0e7d3de98ba7cbe89e7b88c280e40c87073025171d2d702d0b5f/Flask_AutoIndex-0.6.4-py3-none-any.whl
 +
Collecting PyYAML==5.1 (from -r requirements.txt (line 25))
 +
  Using cached https://files.pythonhosted.org/packages/9f/2c/9417b5c774792634834e730932745bc09a7d36754ca00acf1ccd1ac2594d/PyYAML-5.1.tar.gz
 +
Collecting mss==4.0.3 (from -r requirements.txt (line 27))
 +
  Using cached https://files.pythonhosted.org/packages/67/2a/8e26437bcc840e19ca5290897d47f5405e302af27d4a6401e0b0edc39942/mss-4.0.3-py2.py3-none-any.whl
 +
Collecting Pillow==6.2.1 (from -r requirements.txt (line 29))
 +
  Downloading https://files.pythonhosted.org/packages/89/3e/31c2e5385d7588016c6f7ac552e81c3fff2bef4bc61b6f82f8177752405c/Pillow-6.2.1-cp37-cp37m-manylinux1_x86_64.whl (2.1MB)
 +
    100% |████████████████████████████████| 2.1MB 678kB/s
 +
Collecting jsonpickle==1.2 (from -r requirements.txt (line 35))
 +
  Using cached https://files.pythonhosted.org/packages/07/07/c157520a3ebd166c8c24c6ae0ecae7c3968eb4653ff0e5af369bb82f004d/jsonpickle-1.2-py2.py3-none-any.whl
 +
Collecting interface==2.11.1 (from -r requirements.txt (line 39))
 +
  Using cached https://files.pythonhosted.org/packages/f9/80/7283dfe76ceb7eb1868cf97b8c8cb3a988f80757921341f95d5420de2a6e/Interface-2.11.1.tar.gz
 +
Collecting pytest==3.8.2 (from -r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/08/e0/a4945a06380802264b3416d788ad607588c334662b6cd0af54144c45912d/pytest-3.8.2-py2.py3-none-any.whl
 +
Collecting matplotlib==2.2.3 (from -r requirements.txt (line 46))
 +
  Downloading https://files.pythonhosted.org/packages/52/46/ff47fea8e5c528c497fc385c95887131c4319a3411814ba9a766b66a9367/matplotlib-2.2.3-cp37-cp37m-manylinux1_x86_64.whl (12.6MB)
 +
    100% |████████████████████████████████| 12.6MB 116kB/s
 +
Collecting scipy==1.2.2 (from -r requirements.txt (line 48))
 +
  Downloading https://files.pythonhosted.org/packages/f3/84/2cc37b97e96da0be03d5dcebdd967214cae14b14b0131398b374ea89c50e/scipy-1.2.2-cp37-cp37m-manylinux1_x86_64.whl (24.8MB)
 +
    100% |████████████████████████████████| 24.8MB 59kB/s
 +
Collecting pytest-cov==2.8.1 (from -r requirements.txt (line 50))
 +
  Using cached https://files.pythonhosted.org/packages/b9/54/3673ee8be482f81527678ac894276223b9814bb7262e4f730469bb7bf70e/pytest_cov-2.8.1-py2.py3-none-any.whl
 +
Collecting numpy>=1.14.5 (from opencv-python==4.1.2.30->-r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/20/53/127cb49435bcf5d841baf8eafa030931c62a9eac577a641f8c2293d23371/numpy-1.18.0-cp37-cp37m-manylinux1_x86_64.whl (20.1MB)
 +
    100% |████████████████████████████████| 20.1MB 70kB/s
 +
Collecting ndjson==0.1.0 (from berserk==0.3.1->-r requirements.txt (line 12))
 +
  Using cached https://files.pythonhosted.org/packages/39/ba/0628840da7b61fb63a6a0e030291a7a5e5d393a51cbcb27ded8b2a838aa9/ndjson-0.1.0-py2.py3-none-any.whl
 +
Collecting requests>=2.20.0 (from berserk==0.3.1->-r requirements.txt (line 12))
 +
  Using cached https://files.pythonhosted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/requests-2.22.0-py2.py3-none-any.whl
 +
Requirement already satisfied: six in /usr/lib/python3/dist-packages (from python-lichess==0.9->-r requirements.txt (line 14))
 +
Collecting click>=5.1 (from Flask==1.1.1->-r requirements.txt (line 21))
 +
  Using cached https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl
 +
Collecting Werkzeug>=0.15 (from Flask==1.1.1->-r requirements.txt (line 21))
 +
  Using cached https://files.pythonhosted.org/packages/ce/42/3aeda98f96e85fd26180534d36570e4d18108d62ae36f87694b476b83d6f/Werkzeug-0.16.0-py2.py3-none-any.whl
 +
Collecting Jinja2>=2.10.1 (from Flask==1.1.1->-r requirements.txt (line 21))
 +
  Using cached https://files.pythonhosted.org/packages/65/e0/eb35e762802015cab1ccee04e8a277b03f1d8e53da3ec3106882ec42558b/Jinja2-2.10.3-py2.py3-none-any.whl
 +
Collecting itsdangerous>=0.24 (from Flask==1.1.1->-r requirements.txt (line 21))
 +
  Using cached https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
 +
Requirement already satisfied: pytz in /usr/lib/python3/dist-packages (from Flask-RESTful==0.3.7->-r requirements.txt (line 22))
 +
Collecting aniso8601>=0.82 (from Flask-RESTful==0.3.7->-r requirements.txt (line 22))
 +
  Using cached https://files.pythonhosted.org/packages/eb/e4/787e104b58eadc1a710738d4e418d7e599e4e778e52cb8e5d5ef6ddd5833/aniso8601-8.0.0-py2.py3-none-any.whl
 +
Collecting future>=0.13.0 (from Flask-AutoIndex==0.6.4->-r requirements.txt (line 23))
 +
  Using cached https://files.pythonhosted.org/packages/45/0b/38b06fd9b92dc2b68d58b75f900e97884c45bedd2ff83203d933cf5851c9/future-0.18.2.tar.gz
 +
Collecting Flask-Silk>=0.2 (from Flask-AutoIndex==0.6.4->-r requirements.txt (line 23))
 +
  Using cached https://files.pythonhosted.org/packages/05/95/57667716765b21a8fcd0918ae4a99b5de60f8632d7d1a0b401609fbb28ab/Flask-Silk-0.2.tar.gz
 +
Requirement already satisfied: zope.interface in /usr/lib/python3/dist-packages (from interface==2.11.1->-r requirements.txt (line 39))
 +
Collecting zope.schema (from interface==2.11.1->-r requirements.txt (line 39))
 +
  Using cached https://files.pythonhosted.org/packages/3c/e6/5454a9d72372b73aec715bbded44a0311807dcf7869e2b7bcf196a8e92de/zope.schema-4.9.3-py2.py3-none-any.whl
 +
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from pytest==3.8.2->-r requirements.txt (line 44))
 +
Collecting py>=1.5.0 (from pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/76/bc/394ad449851729244a97857ee14d7cba61ddb268dce3db538ba2f2ba1f0f/py-1.8.0-py2.py3-none-any.whl
 +
Collecting atomicwrites>=1.0 (from pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/52/90/6155aa926f43f2b2a22b01be7241be3bfd1ceaf7d0b3267213e8127d41f4/atomicwrites-1.3.0-py2.py3-none-any.whl
 +
Collecting pluggy>=0.7 (from pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
 +
Collecting attrs>=17.4.0 (from pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
 +
Collecting more-itertools>=4.0.0 (from pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/68/03/0604cec1ea13c9f063dd50f900d1a36160334dd3cfb01fd0e638f61b46ba/more_itertools-8.0.2-py3-none-any.whl
 +
Requirement already satisfied: python-dateutil>=2.1 in /usr/lib/python3/dist-packages (from matplotlib==2.2.3->-r requirements.txt (line 46))
 +
Collecting cycler>=0.10 (from matplotlib==2.2.3->-r requirements.txt (line 46))
 +
  Using cached https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
 +
Collecting kiwisolver>=1.0.1 (from matplotlib==2.2.3->-r requirements.txt (line 46))
 +
  Downloading https://files.pythonhosted.org/packages/93/f8/518fb0bb89860eea6ff1b96483fbd9236d5ee991485d0f3eceff1770f654/kiwisolver-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (90kB)
 +
    100% |████████████████████████████████| 92kB 5.3MB/s
 +
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib==2.2.3->-r requirements.txt (line 46))
 +
  Using cached https://files.pythonhosted.org/packages/5d/bc/1e58593167fade7b544bfe9502a26dc860940a79ab306e651e7f13be68c2/pyparsing-2.4.6-py2.py3-none-any.whl
 +
Collecting coverage>=4.4 (from pytest-cov==2.8.1->-r requirements.txt (line 50))
 +
  Downloading https://files.pythonhosted.org/packages/ee/04/3d94488c04c5fa82eb21a04c82b3f4f1a54fc230496aefa233504a39529d/coverage-5.0.1-cp37-cp37m-manylinux1_x86_64.whl (226kB)
 +
    100% |████████████████████████████████| 235kB 3.7MB/s
 +
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
 +
Requirement already satisfied: idna<2.9,>=2.5 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
 +
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
 +
Requirement already satisfied: certifi>=2017.4.17 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
 +
Requirement already satisfied: MarkupSafe>=0.23 in /usr/lib/python3/dist-packages (from Jinja2>=2.10.1->Flask==1.1.1->-r requirements.txt (line 21))
 +
Collecting zope.event (from zope.schema->interface==2.11.1->-r requirements.txt (line 39))
 +
  Using cached https://files.pythonhosted.org/packages/c5/96/361edb421a077a4c208b4a5c212737d78ae03ce67fbbcd01621c49f332d1/zope.event-4.4-py2.py3-none-any.whl
 +
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pluggy>=0.7->pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/e9/71/1a1e0ed0981bb6a67bce55a210f168126b7ebd2065958673797ea66489ca/importlib_metadata-1.3.0-py2.py3-none-any.whl
 +
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pluggy>=0.7->pytest==3.8.2->-r requirements.txt (line 44))
 +
  Using cached https://files.pythonhosted.org/packages/74/3d/1ee25a26411ba0401b43c6376d2316a71addcc72ef8690b101b4ea56d76a/zipp-0.6.0-py2.py3-none-any.whl
 +
Building wheels for collected packages: imutils, PyYAML, interface, future, Flask-Silk
 +
  Running setup.py bdist_wheel for imutils ... done
 +
  Stored in directory: /root/.cache/pip/wheels/16/84/1f/bf88641293cda2c8be81a5c4b8ca973dd9125a6dc3767417fd
 +
  Running setup.py bdist_wheel for PyYAML ... done
 +
  Stored in directory: /root/.cache/pip/wheels/ad/56/bc/1522f864feb2a358ea6f1a92b4798d69ac783a28e80567a18b
 +
  Running setup.py bdist_wheel for interface ... done
 +
  Stored in directory: /root/.cache/pip/wheels/67/ff/9c/32ef7f63060382c02ba8b1f8f33fed59987378e119da38835f
 +
  Running setup.py bdist_wheel for future ... done
 +
  Stored in directory: /root/.cache/pip/wheels/8b/99/a0/81daf51dcd359a9377b110a8a886b3895921802d2fc1b2397e
 +
  Running setup.py bdist_wheel for Flask-Silk ... done
 +
  Stored in directory: /root/.cache/pip/wheels/58/d6/38/94efca8a2a27bdbfb771ef358684f0621a5d99481c8a506f9a
 +
Successfully built imutils PyYAML interface future Flask-Silk
 +
Installing collected packages: numpy, opencv-python, python-chess, ndjson, requests, berserk, python-lichess, imutils, click, Werkzeug, Jinja2, itsdangerous, Flask, aniso8601, Flask-RESTful, future, Flask-Silk, Flask-AutoIndex, PyYAML, mss, Pillow, jsonpickle, zope.event, zope.schema, interface, py, atomicwrites, more-itertools, zipp, importlib-metadata, pluggy, attrs, pytest, cycler, kiwisolver, pyparsing, matplotlib, scipy, coverage, pytest-cov
 +
  Found existing installation: requests 2.18.4
 +
    Not uninstalling requests at /usr/lib/python3/dist-packages, outside environment /usr
 +
  Found existing installation: PyYAML 3.12
 +
    Not uninstalling pyyaml at /usr/lib/python3/dist-packages, outside environment /usr
 +
  Found existing installation: Pillow 5.1.0
 +
    Not uninstalling pillow at /usr/lib/python3/dist-packages, outside environment /usr
 +
Successfully installed Flask-1.1.1 Flask-AutoIndex-0.6.4 Flask-RESTful-0.3.7 Flask-Silk-0.2 Jinja2-2.10.3 Pillow-6.2.1 PyYAML-5.1 Werkzeug-0.16.0 aniso8601-8.0.0 atomicwrites-1.3.0 attrs-19.3.0 berserk-0.3.1 click-7.0 coverage-5.0.1 cycler-0.10.0 future-0.18.2 importlib-metadata-1.3.0 imutils-0.5.3 interface-2.11.1 itsdangerous-1.1.0 jsonpickle-1.2 kiwisolver-1.1.0 matplotlib-2.2.3 more-itertools-8.0.2 mss-4.0.3 ndjson-0.1.0 numpy-1.18.0 opencv-python-4.1.2.30 pluggy-0.13.1 py-1.8.0 pyparsing-2.4.6 pytest-3.8.2 pytest-cov-2.8.1 python-chess-0.29.0 python-lichess-0.9 requests-2.22.0 scipy-1.2.2 zipp-0.6.0 zope.event-4.4 zope.schema-4.9.3
 +
</source>
 +
 +
=== Test ===
 +
<source lang='bash' highlight="1">
 +
scripts/test
 +
============================= test session starts =============================
 +
platform linux -- Python 3.6.8, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
 +
rootdir: /home/wf/source/python/play-chess-with-a-webcam
 +
plugins: cov-2.8.1
 +
collected 11 items                                                           
 +
 +
src/test_Board.py .                                                    [  9%]
 +
src/test_ChessCam.py .                                                  [ 18%]
 +
src/test_OpenCV_version.py .                                            [ 27%]
 +
src/test_Video.py ...                                                  [ 54%]
 +
src/test_findBoard.py .....                                            [100%]
 +
 +
----------- coverage: platform linux, python 3.6.8-final-0 -----------
 +
Name                        Stmts  Miss  Cover
 +
------------------------------------------------
 +
src/Args.py                    10      7    30%
 +
src/Board.py                    33      3    91%
 +
src/BoardFinder.py            186    12    94%
 +
src/Cell.py                    10      4    60%
 +
src/ChessCam.py                86    59    31%
 +
src/InputManager.py            57    37    35%
 +
src/MovementDetector.py        55    40    27%
 +
src/StateDetector.py            92    75    18%
 +
src/Video.py                  133    48    64%
 +
src/mathUtils.py                49    25    49%
 +
src/test_Board.py              23      3    87%
 +
src/test_ChessCam.py            4      0  100%
 +
src/test_OpenCV_version.py      6      0  100%
 +
src/test_Video.py              28      0  100%
 +
src/test_findBoard.py          49      0  100%
 +
------------------------------------------------
 +
TOTAL                          821    313    62%
 +
 +
 +
============================= 11 passed in 32.41s =============================
 +
</source>
 +
 +
== Raspbian 10 buster ==
 +
=== Modify requirements.txt ===
 +
As of 2019-12 there is no current opencv for Raspbian and a few work-arounds are necessary.
 +
<source lang='bash'>
 +
git diff
 +
diff --git a/pcwawc/requirements.txt b/pcwawc/requirements.txt
 +
index 019d524..a277b59 100644
 +
--- a/pcwawc/requirements.txt
 +
+++ b/pcwawc/requirements.txt
 +
@@ -3,7 +3,7 @@
 +
# runtime dependencies
 +
#
 +
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html
 +
-opencv-python==4.1.2.30
 +
+opencv-python==4.1.*
 +
# python-chess
 +
# https://buildmedia.readthedocs.org/media/pdf/python-chess/latest/python-chess.pdf
 +
python-chess==0.29.0
 +
</source>
 +
=== Install ===
 +
<source lang='bash' highlight="1-3">
 +
scripts/install
 +
...
 +
# to avoid warning later
 +
pip3 install --no-cache-dir cairocffi
 +
</source>
 +
==== Issue undefined symbol: __atomic_fetch_add_8 ====
 +
If you get:
 +
<pre>
 +
undefined symbol: __atomic_fetch_add_8
 +
</pre>
 +
* https://github.com/EdjeElectronics/TensorFlow-Object-Detection-on-the-Raspberry-Pi/issues/67
 +
 +
define this:
 +
<source lang='bash'>
 +
export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1.2.0
 +
</source>
 +
 +
=== Test ===
 +
<source lang='bash'>
 +
scripts/run --input ../Chess-Testmedia/TK_scholarsmate30.avi --event 'PlayChessWithaWebCam' --site 'Stuttgart-Germany' --black OTB1 --white OTB2 --round 1 --warp '[[81,18],[271,15],[268,203],[85,203]]' --rotation 90 --nomoves
 +
/usr/local/lib/python3.7/dist-packages/matplotlib/backends/backend_gtk3agg.py:16: UserWarning: The Gtk3Agg backend is known to not work on Python 3.x with pycairo. Try installing cairocffi.
 +
  "The Gtk3Agg backend is known to not work on Python 3.x with pycairo. "
 +
[Event "PlayChessWithaWebCam"]
 +
[Site "Stuttgart-Germany"]
 +
[Date "2019-12-28 20:17:35"]
 +
[Round "1"]
 +
[White "OTB2"]
 +
[Black "OTB1"]
 +
[Result "1-0"]
 +
 +
1. e4 e5 2. Qh5 Nc6 3. Bc4 Nf6 4. Qxf7# 1-0
 +
</source>
 +
 +
== Raspbian 9.8 stretch (not successful) ==
 +
=== Install ===
 +
if the install fails e.g. with an Exception in urlopen you might want to restart the install.
 +
<source lang='bash' highlight="1">
 +
scripts/install
 +
checking that python3  is installed on os Linux ...
 +
/usr/bin/python3
 +
checking that pip3  is installed on os Linux ...
 +
/usr/bin/pip3
 +
Collecting opencv-python (from -r requirements.txt (line 2))
 +
  Using cached https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.4.19-cp35-cp35m-linux_armv7l.whl
 +
Collecting pytest (from -r requirements.txt (line 4))
 +
  Using cached https://files.pythonhosted.org/packages/0c/91/d68f68ce54cd3e8afa1ef73ea1ad44df2438521b64c0820e5fd9b9f13b7d/pytest-5.2.1-py3-none-any.whl
 +
Collecting matplotlib (from -r requirements.txt (line 6))
 +
  Using cached https://www.piwheels.org/simple/matplotlib/matplotlib-3.0.3-cp35-cp35m-linux_armv7l.whl
 +
Collecting scipy (from -r requirements.txt (line 8))
 +
  Using cached https://www.piwheels.org/simple/scipy/scipy-1.3.1-cp35-cp35m-linux_armv7l.whl
 +
Collecting pytest-cov (from -r requirements.txt (line 10))
 +
  Using cached https://files.pythonhosted.org/packages/b9/54/3673ee8be482f81527678ac894276223b9814bb7262e4f730469bb7bf70e/pytest_cov-2.8.1-py2.py3-none-any.whl
 +
Collecting python-chess (from -r requirements.txt (line 12))
 +
  Using cached https://files.pythonhosted.org/packages/58/70/72dc875a30ac7f26e0bec45714d67b19e0f498de920323b906995a741a88/python_chess-0.28.3-py3-none-any.whl
 +
Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python3/dist-packages (from opencv-python->-r requirements.txt (line 2))
 +
Collecting pathlib2>=2.2.0; python_version < "3.6" (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/e9/45/9c82d3666af4ef9f221cbb954e1d77ddbb513faf552aea6df5f37f1a4859/pathlib2-2.3.5-py2.py3-none-any.whl
 +
Collecting packaging (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/cf/94/9672c2d4b126e74c4496c6b3c58a8b51d6419267be9e70660ba23374c875/packaging-19.2-py2.py3-none-any.whl
 +
Collecting atomicwrites>=1.0 (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/52/90/6155aa926f43f2b2a22b01be7241be3bfd1ceaf7d0b3267213e8127d41f4/atomicwrites-1.3.0-py2.py3-none-any.whl
 +
Collecting pluggy<1.0,>=0.12 (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/92/c7/48439f7d5fd6bddb4c04b850bb862b42e3e2b98570040dfaf68aedd8114b/pluggy-0.13.0-py2.py3-none-any.whl
 +
Collecting py>=1.5.0 (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/76/bc/394ad449851729244a97857ee14d7cba61ddb268dce3db538ba2f2ba1f0f/py-1.8.0-py2.py3-none-any.whl (83kB)
 +
    100% |████████████████████████████████| 92kB 2.1MB/s
 +
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/f6/d2/40b3fa882147719744e6aa50ac39cf7a22a913cbcba86a0371176c425a3b/importlib_metadata-0.23-py2.py3-none-any.whl
 +
Collecting attrs>=17.4.0 (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
 +
Collecting wcwidth (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/7e/9f/526a6947247599b084ee5232e4f9190a38f398d7300d866af3ab571a5bfe/wcwidth-0.1.7-py2.py3-none-any.whl
 +
Collecting more-itertools>=4.0.0 (from pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/45/dc/3241eef99eb45f1def35cf93af35d1cf9ef4c0991792583b8f33ea41b092/more_itertools-7.2.0-py3-none-any.whl (57kB)
 +
    100% |████████████████████████████████| 61kB 2.0MB/s
 +
Collecting kiwisolver>=1.0.1 (from matplotlib->-r requirements.txt (line 6))
 +
  Downloading https://www.piwheels.org/simple/kiwisolver/kiwisolver-1.1.0-cp35-cp35m-linux_armv7l.whl (912kB)
 +
    100% |████████████████████████████████| 921kB 344kB/s
 +
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib->-r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/11/fa/0160cd525c62d7abd076a070ff02b2b94de589f1a9789774f17d7c54058e/pyparsing-2.4.2-py2.py3-none-any.whl (65kB)
 +
    100% |████████████████████████████████| 71kB 2.1MB/s
 +
Collecting python-dateutil>=2.1 (from matplotlib->-r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/41/17/c62faccbfbd163c7f57f3844689e3a78bae1f403648a6afb1d0866d87fbb/python_dateutil-2.8.0-py2.py3-none-any.whl (226kB)
 +
    100% |████████████████████████████████| 235kB 1.2MB/s
 +
Collecting cycler>=0.10 (from matplotlib->-r requirements.txt (line 6))
 +
  Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
 +
Collecting coverage>=4.4 (from pytest-cov->-r requirements.txt (line 10))
 +
  Downloading https://www.piwheels.org/simple/coverage/coverage-4.5.4-cp35-cp35m-linux_armv7l.whl (210kB)
 +
    100% |████████████████████████████████| 215kB 538kB/s
 +
Requirement already satisfied: six in /usr/lib/python3/dist-packages (from pathlib2>=2.2.0; python_version < "3.6"->pytest->-r requirements.txt (line 4))
 +
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest->-r requirements.txt (line 4))
 +
  Downloading https://files.pythonhosted.org/packages/74/3d/1ee25a26411ba0401b43c6376d2316a71addcc72ef8690b101b4ea56d76a/zipp-0.6.0-py2.py3-none-any.whl
 +
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from kiwisolver>=1.0.1->matplotlib->-r requirements.txt (line 6))
 +
Installing collected packages: opencv-python, pathlib2, pyparsing, packaging, atomicwrites, more-itertools, zipp, importlib-metadata, pluggy, py, attrs, wcwidth, pytest, kiwisolver, python-dateutil, cycler, matplotlib, scipy, coverage, pytest-cov, python-chess
 +
Successfully installed atomicwrites-1.3.0 attrs-19.3.0 coverage-4.5.4 cycler-0.10.0 importlib-metadata-0.23 kiwisolver-1.1.0 matplotlib-3.0.3 more-itertools-7.2.0 opencv-python-3.4.4.19 packaging-19.2 pathlib2-2.3.5 pluggy-0.13.0 py-1.8.0 pyparsing-2.4.2 pytest-5.2.1 pytest-cov-2.8.1 python-chess-0.28.3 python-dateutil-2.8.0 scipy-1.3.1 wcwidth-0.1.7 zipp-0.6.0
 +
</source>
 +
=== Test ===
 +
if you run into the [https://stackoverflow.com/questions/53347759/importerror-libcblas-so-3-cannot-open-shared-object-file-no-such-file-or-dire ImportError: libcblas.so.3: cannot open shared object file: No such file or directory] error you might want to run both lines otherwise simply try the test script itself
 +
<source lang='bash' highlight="1">
 +
pip3 install opencv-python; sudo apt-get install -y libcblas-dev libhdf5-dev libhdf5-serial-dev libatlas-base-dev libjasper-dev  libqtgui4  libqt4-test
 +
</source>
 +
run tests
 +
<source lang='bash' highlight="1">
 +
scripts/test
 +
...
 +
ImportError: numpy.core.multiarray failed to import
 +
</source>
 +
 +
The issue is that this project needs Python3.7 to work which can only be installed manually by compiling on stretch at this time (which i didn't try out ...)
 +
 +
== Windows 7/10 ==
 +
# Download Python 3.7.3 from https://www.python.org/downloads/release/python-373/
 +
## https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64.exe
 +
=== Alternative: Install via Linux Subsystem ===
 +
This installation uses a "hybrid approach" - we install the web elements e.g. javascript/css/fonts via bash script and then use the
 +
Windows native python and pip to proceed.
 +
* see https://docs.microsoft.com/de-de/windows/wsl/install-win10 with Ubuntu from the Microsoft Store
 +
then follow the linux instructions
 +
<source lang='bash'>
 +
sudo apt-get update
 +
sudo apt-get upgrade
 +
sudo apt-get install xdg-utils
 +
</source>
 +
Access files via Z:
 +
* https://superuser.com/a/1502631/166461
 +
<source lang='bash'>
 +
cd pcwawc
 +
pip install -r requirements.txt
 +
cd ..
 +
set PYTHONPATH=.;%PYTHONPATH%;
 +
</source>

Latest revision as of 12:49, 9 January 2020

OsProject
edit
id  PlayChessWithAWebCam
state  
owner  Wolfgang Fahl
title  Play Chess With A WebCam
url  https://github.com/WolfgangFahl/play-chess-with-a-webcam
version  0.0.1
description  
date  2019/10/21
since  
until  

PlayChessWithAWebCam2019-10-26.png Click here to comment see PlayChessWithAWebCam

Motivation

See MagneticSensorChessBoard1987 for the initial project of 1987. Time has moved on and the goals of the 1987 project can be achieved with less hardware and software in a more convenient manner these days.

Usecases

Play Chess With A Webcam

As a chess player given a physical board and a starting position in FEN notation and a webcam observing the board in a proper angle (e.g. from above) i want to play moves against an opponent that

  1. might sit directly in front of me
  2. might sit with a similar setup remotely in front of a physical board
  3. might play using some other remote means of communication

so that my moves are recorded and transmitted with the option to

  1. later analyze
  2. immediately analyze and if allowed by the oponent take back moves

If the oponent is not at the board I'll have to do his moves manually or later might use some kind of robot to do that for me ...

Detecting Moves by a WebCAM

As a chess player given a logical chess board setting in FEN notation (e.g. starting FEN that I have setup on my physical board being observed by a webcam in HD at e.g. 25 FPS I want to use a webcam to detect my next valid move e.g. e2-e4 so that the logical board changes to the new FEN e.g. (https://lichess.org/editor/rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR_w_KQkq_-) and the move is available in Algebraic_Notation e.g. e2-e4 e.g. to be transferred via Universal_Chess_Interface or e.g. lichess.org

Process Chessgame webcam movie recording to create PGN

As a chess player

I want to process a given movie of a chessgame so that I get a Portable Game Notation of the game's moves

see

https://chess.stackexchange.com/questions/4695/tools-for-automated-notation-webcam-movie-to-pgn/4699

State of Project

As of 2019-12-28 version 0.0.1 has not been released yet. The state of the project is alpha and will be in beta in a few days.

There is already a lof of stuff to try out and to participate in this open source project.

There is a web frontend which you can try out. Sample videos are available at https://github.com/SteinscheisserKarl/Chess-Testmedia/ which you can check out with:

sudo apt-get install git-lfs
git clone https://github.com/SteinscheisserKarl/Chess-Testmedia/
cd Chess-Testmedia
git lfs install
git lfs pull
git clone https://github.com/WolfgangFahl/play-chess-with-a-webcam
cd play-chess-with-a-webcam
scripts/install
scripts/run --input ../Chess-Testmedia/TK_scholarsmate30.avi --event 'PlayChessWithaWebCam' --site 'Stuttgart-Germany' --black OTB1 --white OTB2 --round 1 --warp '[[81,18],[271,15],[268,203],[85,203]]' --rotation 90 --nomoves

to tryout one of the Scholars Mate example video's in command line mode ScholarsMateDebug2019-10-29.png or

scripts/runweb

for the default web cam or

scripts/runweb --input 1

if there is a second webcam installed.

You might want to click the corners of your chessboard to try out the warp function manually or click the .


The scripts:

  • still
  • record

are already useful for taking pictures and movie recordings of your chess match. The detection of the board and moves is not fully operational yet.

If you'd like to experiment a bit you can run the tests which will show some debug output.

Installation

Prerequisites: python3.7 (install script will check and try automatic installation in Ubuntu/MacOS)

git clone https://github.com/WolfgangFahl/play-chess-with-a-webcam
Cloning into 'play-chess-with-a-webcam'...
remote: Enumerating objects: 57, done.
remote: Counting objects: 100% (57/57), done.
remote: Compressing objects: 100% (40/40), done.
remote: Total 385 (delta 29), reused 34 (delta 17), pack-reused 328
Receiving objects: 100% (385/385), 1.79 MiB | 3.17 MiB/s, done.
Resolving deltas: 100% (244/244), done
cd play-chess-with-a-webcam
scripts/install
checking that python3  is installed on os Linux ...
/usr/bin/python3
checking that pip3  is installed on os Linux ...
installing pip3 from apt-package python3-pip
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  libevent-core-2.1-6
Use 'sudo apt autoremove' to remove it.
The following additional packages will be installed:
  libexpat1-dev libpython3-dev libpython3.6-dev python-pip-whl python3-dev
  python3-setuptools python3-wheel python3.6-dev
Suggested packages:
  python-setuptools-doc
The following NEW packages will be installed:
  libexpat1-dev libpython3-dev libpython3.6-dev python-pip-whl python3-dev
  python3-pip python3-setuptools python3-wheel python3.6-dev
0 upgraded, 9 newly installed, 0 to remove and 40 not upgraded.
Need to get 47,5 MB of archives.
After this operation, 81,7 MB of additional disk space will be used.
Do you want to continue? [Y/n] y

MacoS Macports

You might want to set python3

sudo port select --list pip
sudo port select --set pip3 pip37
sudo port select --list python
sudo port select --set python3 python37

Usage

WebUI

Menu

home description save folder videocam camera_alt bug_report crop keyboard_arrow_left keyboard_arrow_right rotate_right play_arrow

Command line usage

scripts/runweb -h
[2019-10-29 09:27:14,631] INFO in webchesscam: python src folder is /Users/wf/source/python/play-chess-with-a-webcam/src
[2019-10-29 09:27:14,646] INFO in webchesscam: Running on Darwin
usage: webchesscam.py [-h] [--port PORT] [--input INPUT] [--host HOST]
                      [--debug] [--rotation ROTATION] [--warp WARP]

WebChessCam

optional arguments:
  -h, --help           show this help message and exit
  --port PORT          port to run server at
  --input INPUT        Manually set the input device.
  --host HOST          host to allow access for
  --debug              show debug output
  --rotation ROTATION  rotation of chessboard
  --warp WARP          warp points

Recording

Still images

scripts/still

Video of match

scripts/record

Example Sources

OpenCV

Also in the examples/opencv directory you'll find:

  • colorcluster.py
  • histogramm.py
  • hough_lines.py
  • ...

hough lines

python3 examples/opencv/hough_lines.py testMedia/chessBoard002.jpg

ChessBoard002.jpg DetectedProbabilisticHough2019-10-21.png DetectedHough2019-10-21.png

histogramm / colorcluster

ChessBoard006.jpg

python3 examples/opencv/histogramm.py testMedia/chessBoard006.jpg

Hsvhistogramm2019-10-21.jpg

python3 examples/opencv/colorcluster.py testMedia/chessBoard006.jpg
Clusterization took 2.8 s for 1 channels
Clusterization took 4.5 s for 2 channels
Clusterization took 6.7 s for 3 channels

ColorCluster2019-10-21.jpg

Testing

scripts/test
---------- coverage: platform darwin, python 3.7.4-final-0 -----------
Name                         Stmts   Miss  Cover
------------------------------------------------
src/Args.py                     10      7    30%
src/Board.py                    79      5    94%
src/BoardDetector.py            53      1    98%
src/BoardFinder.py             185     12    94%
src/Cell.py                     10      3    70%
src/ChessCam.py                 85     59    31%
src/Environment.py              19      0   100%
src/FPSCheck.py                 17      0   100%
src/Field.py                    98      1    99%
src/Game.py                     80     11    86%
src/Histogram.py                72      0   100%
src/InputManager.py             41     29    29%
src/JsonAbleMixin.py            32      7    78%
src/MovementDetector.py         55     40    27%
src/RunningStats.py             61      4    93%
src/StateDetector.py           102      7    93%
src/Video.py                   275    101    63%
src/WebApp.py                  175     84    52%
src/YamlAbleMixin.py            22      4    82%
src/ciede2000.py                88      9    90%
src/imutils/__init__.py          1      0   100%
src/imutils/perspective.py      25      0   100%
src/mathUtils.py                48      7    85%
src/test_Args.py                16      0   100%
src/test_Board.py               99      8    92%
src/test_BoardDetector.py       87      0   100%
src/test_ChessCam.py             4      0   100%
src/test_Field.py               19      0   100%
src/test_Game.py                48      0   100%
src/test_Histogram.py           31      1    97%
src/test_OpenCV_version.py       6      0   100%
src/test_RunningStats.py        35      0   100%
src/test_StateDetector.py       14      0   100%
src/test_Video.py               68      1    99%
src/test_Warp.py                46      2    96%
src/test_findBoard.py           44      0   100%
src/webchesscam.py              94     39    59%
------------------------------------------------
TOTAL                         2244    442    80%

================== 38 passed, 4 warnings in 94.81s (0:01:34)

Hardware

see e.g Raspberry_PI_Chessboard_Camera

Projects

  1. PlayChessWithAWebCam
  2. CV_Chess

UCI compatible GUIs

XBoard

see XBoard

Open Source Projects

Commercial

Links

Research

see also

Stackexchange

Videos

Source Code

play-chess-with-a-webcam

see github fork at

Written in python using python3.7. see https://unix.stackexchange.com/a/410851/38701 for selection your python version on Ubuntu

Code Structure

click classes to see source code at Play Chess With A WebCam github repository

Development Environment

https://www.liclipse.com/ is recommended since it alows interactive graphical debugging and editing with syntax and error hints.

OS-Support

MacOS High Sierra 10.13.6

MacPorts: 2.6.2

Install

scripts/install
checking that python3  is installed on os Darwin ...
/opt/local/bin/python3
checking that pip3  is installed on os Darwin ...
/opt/local/bin/pip3
Requirement already satisfied: opencv-python in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (4.1.1.26)
Requirement already satisfied: pytest in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from -r requirements.txt (line 4)) (5.2.1)
Collecting matplotlib (from -r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/c3/8b/af9e0984f5c0df06d3fab0bf396eb09cbf05f8452de4e9502b182f59c33b/matplotlib-3.1.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (14.4MB)
     |████████████████████████████████| 14.4MB 7.4MB/s 
Collecting scipy (from -r requirements.txt (line 8))
  Downloading https://files.pythonhosted.org/packages/d5/06/1a696649f4b2e706c509cb9333fdc6331fbe71251cede945f9e1fa13ea34/scipy-1.3.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (27.7MB)
     |████████████████████████████████| 27.7MB 7.1MB/s 
Collecting pytest-cov (from -r requirements.txt (line 10))
  Downloading https://files.pythonhosted.org/packages/b9/54/3673ee8be482f81527678ac894276223b9814bb7262e4f730469bb7bf70e/pytest_cov-2.8.1-py2.py3-none-any.whl
Collecting python-chess (from -r requirements.txt (line 12))
  Downloading https://files.pythonhosted.org/packages/58/70/72dc875a30ac7f26e0bec45714d67b19e0f498de920323b906995a741a88/python_chess-0.28.3-py3-none-any.whl (127kB)
     |████████████████████████████████| 133kB 7.1MB/s 
Requirement already satisfied: numpy>=1.14.5 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from opencv-python->-r requirements.txt (line 2)) (1.16.4)
Requirement already satisfied: attrs>=17.4.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (19.1.0)
Requirement already satisfied: more-itertools>=4.0.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (7.2.0)
Requirement already satisfied: py>=1.5.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (1.8.0)
Requirement already satisfied: pluggy<1.0,>=0.12 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (0.13.0)
Requirement already satisfied: atomicwrites>=1.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (1.3.0)
Requirement already satisfied: wcwidth in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (0.1.7)
Requirement already satisfied: importlib-metadata>=0.12; python_version < "3.8" in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (0.23)
Requirement already satisfied: packaging in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->-r requirements.txt (line 4)) (19.2)
Collecting kiwisolver>=1.0.1 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/df/93/8bc9b52a8846be2b9572aa0a7c881930939b06e4abe1162da6a0430b794f/kiwisolver-1.1.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (113kB)
     |████████████████████████████████| 122kB 8.3MB/s 
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from matplotlib->-r requirements.txt (line 6)) (2.4.2)
Requirement already satisfied: python-dateutil>=2.1 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from matplotlib->-r requirements.txt (line 6)) (2.8.0)
Collecting cycler>=0.10 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Collecting coverage>=4.4 (from pytest-cov->-r requirements.txt (line 10))
  Downloading https://files.pythonhosted.org/packages/93/07/8302163cdbe2008441aa69f2119750110fde15ffd8a56a687311b143365a/coverage-4.5.4-cp37-cp37m-macosx_10_13_x86_64.whl (181kB)
     |████████████████████████████████| 184kB 8.4MB/s 
Requirement already satisfied: zipp>=0.5 in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from importlib-metadata>=0.12; python_version < "3.8"->pytest->-r requirements.txt (line 4)) (0.6.0)
Requirement already satisfied: six in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from packaging->pytest->-r requirements.txt (line 4)) (1.12.0)
Requirement already satisfied: setuptools in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib->-r requirements.txt (line 6)) (41.0.1)
Installing collected packages: kiwisolver, cycler, matplotlib, scipy, coverage, pytest-cov, python-chess
Successfully installed coverage-4.5.4 cycler-0.10.0 kiwisolver-1.1.0 matplotlib-3.1.1 pytest-cov-2.8.1 python-chess-0.28.3 scipy-1.3.1

Test

scripts/test 
=========================================== test session starts ===========================================
platform darwin -- Python 3.7.3, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
rootdir: /Users/wf/source/python/play-chess-with-a-webcam
plugins: cov-2.8.1
collected 11 items                                                                                        

src/test_Board.py .                                                                                 [  9%]
src/test_ChessCam.py .                                                                              [ 18%]
src/test_OpenCV_version.py .                                                                        [ 27%]
src/test_Video.py ...                                                                               [ 54%]
src/test_findBoard.py .....                                                                         [100%]

---------- coverage: platform darwin, python 3.7.3-final-0 -----------
Name                         Stmts   Miss  Cover
------------------------------------------------
src/Args.py                     10      7    30%
src/Board.py                    33      3    91%
src/BoardFinder.py             186     12    94%
src/Cell.py                     10      4    60%
src/ChessCam.py                 86     59    31%
src/InputManager.py             57     37    35%
src/MovementDetector.py         55     40    27%
src/StateDetector.py            92     75    18%
src/Video.py                   133     48    64%
src/mathUtils.py                49     25    49%
src/test_Board.py               23      3    87%
src/test_ChessCam.py             4      0   100%
src/test_OpenCV_version.py       6      0   100%
src/test_Video.py               28      0   100%
src/test_findBoard.py           49      0   100%
------------------------------------------------
TOTAL                          821    313    62%


=========================================== 11 passed in 37.60s ===========================================

Ubuntu 18.04.3 LTS bionic beaver

Upgrade Python to 3.7

see https://linuxize.com/post/how-to-install-python-3-7-on-ubuntu-18-04/

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-install python3.7
# install tkinter
sudo apt-get install python3-tk

make python3.7 the default python3

Install

scripts/install 
 scripts/install
Bootstrap already downloaded
Material Design Lite already downloaded
Material Design Icons already downloaded
chessboard.js already downloaded
chessboard-1.0.0.css already downloaded
chessboard-1.0.0.min.css already downloaded
js/jquery-3.4.1.min.js already downloaded
chess.js already downloaded
checking that python3  is installed on os Linux ...
/usr/bin/python3
checking that pip3  is installed on os Linux ...
/usr/bin/pip3
Collecting opencv-python==4.1.2.30 (from -r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/d8/38/60de02a4c9013b14478a3f681a62e003c7489d207160a4d7df8705a682e7/opencv_python-4.1.2.30-cp37-cp37m-manylinux1_x86_64.whl (28.3MB)
    100% |████████████████████████████████| 28.3MB 50kB/s 
Collecting python-chess==0.29.0 (from -r requirements.txt (line 9))
  Using cached https://files.pythonhosted.org/packages/63/eb/003a6c069c0208e169165acd2d90665fa3901baab19b5fa26603d86b7193/python_chess-0.29.0-py3-none-any.whl
Collecting berserk==0.3.1 (from -r requirements.txt (line 12))
  Using cached https://files.pythonhosted.org/packages/bb/09/d25b49f70145e07a5ca7aa1a5ff9bf5499ba0754341a592a2e8d165ed621/berserk-0.3.1-py2.py3-none-any.whl
Collecting python-lichess==0.9 (from -r requirements.txt (line 14))
  Using cached https://files.pythonhosted.org/packages/23/07/6cfaa4ef2649d705defc3e7c8ff7ed3a3bb467400325d00ad9da3acedf39/python_lichess-0.9-py3-none-any.whl
Collecting imutils==0.5.3 (from -r requirements.txt (line 16))
  Using cached https://files.pythonhosted.org/packages/b5/94/46dcae8c061e28be31bcaa55c560cb30ee9403c9a4bb2659768ec1b9eb7d/imutils-0.5.3.tar.gz
Collecting Flask==1.1.1 (from -r requirements.txt (line 21))
  Using cached https://files.pythonhosted.org/packages/9b/93/628509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flask-1.1.1-py2.py3-none-any.whl
Collecting Flask-RESTful==0.3.7 (from -r requirements.txt (line 22))
  Using cached https://files.pythonhosted.org/packages/17/44/6e490150ee443ca81d5f88b61bb4bbb133d44d75b0b716ebe92489508da4/Flask_RESTful-0.3.7-py2.py3-none-any.whl
Collecting Flask-AutoIndex==0.6.4 (from -r requirements.txt (line 23))
  Using cached https://files.pythonhosted.org/packages/dc/43/26df9c0c0e7d3de98ba7cbe89e7b88c280e40c87073025171d2d702d0b5f/Flask_AutoIndex-0.6.4-py3-none-any.whl
Collecting PyYAML==5.1 (from -r requirements.txt (line 25))
  Using cached https://files.pythonhosted.org/packages/9f/2c/9417b5c774792634834e730932745bc09a7d36754ca00acf1ccd1ac2594d/PyYAML-5.1.tar.gz
Collecting mss==4.0.3 (from -r requirements.txt (line 27))
  Using cached https://files.pythonhosted.org/packages/67/2a/8e26437bcc840e19ca5290897d47f5405e302af27d4a6401e0b0edc39942/mss-4.0.3-py2.py3-none-any.whl
Collecting Pillow==6.2.1 (from -r requirements.txt (line 29))
  Downloading https://files.pythonhosted.org/packages/89/3e/31c2e5385d7588016c6f7ac552e81c3fff2bef4bc61b6f82f8177752405c/Pillow-6.2.1-cp37-cp37m-manylinux1_x86_64.whl (2.1MB)
    100% |████████████████████████████████| 2.1MB 678kB/s 
Collecting jsonpickle==1.2 (from -r requirements.txt (line 35))
  Using cached https://files.pythonhosted.org/packages/07/07/c157520a3ebd166c8c24c6ae0ecae7c3968eb4653ff0e5af369bb82f004d/jsonpickle-1.2-py2.py3-none-any.whl
Collecting interface==2.11.1 (from -r requirements.txt (line 39))
  Using cached https://files.pythonhosted.org/packages/f9/80/7283dfe76ceb7eb1868cf97b8c8cb3a988f80757921341f95d5420de2a6e/Interface-2.11.1.tar.gz
Collecting pytest==3.8.2 (from -r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/08/e0/a4945a06380802264b3416d788ad607588c334662b6cd0af54144c45912d/pytest-3.8.2-py2.py3-none-any.whl
Collecting matplotlib==2.2.3 (from -r requirements.txt (line 46))
  Downloading https://files.pythonhosted.org/packages/52/46/ff47fea8e5c528c497fc385c95887131c4319a3411814ba9a766b66a9367/matplotlib-2.2.3-cp37-cp37m-manylinux1_x86_64.whl (12.6MB)
    100% |████████████████████████████████| 12.6MB 116kB/s 
Collecting scipy==1.2.2 (from -r requirements.txt (line 48))
  Downloading https://files.pythonhosted.org/packages/f3/84/2cc37b97e96da0be03d5dcebdd967214cae14b14b0131398b374ea89c50e/scipy-1.2.2-cp37-cp37m-manylinux1_x86_64.whl (24.8MB)
    100% |████████████████████████████████| 24.8MB 59kB/s 
Collecting pytest-cov==2.8.1 (from -r requirements.txt (line 50))
  Using cached https://files.pythonhosted.org/packages/b9/54/3673ee8be482f81527678ac894276223b9814bb7262e4f730469bb7bf70e/pytest_cov-2.8.1-py2.py3-none-any.whl
Collecting numpy>=1.14.5 (from opencv-python==4.1.2.30->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/20/53/127cb49435bcf5d841baf8eafa030931c62a9eac577a641f8c2293d23371/numpy-1.18.0-cp37-cp37m-manylinux1_x86_64.whl (20.1MB)
    100% |████████████████████████████████| 20.1MB 70kB/s 
Collecting ndjson==0.1.0 (from berserk==0.3.1->-r requirements.txt (line 12))
  Using cached https://files.pythonhosted.org/packages/39/ba/0628840da7b61fb63a6a0e030291a7a5e5d393a51cbcb27ded8b2a838aa9/ndjson-0.1.0-py2.py3-none-any.whl
Collecting requests>=2.20.0 (from berserk==0.3.1->-r requirements.txt (line 12))
  Using cached https://files.pythonhosted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/requests-2.22.0-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python3/dist-packages (from python-lichess==0.9->-r requirements.txt (line 14))
Collecting click>=5.1 (from Flask==1.1.1->-r requirements.txt (line 21))
  Using cached https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl
Collecting Werkzeug>=0.15 (from Flask==1.1.1->-r requirements.txt (line 21))
  Using cached https://files.pythonhosted.org/packages/ce/42/3aeda98f96e85fd26180534d36570e4d18108d62ae36f87694b476b83d6f/Werkzeug-0.16.0-py2.py3-none-any.whl
Collecting Jinja2>=2.10.1 (from Flask==1.1.1->-r requirements.txt (line 21))
  Using cached https://files.pythonhosted.org/packages/65/e0/eb35e762802015cab1ccee04e8a277b03f1d8e53da3ec3106882ec42558b/Jinja2-2.10.3-py2.py3-none-any.whl
Collecting itsdangerous>=0.24 (from Flask==1.1.1->-r requirements.txt (line 21))
  Using cached https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
Requirement already satisfied: pytz in /usr/lib/python3/dist-packages (from Flask-RESTful==0.3.7->-r requirements.txt (line 22))
Collecting aniso8601>=0.82 (from Flask-RESTful==0.3.7->-r requirements.txt (line 22))
  Using cached https://files.pythonhosted.org/packages/eb/e4/787e104b58eadc1a710738d4e418d7e599e4e778e52cb8e5d5ef6ddd5833/aniso8601-8.0.0-py2.py3-none-any.whl
Collecting future>=0.13.0 (from Flask-AutoIndex==0.6.4->-r requirements.txt (line 23))
  Using cached https://files.pythonhosted.org/packages/45/0b/38b06fd9b92dc2b68d58b75f900e97884c45bedd2ff83203d933cf5851c9/future-0.18.2.tar.gz
Collecting Flask-Silk>=0.2 (from Flask-AutoIndex==0.6.4->-r requirements.txt (line 23))
  Using cached https://files.pythonhosted.org/packages/05/95/57667716765b21a8fcd0918ae4a99b5de60f8632d7d1a0b401609fbb28ab/Flask-Silk-0.2.tar.gz
Requirement already satisfied: zope.interface in /usr/lib/python3/dist-packages (from interface==2.11.1->-r requirements.txt (line 39))
Collecting zope.schema (from interface==2.11.1->-r requirements.txt (line 39))
  Using cached https://files.pythonhosted.org/packages/3c/e6/5454a9d72372b73aec715bbded44a0311807dcf7869e2b7bcf196a8e92de/zope.schema-4.9.3-py2.py3-none-any.whl
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from pytest==3.8.2->-r requirements.txt (line 44))
Collecting py>=1.5.0 (from pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/76/bc/394ad449851729244a97857ee14d7cba61ddb268dce3db538ba2f2ba1f0f/py-1.8.0-py2.py3-none-any.whl
Collecting atomicwrites>=1.0 (from pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/52/90/6155aa926f43f2b2a22b01be7241be3bfd1ceaf7d0b3267213e8127d41f4/atomicwrites-1.3.0-py2.py3-none-any.whl
Collecting pluggy>=0.7 (from pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting attrs>=17.4.0 (from pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting more-itertools>=4.0.0 (from pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/68/03/0604cec1ea13c9f063dd50f900d1a36160334dd3cfb01fd0e638f61b46ba/more_itertools-8.0.2-py3-none-any.whl
Requirement already satisfied: python-dateutil>=2.1 in /usr/lib/python3/dist-packages (from matplotlib==2.2.3->-r requirements.txt (line 46))
Collecting cycler>=0.10 (from matplotlib==2.2.3->-r requirements.txt (line 46))
  Using cached https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Collecting kiwisolver>=1.0.1 (from matplotlib==2.2.3->-r requirements.txt (line 46))
  Downloading https://files.pythonhosted.org/packages/93/f8/518fb0bb89860eea6ff1b96483fbd9236d5ee991485d0f3eceff1770f654/kiwisolver-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (90kB)
    100% |████████████████████████████████| 92kB 5.3MB/s 
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib==2.2.3->-r requirements.txt (line 46))
  Using cached https://files.pythonhosted.org/packages/5d/bc/1e58593167fade7b544bfe9502a26dc860940a79ab306e651e7f13be68c2/pyparsing-2.4.6-py2.py3-none-any.whl
Collecting coverage>=4.4 (from pytest-cov==2.8.1->-r requirements.txt (line 50))
  Downloading https://files.pythonhosted.org/packages/ee/04/3d94488c04c5fa82eb21a04c82b3f4f1a54fc230496aefa233504a39529d/coverage-5.0.1-cp37-cp37m-manylinux1_x86_64.whl (226kB)
    100% |████████████████████████████████| 235kB 3.7MB/s 
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
Requirement already satisfied: idna<2.9,>=2.5 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
Requirement already satisfied: certifi>=2017.4.17 in /usr/lib/python3/dist-packages (from requests>=2.20.0->berserk==0.3.1->-r requirements.txt (line 12))
Requirement already satisfied: MarkupSafe>=0.23 in /usr/lib/python3/dist-packages (from Jinja2>=2.10.1->Flask==1.1.1->-r requirements.txt (line 21))
Collecting zope.event (from zope.schema->interface==2.11.1->-r requirements.txt (line 39))
  Using cached https://files.pythonhosted.org/packages/c5/96/361edb421a077a4c208b4a5c212737d78ae03ce67fbbcd01621c49f332d1/zope.event-4.4-py2.py3-none-any.whl
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pluggy>=0.7->pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/e9/71/1a1e0ed0981bb6a67bce55a210f168126b7ebd2065958673797ea66489ca/importlib_metadata-1.3.0-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pluggy>=0.7->pytest==3.8.2->-r requirements.txt (line 44))
  Using cached https://files.pythonhosted.org/packages/74/3d/1ee25a26411ba0401b43c6376d2316a71addcc72ef8690b101b4ea56d76a/zipp-0.6.0-py2.py3-none-any.whl
Building wheels for collected packages: imutils, PyYAML, interface, future, Flask-Silk
  Running setup.py bdist_wheel for imutils ... done
  Stored in directory: /root/.cache/pip/wheels/16/84/1f/bf88641293cda2c8be81a5c4b8ca973dd9125a6dc3767417fd
  Running setup.py bdist_wheel for PyYAML ... done
  Stored in directory: /root/.cache/pip/wheels/ad/56/bc/1522f864feb2a358ea6f1a92b4798d69ac783a28e80567a18b
  Running setup.py bdist_wheel for interface ... done
  Stored in directory: /root/.cache/pip/wheels/67/ff/9c/32ef7f63060382c02ba8b1f8f33fed59987378e119da38835f
  Running setup.py bdist_wheel for future ... done
  Stored in directory: /root/.cache/pip/wheels/8b/99/a0/81daf51dcd359a9377b110a8a886b3895921802d2fc1b2397e
  Running setup.py bdist_wheel for Flask-Silk ... done
  Stored in directory: /root/.cache/pip/wheels/58/d6/38/94efca8a2a27bdbfb771ef358684f0621a5d99481c8a506f9a
Successfully built imutils PyYAML interface future Flask-Silk
Installing collected packages: numpy, opencv-python, python-chess, ndjson, requests, berserk, python-lichess, imutils, click, Werkzeug, Jinja2, itsdangerous, Flask, aniso8601, Flask-RESTful, future, Flask-Silk, Flask-AutoIndex, PyYAML, mss, Pillow, jsonpickle, zope.event, zope.schema, interface, py, atomicwrites, more-itertools, zipp, importlib-metadata, pluggy, attrs, pytest, cycler, kiwisolver, pyparsing, matplotlib, scipy, coverage, pytest-cov
  Found existing installation: requests 2.18.4
    Not uninstalling requests at /usr/lib/python3/dist-packages, outside environment /usr
  Found existing installation: PyYAML 3.12
    Not uninstalling pyyaml at /usr/lib/python3/dist-packages, outside environment /usr
  Found existing installation: Pillow 5.1.0
    Not uninstalling pillow at /usr/lib/python3/dist-packages, outside environment /usr
Successfully installed Flask-1.1.1 Flask-AutoIndex-0.6.4 Flask-RESTful-0.3.7 Flask-Silk-0.2 Jinja2-2.10.3 Pillow-6.2.1 PyYAML-5.1 Werkzeug-0.16.0 aniso8601-8.0.0 atomicwrites-1.3.0 attrs-19.3.0 berserk-0.3.1 click-7.0 coverage-5.0.1 cycler-0.10.0 future-0.18.2 importlib-metadata-1.3.0 imutils-0.5.3 interface-2.11.1 itsdangerous-1.1.0 jsonpickle-1.2 kiwisolver-1.1.0 matplotlib-2.2.3 more-itertools-8.0.2 mss-4.0.3 ndjson-0.1.0 numpy-1.18.0 opencv-python-4.1.2.30 pluggy-0.13.1 py-1.8.0 pyparsing-2.4.6 pytest-3.8.2 pytest-cov-2.8.1 python-chess-0.29.0 python-lichess-0.9 requests-2.22.0 scipy-1.2.2 zipp-0.6.0 zope.event-4.4 zope.schema-4.9.3

Test

scripts/test 
============================= test session starts =============================
platform linux -- Python 3.6.8, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
rootdir: /home/wf/source/python/play-chess-with-a-webcam
plugins: cov-2.8.1
collected 11 items                                                            

src/test_Board.py .                                                     [  9%]
src/test_ChessCam.py .                                                  [ 18%]
src/test_OpenCV_version.py .                                            [ 27%]
src/test_Video.py ...                                                   [ 54%]
src/test_findBoard.py .....                                             [100%]

----------- coverage: platform linux, python 3.6.8-final-0 -----------
Name                         Stmts   Miss  Cover
------------------------------------------------
src/Args.py                     10      7    30%
src/Board.py                    33      3    91%
src/BoardFinder.py             186     12    94%
src/Cell.py                     10      4    60%
src/ChessCam.py                 86     59    31%
src/InputManager.py             57     37    35%
src/MovementDetector.py         55     40    27%
src/StateDetector.py            92     75    18%
src/Video.py                   133     48    64%
src/mathUtils.py                49     25    49%
src/test_Board.py               23      3    87%
src/test_ChessCam.py             4      0   100%
src/test_OpenCV_version.py       6      0   100%
src/test_Video.py               28      0   100%
src/test_findBoard.py           49      0   100%
------------------------------------------------
TOTAL                          821    313    62%


============================= 11 passed in 32.41s =============================

Raspbian 10 buster

Modify requirements.txt

As of 2019-12 there is no current opencv for Raspbian and a few work-arounds are necessary.

git diff
diff --git a/pcwawc/requirements.txt b/pcwawc/requirements.txt
index 019d524..a277b59 100644
--- a/pcwawc/requirements.txt
+++ b/pcwawc/requirements.txt
@@ -3,7 +3,7 @@
 # runtime dependencies
 #
 # https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html
-opencv-python==4.1.2.30
+opencv-python==4.1.*
 # python-chess
 # https://buildmedia.readthedocs.org/media/pdf/python-chess/latest/python-chess.pdf
 python-chess==0.29.0

Install

scripts/install 
...
# to avoid warning later 
pip3 install --no-cache-dir cairocffi

Issue undefined symbol: __atomic_fetch_add_8

If you get:

undefined symbol: __atomic_fetch_add_8 

define this:

export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1.2.0

Test

scripts/run --input ../Chess-Testmedia/TK_scholarsmate30.avi --event 'PlayChessWithaWebCam' --site 'Stuttgart-Germany' --black OTB1 --white OTB2 --round 1 --warp '[[81,18],[271,15],[268,203],[85,203]]' --rotation 90 --nomoves
/usr/local/lib/python3.7/dist-packages/matplotlib/backends/backend_gtk3agg.py:16: UserWarning: The Gtk3Agg backend is known to not work on Python 3.x with pycairo. Try installing cairocffi.
  "The Gtk3Agg backend is known to not work on Python 3.x with pycairo. "
[Event "PlayChessWithaWebCam"]
[Site "Stuttgart-Germany"]
[Date "2019-12-28 20:17:35"]
[Round "1"]
[White "OTB2"]
[Black "OTB1"]
[Result "1-0"]

1. e4 e5 2. Qh5 Nc6 3. Bc4 Nf6 4. Qxf7# 1-0

Raspbian 9.8 stretch (not successful)

Install

if the install fails e.g. with an Exception in urlopen you might want to restart the install.

scripts/install 
checking that python3  is installed on os Linux ...
/usr/bin/python3
checking that pip3  is installed on os Linux ...
/usr/bin/pip3
Collecting opencv-python (from -r requirements.txt (line 2))
  Using cached https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.4.19-cp35-cp35m-linux_armv7l.whl
Collecting pytest (from -r requirements.txt (line 4))
  Using cached https://files.pythonhosted.org/packages/0c/91/d68f68ce54cd3e8afa1ef73ea1ad44df2438521b64c0820e5fd9b9f13b7d/pytest-5.2.1-py3-none-any.whl
Collecting matplotlib (from -r requirements.txt (line 6))
  Using cached https://www.piwheels.org/simple/matplotlib/matplotlib-3.0.3-cp35-cp35m-linux_armv7l.whl
Collecting scipy (from -r requirements.txt (line 8))
  Using cached https://www.piwheels.org/simple/scipy/scipy-1.3.1-cp35-cp35m-linux_armv7l.whl
Collecting pytest-cov (from -r requirements.txt (line 10))
  Using cached https://files.pythonhosted.org/packages/b9/54/3673ee8be482f81527678ac894276223b9814bb7262e4f730469bb7bf70e/pytest_cov-2.8.1-py2.py3-none-any.whl
Collecting python-chess (from -r requirements.txt (line 12))
  Using cached https://files.pythonhosted.org/packages/58/70/72dc875a30ac7f26e0bec45714d67b19e0f498de920323b906995a741a88/python_chess-0.28.3-py3-none-any.whl
Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python3/dist-packages (from opencv-python->-r requirements.txt (line 2))
Collecting pathlib2>=2.2.0; python_version < "3.6" (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/e9/45/9c82d3666af4ef9f221cbb954e1d77ddbb513faf552aea6df5f37f1a4859/pathlib2-2.3.5-py2.py3-none-any.whl
Collecting packaging (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/cf/94/9672c2d4b126e74c4496c6b3c58a8b51d6419267be9e70660ba23374c875/packaging-19.2-py2.py3-none-any.whl
Collecting atomicwrites>=1.0 (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/52/90/6155aa926f43f2b2a22b01be7241be3bfd1ceaf7d0b3267213e8127d41f4/atomicwrites-1.3.0-py2.py3-none-any.whl
Collecting pluggy<1.0,>=0.12 (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/92/c7/48439f7d5fd6bddb4c04b850bb862b42e3e2b98570040dfaf68aedd8114b/pluggy-0.13.0-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/76/bc/394ad449851729244a97857ee14d7cba61ddb268dce3db538ba2f2ba1f0f/py-1.8.0-py2.py3-none-any.whl (83kB)
    100% |████████████████████████████████| 92kB 2.1MB/s 
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/f6/d2/40b3fa882147719744e6aa50ac39cf7a22a913cbcba86a0371176c425a3b/importlib_metadata-0.23-py2.py3-none-any.whl
Collecting attrs>=17.4.0 (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting wcwidth (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/7e/9f/526a6947247599b084ee5232e4f9190a38f398d7300d866af3ab571a5bfe/wcwidth-0.1.7-py2.py3-none-any.whl
Collecting more-itertools>=4.0.0 (from pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/45/dc/3241eef99eb45f1def35cf93af35d1cf9ef4c0991792583b8f33ea41b092/more_itertools-7.2.0-py3-none-any.whl (57kB)
    100% |████████████████████████████████| 61kB 2.0MB/s 
Collecting kiwisolver>=1.0.1 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://www.piwheels.org/simple/kiwisolver/kiwisolver-1.1.0-cp35-cp35m-linux_armv7l.whl (912kB)
    100% |████████████████████████████████| 921kB 344kB/s 
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/11/fa/0160cd525c62d7abd076a070ff02b2b94de589f1a9789774f17d7c54058e/pyparsing-2.4.2-py2.py3-none-any.whl (65kB)
    100% |████████████████████████████████| 71kB 2.1MB/s 
Collecting python-dateutil>=2.1 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/41/17/c62faccbfbd163c7f57f3844689e3a78bae1f403648a6afb1d0866d87fbb/python_dateutil-2.8.0-py2.py3-none-any.whl (226kB)
    100% |████████████████████████████████| 235kB 1.2MB/s 
Collecting cycler>=0.10 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Collecting coverage>=4.4 (from pytest-cov->-r requirements.txt (line 10))
  Downloading https://www.piwheels.org/simple/coverage/coverage-4.5.4-cp35-cp35m-linux_armv7l.whl (210kB)
    100% |████████████████████████████████| 215kB 538kB/s 
Requirement already satisfied: six in /usr/lib/python3/dist-packages (from pathlib2>=2.2.0; python_version < "3.6"->pytest->-r requirements.txt (line 4))
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest->-r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/74/3d/1ee25a26411ba0401b43c6376d2316a71addcc72ef8690b101b4ea56d76a/zipp-0.6.0-py2.py3-none-any.whl
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from kiwisolver>=1.0.1->matplotlib->-r requirements.txt (line 6))
Installing collected packages: opencv-python, pathlib2, pyparsing, packaging, atomicwrites, more-itertools, zipp, importlib-metadata, pluggy, py, attrs, wcwidth, pytest, kiwisolver, python-dateutil, cycler, matplotlib, scipy, coverage, pytest-cov, python-chess
Successfully installed atomicwrites-1.3.0 attrs-19.3.0 coverage-4.5.4 cycler-0.10.0 importlib-metadata-0.23 kiwisolver-1.1.0 matplotlib-3.0.3 more-itertools-7.2.0 opencv-python-3.4.4.19 packaging-19.2 pathlib2-2.3.5 pluggy-0.13.0 py-1.8.0 pyparsing-2.4.2 pytest-5.2.1 pytest-cov-2.8.1 python-chess-0.28.3 python-dateutil-2.8.0 scipy-1.3.1 wcwidth-0.1.7 zipp-0.6.0

Test

if you run into the ImportError: libcblas.so.3: cannot open shared object file: No such file or directory error you might want to run both lines otherwise simply try the test script itself

pip3 install opencv-python; sudo apt-get install -y libcblas-dev libhdf5-dev libhdf5-serial-dev libatlas-base-dev libjasper-dev  libqtgui4  libqt4-test

run tests

scripts/test
...
ImportError: numpy.core.multiarray failed to import

The issue is that this project needs Python3.7 to work which can only be installed manually by compiling on stretch at this time (which i didn't try out ...)

Windows 7/10

  1. Download Python 3.7.3 from https://www.python.org/downloads/release/python-373/
    1. https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64.exe

Alternative: Install via Linux Subsystem

This installation uses a "hybrid approach" - we install the web elements e.g. javascript/css/fonts via bash script and then use the Windows native python and pip to proceed.

then follow the linux instructions

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install xdg-utils

Access files via Z:

cd pcwawc
pip install -r requirements.txt
cd ..
set PYTHONPATH=.;%PYTHONPATH%;