Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions app/Dockerfile.jetson
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
RUN apt-get -qq update
RUN apt-get -qq update && apt-get install -qqy python3-distutils patch


RUN set -ex ;\
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RUN wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp/get-pip.p3

apt-get install -y wget python3-distutils patch ;\
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 jetson.patch

RUN pip3 install -r requirements.txt

ENTRYPOINT [ "python3" ]
68 changes: 68 additions & 0 deletions app/jetson.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
diff --git a/app/gear.py b/app/gear.py
index b602dfe..ab92667 100644
--- a/app/gear.py
+++ b/app/gear.py
@@ -27,6 +27,7 @@ def toOneList(l):
return res

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

@@ -54,7 +55,7 @@ def addToGraphRunner(x):
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 @@ def addToStream(x):
# 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 @@ gearsCtx('StreamReader').\
map(addToGraphRunner).\
filter(lambda x: 'cat' in x[0]).\
foreach(addToStream).\
- register('camera:0')
+ register(prefix='camera:0')
+
diff --git a/app/init.py b/app/init.py
index 09f77bc..64a1303 100644
--- a/app/init.py
+++ b/app/init.py
@@ -27,7 +27,7 @@ if __name__ == '__main__':
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
33 changes: 33 additions & 0 deletions camera/Dockerfile.jetson
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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 set -x; \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RUN apt-get install -yqq curl patch

apt-get install -y curl patch; \
curl https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py ;\
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RUN wget -q bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp/get-pip.p3

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