OpenCV+Python — Simple LED Position Locator #1: Frame Capture

Homan Huang
6 min readJan 14, 2021

This is a simple experiment to match the LED location by OpenCV. Each LED of the ‎️‍🌈RGB LED strip has an individual address. You can lit up one by the index of a list; for example, x[3], the 4th LED will be bright. Also, you can control the color by three groups of ‎️‍🌈RGB color codes. At the end of the project, you can use the camera 📷 to pinpoint the location when the LED lit up.

— === Menu === —

🍀1. Install PyCharm & Python
🔧2. Hardware Installation
⚙️3. Software Setup for Hardware
🐍4. Python: Frame Capture

🍀1. Install PyCharm & Python

< === Menu

Downloads

[✔️ ] Download:PyCharm from JetBrain

It’s Community Edition is FREE. That’s good enough for us.

[✔️ ] Download: Python 3.8.7 Win-64

Please install version 3.8. Version 3.9 is the newest but it may not fit every OS. Also, you may need to use the Administrator ID to install the software.

Setup the PyCharm

Open a new project in PyCharm. There are two options that you have to pick.

Choice One — Virtualenv

Choice Two —

I’ll choose ⚗️Pipenv.

Install Libraries

You can add libraries by CLI:

> pip install scikit-image
Requirement ...

If you have problem, please try to add “ — user”

> pip install scikit-image --user

You can add libraries in PyCharm:

File => Settings

Project: Your Project Name => Python Interpreter

➕ sign:

List of Libraries:

  • numpy
  • imutils
  • skimage
  • opencv-contrib-python
  • Pillow

🔧2. Hardware Installation

< === Menu

(💡)Hardware List

  • Webcam or Cell phone
  • Arduino Uno
  • WS2812 RGB LED.
  • Resistor 450–500 Ω
  • Capacitor: 1000uF. It’s optional but you need it if you want to lit up LEDs for 100 with external power.

(🔌) Setup

#1. Soldering 3 pins onto DIN, 4–7V, and GND

#2. Wires:

  • # => UNO board
  • > => LED strip
  • + of capacitor: 5V
  • >DIN => 470Ω => #13

⚙️3. Software Setup for Hardware

< === Menu

VS Code + PlatformIO

Insert a new lib:

Insert into your project:

Your platformio.ini shall be automatically inserted:

[env:uno]
platform = atmelavr
board = uno
framework = arduino
monitor_speed = 9600
monitor_flags =
--echo
lib_deps = fastled/FastLED@^3.4.0

src/main.cpp

Header:

#include <Arduino.h>
#include <FastLED.h>
// LED switch
#define ledPin 13
#define NUM_LEDS 8
// led array
CRGB leds[NUM_LEDS];

setup:

void setup() {
FastLED.addLeds<WS2812, ledPin, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(30);
}

I will load three different colors of LED repeatedly.

void loop() {
for (int i=0; i<NUM_LEDS; i++) {
leds[i] = CRGB::Blue;
FastLED.show();
delay(upTime);
leds[i] = CRGB::Black;
}

FastLED.clear();
FastLED.show();
delay(upTime);

for (int i=0; i<NUM_LEDS; i++) {
leds[i] = CRGB::Red;
FastLED.show();
delay(upTime);
leds[i] = CRGB::Black;
}

FastLED.clear();
FastLED.show();
delay(upTime);

for (int i=0; i<NUM_LEDS; i++) {
leds[i] = CRGB::Green;
FastLED.show();
delay(upTime);
leds[i] = CRGB::Black;
}
FastLED.clear();
FastLED.show();
delay(upTime);
}

Tips: You must use FastLED.clear() and FastLED.show() together; otherwise, the last unit won’t be dim.

🐍4. Python: Frame Capture

< === Menu

In our project, let’s add a new python file, video4led.py.

{🤯} Begin

import cv2
import time
import pathlib

I will add a Main remark gap. The functions of Python are like C working in the Waterfall procedure.

# =============================================
# Main:
# =============================================

Under main are some global variables.

cap = cv2.VideoCapture(1)# camera window
root_win = "LED Capture"
cv2.namedWindow(root_win)
while True:
_, frame = cap.read()
cv2.imshow(root_win, frame)key = cv2.waitKey(1)
if key == ord("q") or key == ord("Q"): # q or Q
break
cap.release()
cv2.destroyAllWindows()

【📲】Android Phone Camera

If you like to replace your webcam with an Android Camera, please follow these procedures:

  • Check server address
  • Open the server address in a browser.
  • ➕ the server address in your program.
# get camera channel
ip_address = "https://192.168.1.66:8080/video"
cap = cv2.VideoCapture(0)
cap.open(ip_address)

It’d work. But you will see a giant window, which is inconvenient.

Upper main:

# change screen size
def ResizeWithAspectRatio(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r), height)
else:
r = width / float(w)
dim = (width, int(h * r))
return cv2.resize(image, dim, interpolation=inter)

This function will change the image size.

I prefer width of 480. Here is the result:

【📸】Auto Capture

There are eight LEDs on the strip. So I need to capture 9 images, one must be all light out.

At the end of the code:

counter = 0
save_on = False
image_path = ".\\led_image"

I set the image folder.

while cap.isOpened():    key = cv2.waitKey(1)
if key == ord("q") or key == ord("Q"): # q or Q
break
elif key == ord("s"):
print("Start recording: 9 frames")
save_on = True
start_time = time.time()
counter = 0

# start to save captured images
if save_on and time.time() - start_time > 1:
print(f'Frame #{counter + 1}')
save_frame(frame)
start_time = time.time()
counter += 1
if counter == 9:
save_on = False

I use “s” key to start the process.

Upper of Main bar, I add save_frame function:

def save_frame(image):
jpgfile = time.strftime("%Y%m%d-%H%M%S.jpg")
savefile = image_path + f"\\{jpgfile}"
cv2.imwrite(savefile, image)
file = pathlib.Path(savefile)
if file.exists():
print("File saved")
else:
print("File NOT saved!")

Run:

Start recording: 9 frames
Frame #1
File NOT saved!

🙅, I forget to create the image folder. Let’s add a new folder, led_image, to the project.

Run again:

Congrats! I have 9 frames captured.

Next part: I will use OpenCV to decipher those images to get the bulbs’ position.

--

--

Homan Huang

Computer Science BS from SFSU. I studied and worked on Android system since 2017. If you are interesting in my past works, please go to my LinkedIn.