Created
September 14, 2019 09:32
-
-
Save addam/191f137806df6a7c3778c952bde7fb4e to your computer and use it in GitHub Desktop.
Interactive board using a laser pointer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import cv2 | |
import numpy | |
import pyautogui | |
# usage: | |
# after launch, a shot from the camera appears. | |
# mark four corners of the projector by clicking in order: top left, bottom left, bottom right, top right | |
# the program moves mouse when it sees the laser pointer on-screen | |
# the program never exits (you have to kill it) | |
# dimensions of the image while being processed | |
# (set this lower for faster processing. Do not set higher than camera resolution) | |
in_shape = 640, 480 | |
# dimensions and of the projector screen and its offset in multi-screen layout | |
out_shape = 1024, 768 | |
out_offset = 1920, 0 | |
tsf = None | |
def camera(source): | |
cam = cv2.VideoCapture(source) | |
while 1: | |
status, img = cam.read() | |
if not status: | |
return | |
yield img | |
def move(pos): | |
pos = [out_offset[i] + int(out_shape[i] * pos[i] / in_shape[i]) for i in range(2)] | |
pyautogui.moveTo(*pos) | |
def init(img): | |
src_points = [] | |
def onmouse(event, x, y, flags, param): | |
if event == cv2.EVENT_LBUTTONDOWN: | |
src_points.append((x, y)) | |
if len(src_points) == 4: | |
cv2.destroyAllWindows() | |
winname = "init" | |
cv2.imshow(winname, img) | |
cv2.setMouseCallback(winname, onmouse) | |
cv2.waitKey() | |
dst_points = numpy.array(((0, 0), (0, in_shape[1]), in_shape, (in_shape[0], 0))) | |
src_points = numpy.array(src_points) | |
tsf, _ = cv2.findHomography(src_points, dst_points) | |
return tsf | |
for img in camera(0): | |
if tsf is None: | |
tsf = init(img) | |
b, g, r = cv2.split(img) | |
img = cv2.warpPerspective(r, tsf, in_shape) | |
_, img = cv2.threshold(img, 245, 255, cv2.THRESH_BINARY) | |
_, contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) | |
positions = list() | |
for pts in contours: | |
if pts.shape[0] > 4: | |
rect = cv2.fitEllipse(pts) | |
cv2.ellipse(img, rect, 255) | |
pos, (w, h), angle = rect | |
if 2 <= w <= 10 and 2 <= h <= 10 and 0.5 <= w / h <= 2: | |
positions.append(pos) | |
if len(positions) == 1: | |
move(positions[0]) | |
# cv2.imshow("warped", img) | |
# if cv2.waitKey(1) == 27: | |
# break |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment