I designed, built, and programmed a smart picture frame that goes along with a laser cut map, which allows displaying pictures based on locations you touch on the map. See the video and details below for more information.
Components/Materials & Key Tools needed for project
Components/Materials:
- Raspberry Pi (I used the Raspberry Pi 5)
- Small portable monitor / screen
- Wood (see video)
- Screws / brackets
- Appropriate HDMI cable
Tools:
- Something to cut wood members (I used a miter saw).
- A laser cutter to cut the front frame cover with precision (I used an Atomstack Laser cutter/engraver).
How to build the frame:
Take a look at this video (I built the frame for a previous project and I am simply re-using it!).
Video: https://youtu.be/42SVtqFRijQ
How to program the Raspberry Pi
Creating and entering virtual environment
To create the virtual environment:
python3.11 -m venv –system-site-packages DIY_Eng
To enter the virtual environment:
source DIY_Eng/bin/activate
To deactivate the virtual environment:
deactivate
Relevant libraries
You will need the following installed within your virtual environment (along with any other dependencies): cv2, pygame, time, numpy, and RPi.GPIO. I showed exactly how to install these and many others in a past video –> Link to video: https://youtu.be/42SVtqFRijQ
Python Code
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
import cv2 import pygame,time import numpy as np import RPi.GPIO as GPIO def aspect_scale(img,pic_no): """ Scales 'img' to fit into box bx/by. This method will retain the original image's aspect ratio """ ix,iy = img.get_size() bx = pic_sizes[pic_no,0]; by = pic_sizes[pic_no,1]; if ix > iy: # fit to width scale_factor = bx/float(ix) sy = scale_factor * iy if sy > by: scale_factor = by/float(iy) sx = scale_factor * ix sy = by else: sx = bx else: # fit to height scale_factor = by/float(iy) sx = scale_factor * ix if sx > bx: scale_factor = bx/float(ix) sx = bx sy = scale_factor * iy else: sy = by return pygame.transform.scale(img, (int(sx),int(sy))) def imgToScrn(pic_no,User_No): img = pygame.image.load("Imgs/" + User_No + "/" + file_names[pic_no]) scaledImg = aspect_scale(img,pic_no) screen.blit(scaledImg, (pic_xy[pic_no,0],pic_xy[pic_no,1]))#Defines img position from top left corner pygame.display.flip() def Display_Black_Scrn(t_sec): img = pygame.image.load("Imgs/Black_Scrn.jpg") screen.blit(img,(0,0)) pygame.display.flip() time.sleep(t_sec) def Wait_for_touch(): touch_detected = False while touch_detected == False: if GPIO.input(sensor_pin_0) == True: Sensor = "0" touch_detected = True elif GPIO.input(sensor_pin_1) == True: Sensor = "1" touch_detected = True elif GPIO.input(sensor_pin_2) == True: Sensor = "2" touch_detected = True elif GPIO.input(sensor_pin_3) == True: Sensor = "3" touch_detected = True else: Sensor = "99" time.sleep(0.2) return Sensor # Define the GPIO pin connected to the TTP223B OUT pin sensor_pin_0 = 17 sensor_pin_1 = 9 sensor_pin_2 = 14 sensor_pin_3 = 21 # Setup the GPIO mode GPIO.setmode(GPIO.BCM) GPIO.setup(sensor_pin_0, GPIO.IN) GPIO.setup(sensor_pin_1, GPIO.IN) GPIO.setup(sensor_pin_2, GPIO.IN) GPIO.setup(sensor_pin_3, GPIO.IN) #Begin section of code for displaying images/video clock = pygame.time.Clock() scrnRect = [pygame.Rect(0,0,1080,1920)]#Screen / TV dimensions in pixels #Define the parameters for the images to be displayed pic_sizes = np.array([[1009,682],[1009,682]])#Size of each image in pixels file_names = np.array(['Top.jpg','Bottom.jpg'])#File name of each picture pic_xy = np.array([[25,94],[25,985]])#Position of each picture measured from top left corner in pixels #Initialize pygame pygame.init() displayInfo = pygame.display.Info() displayWidth = displayInfo.current_w displayHeight = displayInfo.current_h screen = pygame.display.set_mode((displayWidth,displayHeight),pygame.FULLSCREEN) screen.fill(pygame.Color('black')) #Start with a black screen while True: Display_Black_Scrn(2) Sensor = Wait_for_touch() imgToScrn(0,Sensor) imgToScrn(1,Sensor) time.sleep(10) pygame.quit() picam2.close() quit() |
Affiliate Links
| Component | Link |
| Raspberry Pi 5 | https://amzn.to/3W2IAov |
| Raspberry Pi 5 Case | https://amzn.to/4f3xmIV |
| 18-inch x 24-inch x 1/8-inch (3mm) Basswood Sheets | https://amzn.to/4crIzkN |
| 12-inch x 12-inch x 1/8-inch (3mm) Basswood Sheets | https://amzn.to/3ycM5km |
| TTP223B Touch Sensor | https://amzn.to/4bWtlDp |
| Portable Monitor 15.6 Inch | https://amzn.to/3SmVa0J |
| Brackets | https://amzn.to/4cvUhuV |
| Dewalt Miter Saw Clamps | https://amzn.to/3W1EWLK |
| USB C 90 degree adapter | https://amzn.to/46kvwiT |
| Mini HDMI to HDMI 90 degree adapter | https://amzn.to/3Wfwgl2 |
Details on my laser cutter/engraver:
