зеркало из
1
0
Форкнуть 0
This commit is contained in:
Daisuke Nakahara 2019-05-16 02:44:56 -07:00
Родитель 9569541191
Коммит 12b5275475
15 изменённых файлов: 1195 добавлений и 330 удалений

5
.env Normal file
Просмотреть файл

@ -0,0 +1,5 @@
CONTAINER_REGISTRY_URL=<ACR Login Server>
CONTAINER_REGISTRY_USERNAME=<ACR User Name>
CONTAINER_REGISTRY_PASSWORD=<ACR Password>
CONTAINER_MODULE_VERSION=step7-8
CONTAINER_VIDEO_SOURCE=<URL to Video>

330
.gitignore поставляемый
Просмотреть файл

@ -1,330 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/

28
.vscode/launch.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "YoloModule Remote Debug (Python)",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"logToFile": true,
"redirectOutput": true,
"pathMappings": [
{
"localRoot": "${workspaceFolder}/modules/YoloModule",
"remoteRoot": "/app"
}
],
"windows": {
"pathMappings": [
{
"localRoot": "${workspaceFolder}\\modules\\YoloModule",
"remoteRoot": "/app"
}
]
}
}
]
}

92
deployment.template.json Normal file
Просмотреть файл

@ -0,0 +1,92 @@
{
"$schema-template": "1.0.0",
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",
"runtime": {
"type": "docker",
"settings": {
"minDockerVersion": "v1.25",
"loggingOptions": "",
"registryCredentials": {
"bootcampfy19acr": {
"username": "$CONTAINER_REGISTRY_USERNAME",
"password": "$CONTAINER_REGISTRY_PASSWORD",
"address": "$CONTAINER_REGISTRY_URL"
}
}
}
},
"systemModules": {
"edgeAgent": {
"type": "docker",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.0",
"createOptions": {}
}
},
"edgeHub": {
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.0",
"createOptions": {
"HostConfig": {
"PortBindings": {
"5671/tcp": [
{
"HostPort": "5671"
}
],
"8883/tcp": [
{
"HostPort": "8883"
}
],
"443/tcp": [
{
"HostPort": "443"
}
]
}
}
}
}
}
},
"modules": {
"YoloModule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.YoloModule}",
"createOptions": "{\"Env\":[\"VIDEO_PATH=$CONTAINER_VIDEO_SOURCE\", \"VIDEO_WIDTH=0\", \"VIDEO_HEIGHT=0\", \"FONT_SCALE=0.8\"], \"HostConfig\":{\"PortBindings\":{\"80/tcp\":[{\"HostPort\":\"80\"}]}}}"
}
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 7200
}
}
},
"YoloModule" : {
"properties.desired": {
"ConfidenceLevel" : "0.3",
"VerboseMode" : 0,
"Inference" : 1,
"VideoSource" : ""
}
}
}
}

104
modules/YoloModule/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,104 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/

Просмотреть файл

