Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions app/Dockerfile.jetson
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# OSNICK=stretch|bionic|buster
ARG OSNICK=buster

#----------------------------------------------------------------------------------------------
FROM redisfab/redisedgevision-${OSNICK}:0.2.0

# This is due on the following error on ARMv8:
# /usr/lib/aarch64-linux-gnu/libgomp.so.1: cannot allocate memory in static TLS block
# Something is exausting TLS, causing libgomp to fail. Preloading it as a workaround helps.

ENV LD_PRELOAD /usr/lib/aarch64-linux-gnu/libgomp.so.1
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get -qq update && apt-get install -qqy wget python3-distutils patch
RUN wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp/get-pip.py

WORKDIR /app
ADD . /app

# patch init script for aarch64
RUN patch init.py init.patch
RUN patch gear.py gear.patch

RUN pip3 install -r requirements.txt

ENTRYPOINT [ "python3" ]
53 changes: 53 additions & 0 deletions app/gear.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
--- gear.py 2021-03-29 17:15:04.726216533 -0500
+++ gear.py.updated 2021-03-29 17:14:34.195958815 -0500
@@ -27,6 +27,7 @@
return res

def addToGraphRunner(x):
+ x = x['value']
try:
xlog('addToGraphRunner:', 'count=', x['count'])

@@ -54,7 +55,7 @@
animal = index[str(res.index(res1[0]) - 1)][1]
xlog('addToGraphRunner:', 'animal=', animal)

- return (animal, x['img'])
+ return animal, x['img']
except:
xlog('addToGraphRunner: error:', sys.exc_info()[0])

@@ -62,21 +63,24 @@
# save animal name into a new stream
try:
redisgears.executeCommand('xadd', 'cats', 'MAXLEN', '~', str(MAX_IMAGES), '*', 'image', 'data:image/jpeg;base64,' + base64.b64encode(x[1]).decode('utf8'))
+ xlog('addToStream: ', x[0])
except:
xlog('addToStream: error:', sys.exc_info()[0])

def shouldTakeFrame(x):
+ v = x['value']
try:
global framesToDrop
framesToDrop += 1
- xlog('shouldTakeFrame', x['count'], (framesToDrop % 10 == 0))
+ xlog('shouldTakeFrame', v['count'], (framesToDrop % 10 == 0))
return framesToDrop % 10 == 0
except:
xlog('shouldTakeFrame: error:', sys.exc_info()[0])

def passAll(x):
+ v = x['value']
try:
- redisgears.executeCommand('xadd', 'all', 'MAXLEN', '~', str(MAX_IMAGES), '*', 'image', 'data:image/jpeg;base64,' + base64.b64encode(x['img']).decode('utf8'))
+ redisgears.executeCommand('xadd', 'all', 'MAXLEN', '~', str(MAX_IMAGES), '*', 'image', 'data:image/jpeg;base64,' + base64.b64encode(v['img']).decode('utf8'))
except:
xlog('passAll: error:', sys.exc_info()[0])

@@ -87,4 +91,5 @@
map(addToGraphRunner).\
filter(lambda x: 'cat' in x[0]).\
foreach(addToStream).\
- register('camera:0')
+ register(prefix='camera:0')
+
11 changes: 11 additions & 0 deletions app/init.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- init.py 2021-03-29 17:14:57.525688056 -0500
+++ init.py.updated 2021-03-29 17:14:27.563462225 -0500
@@ -27,7 +27,7 @@
print('Loading model - ', end='')
with open('models/mobilenet_v2_1.4_224_frozen.pb', 'rb') as f:
model = f.read()
- res = conn.execute_command('AI.MODELSET', 'mobilenet:model', 'TF', 'CPU', 'INPUTS', 'input', 'OUTPUTS', 'MobilenetV2/Predictions/Reshape_1', model)
+ res = conn.execute_command('AI.MODELSET', 'mobilenet:model', 'TF', 'CPU', 'INPUTS', 'input', 'OUTPUTS', 'MobilenetV2/Predictions/Reshape_1', 'BLOB', model)
print(res)

# Load the gear
30 changes: 30 additions & 0 deletions camera/Dockerfile.jetson
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
FROM nvcr.io/nvidia/l4t-base:r32.5.0

# This is due on the following error on ARMv8:
# /usr/lib/aarch64-linux-gnu/libgomp.so.1: cannot allocate memory in static TLS block
# Something is exausting TLS, causing libgomp to fail. Preloading it as a workaround helps.
# ENV LD_PRELOAD /usr/lib/aarch64-linux-gnu/libgomp.so.1

ENV DEBIAN_FRONTEND=noninteractive
ENV LD_LIBRARY_PATH=/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH
ENV LD_PRELOAD /usr/lib/aarch64-linux-gnu/libgomp.so.1

RUN apt-get -qq update && apt-get upgrade -y
RUN apt-get install -qqy curl patch
RUN curl https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py && python3 /tmp/get-pip.py

RUN pip install redis==3.2.1

WORKDIR /usr/src/app

ADD read_camera_jetson.py ./
ADD *.jpg ./
ADD build_opencv.patch ./

# build opencv from the source for Jetson Nano aarch64
RUN wget https://raw.githubusercontent.com/mdegans/nano_build_opencv/301e95dd6c361ed29dc523a46483f05bafd7f70b/build_opencv.sh
RUN patch build_opencv.sh build_opencv.patch
RUN chmod +x build_opencv.sh
RUN ./build_opencv.sh

CMD [ "python3", "./read_camera_jetson.py", "-u", "redis://redis:6379"]
69 changes: 69 additions & 0 deletions camera/build_opencv.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
diff --git a/build_opencv.sh b/build_opencv.sh
index 486bca9..e3c22c1 100755
--- a/build_opencv.sh
+++ b/build_opencv.sh
@@ -2,6 +2,7 @@
# 2019 Michael de Gans

set -e
+set -x

