MichaelG.
Posts: 5
Joined: Sun Sep 17, 2023 6:29 am
Location: North Wales U.K.

Using a simple webcam to actuate switches

Sun Sep 17, 2023 8:47 am

I am new to the forum, so I would first like to comment that I was very pleased to find this dedicated thread for Assistive Technology.
.

There is an extremely useful little application [currently for Windows and Linux] called Switch Viacam … and I am hoping that someone might adapt it to work on the Raspberry Pi

For clarity; please note that I have already written to the developer [Cesar Mauri] and received this encouraging response:

Hi Michael
Sadly, the project has been abandoned due to the lack of fund. The project is open source, and it works both for Windows and Linux, thus should be possible to build for a Raspberry Pi. 
see https://sourceforge.net/projects/sviacam/
Regards
Cesar


Using this application, one can set two rectangular regions [of any size and proportions] in the field of view, and use them to actuate ‘switches’ … Clearly the Raspberry Pi, with its GPIO, would be an ideal host.

Integration with guvcview would probably be ideal https://sourceforge.net/p/guvcview/tickets/74/
but simply porting sviacam to the RasPi environment would be a wonderful start.

MichaelG.
.
The short video demonstrations: https://youtu.be/u5J5WIo5Hyc

User avatar
B.Goode
Posts: 15868
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Using a simple webcam to actuate switches

Mon Sep 18, 2023 9:38 am

In the absence of any other more informed comment I will contribute the following -
MichaelG. wrote:
Sun Sep 17, 2023 8:47 am
I have already written to the developer [Cesar Mauri] and received this encouraging response:
Hi Michael
Sadly, the project has been abandoned due to the lack of fund.

I don't find that 'encouraging'. The code has not been touched for 10 years and it seems unlikely that the developer will provide active support to anyone wishing to use it.


I have no practical experience with webcams or computer vision, but may I suggest that as of 3Q23 a solution based on the actively developed and supported OpenCV package might be a better place to start a new development -
https://docs.opencv.org/4.8.0/
Beware of the Leopard

gordon77
Posts: 7723
Joined: Sun Aug 05, 2012 3:12 pm

Re: Using a simple webcam to actuate switches

Mon Sep 18, 2023 1:36 pm

Here's some python code which will set 2 gpios, 20 and 21... switched by changes in 2 defined areas

Requires opencv installed, use sudo apt-get install python3-opencv
To get it to work under Bullseye try...
sudo apt install libsdl2-ttf-2.0-0
and
python3 -m pip3 install -U pygame --user ( if you get an error try pip instead of pip3)

Left click on image will move area1, right click area2

Left /right click on crop buttons to change detection areas.

Threshold defines the level change in pixels required to be detected as changed.
detection defines the percentage of pixels in the area required to be changed to be detected as a change.

It also allows the control of the camera


Code: Select all

#!/usr/bin/python3

"""Copyright (c) 2023
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. """

