Create Iterable mouse click event in Python? - python-3.x

I am trying to show image to user and asking to click on 4 points for a rectangle from user and once user is done he will press 'c' and exit and my script should return the touch points by user.
For this approach I have written below script using OpenCV,, but not sure how to make class for this purpose iterable, might be I am wrong with some OO technical part but requirement and logic is correct because when not created inside class both functions works fine.
Code:
class mouse_select_points:
''' Select 4 user points from user and crop to straighten'''
__depends__ = ['img_path']
__provides__ = ['ratio','image_resized','click_points']
def __init__(self, thickness=2,shape=(400,600),click_count=0,click_points=[],img_path=""):
self.thickness = thickness
self.shape = shape
self.lent = click_count
self.refPt = click_points
self.img = img_path
self.font = cv2.FONT_HERSHEY_SIMPLEX
def __call__(self):
image = cv2.imread(self.img)
print("first loaded image size:",image.shape)
orig_resized = image.copy() #create a copy of resized image
ratio = image.shape[1] / 600.0
self.shape = image.shape
cv2.namedWindow("image")
cv2.setMouseCallback("image", self._click_and_crop, param = [image] ) #setting param as image to be sent to mouse click function callback
# keep looping until the 'c' key is pressed
while True:
# display the image and wait for a keypress
cv2.imshow("image", image)
cv2.putText(image,"press 'c' to crop or 'r' to reset",(10,15), self.font, .5,(255,255,255),1,cv2.LINE_AA)
key = cv2.waitKey(1) & 0xFF
# if the 'c' key is pressed, break from the loop
elif key == ord("c") and self.lent == 4:
break
return ratio,orig_resized,self.refPt
def _click_and_crop(self,event, x, y, flags, param):
image = param[0]
# if the left mouse button was clicked, record the starting
# (x, y) coordinates and indicate that cropping is being performed
if event == cv2.EVENT_LBUTTONDOWN:
self.refPt.append([x, y])
cv2.circle(image,(int(x),int(y)),self.thickness,(255,1,255),-1)
self.lent += 1
print("inside if")
cv2.imshow("image", image)
##testing
ratio,orig_image = mouse_select_points(img_path=r"Image1.JPG")

I think you want to pick the points repeatly. Here is it.
#!/usr/bin/python3
# 2018.06.13 13:40:12 CST
# 2018.06.13 14:17:49 CST
import cv2
class PickPoints:
''' Select 4 user points from user and crop to straighten'''
__depends__ = ['img_path']
__provides__ = ['ratio','image_resized','click_points']
def __init__(self, thickness=2,shape=(400,600),click_count=0,click_points=[],img_path=""):
self.thickness = thickness
self.shape = shape
self.lent = click_count
self.refPt = click_points
self.img = img_path
self.font = cv2.FONT_HERSHEY_SIMPLEX
def __call__(self):
image = cv2.imread(self.img)
#print("first loaded image size:",image.shape)
print("="*60)
orig_resized = image.copy() #create a copy of resized image
self.shape = image.shape
self.lent = 0
self.refPt = []
self.to_exit = False
cv2.namedWindow("image")
cv2.setMouseCallback("image", self._click_and_crop, param = [image] ) #setting param as image to be sent to mouse click function callback
# keep looping until the 'c' key is pressed
while True:
# display the image and wait for a keypress
cv2.imshow("image", image)
cv2.putText(image,"press 'c' to crop or 'r' to reset",(10,15), self.font, .5,(255,255,255),1,cv2.LINE_AA)
key = cv2.waitKey(30) & 0xFF
# if the 'c' key is pressed, break from the loop
if key == ord("r"):
print("Reset")
self.lent = 0
self.refPt = []
image[:] = orig_resized
if key == ord("c"):
pass
if self.to_exit or key in (27, ord('q'), ord('Q')):
print("Exist")
cv2.destroyAllWindows()
self.to_exit = False
break
return self.refPt
def _click_and_crop(self,event, x, y, flags, param):
image = param[0]
# if the left mouse button was clicked, record the starting
# (x, y) coordinates and indicate that cropping is being performed
if event == cv2.EVENT_LBUTTONDOWN:
if len(self.refPt) <4:
self.refPt.append([x, y])
cv2.circle(image,(int(x),int(y)),self.thickness,(0,255,0),-1)
self.lent += 1
print("#{} {}".format(self.lent, self.refPt[-1]))
cv2.imshow("image", image)
if event == cv2.EVENT_RBUTTONDOWN:
self.to_exit = True
##testing
fname = "/home/auss/Pictures/test.png"
pk = PickPoints(img_path=fname)
print(pk())
print(pk())
print(pk())

Related

How To drag an image object in WxPython GUI?

In below code, I have image shaped transparent window and a image inside of it, I would like to move the image(screw photo)by mouse. I wrote a bind function for that screw image but it does not move? what might be the problem?
As it can be seen I added images and bind functions. Is there a missing logic?
import wx
from wx import *
import wx.lib.statbmp as sb
from io import StringIO
# Create a .png image with something drawn on a white background
# and put the path to it here.
IMAGE_PATH = './wood.png'
class ShapedFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Shaped Window",
style = wx.FRAME_SHAPED | wx.SIMPLE_BORDER | wx.STAY_ON_TOP)
self.hasShape = False
self.delta = wx.Point(0,0)
# Load the image
image = wx.Image(IMAGE_PATH, wx.BITMAP_TYPE_PNG)
image.SetMaskColour(255,255,255)
image.SetMask(True)
self.bmp = wx.Bitmap(image)
self.SetClientSize((self.bmp.GetWidth(), self.bmp.GetHeight()))
dc = wx.ClientDC(self)
dc.DrawBitmap(self.bmp, 0,0, True)
self.SetWindowShape()
self.Bind(wx.EVT_RIGHT_UP, self.OnExit)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_WINDOW_CREATE, self.SetWindowShape)
panel = MyPanel(parent=self)
def SetWindowShape(self, evt=None):
r = wx.Region(self.bmp)
self.hasShape = self.SetShape(r)
def OnDoubleClick(self, evt):
if self.hasShape:
self.SetShape(wx.Region())
self.hasShape = False
else:
self.SetWindowShape()
def OnPaint(self, evt):
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bmp, 0,0, True)
def OnExit(self, evt):
self.Close()
def OnLeftDown(self, evt):
self.CaptureMouse()
pos = self.ClientToScreen(evt.GetPosition())
origin = self.GetPosition()
self.delta = wx.Point(pos.x - origin.x, pos.y - origin.y)
def OnMouseMove(self, evt):
if evt.Dragging() and evt.LeftIsDown():
pos = self.ClientToScreen(evt.GetPosition())
newPos = (pos.x - self.delta.x, pos.y - self.delta.y)
self.Move(newPos)
def OnLeftUp(self, evt):
if self.HasCapture():
self.ReleaseMouse()
class MyPanel(wx.Panel):
# A panel is a window on which controls are placed. (e.g. buttons and text boxes)
# wx.Panel class is usually put inside a wxFrame object. This class is also inherited from wxWindow class.
def __init__(self,parent):
super().__init__(parent=parent)
MyImage(self)
class MyImage(wx.StaticBitmap):
def __init__(self,parent):
super().__init__(parent=parent)
jpg1 = wx.Image('./Images/screwsmall.png', wx.BITMAP_TYPE_ANY).ConvertToBitmap()
# bitmap upper left corner is in the position tuple (x, y) = (5, 5)
self.myImage = wx.StaticBitmap(parent, -1, jpg1, (10 + jpg1.GetWidth(), 5), (jpg1.GetWidth(), jpg1.GetHeight()))
self.myImage.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.myImage.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
def OnMouseMove(self, evt):
if evt.Dragging() and evt.LeftIsDown():
pos = self.ClientToScreen(evt.GetPosition())
newPos = (pos.x - self.delta.x, pos.y - self.delta.y)
self.Move(newPos)
def OnLeftUp(self, evt):
if self.HasCapture():
self.ReleaseMouse()
def OnLeftDown(self, evt):
self.CaptureMouse()
pos = self.ClientToScreen(evt.GetPosition())
origin = self.GetPosition()
self.delta = wx.Point(pos.x - origin.x, pos.y - origin.y)
if __name__ == '__main__':
app = wx.App()
ShapedFrame().Show()
app.MainLoop()
Visual output of my code you can use different shapes in local directory. To install wxpython for 3.x you can check this link https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04/ download your version for ubuntu and use pip install command.
I am going to put my answer. As it can be seen in the #RolfofSaxony comment, there is a drag image demo inside the WXPYTHON tar file. In that DragImage.py file there are two different classes do the dragging job. I modified those functions and wrote my own two class. You can use these classes in your code as a component. My code is working and tested.
class DragShape:
def __init__(self, bmp):
self.bmp = bmp
self.pos = (0,0)
self.shown = True
self.text = None
self.fullscreen = False
def HitTest(self, pt):
rect = self.GetRect()
return rect.Contains(pt)
def GetRect(self):
return wx.Rect(self.pos[0], self.pos[1],
self.bmp.GetWidth(), self.bmp.GetHeight())
def Draw(self, dc, op = wx.COPY):
if self.bmp.IsOk():
memDC = wx.MemoryDC()
memDC.SelectObject(self.bmp)
dc.Blit(self.pos[0], self.pos[1],
self.bmp.GetWidth(), self.bmp.GetHeight(),
memDC, 0, 0, op, True)
return True
else:
return False
#----------------------------------------------------------------------
class DragCanvas(wx.ScrolledWindow):
def __init__(self, parent, ID):
wx.ScrolledWindow.__init__(self, parent, ID)
self.shapes = []
self.dragImage = None
self.dragShape = None
self.hiliteShape = None
self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
bmp = images.TheKid.GetBitmap()
shape = DragShape(bmp)
shape.pos = (200, 5)
self.shapes.append(shape)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
# We're not doing anything here, but you might have reason to.
# for example, if you were dragging something, you might elect to
# 'drop it' when the cursor left the window.
def OnLeaveWindow(self, evt):
pass
# Go through our list of shapes and draw them in whatever place they are.
def DrawShapes(self, dc):
for shape in self.shapes:
if shape.shown:
shape.Draw(dc)
# This is actually a sophisticated 'hit test', but in this
# case we're also determining which shape, if any, was 'hit'.
def FindShape(self, pt):
for shape in self.shapes:
if shape.HitTest(pt):
return shape
return None
# Fired whenever a paint event occurs
def OnPaint(self, evt):
dc = wx.PaintDC(self)
self.PrepareDC(dc)
self.DrawShapes(dc)
# print('OnPaint')
# Left mouse button is down.
def OnLeftDown(self, evt):
# Did the mouse go down on one of our shapes?
shape = self.FindShape(evt.GetPosition())
# If a shape was 'hit', then set that as the shape we're going to
# drag around. Get our start position. Dragging has not yet started.
# That will happen once the mouse moves, OR the mouse is released.
if shape:
self.dragShape = shape
self.dragStartPos = evt.GetPosition()
# Left mouse button up.
def OnLeftUp(self, evt):
if not self.dragImage or not self.dragShape:
self.dragImage = None
self.dragShape = None
return
# Hide the image, end dragging, and nuke out the drag image.
self.dragImage.Hide()
self.dragImage.EndDrag()
self.dragImage = None
if self.hiliteShape:
self.RefreshRect(self.hiliteShape.GetRect())
self.hiliteShape = None
# reposition and draw the shape
# Note by jmg 11/28/03
# Here's the original:
#
# self.dragShape.pos = self.dragShape.pos + evt.GetPosition() - self.dragStartPos
#
# So if there are any problems associated with this, use that as
# a starting place in your investigation. I've tried to simulate the
# wx.Point __add__ method here -- it won't work for tuples as we
# have now from the various methods
#
# There must be a better way to do this :-)
#
self.dragShape.pos = (
self.dragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0],
self.dragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1]
)
self.dragShape.shown = True
self.RefreshRect(self.dragShape.GetRect())
self.dragShape = None
# The mouse is moving
def OnMotion(self, evt):
# Ignore mouse movement if we're not dragging.
if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
return
# if we have a shape, but haven't started dragging yet
if self.dragShape and not self.dragImage:
# only start the drag after having moved a couple pixels
tolerance = 2
pt = evt.GetPosition()
dx = abs(pt.x - self.dragStartPos.x)
dy = abs(pt.y - self.dragStartPos.y)
if dx <= tolerance and dy <= tolerance:
return
# refresh the area of the window where the shape was so it
# will get erased.
self.dragShape.shown = False
self.RefreshRect(self.dragShape.GetRect(), True)
self.Update()
item = self.dragShape.text if self.dragShape.text else self.dragShape.bmp
self.dragImage = wx.DragImage(item,
wx.Cursor(wx.CURSOR_HAND))
hotspot = self.dragStartPos - self.dragShape.pos
self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)
self.dragImage.Move(pt)
self.dragImage.Show()
# if we have shape and image then move it, posibly highlighting another shape.
elif self.dragShape and self.dragImage:
onShape = self.FindShape(evt.GetPosition())
unhiliteOld = False
hiliteNew = False
# figure out what to hilite and what to unhilite
if self.hiliteShape:
if onShape is None or self.hiliteShape is not onShape:
unhiliteOld = True
if onShape and onShape is not self.hiliteShape and onShape.shown:
hiliteNew = True
# if needed, hide the drag image so we can update the window
if unhiliteOld or hiliteNew:
self.dragImage.Hide()
if unhiliteOld:
dc = wx.ClientDC(self)
self.hiliteShape.Draw(dc)
self.hiliteShape = None
if hiliteNew:
dc = wx.ClientDC(self)
self.hiliteShape = onShape
self.hiliteShape.Draw(dc, wx.INVERT)
# now move it and show it again if needed
self.dragImage.Move(evt.GetPosition())
if unhiliteOld or hiliteNew:
self.dragImage.Show()