@ -0,0 +1,20 @@
FROM ubuntu:xenial
WORKDIR /app
RUN apt-get update && \
apt-get install -y --no-install-recommends libcurl4-openssl-dev python-pip libboost-python-dev libgtk2.0-dev && \
rm -rf /var/lib/apt/lists/*
COPY /build/requirements.txt ./
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install tornado==4.5.3 trollius && \
pip install -U youtube-dl
ADD /app/ .
# Expose the port
EXPOSE 80
ENTRYPOINT [ "python", "-u", "./main.py" ]

Просмотреть файл

@ -0,0 +1,61 @@
# Base on work from https://github.com/Bronkoknorb/PyImageStream
import trollius as asyncio
import tornado.ioloop
import tornado.web
import tornado.websocket
import threading
import base64
import os
class ImageStreamHandler(tornado.websocket.WebSocketHandler):
def initialize(self, videoCapture):
self.clients = []
self.videoCapture = videoCapture
def check_origin(self, origin):
return True
def open(self):
self.clients.append(self)
print("Image Server Connection::opened")
def on_message(self, msg):
if msg == 'next':
frame = self.videoCapture.get_display_frame()
if frame != None:
encoded = base64.b64encode(frame)
self.write_message(encoded, binary=False)
def on_close(self):
self.clients.remove(self)
print("Image Server Connection::closed")
class ImageServer(threading.Thread):
def __init__(self, port, videoCapture):
threading.Thread.__init__(self)
self.setDaemon(True)
self.port = port
self.videoCapture = videoCapture
def run(self):
print ('ImageServer::run() : Started Image Server')
try:
loop = asyncio.new_event_loop()
asyncio.set_event_loop( loop )
indexPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
app = tornado.web.Application([
(r"/stream", ImageStreamHandler, {'videoCapture': self.videoCapture}),
(r"/(.*)", tornado.web.StaticFileHandler, {'path': indexPath, 'default_filename': 'index.html'})
])
app.listen(self.port)
print ('ImageServer::Started.')
tornado.ioloop.IOLoop.instance().start()
except Exception as e:
print('ImageServer::exited run loop. Exception - '+ str(e))
def close(self):
print ('ImageServer::close()')

Просмотреть файл

@ -0,0 +1,324 @@
#To make python 2 and python 3 compatible code
from __future__ import division
from __future__ import absolute_import
import cv2
import numpy as np
import requests
import time
import json
import os
import ImageServer
from ImageServer import ImageServer
import VideoStream
from VideoStream import VideoStream
'''***********************************************************
Step-10 : Uncomment Start
***********************************************************'''
# import YoloInference
# from YoloInference import YoloInference
'''***********************************************************
Step-10 : Uncomment End
***********************************************************'''
class VideoCapture(object):
def __init__(
self,
videoPath = "",
verbose = True,
videoW = 0,
videoH = 0,
fontScale = 1.0,
inference = True,
confidenceLevel = 0.5):
self.videoPath = videoPath
self.verbose = verbose
self.videoW = videoW
self.videoH = videoH
self.inference = inference
self.confidenceLevel = confidenceLevel
self.useStream = False
self.useMovieFile = False
self.frameCount = 0
self.vStream = None
self.vCapture = None
self.displayFrame = None
self.fontScale = float(fontScale)
self.captureInProgress = False
print("VideoCapture::__init__()")
print("OpenCV Version : %s" % (cv2.__version__))
print("===============================================================")
print("Initialising Video Capture with the following parameters: ")
print(" - Video path : " + self.videoPath)
print(" - Video width : " + str(self.videoW))
print(" - Video height : " + str(self.videoH))
print(" - Font Scale : " + str(self.fontScale))
print(" - Inference? : " + str(self.inference))
print(" - ConficenceLevel : " + str(self.confidenceLevel))
print("")
self.imageServer = ImageServer(80, self)
self.imageServer.start()
'''***********************************************************
Step-10 : Uncomment Start
***********************************************************'''
# self.yoloInference = YoloInference(self.verbose, self.fontScale)
'''***********************************************************
Step-10 : Uncomment End
***********************************************************'''
def __IsCaptureDev(self, videoPath):
try:
return '/dev/video' in videoPath.lower()
except ValueError:
return False
def __IsRtsp(self, videoPath):
try:
return 'rtsp:' in videoPath.lower()
except ValueError:
return False
def __IsYoutube(self, videoPath):
try:
return 'www.youtube.com' in videoPath.lower()
except ValueError:
return False
def __enter__(self):
if self.verbose:
print("videoCapture::__enter__()")
self.setVideoSource(self.videoPath)
return self
def setVideoSource(self, newVideoPath):
if self.captureInProgress:
self.captureInProgress = False
time.sleep(1.0)
if self.vCapture:
self.vCapture.release()
self.vCapture = None
elif self.vStream:
self.vStream.stop()
self.vStream = None
if self.__IsRtsp(newVideoPath):
print("\r\n===> RTSP Video Source")
self.useStream = True
self.useMovieFile = False
self.videoPath = newVideoPath
if self.vStream:
self.vStream.start()
self.vStream = None
if self.vCapture:
self.vCapture.release()
self.vCapture = None
self.vStream = VideoStream(newVideoPath).start()
# Needed to load at least one frame into the VideoStream class
time.sleep(1.0)
self.captureInProgress = True
elif self.__IsYoutube(newVideoPath):
print("\r\n===> YouTube Video Source")
self.useStream = False
self.useMovieFile = True
# This is video file
self.downloadVideo(newVideoPath)
self.videoPath = newVideoPath
if self.vCapture.isOpened():
self.captureInProgress = True
else:
print("===========================\r\nWARNING : Failed to Open Video Source\r\n===========================\r\n")
elif self.__IsCaptureDev(newVideoPath):
print("===> Webcam Video Source")
if self.vStream:
self.vStream.start()
self.vStream = None
if self.vCapture:
self.vCapture.release()
self.vCapture = None
self.videoPath = newVideoPath
self.useMovieFile = False
self.useStream = False
self.vCapture = cv2.VideoCapture(newVideoPath)
if self.vCapture.isOpened():
self.captureInProgress = True
else:
print("===========================\r\nWARNING : Failed to Open Video Source\r\n===========================\r\n")
else:
print("===========================\r\nWARNING : No Video Source\r\n===========================\r\n")
self.useStream = False
self.useYouTube = False
self.vCapture = None
self.vStream = None
return self
def downloadVideo(self, videoUrl):
if self.captureInProgress:
bRestartCapture = True
time.sleep(1.0)
if self.vCapture:
print("Relase vCapture")
self.vCapture.release()
self.vCapture = None
else:
bRestartCapture = False
if os.path.isfile('/app/video.mp4'):
os.remove("/app/video.mp4")
print("Start downloading video")
os.system("youtube-dl -o /app/video.mp4 -f mp4 " + videoUrl)
print("Download Complete")
self.vCapture = cv2.VideoCapture("/app/video.mp4")
time.sleep(1.0)
self.frameCount = int(self.vCapture.get(cv2.CAP_PROP_FRAME_COUNT))
if bRestartCapture:
self.captureInProgress = True
def get_display_frame(self):
return self.displayFrame
def start(self):
while True:
if self.captureInProgress:
self.__Run__()
if not self.captureInProgress:
time.sleep(1.0)
def __Run__(self):
print("===============================================================")
print("videoCapture::__Run__()")
print(" - Stream : " + str(self.useStream))
print(" - useMovieFile : " + str(self.useMovieFile))
cameraH = 0
cameraW = 0
frameH = 0
frameW = 0
if self.useStream and self.vStream:
cameraH = int(self.vStream.stream.get(cv2.CAP_PROP_FRAME_HEIGHT))
cameraW = int(self.vStream.stream.get(cv2.CAP_PROP_FRAME_WIDTH))
elif self.useStream == False and self.vCapture:
cameraH = int(self.vCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))
cameraW = int(self.vCapture.get(cv2.CAP_PROP_FRAME_WIDTH))
else:
print("Error : No Video Source")
return
if self.videoW != 0 and self.videoH != 0 and self.videoH != cameraH and self.videoW != cameraW:
needResizeFrame = True
frameH = self.videoH
frameW = self.videoW
else:
needResizeFrame = False
frameH = cameraH
frameW = cameraW
if needResizeFrame:
print("Original frame size : " + str(cameraW) + "x" + str(cameraH))
print(" New frame size : " + str(frameW) + "x" + str(frameH))
print(" Resize : " + str(needResizeFrame))
else:
print("Camera frame size : " + str(cameraW) + "x" + str(cameraH))
print(" frame size : " + str(frameW) + "x" + str(frameH))
# Check camera's FPS
if self.useStream:
cameraFPS = int(self.vStream.stream.get(cv2.CAP_PROP_FPS))
else:
cameraFPS = int(self.vCapture.get(cv2.CAP_PROP_FPS))
if cameraFPS == 0:
print("Error : Could not get FPS")
return
print("Frame rate (FPS) : " + str(cameraFPS))
currentFPS = cameraFPS
perFrameTimeInMs = 1000 / cameraFPS
while True:
# Get current time before we capture a frame
tFrameStart = time.time()
if not self.captureInProgress:
break
if self.useMovieFile:
currentFrame = int(self.vCapture.get(cv2.CAP_PROP_POS_FRAMES))
if currentFrame >= self.frameCount:
self.vCapture.set(cv2.CAP_PROP_POS_FRAMES, 0)
try:
# Read a frame
if self.useStream:
frame = self.vStream.read()
else:
frame = self.vCapture.read()[1]
except:
print("ERROR : Exception during capturing")
# Rezie frame if flagged
if needResizeFrame:
frame = cv2.resize(frame, (self.videoW, self.videoH))
# Run Object Detection
'''***********************************************************
Step-10 : Uncomment Start
***********************************************************'''
# if self.inference:
# self.yoloInference.runInference(frame, frameW, frameH, self.confidenceLevel, self.verbose)
'''***********************************************************
Step-10 : Uncomment Start
***********************************************************'''
# Calculate FPS
timeElapsedInMs = (time.time() - tFrameStart) * 1000
currentFPS = 1000.0 / timeElapsedInMs
if (currentFPS > cameraFPS):
# Cannot go faster than Camera's FPS
currentFPS = cameraFPS
# Add FPS Text to the frame
cv2.putText( frame, "FPS " + str(round(currentFPS, 1)), (10, int(30 * self.fontScale)), cv2.FONT_HERSHEY_SIMPLEX, self.fontScale, (0,0,255), 2)
self.displayFrame = cv2.imencode( '.jpg', frame )[1].tobytes()
timeElapsedInMs = (time.time() - tFrameStart) * 1000
if (1000 / cameraFPS) > timeElapsedInMs:
# This is faster than image source (e.g. camera) can feed.
waitTimeBetweenFrames = perFrameTimeInMs - timeElapsedInMs
#if self.verbose:
#print(" Wait time between frames :" + str(int(waitTimeBetweenFrames)))
time.sleep(waitTimeBetweenFrames/1000.0)
def __exit__(self, exception_type, exception_value, traceback):
if self.vCapture:
self.vCapture.release()
self.imageServer.close()
cv2.destroyAllWindows()

Просмотреть файл

@ -0,0 +1,71 @@
#To make python 2 and python 3 compatible code
from __future__ import absolute_import
from threading import Thread
import sys
if sys.version_info[0] < 3:#e.g python version <3
import cv2
else:
import cv2
from cv2 import cv2
# pylint: disable=E1101
# pylint: disable=E0401
# Disabling linting that is not supported by Pylint for C extensions such as OpenCV. See issue https://github.com/PyCQA/pylint/issues/1955
# import the Queue class from Python 3
if sys.version_info >= (3, 0):
from queue import Queue
# otherwise, import the Queue class for Python 2.7
else:
from Queue import Queue
#This class reads all the video frames in a separate thread and always has the keeps only the latest frame in its queue to be grabbed by another thread
class VideoStream(object):
def __init__(self, path, queueSize=3):
print("===============================================================\r\nVideoStream::__init__()")
self.stream = cv2.VideoCapture(path)
self.stopped = False
self.Q = Queue(maxsize=queueSize)
def start(self):
# start a thread to read frames from the video stream
t = Thread(target=self.update, args=())
t.daemon = True
t.start()
return self
def update(self):
try:
while True:
if self.stopped:
return
if not self.Q.full():
(grabbed, frame) = self.stream.read()
# if the `grabbed` boolean is `False`, then we have
# reached the end of the video file
if not grabbed:
self.stop()
return
self.Q.put(frame)
#Clean the queue to keep only the latest frame
while self.Q.qsize() > 1:
self.Q.get()
except Exception as e:
print("got error: "+str(e))
def read(self):
return self.Q.get()
def more(self):
return self.Q.qsize() > 0
def stop(self):
self.stopped = True
def __exit__(self, exception_type, exception_value, traceback):
self.stream.release()

Просмотреть файл

@ -0,0 +1,185 @@
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.
import os
import random
import sys
import time
import json
import iothub_client
# pylint: disable=E0611
# Disabling linting that is not supported by Pylint for C extensions such as iothub_client. See issue https://github.com/PyCQA/pylint/issues/1955
from iothub_client import (IoTHubModuleClient, IoTHubClientError, IoTHubError,
IoTHubMessage, IoTHubMessageDispositionResult,
IoTHubTransportProvider)
import VideoCapture
from VideoCapture import VideoCapture
def send_to_Hub_callback(strMessage):
message = IoTHubMessage(bytearray(strMessage, 'utf8'))
print("\r\nsend_to_Hub_callback()")
print(" - message : %s" & message)
hubManager.send_event_to_output("output1", message, 0)
# Callback received when the message that we're forwarding is processed.
def send_confirmation_callback(message, result, user_context):
print("\r\nsend_confirmation_callback()")
print(" - result : %s" % result)
def device_twin_callback(update_state, payload, user_context):
global hubManager
global videoCapture
if (("%s"%(update_state)) == "PARTIAL"):
jsonData = json.loads(payload)
else:
jsonData = json.loads(payload).get('desired')
print("\r\ndevice_twin_callback()")
print(" - status : %s" % update_state )
print(" - payload : \r\n%s" % json.dumps(jsonData, indent=4))
if "ConfidenceLevel" in jsonData:
print(" - ConfidenceLevel : " + str(jsonData['ConfidenceLevel']))
videoCapture.confidenceLevel = float(jsonData['ConfidenceLevel'])
if "VerboseMode" in jsonData:
print(" - Verbose : " + str(jsonData['VerboseMode']))
if jsonData['VerboseMode'] == 0:
videoCapture.verbose = False
else:
videoCapture.verbose = True
if "Inference" in jsonData:
print(" - Inference : " + str(jsonData['Inference']))
if jsonData['Inference'] == 0:
videoCapture.inference = False
else:
videoCapture.inference = True
if "VideoSource" in jsonData:
strUrl = str(jsonData['VideoSource'])
print(" - VideoSource : " + strUrl)
if strUrl.lower() != videoCapture.videoPath.lower() and strUrl != "":
videoCapture.setVideoSource(strUrl)
device_twin_send_reported(hubManager)
def device_twin_send_reported(hubManager):
global videoCapture
jsonTemplate = "{\"ConfidenceLevel\": \"%s\",\"VerboseMode\": %d,\"Inference\": %d, \"VideoSource\":\"%s\"}"
strUrl = videoCapture.videoPath
jsonData = jsonTemplate % (
str(videoCapture.confidenceLevel),
videoCapture.verbose,
videoCapture.inference,
strUrl)
print("\r\ndevice_twin_send_reported()")
print(" - payload : \r\n%s" % json.dumps(jsonData, indent=4))
hubManager.send_reported_state(jsonData, len(jsonData), 1002)
def send_reported_state_callback(status_code, user_context):
print("\r\nsend_reported_state_callback()")
print(" - status_code : [%d]" % (status_code) )
class HubManager(object):
def __init__(
self,
messageTimeout,
protocol,
verbose):
# Communicate with the Edge Hub
self.messageTimeout = messageTimeout
self.client_protocol = protocol
self.client = IoTHubModuleClient()
self.client.create_from_environment(protocol)
self.client.set_option("messageTimeout", self.messageTimeout)
self.client.set_option("product_info","edge-yolo-capture")
if verbose:
self.client.set_option("logtrace", 1)#enables MQTT logging
self.client.set_module_twin_callback(
device_twin_callback, None)
def send_reported_state(self, reported_state, size, user_context):
self.client.send_reported_state(
reported_state, size,
send_reported_state_callback, user_context)
def send_event_to_output(self, outputQueueName, event, send_context):
self.client.send_event_async(outputQueueName, event, send_confirmation_callback, send_context)
def main(
videoPath ="",
verbose = False,
videoWidth = 0,
videoHeight = 0,
fontScale = 1.0,
inference = False,
confidenceLevel = 0.8
):
global hubManager
global videoCapture
try:
print("\nPython %s\n" % sys.version )
print("Yolo Capture Azure IoT Edge Module. Press Ctrl-C to exit." )
with VideoCapture(videoPath,
verbose,
videoWidth,
videoHeight,
fontScale,
inference,
confidenceLevel) as videoCapture:
try:
hubManager = HubManager(10000, IoTHubTransportProvider.MQTT, False)
except IoTHubError as iothub_error:
print("Unexpected error %s from IoTHub" % iothub_error )
return
videoCapture.start()
except KeyboardInterrupt:
print("Camera capture module stopped" )
def __convertStringToBool(env):
if env in ['True', 'TRUE', '1', 'y', 'YES', 'Y', 'Yes']:
return True
elif env in ['False', 'FALSE', '0', 'n', 'NO', 'N', 'No']:
return False
else:
raise ValueError('Could not convert string to bool.')
if __name__ == '__main__':
try:
VIDEO_PATH = os.environ['VIDEO_PATH']
VERBOSE = __convertStringToBool(os.getenv('VERBOSE', 'False'))
VIDEO_WIDTH = int(os.getenv('VIDEO_WIDTH', 0))
VIDEO_HEIGHT = int(os.getenv('VIDEO_HEIGHT',0))
FONT_SCALE = os.getenv('FONT_SCALE', 1)
INFERENCE = __convertStringToBool(os.getenv('INFERENCE', 'False'))
CONFIDENCE_LEVEL = float(os.getenv('CONFIDENCE_LEVEL', "0.8"))
except ValueError as error:
print(error )
sys.exit(1)
main(VIDEO_PATH, VERBOSE, VIDEO_WIDTH, VIDEO_HEIGHT, FONT_SCALE, INFERENCE, CONFIDENCE_LEVEL)

Просмотреть файл

@ -0,0 +1,28 @@
<html>
<head>
<title>Video Stream</title>
<meta http-equiv="content-type" charset="utf-8">
</head>
<body>
<img id="currentImage" style="border:2px solid teal">
<script>
var img = document.getElementById("currentImage");
url = document.URL.replace('http','ws')
var ws = new WebSocket(url + "stream");
ws.onopen = function() {
console.log("connection was established");
ws.send("next");
};
ws.onmessage = function(msg) {
img.src = 'data:image/png;base64, ' + msg.data;
};
img.onload = function() {
ws.send("next");
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,80 @@
person
bicycle
car
motorbike
aeroplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
sofa
pottedplant
bed
diningtable
toilet
tvmonitor
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush

Просмотреть файл

@ -0,0 +1,182 @@
[net]
# Testing
batch=1
subdivisions=1
# Training
# batch=64
# subdivisions=2
width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 500200
policy=steps
steps=400000,450000
scales=.1,.1
[convolutional]
batch_normalize=1
filters=16
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=2
[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=2
[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=2
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=2
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=2
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=1
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky
###########
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[convolutional]
size=1
stride=1
pad=1
filters=255
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
classes=80
num=6
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
[route]
layers = -4
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[upsample]
stride=2
[route]
layers = -1, 8
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[convolutional]
size=1
stride=1
pad=1
filters=255
activation=linear
[yolo]
mask = 0,1,2
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
classes=80
num=6
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

Двоичные данные
modules/YoloModule/app/yolo/yolov3-tiny.weights Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,15 @@
{
"$schema-version": "0.0.1",
"description": "",
"image": {
"repository": "$CONTAINER_REGISTRY_URL/yolomodule",
"tag": {
"version": "$CONTAINER_MODULE_VERSION",
"platforms": {
"amd64": "./Dockerfile.amd64"
}
},
"buildOptions": []
},
"language": "python"
}