import os
import pygame, sys
from pygame.locals import *
import pygame.camera
import cv2
import numpy as np
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(20,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.output(20, GPIO.LOW)
GPIO.output(21, GPIO.LOW)

# version 0.6

# preview window
preview_width  = 640
preview_height = 480

# detection area 1a
x1 = int(preview_width/4)
y1 = int(preview_height/2)
h_crop1    = 50
v_crop1    = 50
threshold1 = 20
detection1 = 10 # % of pixel changes
relay1     = 5

# detection area 2
x2 = int(preview_width * 0.75)
y2 = int(preview_height/2)
h_crop2    = 50
v_crop2    = 50
threshold2 = 20
detection2 = 10 # % of pixel changes
relay2     = 5

active = 1
preview = 0

# check config_file exists, if not then write default values
config_file = "USB_config.txt"
if not os.path.exists(config_file):
    defaults = [x1,y1,h_crop1,v_crop1,threshold1,detection1,relay1,x2,y2,h_crop2,v_crop2,threshold2,detection2,relay2]
    with open(config_file, 'w') as f:
        for item in defaults:
            f.write("%s\n" % item)

# read config file
config = []
with open(config_file, "r") as file:
   line = file.readline()
   while line:
      config.append(line.strip())
      line = file.readline()
config = list(map(int,config))

x1         = config[0]
y1         = config[1]
h_crop1    = config[2]
v_crop1    = config[3]
threshold1 = config[4]
detection1 = config[5]
relay1     = config[6]
x2         = config[7]
y2         = config[8]
h_crop2    = config[9]
v_crop2    = config[10]
threshold2 = config[11]
detection2 = config[12]
relay2     = config[13]



# set button sizes
bw = 160 
bh = 34
ft = int(bh/2.2) 
fv = int(bh/2.2)

#initialise pygame   
pygame.init()
pygame.camera.init()

# find camera
if os.path.exists('/dev/video0'):
    usb = 0
    cam = pygame.camera.Camera("/dev/video0",(preview_width,preview_height))
    path = '/dev/video0'
    cam.start()
elif os.path.exists('/dev/video1'):
    usb = 1
    cam = pygame.camera.Camera("/dev/video1",(preview_width,preview_height))
    path = '/dev/video1'
    cam.start()
else:
    print ("No USB Camera Found")
    sys.exit()

global greyColor, redColor, greenColor, blueColor, dgryColor, lgryColor, blackColor, whiteColor, purpleColor, yellowColor
lgryColor =   pygame.Color(192, 192, 192)
blackColor =  pygame.Color(  0,   0,   0)
whiteColor =  pygame.Color(200, 200, 200)
greyColor =   pygame.Color(128, 128, 128)
dgryColor =   pygame.Color( 64,  64,  64)
greenColor =  pygame.Color(  0, 255,   0)
purpleColor = pygame.Color(255,   0, 255)
yellowColor = pygame.Color(255, 255,   0)
blueColor =   pygame.Color(  0,   0, 255)
redColor =    pygame.Color(220,   0,   0)

def button(row, bColor):
    global preview_width,bw,bh
    colors = [greyColor, dgryColor]
    Color = colors[bColor]
    bx = preview_width
    by = row * bh
    pygame.draw.rect(windowSurfaceObj,Color,Rect(bx,by,bw-1,bh))
    pygame.draw.line(windowSurfaceObj,whiteColor,(bx,by),(bx+bw,by))
    pygame.draw.line(windowSurfaceObj,greyColor,(bx+bw-1,by),(bx+bw-1,by+bh))
    pygame.draw.line(windowSurfaceObj,whiteColor,(bx,by),(bx,by+bh-1))
    pygame.draw.line(windowSurfaceObj,dgryColor,(bx,by+bh-1),(bx+bw-1,by+bh-1))
    pygame.display.update(bx, by, bw, bh)
    return

def text(row,fColor,top,upd,msg,fsize,bcolor):
    global bh,preview_width,fv
    colors =  [dgryColor, greenColor, yellowColor, redColor, purpleColor, blueColor, whiteColor, greyColor, blackColor, purpleColor]
    Color  =  colors[fColor]
    bColor =  colors[bcolor]
    bx = preview_width
    by = row * bh
    if os.path.exists ('/usr/share/fonts/truetype/freefont/FreeSerif.ttf'): 
        fontObj = pygame.font.Font('/usr/share/fonts/truetype/freefont/FreeSerif.ttf', int(fsize))
    else:
        fontObj = pygame.font.Font(None, int(fsize))
    msgSurfaceObj = fontObj.render(msg, False, Color)
    msgRectobj =  msgSurfaceObj.get_rect()
    if top == 0:
        pygame.draw.rect(windowSurfaceObj,bColor,Rect(bx+1,by+1,bw-4,int(bh/2)))
        msgRectobj.topleft = (bx + 5, by + 3)
    elif msg[0:2]== "X1" or msg[0:2]== "X2":
        pygame.draw.rect(windowSurfaceObj,bColor,Rect(bx+5,by+int(bh/2),int(bw/2),int(bh/2)-2))
        msgRectobj.topleft = (bx + 5, by + 1 + int(bh/2)-int(bh/20))
    elif msg[0:2]== "Y1" or msg[0:2]== "Y2":
        pygame.draw.rect(windowSurfaceObj,bColor,Rect(bx+int(bw/2),by+int(bh/2),int(bw/2),int(bh/2)-2))
        msgRectobj.topleft = (bx + int(bw/2), by + 1 + int(bh/2)-int(bh/20))
    elif msg == "Refresh":
       pygame.draw.rect(windowSurfaceObj,bColor,Rect(bx+int(bw/2),by+int(bh/2)+1,int(bw/2),int(bh/2)-2))
       msgRectobj.topleft = (bx + int(bw/2) + 5, by + 1 + int(bh/2)-int(bh/20))
    else:
        pygame.draw.rect(windowSurfaceObj,bColor,Rect(bx+int(bw/2.2),by+int(bh/2)-1,int(bw/2),int(bh/2)-2))
        msgRectobj.topleft = (bx + int(bw/2.2), by + 1 + int(bh/2)-int(bh/20))
       
    windowSurfaceObj.blit(msgSurfaceObj, msgRectobj)
    if upd == 1:
        pygame.display.update(bx, by, bw, bh)
    if msg[0:9] == 'CAPTURING':
        pygame.display.update(5, 3, preview_width,ft + 12)

txt = "lsusb > usb_list.txt"
os.system(txt)
webcam = 0
old_crop1 = []
old_crop2 = []

with open("usb_list.txt", "r") as file:
    line = file.readline()
    if "C270" in line and "Logitech" in line: 
        webcam = 270
    while line:
        line = file.readline()
        if "C270" in line and "Logitech" in line: 
            webcam = 270
       
def camera_controls():
    # find camera controls
    global usb,parameters,preview_height,bh,ft,fv,text
    txt = "v4l2-ctl -l -d " + str(usb) + " > cam_ctrls.txt"
    os.system(txt)
    config = []
    with open("cam_ctrls.txt", "r") as file:
        line = file.readline()
        while line:
            config.append(line.strip())
            line = file.readline()
    parameters = []
    for x in range(0,len(config)):
        fet = config[x].split(' ')
        name = ""
        minm = -1
        maxm = -1
        step = -1
        defa = -1
        valu = -1
        for y in range(0,len(fet)):
            name = fet[0]
            if fet[y][0:3] == "min":
                minm = fet[y][4:]
            if fet[y][0:3] == "max":
                maxm = fet[y][4:]
            if fet[y][0:3] == "ste":
                step = fet[y][5:]
                if webcam == 270 and (name == "exposure_absolute" or name == "white_balance_temperature"):
                    step = 50
            if fet[y][0:3] == "def":
                defa = fet[y][8:]
            if fet[y][0:3] == "val":
                valu = fet[y][6:]
            if valu != -1 and defa != -1: 
                parameters.append(name)
                parameters.append(minm)
                parameters.append(maxm)
                parameters.append(step)
                parameters.append(defa)
                parameters.append(valu)
                name = ""
                minm = -1
                maxm = -1
                step = -1
                defa = -1
                valu = -1
    if len(parameters) > 0:
        bh = int(preview_height/((len(parameters)/6)+3))
        bh = min(bh,80)
        ft = int(bh/2.2)
        ft = min(ft,20)
        fv = int(bh/2.2)
        fv = min(fv,20)

camera_controls()

#setup window
windowSurfaceObj = pygame.display.set_mode((preview_width + bw,preview_height),1,24)
pygame.display.set_caption('Pi USB Camera')


def setup_menu1():
    global parameters,preview_height,bh,active
    for d in range(0,int(len(parameters)/6) + 3):
        button(d,0)
    button(int(preview_height/bh),0)
    if active == 0:
        text(0,0,0,1,"Active",ft + 4,7)
    else:
        text(0,1,0,1,"Active",ft + 4,7) 
    text(1,5,0,1,"RETURN to",ft,7) 
    text(1,5,1,1,"MAIN MENU",ft,7)
    l = len(parameters)
    l = min(l,(int(preview_height/bh)-2)*6)
    for d in range(0,l,6):
        text(int(d/6) + 2,5,0,1,parameters[d],ft,7)
        text(int(d/6) + 2,3,1,1,str(parameters[d+5]),fv,7)
        if int(parameters[d + 1]) != -1:
            j = 1 + int(int(parameters[d+5]) / (int(parameters[d + 2]) - int(parameters[d + 1]))  * bw)
            pygame.draw.rect(windowSurfaceObj,(100,100,100),Rect(preview_width + 2,((int(d/6)+2) * bh)+2,j+1,5))
            pygame.draw.rect(windowSurfaceObj,(255,1,1),Rect(preview_width + (j-5),((int(d/6)+2) * bh) + 2,8,5))
    text(int(preview_height/bh)-1,3,0,1,"EXIT",fv,7)
    text(int(preview_height/bh)-1,2,1,1,"Refresh",fv,7)

def setup_menu0():
    global preview_height,bh,h_crop1,h_crop2,v_crop1,v_crop2,threshold1,threshold2,detection1,detection2,active
    for d in range(0,int(len(parameters)/6) + 3):
        button(d,0)
    button(int(preview_height/bh)-1,0)
    if active == 0:
        text(0,0,0,1,"Active",ft + 4,7)
    else:
        text(0,1,0,1,"Active",ft + 4,7)
    text(1,2,0,1,"CROP 1",ft,7) 
    text(1,2,1,1,"X1: " + str(h_crop1),ft,7)
    text(1,2,1,1,"Y1: " + str(v_crop1),ft,7)
    text(2,2,0,1,"Threshold 1",ft,7) 
    text(2,3,1,1,str(threshold1),ft,7)
    text(3,2,0,1,"Detection 1",ft,7) 
    text(3,3,1,1,str(detection1),ft,7)
    text(4,2,0,1,"Relay 1 time",ft,7) 
    text(4,3,1,1,str(relay1),ft,7)
    text(5,1,0,1,"CROP 2",ft,7) 
    text(5,1,1,1,"X2: " + str(h_crop2),ft,7)
    text(5,1,1,1,"Y2: " + str(v_crop2),ft,7)
    text(6,1,0,1,"Threshold 2",ft,7) 
    text(6,3,1,1,str(threshold2),ft,7)
    text(7,1,0,1,"Detection 2",ft,7) 
    text(7,3,1,1,str(detection2),ft,7)
    text(8,1,0,1,"Relay 2 time",ft,7) 
    text(8,3,1,1,str(relay2),ft,7)
    text(9,5,0,1,"CAMERA",ft,7)
    text(9,5,1,1,"SETTINGS",ft,7)
    if preview == 0:
        text(10,0,0,1,"Show Detection",ft + 4,7)
    else:
        text(10,1,0,1,"Show Detection",ft + 4,7)

    text(int(preview_height/bh)-1,3,0,1,"EXIT",fv,7)
    text(int(preview_height/bh)-1,2,1,1,"Refresh",fv,7)
    
det1   = 0
det2   = 0
timer1 = time.monotonic()
timer2 = time.monotonic()
menu   = 0
setup_menu0()

while True:
    # clear relays after time out
    if time.monotonic() - timer1 > relay1:
        GPIO.output(20, GPIO.LOW)
        if menu == 0:
            text(3,2,0,1,"Detection 1",ft,7)
    if time.monotonic() - timer2 > relay2:
        GPIO.output(21, GPIO.LOW)
        if menu == 0:
            text(7,1,0,1,"Detection 2",ft,7)
        
    # get a preview picture
    image = cam.get_image()
    catSurfaceObj = image
    windowSurfaceObj.blit(catSurfaceObj,(0,0))
    # DRAW DETECTION AREAS
    if det1 == 0:
        pygame.draw.rect(windowSurfaceObj, (255,255,0), Rect(x1 - h_crop1,y1 - v_crop1 ,h_crop1*2,v_crop1*2), 2)
    else:
        pygame.draw.rect(windowSurfaceObj, (255,0,0), Rect(x1 - h_crop1,y1 - v_crop1 ,h_crop1*2,v_crop1*2), 2)
    if det2 == 0:
        pygame.draw.rect(windowSurfaceObj, (0,255,0), Rect(x2 - h_crop2,y2 - v_crop2 ,h_crop2*2,v_crop2*2), 2)
    else:
        pygame.draw.rect(windowSurfaceObj, (255,0,0), Rect(x2 - h_crop2,y2 - v_crop2 ,h_crop2*2,v_crop2*2), 2)
    
    # CROP DETECTION AREAS
    image1 = pygame.surfarray.pixels3d(image)
    crop1 = image1[x1-h_crop1:x1+h_crop1,y1-v_crop1:y1+v_crop1]
    crop2 = image1[x2-h_crop2:x2+h_crop2,y2-v_crop2:y2+v_crop2]
    gray1 = cv2.cvtColor(crop1,cv2.COLOR_RGB2GRAY)
    gray2 = cv2.cvtColor(crop2,cv2.COLOR_RGB2GRAY)
    pygame.display.update()

    # COMPARE NEW CROP1 WITH OLD CROP1
    if np.shape(gray1) == np.shape(old_crop1):
        dt = np.dtype(np.int16) 
        array1 = abs(np.subtract(np.array(gray1),np.array(old_crop1),dtype=dt))
        # APPLY THRESHOLD VALUE
        array1[array1 <  threshold1] = 0
        array1[array1 >= threshold1] = 1
        sum1 = np.sum(array1)
        if preview == 1:
            imagep1 = pygame.surfarray.make_surface(array1 * 201)
            imagep1.set_colorkey(0, pygame.RLEACCEL)
        if preview == 1 and np.shape(gray1) == np.shape(old_crop1):
            imagep1 = pygame.transform.scale(imagep1, (h_crop1*2,v_crop1*2))
            windowSurfaceObj.blit(imagep1, (x1-h_crop1,y1-v_crop1))
            pygame.display.update()
        # detection of motion1
        diff1 = (v_crop1 * h_crop1) * 4
        if (sum1/diff1) * 100 > detection1 and active == 1:
            det1 = 1
            GPIO.output(20, GPIO.HIGH)
            if menu == 0:
                text(3,6,0,1,"Detection 1    " + str(int((sum1/diff1) * 100)) + " %",ft,3)
            timer1 = time.monotonic()
        else:
            det1 = 0
    old_crop1 = np.array(gray1)

    # COMPARE NEW CROP2 WITH OLD CROP2
    if np.shape(gray2) == np.shape(old_crop2):
        dt = np.dtype(np.int16) 
        array2 = abs(np.subtract(np.array(gray2),np.array(old_crop2),dtype=dt))
        # APPLY THRESHOLD VALUE
        array2[array2 <  threshold2] = 0
        array2[array2 >= threshold2] = 1
        sum2 = np.sum(array2)
        if preview == 1:
            imagep2 = pygame.surfarray.make_surface(array2 * 201)
            imagep2.set_colorkey(0, pygame.RLEACCEL)
        if preview == 1 and np.shape(gray2) == np.shape(old_crop2):
            imagep2 = pygame.transform.scale(imagep2, (h_crop2*2,v_crop2*2))
            windowSurfaceObj.blit(imagep2, (x2-h_crop2,y2-v_crop2))
            pygame.display.update()
        # detection of motion2
        diff2 = (v_crop2 * h_crop2) * 4
        if (sum2/diff2) * 100 > detection2 and active == 1:
            det2 = 1
            GPIO.output(21, GPIO.HIGH)
            if menu == 0:
                text(7,6,0,1,"Detection 2    " + str(int((sum2/diff2) * 100)) + " %",ft,3)
            timer2 = time.monotonic()
        else:
            det2 = 0
    old_crop2 = np.array(gray2)
    
    #check for any mouse button presses
    for event in pygame.event.get():
        if event.type == QUIT:
            GPIO.output(20, GPIO.LOW)
            GPIO.output(21, GPIO.LOW)
            cam.stop()
            pygame.display.quit()
            sys.exit()

        elif (event.type == MOUSEBUTTONUP):
            mousex, mousey = event.pos
            
            # set DETECTION AREAS POSITIONS (click on picture)
            if mousex < preview_width and mousey < preview_height:
                if event.button == 3: # right click
                    x2 = mousex
                    y2 = mousey
                    if y2 + v_crop2 > preview_height:
                        y2 = preview_height - v_crop2
                    if y2 - v_crop2 < 0:
                        y2 = v_crop2
                    if x2 + h_crop2 > preview_width :
                        x2 = preview_width - h_crop2
                    if x2 - h_crop2 < 0:
                        x2 = h_crop2
                    old_crop2 = []

                elif event.button == 1: # left click
                    x1 = mousex
                    y1 = mousey
                    if y1 + v_crop1 > preview_height:
                        y1 = preview_height - v_crop1
                    if y1 - v_crop1 < 0:
                        y1 = v_crop1
                    if x1 + h_crop1 > preview_width :
                        x1 = preview_width - h_crop1
                    if x1 - h_crop1 < 0:
                        x1 = h_crop1
                    old_crop1 = []


            # menu 0 selection   
            if mousex > preview_width and menu == 0:
                button_row = int((mousey)/bh) + 1
                if mousex < preview_width + int(bw/2):
                    button_col = 1
                else:
                    button_col = 2
                if button_row > 2 + len(parameters)/6:
                    if mousex < preview_width + int(bw/2):
                        # exit
                        cam.stop()
                        pygame.display.quit()
                        sys.exit()
                    else:
                        # refresh control readings
                        camera_controls()
                        if menu == 0:
                            setup_menu0()
                        else:
                            setup_menu1()
                            
                elif button_row == 1:
                    active +=1
                    if active == 2:
                        active = 0
                        text(0,0,0,1,"Active",ft + 4,7)
                        GPIO.output(20, GPIO.LOW)
                        GPIO.output(21, GPIO.LOW)
                        if menu == 0:
                            text(3,2,0,1,"Detection 1",ft,7)
                            text(7,1,0,1,"Detection 2",ft,7)
                    else:
                        text(0,1,0,1,"Active",ft + 4,7)
                            
                elif button_row == 2 :
                    if button_col == 2 and event.button != 3:
                        v_crop1 -= 10
                    elif button_col == 2 and event.button == 3:
                        v_crop1 += 10
                    elif button_col == 1 and event.button != 3:
                        h_crop1 -= 10
                    elif button_col == 1 and event.button == 3:
                        h_crop1 += 10
                    v_crop1 = max(v_crop1,10)
                    h_crop1 = max(h_crop1,10)
                    if y1 + v_crop1 > preview_height or y1 - v_crop1 < 0:
                        v_crop1 -= 10
                    if x1 + h_crop1 > preview_width or x1 - h_crop1 < 0:
                        h_crop1 -= 10
                    text(1,2,1,1,"X1: " + str(h_crop1),ft,7)
                    text(1,2,1,1,"Y1: " + str(v_crop1),ft,7)

                elif button_row == 3:
                    if button_col == 2 :
                        threshold1 += 1
                    else:
                        threshold1 -= 1
                    threshold1 = max(threshold1,0)
                    threshold1 = min(threshold1,255)
                    text(2,3,1,1,str(threshold1),ft,7)

                elif button_row == 4:
                    if button_col == 2 :
                        detection1 += 1
                    else:
                        detection1 -= 1
                    detection1 = max(detection1,0)
                    detection1 = min(detection1,255)
                    text(3,3,1,1,str(detection1),ft,7)

                elif button_row == 5:
                    if button_col == 2 :
                        relay1 += 1
                    else:
                        relay1 -= 1
                    relay1 = max(relay1,1)
                    relay1 = min(relay1,60)
                    text(4,3,1,1,str(relay1),ft,7)

                elif button_row == 6:
                    if button_col == 2 and event.button != 3:
                        v_crop2 -= 10
                    elif button_col == 2 and event.button == 3:
                        v_crop2 += 10
                    elif button_col == 1 and event.button != 3:
                        h_crop2 -= 10
                    elif button_col == 1 and event.button == 3:
                        h_crop2 += 10
                    v_crop2 = max(v_crop2,10)
                    h_crop2 = max(h_crop2,10)
                    if y2 + v_crop2 > preview_height or y2 - v_crop2 < 0:
                        v_crop2 -= 10
                    if x2 + h_crop1 > preview_width or x2 - h_crop2 < 0:
                        h_crop2 -= 10
                    text(5,1,1,1,"X2: " + str(h_crop2),ft,7)
                    text(5,1,1,1,"Y2: " + str(v_crop2),ft,7)
                    
                elif button_row == 7:
                    if button_col == 2 :
                        threshold2 += 1
                    else:
                        threshold2 -= 1
                    threshold2 = max(threshold2,0)
                    threshold2 = min(threshold2,255)
                    text(6,3,1,1,str(threshold2),ft,7)
                    
                elif button_row == 8:
                    if button_col == 2 :
                        detection2 += 1
                    else:
                        detection2 -= 1
                    detection2 = max(detection2,0)
                    detection2 = min(detection2,255)
                    text(7,3,1,1,str(detection2),ft,7)

                elif button_row == 9:
                    if button_col == 2 :
                        relay2 += 1
                    else:
                        relay2 -= 1
                    relay2 = max(relay2,1)
                    relay2 = min(relay2,60)
                    text(8,3,1,1,str(relay2),ft,7)
                    
                elif button_row == 10:
                    menu = 1
                    setup_menu1()

                elif button_row == 11:
                    preview +=1
                    if preview == 2:
                        preview = 0
                        text(10,0,0,1,"Show Detection",ft + 4,7)
                    else:
                        text(10,1,0,1,"Show Detection",ft + 4,7)
                
            # menu 1 selection (CAMERA CONTROLS)
            if mousex > preview_width and menu == 1:
                button_row = int((mousey)/bh) + 1
                if mousex < preview_width + int(bw/2):
                    button_col = 1
                else:
                    button_col = 2
                if button_row > 2 + len(parameters)/6:
                    if mousex < preview_width + int(bw/2):
                        # exit
                        cam.stop()
                        pygame.display.quit()
                        sys.exit()
                    else:
                        # refresh control readings
                        camera_controls()
                        if menu == 0:
                            setup_menu0()
                        else:
                            setup_menu1()
                        
                elif button_row == 1:
                    active +=1
                    if active == 2:
                        active = 0
                        text(0,0,0,1,"Active",ft + 4,7)
                        GPIO.output(20, GPIO.LOW)
                        GPIO.output(21, GPIO.LOW)
                        if menu == 0:
                            text(3,2,0,1,"Detection 1",ft,7)
                            text(7,1,0,1,"Detection 2",ft,7)
                    else:
                        text(0,1,0,1,"Active",ft + 4,7)

                elif button_row == 2 :
                    menu = 0
                    setup_menu0()


                    
                else:
                    # change a camera parameter
                    p = int(parameters[((button_row - 3)*6) + 5])

                    if mousey < ((button_row - 1)*bh) + 8:
                        p = int(((mousex-preview_width) / bw) * (int(parameters[((button_row - 3)*6) + 2])-int(parameters[((button_row - 3)*6) + 1])))
                    elif mousex < preview_width + int(bw/2):
                        if int(parameters[((button_row-3)*6) + 3]) == -1:
                           p -=1
                        else:
                           p -=int(parameters[((button_row-3)*6) + 3])
                        if int(parameters[((button_row-3)*6) + 1]) != -1:
                           p = max(p,int(parameters[((button_row-2)*6) + 1]))
                        else:
                           p = max(p,0)
                    else:
                        if int(parameters[((button_row-3)*6) + 3]) == -1:
                           p +=1
                        else:
                           p +=int(parameters[((button_row-3)*6) + 3])
                        if int(parameters[((button_row-3)*6) + 2]) != -1:
                            p = min(p,int(parameters[((button_row-3)*6) + 2]))
                        else:
                            p = min(p,1)
                    parameters[((button_row-3)*6) + 5] = str(p)
                    text(int(button_row-1),3,1,1,str(p),fv,7)
                    txt = "v4l2-ctl -c " + parameters[(button_row-3)*6] + "=" + str(p)
                    os.system(txt)
                    if int(parameters[((button_row-3)*6) + 1]) != -1:
                        pygame.draw.rect(windowSurfaceObj,greyColor,Rect(preview_width,(int(button_row-1) * bh) + 2,bw,5))
                        j = int(int(parameters[((button_row-3)*6) + 5]) / (int(parameters[((button_row-3)*6) + 2]) - int(parameters[((button_row-3)*6) + 1]))  * (bw))
                        pygame.draw.rect(windowSurfaceObj,(100,100,100),Rect(preview_width + 2,(int(button_row-1) * bh) + 2,j+1,5))
                        pygame.draw.rect(windowSurfaceObj,(255,1,1),Rect(preview_width + (j-5),(int(button_row-1) * bh) + 2,8,5))

            defaults = [x1,y1,h_crop1,v_crop1,threshold1,detection1,relay1,x2,y2,h_crop2,v_crop2,threshold2,detection2,relay2]
            with open(config_file, 'w') as f:
                for item in defaults:
                    f.write("%s\n" % item)
Attachments
screen4.jpg
screen4.jpg (52.6 KiB) Viewed 8880 times
Last edited by gordon77 on Wed Sep 20, 2023 7:28 am, edited 14 times in total.

MichaelG.
Posts: 5
Joined: Sun Sep 17, 2023 6:29 am
Location: North Wales U.K.

Re: Using a simple webcam to actuate switches

Mon Sep 18, 2023 3:25 pm

[I don't find that 'encouraging'. The code has not been touched for 10 years and it seems unlikely that the developer will provide active support to anyone wishing to use it./quote]

.

Thanks for responding

But we evidently put a different interpretation on ‘encouraging’ :(
I found encouragement in the fact that a developer whose project funding had dried-up years ago, replied to me promptly, and emphasised that anyone would be free to use and adapt his code.


Sadly, I do not have the necessary skills, which I why I posted here.

I found their project inspirational, and hoped someone might pick it up.

MichaelG.

MichaelG.
Posts: 5
Joined: Sun Sep 17, 2023 6:29 am
Location: North Wales U.K.

Re: Using a simple webcam to actuate switches

Tue Sep 19, 2023 7:40 am

gordon77 wrote:
Mon Sep 18, 2023 1:36 pm
Here's some python code which will set 2 gpios, 20 and 21... switched by changes in 2 defined areas […]
.

Many thanks for providing that, Gordon

… it may be a while before I can try it, as other matters have taken priority, but it’s very much appreciated.

MichaelG.

gordon77
Posts: 7723
Joined: Sun Aug 05, 2012 3:12 pm

Re: Using a simple webcam to actuate switches

Tue Sep 19, 2023 1:04 pm

MichaelG. wrote:
Tue Sep 19, 2023 7:40 am
gordon77 wrote:
Mon Sep 18, 2023 1:36 pm
Here's some python code which will set 2 gpios, 20 and 21... switched by changes in 2 defined areas […]
.

Many thanks for providing that, Gordon

… it may be a while before I can try it, as other matters have taken priority, but it’s very much appreciated.

MichaelG.
Note code updated...

MichaelG.
Posts: 5
Joined: Sun Sep 17, 2023 6:29 am
Location: North Wales U.K.

Re: Using a simple webcam to actuate switches

Thu Sep 21, 2023 8:40 am

You are a Star, Gordon !!

I’ve just installed the software as per your very clear instructions [ yes, using pip instead of pip3 ] and it runs beautifully.
I have not yet attached any hardware to the GPIO, but I have every confidence

Aside from anything else, this will give me a useful kick-start in trying to learn Python

Many thanks
MichaelG.

gordon77
Posts: 7723
Joined: Sun Aug 05, 2012 3:12 pm

Re: Using a simple webcam to actuate switches

Thu Sep 21, 2023 9:01 am

MichaelG. wrote:
Thu Sep 21, 2023 8:40 am
You are a Star, Gordon !!

I’ve just installed the software as per your very clear instructions [ yes, using pip instead of pip3 ] and it runs beautifully.
I have not yet attached any hardware to the GPIO, but I have every confidence

Aside from anything else, this will give me a useful kick-start in trying to learn Python

Many thanks
MichaelG.
What usb camera are using ? What controls does it give ?

MichaelG.
Posts: 5
Joined: Sun Sep 17, 2023 6:29 am
Location: North Wales U.K.

Re: Using a simple webcam to actuate switches

Thu Sep 21, 2023 9:32 am

A dirt-cheap 640x480 webcam that I have modified for close-up work

usb_list.txt identifies it as:
Bus 001 Device 005: ID 1e4e:0102 Cubeternet GL-UPC822 UVC WebCam

brightness
contrast
saturation
hue
white balance automatic
gamma
power_line_Frequency {strangely this is showing 2}
white_balance temperature
sharpness
auto_exposure
exposure_time absolute
exposure_dynamic framerate

MichaelG.

gordon77
Posts: 7723
Joined: Sun Aug 05, 2012 3:12 pm

Re: Using a simple webcam to actuate switches

Thu Sep 21, 2023 11:17 am

Thanks. Good to know it works OK

Return to “Assistive technology and accessibility”