Memory game using pygame

I am making a memory game for an assignment. I can get all the tiles to be covered and make them reveal themselves upon being clicked on but I cannot cover them after they have been clicked on or match them. I dont know how to match the tiles also.
class Tile:
surface = None
border_size = 3
border_color = pygame.Color('black')
# An object in this class represents a Dot that moves
#classmethod
def set_surface(cls,game_surface):
cls.surface = game_surface
# instance method
def __init__(self,x , y, image, cover):
self.image = image
self.cover = cover
self.covered = True
self.time_cover = None
# self.timer = pygame.time.get_ticks()
width = self.image.get_width()
height = self.image.get_height()
self.rect = pygame.Rect(x, y, width, height)
def draw(self):
pygame.draw.rect(Tile.surface,Tile.border_color,self.rect,Tile.border_size)
Tile.surface.blit(self.image,self.rect)
if self.covered:
Tile.surface.blit(self.cover, self.rect)
def select(self, position):
valid_click = False
if self.rect.collidepoint(position):
if self.covered:
valid_click = True
self.expose_tile()
self.time_cover = pygame.time.get_ticks() + 2000
self.update()
else:
valid_click = False
return valid_click
def update(self):
if not self.covered and self.time_cover >= 2000:
self.covered = True
return self.covered
def expose_tile(self):
# if a tile is clicked this method will show the pic ture underneath that tile
self.covered = False
def __eq__ (self, other_tile):
pass
When you call update() in the main application loop, then revealed tiles will be covered after 2 seconds.
But you can add a cover_tile method, too:
class Tile:
# [...]
def cover_tile(self):
self.covered = True
If matching tiles share the same image (self.image), then matching tiles can be identified by comparing the images. e.g.:
(In the following tileA and tileB are instances of Tile)
if tielA.image != tileB.image:
tileA.cover_tile()
tileB.cover_tile()
else
print("matching")

How to save video Python 3.5

I have a video 256x300 uint8 (gray). I am tracking an object and displaying a rectangle in the video. I'd like to save that video (with the rectangle displayed). I tried some examples but they are all for RGB video.
import cv2
import sys
import subprocess as sp
if __name__ == '__main__' :
# Set up tracker.
# Instead of MIL, you can also use
# BOOSTING, KCF, TLD, MEDIANFLOW or GOTURN
tracker = cv2.Tracker_create("MIL")
# Read video
video = cv2.VideoCapture("videotest.avi")
# Exit if video not opened.
if not video.isOpened():
print("Could not open video")
sys.exit()
# Read first frame.
ok, frame = video.read()
if not ok:
print("Cannot read video file")
sys.exit()
# Define an initial bounding box
bbox = (90, 10, 30, 30)
# Uncomment the line below to select a different bounding box
# bbox = cv2.selectROI(frame, False)
# Initialize tracker with first frame and bounding box
ok = tracker.init(frame, bbox)
while True:
# Read a new frame
ok, frame = video.read()
if not ok:
break
# Update tracker
ok, bbox = tracker.update(frame)
# Draw bounding box
if ok:
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (0,0,255))
# Display result
cv2.imshow("Tracking", frame)
# Exit if ESC pressed
k = cv2.waitKey(1) & 0xff
if k == 27 : break
video.release()
cv2.destroyAllWindows()

