Difference between revisions of "PlayChessWithAWebCam"

From BITPlan Wiki
Jump to navigation Jump to search
Line 232: Line 232:
  
 
=== Code Structure ===
 
=== Code Structure ===
click classes to see source code at [https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src Play Chess With A WebCam github repository]
+
    click classes to see source code at [https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src Play Chess With A WebCam github repository]
 
   <uml>
 
   <uml>
 
     hide circle
 
     hide circle
 
     left to right direction
 
     left to right direction
  
   note top of GameEngine: This class is used to change the game state using StateClass.
+
   note top of SquareKind: kind of Square.
   class GameEngine [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/GameEngine.py]] {
+
   class SquareKind [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Field.py]] {
     __init__(argv)
+
     title(titles=["whitefield","blackfield","whitepiece","blackpiece"])
    mainLoop()
+
  }
     play()
+
 
 +
  class Channel [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/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/src/Field.py]] {
 
   class FieldState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/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/src/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/src/Field.py]] {
 +
    __init__(field,grid,roiIndex,relPixelLambda)
 +
    pixelList()
 +
    analyze(image)
 +
    interPolate(rx,ry)
 
   }
 
   }
  
  
   note top of Field: a single Field of a chessboard as observed from a WebCam.
+
   note top of Field: a single Field of a chess board as observed from a WebCam.
 
   class Field [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Field.py]] {
 
   class Field [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Field.py]] {
    drawDebug(video,image,color,borderColor=(0,0,0))
 
 
     getColor()
 
     getColor()
 
     analyzeColor(image,hsv,distance=1,step=1)
 
     analyzeColor(image,hsv,distance=1,step=1)
Line 256: Line 282:
 
     getFieldState()
 
     getFieldState()
 
     __init__(board,row,col)
 
     __init__(board,row,col)
 +
    getRect()
 +
    drawDebug(video,image,detectedFieldState)
 
     hsv_to_rgb(h,s,v)
 
     hsv_to_rgb(h,s,v)
 
     getPiece()
 
     getPiece()
 +
    divideInROIs(grid,roiLambda)
 
   }
 
   }
  
 +
  class DetectState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/detectstate.py]] {
 +
    invalidEnd()
 +
    validEnd()
 +
    check(validChanges,diffSum,diffSumDelta,meanFrameCount)
 +
    nextFrame()
 +
    __init__(validDiffSumTreshold,invalidDiffSumTreshold,diffSumDeltaTreshold,onPieceMoveDetected=None,onMoveDetected=None)
 +
  }
  
   note top of InputManager: manage the video input and supply frames.
+
 
   class InputManager [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/InputManager.py]] {
+
   note top of DetectColorState: detect state from Color Distribution.
     __init__(argv)
+
   class DetectColorState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/detectstate.py]] {
     getFrame()
+
     __init__(trapez)
 +
    squareState(fieldColorStats,tSquare,percent)
 +
    check(image,averageColors,drawDebug=False)
 +
    drawDebug()
 +
     inRange(stats,fs,percent)
 
   }
 
   }
  
Line 280: Line 320:
 
     piecesOfColor(color)
 
     piecesOfColor(color)
 
     setPgn(pgn)
 
     setPgn(pgn)
 +
    takeback()
 
     GetCellName(col,row)
 
     GetCellName(col,row)
 
     fieldStateCounts()
 
     fieldStateCounts()
 
     __init__(dominatorOffset=(0,-1))
 
     __init__(dominatorOffset=(0,-1))
 
     performMove(move)
 
     performMove(move)
 +
    getPgn()
 
     fieldAt(row,col)
 
     fieldAt(row,col)
 
     unicode()
 
     unicode()
     pgn()
+
     move(ucimove)
 +
  }
 +
 
 +
 
 +
  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/src/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/src/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()
 +
  }
 +
 
 +
 
 +
  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/src/game.py]] {
 +
    showDebug()
 +
    __init__(gameid)
 
   }
 
   }
  
   class Cell [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Cell.py]] {
+
 
     __repr__()
+
  note top of WebCamGame: keeps track of a webcam games state in a JavaScript compatible way to exchange game and webcam/board State information.
     __init__(coords)
+
   class WebCamGame [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/game.py]] {
     GetCoords()
+
     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.
 
   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/src/WebApp.py]] {
+
   class Warp [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/game.py]] {
 +
    updatePoints()
 
     rotate(angle)
 
     rotate(angle)
 
     addPoint(px,py)
 
     addPoint(px,py)
     __init__(rotation=0,bgrColor=(0,255,0))
+
     __init__(pointList=[],rotation=0,bgrColor=(0,255,0))
 +
  }
 +
 
 +
 
 +
  note top of Environment4Test: Test Environment.
 +
  class Environment4Test [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Environment4Test.py]] {
 +
    loadFromImageInfo(webApp,imageInfo)
 +
    __init__()
 +
    getImage(num)
 +
    prepareFromImageInfo(imageInfo)
 +
    getImageWithVideo(num)
 
   }
 
   }
  
Line 309: Line 396:
 
     chessFEN(fen)
 
     chessFEN(fen)
 
     genVideo(video)
 
     genVideo(video)
     chessPgn(pgn,fen)
+
     __init__(args,logger=None)
     genVideoStreamed(video)
+
     chessMove(move)
 
     chessForward()
 
     chessForward()
 +
    chessFindBoard()
 +
    log(msg)
 
     videoFeed()
 
     videoFeed()
 
     videoPause()
 
     videoPause()
     __init__(args,warpPointBGRColor=(0,255,0))
+
     videoRecord(path)
 
     chessWebCamClick(x,y,w,h)
 
     chessWebCamClick(x,y,w,h)
 +
    chessPgn(pgn)
 +
    chessSave()
 
     index(msg)
 
     index(msg)
     download(path,filename)
+
     #genVideoStreamed(video)
 +
    indexException(e)
 +
    chessGameState(gameid)
 +
    timeStamp()
 +
    chessGameColors()
 +
    setDebug(debug)
 +
    createNewCame()
 +
    photoDownload(path,filename)
 
     warpAndRotate(image)
 
     warpAndRotate(image)
 
     chessTakeback()
 
     chessTakeback()
Line 332: Line 430:
 
   }
 
   }
  
   class BadSegmentation [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/BoardFinder.py]] {
+
 
 +
  note top of Transformation: Transformation kind.
 +
  class Transformation [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/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/src/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/src/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)
 
   }
 
   }
  
   BadSegmentation --|> Exception
+
 
   class BoardFinder [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/BoardFinder.py]] {
+
   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.
     getBlackMaxSide(colorImage)
+
   class FieldState [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/ChessTrapezoid.py]] {
    setSide(side)
+
     title(titles=["whiteempty","whiteonwhite","blackonwhite","blackempty","whiteonblack","blackonblack"])
    __init__(inImage)
 
    calibrateCornerMarker(dotImage)
 
    rotateImage(image)
 
    GetFullImageBoard(rectCoordinates=None,rotations=None)
 
    prepare()
 
    DetectBoardOrientation()
 
    getDominatorOffset()
 
    GetChessBoardCoordinates(rotation)
 
    updateImage(inFrame)
 
 
   }
 
   }
  
   class BadImage [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/MovementDetector.py]] {
+
 
     __init__(value)
+
  note top of FieldColorStats: Color statistics for Fields.
 +
  class FieldColorStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/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/src/ChessTrapezoid.py]] {
 +
    colorRange(rangeFactor)
 +
    fixMeans(means,stds,pixels,nonzero)
 +
     __init__(image)
 +
    fix(value)
 
     __str__()
 
     __str__()
 +
    countNonZero(image)
 
   }
 
   }
  
  BadImage --|> Exception
 
  
   note top of MovementDetector: This class used to detect if a move has occured in the board.
+
   note top of SquareChange: keep track of changes of a square over time.
   class MovementDetector [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/MovementDetector.py]] {
+
   class SquareChange [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/ChessTrapezoid.py]] {
     _getMovements()
+
     push(stats,value)
    detectMove(colorImage)
+
     __init__(value,stats)
     __init__(colorImage)
 
    _changeState(newBoard,newImage)
 
 
   }
 
   }
  
   class ArenaQuit [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/uci.py]] {
+
 
 +
  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/src/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)
 
   }
 
   }
  
  ArenaQuit --|> Exception
 
  
   note top of Uci: This class interacts with stdin and stdout with Arena in the UCI.
