Initializing the Addressable LEDs

Before doing any programming, one important step of the process is to initialize the the WS2812B as they will turn on each time power is connect to the Raspberry Pi. The easiest thing to do here is to write a simple Python program that will be executed every time the Pi boots, initializing (turning off) the Addressable RGB LEDs without requiring a manual script run.

 

Editing rc.local

The rc utility is the command script which controls the automatic boot process, rc.local is traditionally executed after all the normal system services are started, this is the perfect place to add the call to the initialization script. The rc.local file should be edited with root, for example:

 

sudo nano /etc/rc.local

or

sudo vi /etc/rc.local

 

Then I added the commands below before exit 0 at the end of rc.local:

file="/home/pi/picasso/init_ws2812b.py"
if [ -f "$file" ]
then
    python3 $file
fi

 

Initializing the WS2812B LEDs with Python

The Addressable LEDs could be initialized turning them off -or in other words lighting them up "black" RGB (0, 0, 0). Below Python script does the trick:

 

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Turns Off (initializes) the WS2812B Addressable LEDs
#
# Luis Ortiz - luislab.com
# May 19, 2019

import board
import neopixel
import subprocess

numLEDs = 5
ledStrip = neopixel.NeoPixel(board.D18,
                             numLEDs,
                             brightness=0.2,
                             auto_write=True)
ledPos  = 0
ledStrip.fill((0, 0, 0))

 

I added the script above to a new file /home/pi/picasso/init_ws2812b.py, then assigned execution permissions with the command chmod u+x /home/pi/picasso/init_ws2812b.py, and that is it!, the script will run every time the Pi is restarted turning off the addressable RGB leds.

 

Displaying Holograms

The Holograms can be anything: a static Image, an animated GIF, a video file or a complex made animation. In my case I chose to make few hologram videos in mp4 format, which I will be reproducing in a loop with OpenCV, a widely-used library for video and image processing.

 

The way OpenCV works when playing video is by reading each frame of the video one-at-a-time and displaying each frame as an image in sequence.

 

Installing OpenCV

To use use OpenCV library on Python, it needs to be installed along with some dependencies with the following commands (no particular order is required):

 

sudo pip3 install opencv-python

sudo apt-get install libcblas-dev
sudo apt-get install libatlas-base-dev
sudo apt-get install libjasper-dev
sudo apt-get install libqtgui4
sudo apt-get install libqt4-test

 

Playing video in Python

Below Python script will play a video in a loop, full-screen mode without any visible window or borders and with a safe way to end the script (ESC key)

 

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Tests WS2812B Addressable LED with basic color pattern and some random RGB
#
# Luis Ortiz - luislab.com
# May 19, 2019

import cv2

print("OpenCV", cv2.__version__)

vidFile = "Element14.mp4"
winName = "Element14"

vid = cv2.VideoCapture(vidFile)
if not vid.isOpened():
     print("Error: Could not open ", vidFile)
     exit()

vidFPS = vid.get(cv2.CAP_PROP_FPS)
waitPerFrame = int(1000 / vidFPS)        # in milliseconds
print("fps:", vidFPS)
print("Time between frames:", waitPerFrame, "ms")

cv2.namedWindow(winName, cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty(winName, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

try:
     while True:
          retVal, frame = vid.read()

          if retVal:
               cv2.imshow(winName, frame)
          else:
               vid.set(cv2.CAP_PROP_POS_FRAMES, 0) #End of video

if cv2.waitKey(waitPerFrame) == 27: # ESC to quit
     print("Aborted at frame:", vid.get(cv2.CAP_PROP_POS_FRAMES))
     break

finally:
     vid.release()
     cv2.destroyAllWindows()
     print("Bye!")

 

Webcam motion detection

 

Camera setup

On a fresh Raspbian installation is necessary to enable the camera support using sudo raspi-config, then with the cursor keys navigating to the options Interfacing Options > Camera > Yes > Finish to activate the camera and finally it will ask to reboot.

 

To test the camera the camera I used raspistill, one of few applications provided in Raspbian intended for capturing images:

 

raspistill -v -o webcamtest.jpg

 

Then I verified that the image was created by looking at the files it the current directory.

 

Detecting motion in Python

Once more we will be using OpenCV, this time for motion detection. Basically this script captures from the webcam a still image at regular intervals and does a series of image filtering to convert it to gray scale, removes some noise, and then compares the difference between two consecutive frames with a given threshold, a difference greater than such threshold will be considered as motion detection.

 

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Webcam motion detection
#
# Luis Ortiz - luislab.com
# May 19,2019

import cv2
#import numpy as np
from datetime import datetime

def resizeImg(image, width = 0, height = 0, inter=cv2.INTER_AREA):
    if width <= 0 and height <= 0:
        return image

    (oldH, oldW) = image.shape[:2]

    if height > 0:
        ratio = height / float(oldH)
        newDim = (int(oldW * ratio), height)
    elif width > 0:
        ratio = width / float(oldW)
        newDim = (width, int(oldH * ratio))

    resizedImg = cv2.resize(image, newDim, interpolation=inter)
    return resizedImg

camera = cv2.VideoCapture(0)          ## Webcam capture

prevFrame = None

frameWidth = camera.get(cv2.CAP_PROP_FRAME_WIDTH)
frameHeight = camera.get(cv2.CAP_PROP_FRAME_HEIGHT)
print("Camera resolution:", frameWidth, "x", frameHeight)

sensivityVal = 5
gaussKern    = 21   ## Gaussian kernel
minContour   = 4000

while (camera.isOpened()):
    capSuccess, currFrame = camera.read()
    MOTION = False

    if currFrame is None:
        break

    currFrame = resizeImg(currFrame, width=320)
    grayFrame = cv2.cvtColor(currFrame, cv2.COLOR_BGR2GRAY)
    grayFrame = cv2.GaussianBlur(grayFrame, (gaussKern, gaussKern), 0)

    if prevFrame is None:
        prevFrame = grayFrame
        continue

    # Difference between previous and current frame
    frameDiff = cv2.absdiff(prevFrame, grayFrame)
    thresh = cv2.threshold(frameDiff, sensivityVal, 0xff, cv2.THRESH_BINARY)[1]

    # If changes are greater than sensivityVal it will show white color (FF)
    dilate = cv2.dilate(thresh, None, iterations=2)

    # Finds contour of moving object
    _, cnts, _ = cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for c in cnts:
        # Ignores too small contours
        if cv2.contourArea(c) < minContour:
            continue
        MOTION = True

        (x, y, w, h) = cv2.boundingRect(c)
        cv2.rectangle(currFrame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    cv2.imshow("Current frame", currFrame)

    if cv2.waitKey(100) == 27:
        print("Aborted")
        break

    prevFrame = grayFrame
    if MOTION:
        print("Motion", datetime.now())

camera.release()
cv2.destroyAllWindows()

 

For illustration purposes the scrip above displays an image indicating the area where motion was detected, also displays a timestamp when the motion occurred

Hologram Pi-ramid - Motion Detection

 

Displaying Holograms, Finally!

Combining video display, webcam motion detection and addressable LEDs Holograms can be displayed adding awesome effects, since everything is done in Python the video, motion detection and the addressable LED effects can be combined with ease.

 

 

 

Blogs in this series

 

  1. Hologram Pi-ramid - Intro and initial design
  2. Hologram Pi-ramid - 3D CAD/CAM design
  3. Hologram Pi-ramid - 3D printed parts and initial assembly
  4. Hologram Pi-ramid - Plexiglass Pyramid
  5. Hologram Pi-ramid - My name is Automan
  6. Hologram Pi-ramid - PCB Design
  7. Hologram Pi-ramid - Painting the 3D printed parts
  8. Hologram Pi-ramid - Electronic Parts
  9. Hologram Pi-ramid - Displaying Holograms
  10. Hologram Pi-ramid - Project complete!

 

 

 

Previous
Electronic Parts

Next
Project complete!