Opencv draw a rectangle in a picture were never shown

Hey everybody i have some trouble using opencv 3.x and python 3.x.
What i want to do is to draw a basic rectangle in a picture but the rectangle will never be drawn.
I read this similar thread but it doesn't helped me with my fault.
Python OpenCV: mouse callback for drawing rectangle
It would be nice if someone could give me a hint.
#!/usr/bin/env python3
import cv2
import numpy as np
Path = 'picture.jpg'
image_float_size = 400.0
image_int_size = int(image_float_size)
color = [0,255,0]
rectangle = False
def on_event(event,x,y,flags,param):
global startpointx,startpointy,rectangle
if event == cv2.EVENT_LBUTTONDOWN:
rectangle = True
startpointx = x
startpointy = y
print('Down',x,y) #debugging
cv2.rectangle(resized,(x,y),(x,y),(0,255,0),-1)
elif event == cv2.EVENT_LBUTTONUP:
rectangle = False
print('Up',x,y)
cv2.rectangle(resized,(startpointx,startpointy),(x,y),(0,255,0),-1)
elif event == cv2.EVENT_MOUSEMOVE:
if rectangle:
print('Move',startpointx,startpointy,x,y)#debugging
cv2.rectangle(resized,(startpointx,startpointy),(x,y),(0,255,0),-1)
# Read the image and convert it into gray
image = cv2.imread(Path)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# resize the image
ration = image_float_size / gray_image.shape[1]
dim = (image_int_size,int(gray_image.shape[0]*ration))
resized = cv2.resize(gray_image, dim, interpolation = cv2.INTER_AREA)
# set window for the image
cv2.namedWindow('window')
# mouse callback
cv2.setMouseCallback('window',on_event)
# wait forever for user to press any key, after key pressed close all windows
while True:
cv2.imshow('window',resized)
if cv2.waitKey(0):
break
cv2.destroyAllWindows()
You perform drawing (displaying of an image by using cv2.imshow) only once because cv2.waitKey(0) waits indefinitely. If you use some non-zero argument it will wait for that number of milliseconds. But notice that you're constantly rewriting/modifying an image. This is probably not what you want. I think you need to create a temporary (drawing) copy of an image first and restore it each time from original one before new drawing (rectangle).
#!/usr/bin/env python3
import cv2
import numpy as np
Path = 'data/lena.jpg'
image_float_size = 400.0
image_int_size = int(image_float_size)
color = [0,255,0]
rectangle = False
def on_event(event,x,y,flags,param):
global draw_image
global startpointx,startpointy,rectangle
if event == cv2.EVENT_LBUTTONDOWN:
rectangle = True
startpointx = x
startpointy = y
print('Down',x,y) #debugging
draw_image = resized.copy()
cv2.rectangle(draw_image,(x,y),(x,y),(0,255,0))
elif event == cv2.EVENT_LBUTTONUP:
rectangle = False
print('Up',x,y)
draw_image = resized.copy()
cv2.rectangle(draw_image,(startpointx,startpointy),(x,y),(0,255,0))
elif event == cv2.EVENT_MOUSEMOVE:
if rectangle:
print('Move',startpointx,startpointy,x,y)#debugging
draw_image = resized.copy()
cv2.rectangle(draw_image,(startpointx,startpointy),(x,y),(0,255,0))
# Read the image and convert it into gray
image = cv2.imread(Path)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# resize the image
ration = image_float_size / gray_image.shape[1]
dim = (image_int_size,int(gray_image.shape[0]*ration))
resized = cv2.resize(gray_image, dim, interpolation = cv2.INTER_AREA)
draw_image = resized.copy()
# set window for the image
cv2.namedWindow('window')
# mouse callback
cv2.setMouseCallback('window',on_event)
while True:
cv2.imshow('window', draw_image)
ch = 0xFF & cv2.waitKey(1)
if ch == 27:
break
cv2.destroyAllWindows()