# change default constants here:
readonly PREFIX=/usr/local # install prefix, (can be ~/.local for a user install)
@@ -24,7 +25,7 @@ cleanup () {
if ! [[ "$1" -eq "--test-warning" ]] ; then
echo "(Doing so may make running tests on the build later impossible)"
fi
- read -p "Y/N " yn
+ yn="Y"
case ${yn} in
[Yy]* ) rm -rf /tmp/build_opencv ; break;;
[Nn]* ) exit ;;
@@ -53,9 +54,9 @@ install_dependencies () {
# open-cv has a lot of dependencies, but most can be found in the default
# package repository or should already be installed (eg. CUDA).
echo "Installing build dependencies."
- sudo apt-get update
- sudo apt-get dist-upgrade -y --autoremove
- sudo apt-get install -y \
+ apt-get update
+ apt-get dist-upgrade -y --autoremove
+ apt-get install -y \
build-essential \
cmake \
git \
@@ -104,7 +105,7 @@ install_dependencies () {
configure () {
local CMAKEFLAGS="
-D BUILD_EXAMPLES=OFF
- -D BUILD_opencv_python2=ON
+ -D BUILD_opencv_python2=OFF
-D BUILD_opencv_python3=ON
-D CMAKE_BUILD_TYPE=RELEASE
-D CMAKE_INSTALL_PREFIX=${PREFIX}
@@ -114,13 +115,13 @@ configure () {
-D CUDNN_VERSION='8.0'
-D EIGEN_INCLUDE_PATH=/usr/include/eigen3
-D ENABLE_NEON=ON
- -D OPENCV_DNN_CUDA=ON
+ -D OPENCV_DNN_CUDA=OFF
-D OPENCV_ENABLE_NONFREE=ON
-D OPENCV_EXTRA_MODULES_PATH=/tmp/build_opencv/opencv_contrib/modules
-D OPENCV_GENERATE_PKGCONFIG=ON
-D WITH_CUBLAS=ON
- -D WITH_CUDA=ON
- -D WITH_CUDNN=ON
+ -D WITH_CUDA=OFF
+ -D WITH_CUDNN=OFF
-D WITH_GSTREAMER=ON
-D WITH_LIBV4L=ON
-D WITH_OPENGL=ON"
@@ -175,7 +176,7 @@ main () {
if [[ -w ${PREFIX} ]] ; then
make install 2>&1 | tee -a install.log
else
- sudo make install 2>&1 | tee -a install.log
+ make install 2>&1 | tee -a install.log
fi

cleanup --test-warning
133 changes: 133 additions & 0 deletions camera/read_camera_jetson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import argparse
import cv2
import redis
import time
import sys
import os
import atexit

try:
import urllib.parse
except ImportError:
import urllib.parse as urlparse

IMAGE_WIDTH = 640
IMAGE_HEIGHT = 480

MAX_IMAGES = 1000 # 5

def gstreamer_pipeline(
capture_width=IMAGE_WIDTH,
capture_height=IMAGE_HEIGHT,
display_width=IMAGE_WIDTH,
display_height=IMAGE_HEIGHT,
framerate=15,
flip_method=0,
):
return (
"nvarguscamerasrc ! "
"video/x-raw(memory:NVMM), "
"width=(int)%d, height=(int)%d, "
"format=(string)NV12, framerate=(fraction)%d/1 ! "
"nvvidconv flip-method=%d ! "
"video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
"videoconvert ! "
"video/x-raw, format=(string)BGR ! appsink"
% (
capture_width,
capture_height,
framerate,
flip_method,
display_width,
display_height,
)
)


class Webcam:
def __init__(self, infile=0, fps=15.0):
if infile:
self.cam = cv2.VideoCapture(infile)
self.cam.set(cv2.CAP_PROP_FPS, fps)
self.cam.set(cv2.CAP_PROP_FRAME_WIDTH, IMAGE_WIDTH)
self.cam.set(cv2.CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
else:
self.cam = cv2.VideoCapture(gstreamer_pipeline(flip_method=0), cv2.CAP_GSTREAMER)
atexit.register(self.cam.release)


def __iter__(self):
self.count = -1
return self

def __next__(self): # Python 2.7
self.count += 1

# Read image
ret_val, img0 = self.cam.read()
assert ret_val, 'Webcam Error'

# Preprocess
# img = cv2.flip(img0, 1)
img = img0

return self.count, img

def __len__(self):
return 0


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('infile', help='Input file (leave empty to use webcam)', nargs='?', type=str, default=None)
parser.add_argument('-o', '--output', help='Output stream key name', type=str, default='camera:0')
parser.add_argument('-u', '--url', help='Redis URL', type=str, default='redis://localhost:6379')
parser.add_argument('--fmt', help='Frame storage format', type=str, default='.jpg')
parser.add_argument('--fps', help='Frames per second (webcam)', type=float, default=15.0)
parser.add_argument('--maxlen', help='Maximum length of output stream', type=int, default=1000)
parser.add_argument('--test', help='transmit image instead of reading webcam', action="store_true")
args = parser.parse_args()

# Set up Redis connection
url = urllib.parse.urlparse(args.url)
conn = redis.Redis(host=url.hostname, port=url.port)
if not conn.ping():
raise Exception('Redis unavailable')
print('Connected to Redis')
sys.stdout.flush()

if args.test is False:
print('Operating in camera mode')
sys.stdout.flush()
if args.infile is None:
loader = Webcam(infile=0, fps=args.fps)
else:
loader = Webcam(infile=int(args.infile), fps=args.fps)

for (count, img) in loader:
_, data = cv2.imencode(args.fmt, img)
msg = {
'count': count,
'image': data.tobytes()
}
_id = conn.execute_command('xadd', args.output, 'MAXLEN', '~', str(MAX_IMAGES), '*', 'count', msg['count'], 'img', msg['image'])
print('count: {} id: {}'.format(count, _id))
sys.stdout.flush()
else:
image_file = os.environ['ANIMAL'] + '.jpg'
print('Operating in test mode with image ' + image_file)
sys.stdout.flush()
img0 = cv2.imread(image_file)
img = cv2.resize(img0, (IMAGE_WIDTH, IMAGE_HEIGHT))
_, data = cv2.imencode(args.fmt, img)
count = 1
while True:
msg = {
'count': count,
'image': data.tobytes()
}
_id = conn.execute_command('xadd', args.output, 'MAXLEN', '~', str(MAX_IMAGES), '*', 'count', msg['count'], 'img', msg['image'])
# print('count: {} rc: {} id: {}'.format(count, rc, _id))
# sys.stdout.flush()
count += 1
time.sleep(0.1)
Loading