+
   note top of Corners: Chess board corners.
   class Uci [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/uci.py]] {
+
  class Corners [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/boardfinder.py]] {
     _setPosition(tokens)
+
    sortXY(xy)
     getResponse()
+
    trapezColRows(cols,rows)
     sendMove(move)
+
    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)
 +
  }
 +
 
 +
 
 +
  note top of BoardFinder: find a chess board in the given image.
 +
   class BoardFinder [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/boardfinder.py]] {
 +
     drawPolygon(image,pos,polygon,whiteColor,blackColor)
 +
    findChessBoard(image,title)
 +
    expand(image,title,histograms,corners)
 +
    getColorFiltered(image,histograms,title,corners)
 +
    maskPolygon(image,polygon)
 +
    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)
 
   }
 
   }
  
Line 382: Line 566:
 
     writeJson(name,postfix=".json")
 
     writeJson(name,postfix=".json")
 
     readJson(name,postfix=".json")
 
     readJson(name,postfix=".json")
 +
    asJson()
 +
  }
 +
 +
 +
  note top of MovingAverage: calculate a moving average.
 +
  class MovingAverage [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/RunningStats.py]] {
 +
    __init__(maxlen)
 +
    push(value)
 +
    mean()
 
   }
 
   }
  
 +
  class MinMaxMixin    [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/RunningStats.py]] {
 +
    pushMinMax(value)
 +
    formatMinMax(formatM="%.1f-%.1f")
 +
    initMinMax()
 +
    __str__()
 +
  }
  
   note top of RunningStats: calculate mean, variance and standard deviation in one pass using Welfford's algorithm.
+
 
 +
   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/src/RunningStats.py]] {
 
   class RunningStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/RunningStats.py]] {
 +
    format(formatS="%d%.1f±%.1f")
 
     variance()
 
     variance()
 
     __init__()
 
     __init__()
 +
    __str__()
 
     standard_deviation()
 
     standard_deviation()
 
     clear()
 
     clear()
 
     mean()
 
     mean()
 
     push(xvalue)
 
     push(xvalue)
 +
  }
 +
 +
 +
  note top of MinMaxStats: running statistics with minimum and maximum.
 +
  class MinMaxStats [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/RunningStats.py]] {
 +
    formatMinMax(formatR="%d%.1f±%.1f",formatM="%.1f-%.1f")
 +
    __init__()
 +
    push(value)
 
   }
 
   }
  
Line 405: Line 615:
 
     square(value)
 
     square(value)
 
     standard_deviation()
 
     standard_deviation()
 +
    clear()
 
     rgbColorKey()
 
     rgbColorKey()
 
     mean()
 
     mean()
Line 413: Line 624:
 
   class WebChessCamArgs [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/webchesscam.py]] {
 
   class WebChessCamArgs [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/webchesscam.py]] {
 
     chessWebCamClick(width,height)
 
     chessWebCamClick(width,height)
 +
    autoindex(path='.')
 
     __init__(argv)
 
     __init__(argv)
    chessPgn()
 
 
     chessMove(move)
 
     chessMove(move)
 
     chessForward()
 
     chessForward()
     download(filename)
+
     chessFindBoard()
 +
    photoDownload(filename)
 +
    chessSave()
 +
    chessUpdate()
 
     video_pause()
 
     video_pause()
 
     video_feed()
 
     video_feed()
 +
    chessGameState(gameid)
 +
    chessGameColors()
 
     chessTakeback()
 
     chessTakeback()
 
     chessDebug()
 
     chessDebug()
Line 425: Line 641:
 
     photo()
 
     photo()
 
     videoRotate90()
 
     videoRotate90()
 +
    video_record()
 
     home()
 
     home()
 
   }
 
   }
Line 438: Line 655:
 
   }
 
   }
  
  class UserExit [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/ChessCam.py]] {
 
  }
 
 
  UserExit --|> Exception
 
  
   note top of ChessCam: Chess Camera get next move by analyzing movements.
+
   note top of Environment: Runtime Environment.
   class ChessCam [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/ChessCam.py]] {
+
   class Environment [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Environment.py]] {
 
     __init__()
 
     __init__()
     analyzeFrame()
+
     checkDir(path)
    playChessWithCam(args)
 
    prepare(argv)
 
    getNextMove()
 
    getDominatorOffset()
 
    detectMovement()
 
    playChessWithCamMoves()
 
 
   }
 
   }
  
  
   note top of Args: This class parses command line arguments and generates a usage.
+
   note top of PlotType: kind of Plot.
  class Args [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Args.py]] {
+
   class PlotType [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/PlotLib.py]] {
    __init__(args)
 
  }
 
 
 
   class CannotBuildStateException [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/StateDetector.py]] {
 
    __init__(value)
 
    __str__()
 
 
   }
 
   }
  
  CannotBuildStateException --|> Exception
+
   class PlotLib [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/PlotLib.py]] {
   class StateDetector [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/StateDetector.py]] {
+
     __init__(title,pagesize,imagesPerPage=4)
     _divideInCells()
+
    addPlot(image,imageTitle,xvalues=[],yvalues=[],isBGR=False)
     detectState(colorImage)
+
    addInfos(pdf,infos)
     _findIntersects()
+
    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)
 
   }
 
   }
  
Line 476: Line 686:
 
   note top of Video: Video handling e.g. recording/writing
 
   note top of Video: Video handling e.g. recording/writing
 
   class Video [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Video.py]] {
 
   class Video [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/Video.py]] {
     record(prefix,printHints=True)
+
     prepareRecording(filename,width,height,fps=None)
     imencode(frame,format=".jpg")
+
    readImage(filePath)
     pause(ispaused)
+
    drawText(frame,text,bottomLeftCornerOfText,font,fontScale,fontBGRColor,lineThickness)
     rotate(image,angle,center=None,scale=1.0)
+
    still(prefix,imgformat="jpg",close=True,printHints=True,show=False,postProcess=None)
     open(filePath)
+
    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)
    timeStamp(separator='',timeseparator='')
 
    is_int(s)
 
 
     checkFilePath(filePath,raiseException=True)
 
     checkFilePath(filePath,raiseException=True)
 +
    open(filePath)
 +
    sumIntensity(image)
 +
    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__()
 
     __init__()
    sumIntensity(image)
 
    drawTrapezoid(image,points,color)
 
    readFrame(show=False,postProcess=None)
 
 
     drawCircle(image,center,radius=10,color=(0,255,0),thickness=1)
 
     drawCircle(image,center,radius=10,color=(0,255,0),thickness=1)
 +
    timeStamp(separator='',timeseparator='')
 
     readJpgImage(show=False,postProcess=None)
 
     readJpgImage(show=False,postProcess=None)
 +
    pause(ispaused)
 +
    fileTimeStamp()
 
     getSubRect(image,rect)
 
     getSubRect(image,rect)
    drawRectangle(image,pt1,pt2,color=(0,255,0),thickness=1)
 
    play()
 
    setup(cap)
 
    addTimeStamp(frame,withFrames=True,withFPS=True,fontBGRColor=(0,255,0),fontScale=1.0,font=cv2.FONT_HERSHEY_SIMPLEX,lineThickness=2)
 
    warp(image,pts,squared=True)
 
    fileTimeStamp()
 
    showImage(image,title,keyCheck=True,keyWait=5)
 
    still(prefix,format="jpg",close=True,printHints=True,show=False,postProcess=None)
 
    checkCap()
 
    capture(device)
 
    houghTransformP(image)
 
    createBlank(width,height,rgb_color=(0,0,0))
 
 
     still2File(filename,format="jpg",close=True,printHints=True,show=False,postProcess=None)
 
     still2File(filename,format="jpg",close=True,printHints=True,show=False,postProcess=None)
     close()
+
     getEmptyImage4WidthAndHeight(w,h,channels)
     paused()
+
     rotate(image,angle,center=None,scale=1.0)
     readImage(filePath)
+
     showAndWriteImage(image,title,path="/tmp/",imageFormat=".jpg",keyCheck=True,keyWait=5)
 
   }
 
   }
  
Line 524: Line 743:
 
   note top of BoardDetector: detect a chess board's state from the given image.
 
   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/src/BoardDetector.py]] {
 
   class BoardDetector [[https://github.com/WolfgangFahl/play-chess-with-a-webcam/tree/master/src/BoardDetector.py]] {
     __init__(board,video)
+
     divideInFields(image)
 +
    sortByFieldState()
 +
    genFields()
 
     analyze(image,frameIndex,distance=3,step=1)
 
     analyze(image,frameIndex,distance=3,step=1)
 
     analyzeColors(image,distance=3,step=1)
 
     analyzeColors(image,distance=3,step=1)
 +
    analyzeFields(image,grid,roiLambda)
 +
    __init__(board,video,speedup=1)
 
   }
 
   }
  
Line 551: Line 774:
 
   skinparam noteFontSize 14
 
   skinparam noteFontSize 14
 
</uml>
 
</uml>
 +
  
  

Revision as of 05:49, 8 December 2019

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

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.

State of Project

As of 2019-12-07 version 0.0.1 has not been released yet. The state of the project is development/alpha.

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 e.g. with:

scripts/install
scripts/runweb --input testMedia/scholarsmate.avi --debug --warp '[[140,7],[506,10],[507,378],[136,373]]' --rotation 270

to tryout the Scholars Mate example video 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

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
Get:1 http://de.archive.ubuntu.com/ubuntu bionic-updates/main amd64 libexpat1-dev amd64 2.2.5-3ubuntu0.2 [122 kB]
Get:2 http://de.archive.ubuntu.com/ubuntu bionic-updates/main amd64 libpython3.6-dev amd64 3.6.8-1~18.04.3 [44,8 MB]
Get:3 http://de.archive.ubuntu.com/ubuntu bionic-updates/main amd64 libpython3-dev amd64 3.6.7-1~18.04 [7.328 B]
Get:4 http://de.archive.ubuntu.com/ubuntu bionic-updates/universe amd64 python-pip-whl all 9.0.1-2.3~ubuntu1.18.04.1 [1.653 kB]
Get:5 http://de.archive.ubuntu.com/ubuntu bionic-updates/main amd64 python3.6-dev amd64 3.6.8-1~18.04.3 [508 kB]
Get:6 http://de.archive.ubuntu.com/ubuntu bionic-updates/main amd64 python3-dev amd64 3.6.7-1~18.04 [1.288 B]
Get:7 http://de.archive.ubuntu.com/ubuntu bionic-updates/universe amd64 python3-pip all 9.0.1-2.3~ubuntu1.18.04.1 [114 kB]
Get:8 http://de.archive.ubuntu.com/ubuntu bionic/main amd64 python3-setuptools all 39.0.1-2 [248 kB]
Get:9 http://de.archive.ubuntu.com/ubuntu bionic/universe amd64 python3-wheel all 0.30.0-0.2 [36,5 kB]
Fetched 47,5 MB in 7s (7.072 kB/s)                                            
Selecting previously unselected package libexpat1-dev:amd64.
(Reading database ... 198536 files and directories currently installed.)
Preparing to unpack .../0-libexpat1-dev_2.2.5-3ubuntu0.2_amd64.deb ...
Unpacking libexpat1-dev:amd64 (2.2.5-3ubuntu0.2) ...
Selecting previously unselected package libpython3.6-dev:amd64.
Preparing to unpack .../1-libpython3.6-dev_3.6.8-1~18.04.3_amd64.deb ...
Unpacking libpython3.6-dev:amd64 (3.6.8-1~18.04.3) ...
Selecting previously unselected package libpython3-dev:amd64.
Preparing to unpack .../2-libpython3-dev_3.6.7-1~18.04_amd64.deb ...
Unpacking libpython3-dev:amd64 (3.6.7-1~18.04) ...
Selecting previously unselected package python-pip-whl.
Preparing to unpack .../3-python-pip-whl_9.0.1-2.3~ubuntu1.18.04.1_all.deb ...
Unpacking python-pip-whl (9.0.1-2.3~ubuntu1.18.04.1) ...
Selecting previously unselected package python3.6-dev.
Preparing to unpack .../4-python3.6-dev_3.6.8-1~18.04.3_amd64.deb ...
Unpacking python3.6-dev (3.6.8-1~18.04.3) ...
Selecting previously unselected package python3-dev.
Preparing to unpack .../5-python3-dev_3.6.7-1~18.04_amd64.deb ...
Unpacking python3-dev (3.6.7-1~18.04) ...
Selecting previously unselected package python3-pip.
Preparing to unpack .../6-python3-pip_9.0.1-2.3~ubuntu1.18.04.1_all.deb ...
Unpacking python3-pip (9.0.1-2.3~ubuntu1.18.04.1) ...
Selecting previously unselected package python3-setuptools.
Preparing to unpack .../7-python3-setuptools_39.0.1-2_all.deb ...
Unpacking python3-setuptools (39.0.1-2) ...
Selecting previously unselected package python3-wheel.
Preparing to unpack .../8-python3-wheel_0.30.0-0.2_all.deb ...
Unpacking python3-wheel (0.30.0-0.2) ...
Setting up python-pip-whl (9.0.1-2.3~ubuntu1.18.04.1) ...
Setting up python3-wheel (0.30.0-0.2) ...
Setting up python3-pip (9.0.1-2.3~ubuntu1.18.04.1) ...
Setting up libexpat1-dev:amd64 (2.2.5-3ubuntu0.2) ...
Setting up python3-setuptools (39.0.1-2) ...
Setting up libpython3.6-dev:amd64 (3.6.8-1~18.04.3) ...
Setting up python3.6-dev (3.6.8-1~18.04.3) ...
Setting up libpython3-dev:amd64 (3.6.7-1~18.04) ...
Setting up python3-dev (3.6.7-1~18.04) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for doc-base (0.10.8) ...
Processing 1 added doc-base file...
Collecting opencv-python (from -r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/5e/7e/bd5425f4dacb73367fddc71388a47c1ea570839197c2bcad86478e565186/opencv_python-4.1.1.26-cp36-cp36m-manylinux1_x86_64.whl (28.7MB)
    100% |████████████████████████████████| 28.7MB 30kB/s 
Collecting pytest (from -r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/0c/91/d68f68ce54cd3e8afa1ef73ea1ad44df2438521b64c0820e5fd9b9f13b7d/pytest-5.2.1-py3-none-any.whl (226kB)
    100% |████████████████████████████████| 235kB 2.5MB/s 
Collecting matplotlib (from -r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/57/4f/dd381ecf6c6ab9bcdaa8ea912e866dedc6e696756156d8ecc087e20817e2/matplotlib-3.1.1-cp36-cp36m-manylinux1_x86_64.whl (13.1MB)
    100% |████████████████████████████████| 13.1MB 69kB/s 
Collecting scipy (from -r requirements.txt (line 8))
  Downloading https://files.pythonhosted.org/packages/29/50/a552a5aff252ae915f522e44642bb49a7b7b31677f9580cfd11bcc869976/scipy-1.3.1-cp36-cp36m-manylinux1_x86_64.whl (25.2MB)
    100% |████████████████████████████████| 25.2MB 34kB/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)
    100% |████████████████████████████████| 133kB 3.5MB/s 
Collecting numpy>=1.11.3 (from opencv-python->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/0e/46/ae6773894f7eacf53308086287897ec568eac9768918d913d5b9d366c5db/numpy-1.17.3-cp36-cp36m-manylinux1_x86_64.whl (20.0MB)
    100% |████████████████████████████████| 20.0MB 45kB/s 
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 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 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 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 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 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 4.4MB/s 
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 4.8MB/s 
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/lib/python3/dist-packages (from matplotlib->-r requirements.txt (line 6))
Requirement already satisfied: python-dateutil>=2.1 in /usr/lib/python3/dist-packages (from matplotlib->-r requirements.txt (line 6))
Collecting kiwisolver>=1.0.1 (from matplotlib->-r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/f8/a1/5742b56282449b1c0968197f63eae486eca2c35dcd334bab75ad524e0de1/kiwisolver-1.1.0-cp36-cp36m-manylinux1_x86_64.whl (90kB)
    100% |████████████████████████████████| 92kB 5.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://files.pythonhosted.org/packages/51/b1/13609068fff1c8c056f0c4601ad6985cf5c1bbfc529196ab08bd2a57dc39/coverage-4.5.4-cp36-cp36m-manylinux1_x86_64.whl (205kB)
    100% |████████████████████████████████| 215kB 2.8MB/s 
Requirement already satisfied: six in /usr/lib/python3/dist-packages (from packaging->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: numpy, opencv-python, more-itertools, zipp, importlib-metadata, pluggy, atomicwrites, packaging, wcwidth, attrs, py, pytest, kiwisolver, 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.1.1 more-itertools-7.2.0 numpy-1.17.3 opencv-python-4.1.1.26 packaging-19.2 pluggy-0.13.0 py-1.8.0 pytest-5.2.1 pytest-cov-2.8.1 python-chess-0.28.3 scipy-1.3.1 wcwidth-0.1.7 zipp-0.6.0

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 =============================

Rapspbian 9.8 stretch

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

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