window re-sizing using tkinter

I've coded a GUI based Othello game. Am having a bit trouble re-sizing the game board. here is the code I have so far:
BOXWIDTH=60
BOXHEIGHT=60
class player:
"""Make a user player to play the game via a GUI."""
def __init__(self,row,column):
# create the GUI state variables
self.alive = True
self.move = None
self.move_played = False
# create the GUI windows and handlers
self.root = tkinter.Tk()
self.root.wm_title('Othello')
self.root.protocol("WM_DELETE_WINDOW", self.quit)
# create a button to get the No move command from the user
tkinter.Button(self.root, text="No Move", command = self.nomove).pack()
# create a label for displaying the next player's name
self.movemesg = tkinter.StringVar()
tkinter.Label(self.root, textvariable=self.movemesg).pack()
self.canvas = tkinter.Canvas(self.root, bg="darkgreen",
height = BOXHEIGHT*row,
width = BOXWIDTH*column)
self.canvas.bind("<Button-1>", self.click)
# create a box for highlighting the last move
self.lastbox = self.canvas.create_rectangle(0, 0, BOXWIDTH*column,
BOXHEIGHT*row,
outline="red")
# draw the game canvas
for i in range(1,row):
# horizontal lines
self.canvas.create_line(0, i*BOXHEIGHT,
BOXWIDTH*column, i*BOXHEIGHT)
for i in range(1,column):
# vertical lines
self.canvas.create_line(i*BOXWIDTH, 0,
i*BOXWIDTH, BOXHEIGHT*row)
# the board will store the widgets to be displayed in each square
self.board = [[None for y in range(row)]
for x in range(column)]
# display the window
self.canvas.pack()
self.canvas.focus_set()
self.root.update()
def draw_board(self, game, last_move):
"""Draw an othello game on the board."""
ws = str(sum(x.count(1) for x in game.board))
bs = str(sum(x.count(-1) for x in game.board))
if game.player == -1:
self.movemesg.set("Black to play "+'\nSCORE: White = '+ws+' Black = ' + bs)
else:
self.movemesg.set("White to play "+'\nSCORE: White = '+ws+' Black = ' + bs)
for i in range(game.column):
for j in range(game.row):
color = game.get_color((i,j))
if color == -1:
board_color = "black"
elif color == 1:
board_color = "white"
else:
if self.board[i][j] is not None:
self.canvas.delete(self.board[i][j])
self.board[i][j] = None
continue
if self.board[i][j] is None:
self.board[i][j] = self.canvas.create_oval(
i*BOXWIDTH+2, j*BOXHEIGHT+2, (i+1)*BOXWIDTH-2,
(j+1)*BOXHEIGHT-2, fill = board_color)
else:
self.canvas.itemconfig(self.board[i][j], fill=board_color)
I want the game board to resize i.e it must cause the area in which the board is drawn to change size correspondingly, with the game board redrawn to fill the available space. Any help on this would be great.
Your first problem is that the canvas wasn't told to grow when the main window grows. Change your pack statement to this:
self.canvas.pack(fill="both", expand=True)
Next, you will need to create a binding that gets called whenever the canvas resizes. You can do this by binding to <Configure>. For example:
self.canvas.bind("<Configure>", self.on_configure)
Finally, you will need to create a function that does nothing except redraw the board. You will call this method from the on_configure method.

Resources