Commit 5e266278 authored by kayef.ahamad's avatar kayef.ahamad

Init Commit

parent 552976d0
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*pyc
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-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/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
.idea/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# 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/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
*.pyc
File added
FROM python:3.7-slim
RUN apt-get update && apt-get install tzdata -y
FROM python:3.7
RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y
# RUN apt-get update && apt-get install -y \
# curl apt-utils apt-transport-https debconf-utils gcc build-essential gcc-6-test-results\
# && rm -rf /var/lib/apt/lists/*
RUN apt-get update
RUN apt-get install tzdata vim -y
RUN apt-get update && apt-get install tzdata ffmpeg libsm6 libxext6 -y
ADD . /app
WORKDIR /app
RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt
#RUN pip3 install matplotlib>=3.2.2 tensorboard>=2.4.1 numpy>=1.18.5 opencv-python>=4.1.2 Pillow>=7.1.2 PyYAML>=5.3.1 requests>=2.23.0 scipy>=1.4.1 torch>=1.7.0 torchvision>=0.8.1 tqdm>=4.41.0 pandas seaborn expiringdict minio cachetools
#RUN pip3 install pymongo Cython paho-mqtt==1.5.0 scikit-learn==0.22.2
RUN pip3 install absl-py==1.3.0 asttokens==2.2.1 backcall==0.2.0 cachetools==5.2.0 certifi==2022.12.7 charset-normalizer==2.1.1 colorama==0.4.6 contourpy==1.0.6
RUN pip3 install cycler==0.11.0 Cython==0.29.32 decorator==5.1.1 dnspython==2.2.1 executing==1.2.0 expiringdict==1.2.2 fonttools==4.38.0
RUN pip3 install google-auth==2.15.0 google-auth-oauthlib==0.4.6
RUN pip3 install grpcio==1.51.1 idna==3.4 importlib-metadata==5.1.0 ipython jedi==0.18.2 kiwisolver==1.4.4 Markdown==3.4.1 MarkupSafe==2.1.1 matplotlib matplotlib-inline==0.1.6 minio==7.1.12
RUN pip3 install oauthlib==3.2.2 opencv-python==4.6.0.66 packaging==22.0 paho-mqtt==1.6.1 pandas parso==0.8.3 pickleshare==0.7.5 Pillow==9.3.0 prompt-toolkit==3.0.36 protobuf==3.20.3 pure-eval==0.2.2 pyasn1==0.4.8 pyasn1-modules==0.2.8 Pygments==2.13.0 pymongo==4.3.3 pyparsing==3.0.9 python-dateutil==2.8.2 pytz==2022.6 PyYAML==6.0 requests==2.28.1 requests-oauthlib==1.3.1 rsa==4.9 tqdm==4.64.1 traitlets==5.7.0 typing_extensions==4.4.0 urllib3==1.26.13 wcwidth==0.2.5 Werkzeug==2.2.2 zipp==3.11.0
RUN pip3 install seaborn psycopg2-binary scipy>=1.4.1 numpy==1.21.6
CMD ["bash","app.sh"]
ADD . /app
ADD Arial.ttf /root/.config/Ultralytics/
WORKDIR /app
CMD ["python3","app.py"]
# People Counting System
* Using Open Vino Model
* Using a push frequency of 1 second
* Developed for Vedanta Steel Demo
\ No newline at end of file
# aart_ppe_detection
This diff is collapsed.
import os
#
# os.environ['config'] = '{"MONGO_URI": "mongodb://192.168.3.220:2717", "MONGO_DATABASE": "ilens_ai", ' \
# '"MONGO_COLLECTION": "janusDeployment", "MONGO_KEY": "deploymentId", "MONGO_VALUE": "test_ppe", "MONGO_COLL": "serviceConfiguration", "MONGO_DB": "ilens_ai" }'
import cv2
# os.environ["config"]="{\"TZ\": \"Asia/Kolkata\", \"MONGO_URI\": \"mongodb://admin:iLens$1234@192.168.3.181:2717/admin\", \"MONGO_DATABASE\": \"ilens_ai\", \"MONGO_COLLECTION\": \"janusDeployment\", \"MONGO_KEY\": \"deploymentId\", \"MONGO_VALUE\": \"aarti_ppe\", \"MONGO_COLL\": \"serviceConfiguration\", \"MONGO_DB\": \"ilens_ai\"}"
from edge_engine.edge_processor import ExecutePipeline
from edge_engine.edge_processor import Pubs
from scripts import Ppe
from edge_engine.common.config import EDGE_CONFIG
from scripts.core.model_dummy import PPEDetection
if __name__ == '__main__':
pubs = Pubs()
mod = PPEDetection(config=EDGE_CONFIG,
pubs=pubs,
device_id=EDGE_CONFIG['deviceId'])
ex = ExecutePipeline(mod)
ex.run_model()
pubs = Pubs()
mod = Ppe(config=EDGE_CONFIG,
model_config=EDGE_CONFIG["modelConfig"],
pubs=pubs,
device_id=EDGE_CONFIG['deviceId'])
ex = ExecutePipeline(mod)
ex.run_model()
# For testing Only
# cap = cv2.VideoCapture("data/aarti.mp4")
# count = 0
# while True:
# ret, frame = cap.read()
# if not ret:
# print("Error reading frame from stream")
# break
# frame = cv2.resize(frame, (800, 600),
# interpolation=cv2.INTER_LINEAR)
# obj = {'frame': frame, 'frameId': count}
# frame = mod._predict(obj)
# count = count + 1
# # if cv2.waitKey(1) & 0xFF == ord('q'):
# # break
# cap.release()
#source /opt/intel/openvino/bin/setupvars.sh
source /opt/intel/openvino/bin/setupvars.sh
python3 app.py
\ No newline at end of file
This diff is collapsed.
from edge_engine.ai.model.modelwraper import ModelWrapper
from abc import ABC, abstractmethod
class ModelWrapper(ABC):
def __init__(self, path=None):
"""Implement code to load mask_model here"""
pass
def _pre_process(self, x):
"""Implement code to process raw input into format required for mask_model inference here"""
return x
def _post_process(self, x):
"""Implement any code to post-process mask_model inference response here"""
return x
@abstractmethod
def _predict(self, x):
"""Implement core mask_model inference code here"""
pass
def predict(self, x):
pre_x = self._pre_process(x)
prediction = self._predict(pre_x)
result = self._post_process(prediction)
return result
# import the necessary packages
import cv2
import numpy as np
class GammaPreprocessor:
def __init__(self, gamma=1.0):
# creating Gamma table
self.invGamma = 1.0 / gamma
self.table = np.array([((i / 255.0) ** self.invGamma) * 255
for i in np.arange(0, 256)]).astype("uint8")
def preprocess(self, image):
return cv2.LUT(image, self.table)
# import the necessary packages
from keras.preprocessing.image import img_to_array
class ImageToArrayPreprocessor:
def __init__(self, dataFormat=None):
# store the image data format
self.dataFormat = dataFormat
def preprocess(self, image):
# apply the Keras utility function that correctly rearranges
# the dimensions of the image
return img_to_array(image, data_format=self.dataFormat)
# import the necessary packages
import cv2
class SimpleHistogramPreprocessor:
def __init__(self):
pass
def preprocess(self, image):
# Run Histogram simple Equalization
return cv2.equalizeHist(image)
# import the necessary packages
import cv2
class SimplePreprocessor:
def __init__(self, width, height, inter=cv2.INTER_AREA):
# store the target image width, height, and interpolation
# method used when resizing
self.width = width
self.height = height
self.inter = inter
def preprocess(self, image):
# resize the image to a fixed size, ignoring the aspect
# ratio
return cv2.resize(image, (self.width, self.height),
interpolation=self.inter)
import os
import sys
from edge_engine.common.constants import LicenseModule
from dateutil import parser
from datetime import datetime
from pymongo import MongoClient
from copy import deepcopy
import json
def licence_validator(payload):
try:
dt = parser.parse(payload['valid_till'])
now = datetime.now()
if (now > dt):
sys.stdout.write("Licence Expired \n".format())
sys.stdout.flush()
return False
return True
except KeyError as e:
sys.stderr.write("Error loading licence")
return False
def get_config_from_mongo(mongo_uri, dbname, basecollection,
key, value):
mongo = MongoClient(mongo_uri)
db = mongo[dbname]
config = db[basecollection].find_one({key: value}, {"_id": False})
return config
def load_conf(config,mongo_uri, dbname):
mongo = MongoClient(mongo_uri)
db = mongo[dbname]
pub_configs = []
for conf in config['pubConfigs']:
if conf["type"].lower() in ["mqtt","mongo",]:
key= conf["key"]
value=conf["value"]
collection = conf["conectionCollection"]
pub_conf = db[collection].find_one({key: value}, {"_id": False})
pub_conf.update(conf)
pub_configs.append(pub_conf)
else :
pub_configs.append(conf)
config['pubConfigs'] = pub_configs
return config
# """
# {
# "MONGO_URI": "mongodb://192.168.3.220:21017",
# "MONGO_DATABASE": "ilens_thermal_app",
# "MONGO_COLLECTION": "janus_deployment_details",
# "MONGO_KEY": "deploymentId",
# "MONGO_VALUE": "ddd"
# }
# """
LOG_LEVEL = os.environ.get("LOG_LEVEL", default="INFO").upper()
LOG_HANDLER_NAME = os.environ.get("LOG_HANDLER_NAME", default="ilens-edge_engine")
BASE_LOG_PATH = os.environ.get('BASE_LOG_PATH',
default=os.path.join(os.getcwd(), "logs".format()))
if not os.path.isdir(BASE_LOG_PATH):
os.mkdir(BASE_LOG_PATH)
CONFIG_ENV = json.loads(os.environ.get('config', default=None))
sys.stdout.write("config->{} \n".format(json.dumps(CONFIG_ENV)))
MONGO_URI = CONFIG_ENV.get('MONGO_URI', None)
MONGO_DATABASE = CONFIG_ENV.get('MONGO_DATABASE', None)
MONGO_COLLECTION = CONFIG_ENV.get('MONGO_COLLECTION', None)
MONGO_KEY = CONFIG_ENV.get('MONGO_KEY', None)
MONGO_VALUE = CONFIG_ENV.get('MONGO_VALUE',None)
if MONGO_URI == None \
or MONGO_DATABASE is None \
or MONGO_COLLECTION is None \
or MONGO_KEY is None \
or MONGO_VALUE is None:
sys.stderr.write("invalid mongo config \n")
sys.exit(1)
EDGE_CONFIG = get_config_from_mongo(
mongo_uri=MONGO_URI,
dbname=MONGO_DATABASE, basecollection=MONGO_COLLECTION,
key=MONGO_KEY, value=MONGO_VALUE
)
DEVICE_ID = EDGE_CONFIG["deviceId"]
if EDGE_CONFIG is None:
sys.stderr.write("invalid EDGE_CONFIG config \n")
sys.exit(1)
EDGE_CONFIG=load_conf(EDGE_CONFIG, mongo_uri=MONGO_URI,
dbname=MONGO_DATABASE)
DATA_PATH = EDGE_CONFIG["inputConf"].get('dataPath',os.path.join(os.getcwd(), "data".format()))
sys.stderr.write("Loading data from {} \n".format(DATA_PATH))
\ No newline at end of file
This diff is collapsed.
class LicenseModule:
private_key = "3139343831323738414d47454e3936363538373136"
encoding_algorithm = "HS256"
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from edge_engine.common.config import LOG_LEVEL, LOG_HANDLER_NAME, BASE_LOG_PATH
import logging
from logging.handlers import RotatingFileHandler
from logging import WARNING,INFO,DEBUG,ERROR
import os
DEFAULT_FORMAT = '%(asctime)s %(levelname)5s %(name)s %(message)s'
DEBUG_FORMAT = '%(asctime)s %(levelname)5s %(name)s [%(threadName)5s:%(filename)5s:%(funcName)5s():%(lineno)s] %(message)s'
EXTRA = {}
FORMATTER = DEFAULT_FORMAT
if LOG_LEVEL.strip() == "DEBUG":
FORMATTER = DEBUG_FORMAT
def get_logger(log_handler_name, extra=EXTRA):
"""
Purpose : To create logger .
:param log_handler_name: Name of the log handler.
:param extra: extra args for the logger
:return: logger object.
"""
log_path = os.path.join(BASE_LOG_PATH, log_handler_name + ".log")
logstash_temp = os.path.join(BASE_LOG_PATH, log_handler_name + ".db")
logger = logging.getLogger(log_handler_name)
logger.setLevel(LOG_LEVEL.strip().upper())
log_handler = logging.StreamHandler()
log_handler.setLevel(LOG_LEVEL)
formatter = logging.Formatter(FORMATTER)
log_handler.setFormatter(formatter)
handler = RotatingFileHandler(log_path, maxBytes=10485760,
backupCount=5)
handler.setFormatter(formatter)
logger.addHandler(log_handler)
logger.addHandler(handler)
logger = logging.LoggerAdapter(logger, extra)
return logger
logger = get_logger(LOG_HANDLER_NAME)
import os, time
from minio import Minio
from edge_engine.common.logsetup import logger
class MinioClient:
def __init__(self ,SECRET_KEY, ACCESS_KEY, BUCKET_NAME, LOCAL_DATA_PATH, MINIO_IP):
logger.info("Initalizing minioclient !!")
self.SECRET_KEY = SECRET_KEY
self.ACCESS_KEY = ACCESS_KEY
self.BUCKET_NAME = BUCKET_NAME
self.LOCAL_DATA_PATH = LOCAL_DATA_PATH
self.MINIO_IP = MINIO_IP
self.logfile = "./logs/videowrite.log"
self.minioClient = self.connect_to_minio()
self.create_bucket(self.BUCKET_NAME)
def connect_to_minio(self):
if self.SECRET_KEY is not None and self.ACCESS_KEY is not None:
logger.info("Connecting to Minio Service... !!! ")
minio_client = Minio(self.MINIO_IP, access_key = self.ACCESS_KEY, secret_key = self.SECRET_KEY,
region='us-east-1', secure=False)
return minio_client
else:
logger.info('Access Key and Secret Key String cannot be null')
raise Exception('Access Key and Secret Key String cannot be null')
def create_bucket(self, bucket_name):
try:
if bucket_name not in self.list_buckets():
logger.info("Creating bucket {}...".format(bucket_name))
self.minioClient.make_bucket(bucket_name, location="us-east-1")
else:
logger.info("Bucket already exists....")
except Exception as err:
logger.error(err)
def save_to_bucket(self, bucket_name, data_obj):
try:
with open(data_obj, 'rb') as file:
file_stat = os.stat(data_obj)
self.minioClient.put_object(bucket_name, data_obj.split(self.LOCAL_DATA_PATH)[1],
file, file_stat.st_size)
except Exception as err:
logger.error(err)
def list_buckets(self):
bucketobjects = self.minioClient.list_buckets()
bucketlist = []
for eachbucket in bucketobjects:
bucketlist.append(eachbucket.name)
return bucketlist
def read_write_logs(self):
try:
f = open(self.logfile)
except Exception as err:
print(err)
with open(self.logfile, "a") as startfile:
startfile.write("")
f = open(self.logfile)
return [line.split('\n')[0] for line in f]
def write_write_logs(self, log_str):
with open(self.logfile, "a") as my_file:
my_file.write(log_str + "\n")
def upload(self):
if self.LOCAL_DATA_PATH[-1]!='/':
self.LOCAL_DATA_PATH = self.LOCAL_DATA_PATH+"/"
while True:
listoffiles = [os.path.join(path, name) for path, subdirs, files in os.walk(self.LOCAL_DATA_PATH) for name in files]
listofwrittenfiles = self.read_write_logs()
listofnewfiles = list(set(listoffiles) - set(listofwrittenfiles))
for fileName in listofnewfiles:
try:
logger.info("Uploading {}..".format(fileName.split(self.LOCAL_DATA_PATH)[1]))
self.save_to_bucket(self.BUCKET_NAME, fileName)
self.write_write_logs(fileName)
except Exception as e:
logger.error(e)
time.sleep(5)
# if __name__=='__main__':
# SECRET_KEY = 'minioadmin'
# ACCESS_KEY = 'minioadmin'
# BUCKET_NAME = 'videobucket'
# MINIO_IP = '192.168.3.220:29000'
# LOCAL_DATA_PATH = "F:/GDrive Data/Downloads"
# obj = MinioClient(SECRET_KEY, ACCESS_KEY, BUCKET_NAME, LOCAL_DATA_PATH, MINIO_IP)
# obj.upload()
\ No newline at end of file
from edge_engine.common.logsetup import logger
from edge_engine.common.config import EDGE_CONFIG
from edge_engine.streamio.datastream import MQTT
from edge_engine.streamio.datastream import VideoOutputStream
from edge_engine.streamio.datastream import FrameOutputStream
from edge_engine.streamio.datastream import FFMPEGOutputStream
from edge_engine.streamio.datastream import MongoDataStreamOut
from edge_engine.streamio.videostream import ThreadedVideoStream
from edge_engine.streamio.videostream import FileVideoStream
from edge_engine.streamio.bkp_frameProcessor import FrameProcessor
from edge_engine.common.minio_server import MinioClient
import json
from threading import Thread
class Pubs():
def __init__(self):
self.mqtt_pub = None
self.frame_write = None
self.video_write = None
self.mongo_write = None
self.rtp_write = None
self.build_pubs()
if 'minioConfig' in EDGE_CONFIG.keys() and \
isinstance(EDGE_CONFIG["minioConfig"],dict):
self.minio_thread = self.start_minio(EDGE_CONFIG["minioConfig"])
@staticmethod
def start_minio(minio_conf):
obj = MinioClient(minio_conf['secretKey'], minio_conf['accessKey'],
minio_conf['bucketName'], minio_conf['localDataPath'],
minio_conf['ip'])
t = Thread(target=obj.upload)
t.start()
return t
def build_pubs(self):
logger.info("building publishers ")
for conf in EDGE_CONFIG["pubConfigs"]:
if conf["type"].upper() == "MQTT":
self.mqtt_pub = MQTT(broker=conf["broker"], topic=conf["topic"], port=conf["port"]
, publish_hook=json.dumps)
elif conf["type"].upper() == "FRAMEWRITE":
self.frame_write = FrameOutputStream(
basepath=conf["basepath"],
iformat=conf["iformat"],
filenameFormat=conf["filenameFormat"],
publish_hook=None)
elif conf["type"].upper() == "VIDEOWRITE":
self.video_write = VideoOutputStream(basepath=conf["basepath"],
dims=conf["dims"],
filenameFormat=conf["filenameFormat"],
fps=conf["fps"], publish_hook=None)
elif conf["type"].upper() == "MONGO":
self.mongo_write = MongoDataStreamOut(host=conf["host"],
port=conf["port"],
dbname=conf["dbname"],
collection=conf["collection"],
keys=conf["keys"],
authsource=conf["authSource"],
username=conf["username"],
password=conf["password"],
publish_hook=None)
elif conf["type"].upper() == "RTP":
self.rtp_write = FFMPEGOutputStream(conf["ffmpegCmd"], conf["RTPEndpoint"]
, publish_hook=None)
else:
logger.error("Unsupported publisher {}".format(conf["type"]))
class ExecutePipeline:
def __init__(self, model):
self.model = model
def run_model(self):
if EDGE_CONFIG["inputConf"]["sourceType"].lower() in ["rtsp", "usbcam"]:
logger.info("Selected input stream as Direct cv input")
self.threadedVideoStream = ThreadedVideoStream(stream_config=EDGE_CONFIG["inputConf"])
self.threadedVideoStream.start()
self.frameProcessor = FrameProcessor(stream=self.threadedVideoStream,
model=self.model)
elif EDGE_CONFIG["inputConf"]["sourceType"].lower() == "videofile":
self.fileVideoStream = FileVideoStream(stream_config=EDGE_CONFIG["inputConf"])
self.fileVideoStream.start()
self.frameProcessor = FrameProcessor(stream=self.fileVideoStream, model=self.model)
else:
raise ValueError("unsupported source {}".format(EDGE_CONFIG["inputConf"]["sourceType"]))
self.start_model()
def start_model(self):
self.frameProcessor.run_model()
from edge_engine.streamio.bkp_frameProcessor import FrameProcessor
from .datastreamprocessor import DataStreamProcessor
from edge_engine.common.logsetup import logger
from edge_engine.common.config import DEVICE_ID
from uuid import uuid4
import traceback
class FrameProcessor:
def __init__(self, stream, model):
self.model = model
self.stream = stream
logger.info("Setting up frame processor !!")
def run_model(self):
while self.stream.stream.isOpened():
try:
frame = self.stream.read()
data = {"frame": frame[0], "frameId": frame[1], "deviceId": "{}".format(DEVICE_ID)}
logger.info(50*"$$")
logger.info(data)
logger.info(50*"$$")
self.model.predict(data)
logger.debug("publishing mask_model output")
except Exception as e:
logger.error(e)
logger.error(traceback.format_exc())
\ No newline at end of file
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
from edge_engine.streamio.datastream.mongodatastreamout import MongoDataStreamOut
from edge_engine.streamio.datastream.frameoutputstream import FrameOutputStream
from edge_engine.streamio.datastream.videooutputstream import VideoOutputStream
from edge_engine.streamio.datastream.mqttstream import MQTT
from edge_engine.streamio.datastream.ffmpegdata_streamout import FFMPEGOutputStream
\ No newline at end of file
from abc import ABC, abstractmethod
class DataStreamWrapper(ABC):
def __init__(self):
"""Implement code to load mask_model here"""
pass
def publish(self, x):
"""Implement code to publish"""
return x
def subscribe(self,hook):
"""Implement code to subscribe"""
return None
\ No newline at end of file
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
import subprocess as sp
class FFMPEGOutputStream(DataStreamWrapper):
def __init__(self, ffmpeg_cmd, rtp_endpoint, publish_hook=None):
super().__init__()
self.ffmpeg_cmd = ffmpeg_cmd
self.rtp_endpoint = rtp_endpoint
self.ffmpeg_cmd.append(self.rtp_endpoint[0])
self.proc = sp.Popen(self.ffmpeg_cmd, stdin=sp.PIPE, shell=False)
self.publish_hook = publish_hook
def publish(self, x):
if self.publish_hook is not None:
x = self.publish_hook(x)
frame = x["frame"]
self.proc.stdin.write(frame.tostring())
self.proc.stdin.flush()
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
import cv2
import base64
import numpy as np
import os
from edge_engine.common.logsetup import logger
from datetime import datetime
class FrameOutputStream(DataStreamWrapper):
def __init__(self, basepath, iformat="jpg", filenameFormat="{deviceId}_{frameId}_{timestamp}", publish_hook=None):
super().__init__()
self.basepath = basepath
self.iformat = iformat
self.filenameFormat = filenameFormat
self.publish_hook = publish_hook
def publish(self, x):
if self.publish_hook is not None:
x= self.publish_hook(x)
frame = x["frame"]
frame = base64.b64decode(frame.split("data:image/jpeg;base64,")[1])
frame = np.fromstring(frame, np.uint8)
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
path = os.path.join(self.basepath, datetime.now().date().isoformat())
if not os.path.isdir(path):
logger.info("Creating {} \n".format(path))
os.mkdir(path)
cv2.imwrite("{path}.{iformat}".format(path=os.path.join(path, self.filenameFormat.format(**x)),
iformat=self.iformat), frame)
return True
def subscribe(self, hook):
super().subscribe(hook)
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
from pymongo import MongoClient
class MongoDataStreamOut(DataStreamWrapper):
def __init__(self, host, port, dbname, collection, keys, authsource,username=None,password=None, publish_hook=None):
super().__init__()
self.host = host
self.port = port
self.dbname = dbname
self.username = username
self.password = password
self.collection = collection
self.publish_hook = publish_hook
self.mongo = MongoClient(host=host,
port=int(port),username=self.username,password=self.password)
self.db = self.mongo[dbname]
self.keys = keys
self.authsource = authsource
def subscribe(self, hook=None):
pass
def publish(self, data):
if self.publish_hook is not None:
data = self.publish_hook(data)
fin_dat = {}
for k, v in data.items():
if k in self.keys:
fin_dat[k] = v
self.db[self.collection].insert(fin_dat)
import paho.mqtt.client as paho
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
from edge_engine.common.logsetup import logger
from uuid import uuid4
import traceback
class MQTT(DataStreamWrapper):
@staticmethod
def on_connect(client, userdata, flags, rc):
logger.info("Connection returned with result code:" + str(rc))
@staticmethod
def on_disconnect(client, userdata, rc):
logger.info("Disconnection returned result:" + str(rc))
@staticmethod
def on_subscribe(client, userdata, mid, granted_qos):
logger.debug("Subscribing MQTT {} {} {} {}".format(client, userdata, mid, granted_qos))
def on_message(self, client, userdata, msg):
logger.debug("Received message, topic:" + msg.topic + "payload:" + str(msg.payload))
if self.subscribe_hook is not None:
self.subscribe_hook(msg.payload.decode())
def __init__(self, broker, port, topic, qos=2, subscribe_hook=None, publish_hook=None):
super().__init__()
self.broker = broker
self.port = int(port)
self.topic = topic
self.client_name = "{}".format(uuid4())
self.client = paho.Client(self.client_name)
self.client.on_connect = self.on_connect
self.client.on_disconnect = self.on_disconnect
self.client.on_subscribe = self.on_subscribe
self.client.on_message = self.on_message
self.client.connect(host=self.broker, port=self.port)
self.subscribe_hook = subscribe_hook
self.publish_hook = publish_hook
self.qos = qos
def subscribe(self, hook=None):
if hook is not None:
self.subscribe_hook =hook
self.client.subscribe((self.topic, self.qos))
self.client.loop_forever()
def publish(self, data):
try:
if self.publish_hook is not None:
data = self.publish_hook(data)
self.client.publish(self.topic, data)
except Exception as e:
logger.error(e)
logger.error(traceback.format_exc())
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
import cv2
import base64
import numpy as np
import os
from edge_engine.common.logsetup import logger
from datetime import datetime
class VideoOutputStream(DataStreamWrapper):
def __init__(self, basepath, dims, filenameFormat="{deviceId}_{timestamp}", fps=30, publish_hook=None):
super().__init__()
self.basepath = basepath
self.dims = (int(dims[0]),int(dims[1]))
self.fps = float(fps)
self.filenameFormat = filenameFormat
self.publish_hook = publish_hook
self.four_cc = cv2.VideoWriter_fourcc(*'mp4v')
self.out = None
def publish(self, x):
if self.publish_hook is not None:
x = self.publish_hook(x)
if len(x["metric"]) > 0:
if self.out is None:
path = os.path.join(self.basepath, datetime.now().date().isoformat())
if not os.path.isdir(path):
logger.info("Creating {} \n".format(path))
os.mkdir(path)
self.out = cv2.VideoWriter("{}.mp4".format(os.path.join(path, self.filenameFormat.format(**x))),
self.four_cc, self.fps, self.dims)
frame = x["frame"]
frame = base64.b64decode(frame.split("data:image/jpeg;base64,")[1])
frame = np.fromstring(frame, np.uint8)
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
self.out.write(frame)
else:
if self.out is not None:
self.out.release()
self.out = None
return True
def subscribe(self, hook):
super().subscribe(hook)
from edge_engine.common.logsetup import logger
class DataStreamProcessor:
def __init__(self, model, subsciber, publishers=list()):
self.model = model
self.subsciber = subsciber
self.publishers = publishers
logger.info("Setting up frame processor !!")
def processstream(self, msg):
print(msg)
def run_model(self):
self.subsciber.subscribe(hook=self.processstream)
from edge_engine.common.logsetup import logger
from edge_engine.common.config import DEVICE_ID
from uuid import uuid4
import traceback
class FrameProcessor:
def __init__(self, stream, model):
self.model = model
self.stream = stream
logger.info("Setting up frame processor !!")
def run_model(self):
while self.stream.stream.isOpened():
try:
logger.debug("Getting frame mask_model")
frame = self.stream.read()
logger.debug("Running mask_model")
data = {"frame": frame[0], "frameId":frame[1] , "deviceId": "{}".format(DEVICE_ID)}
self.model.predict(data)
logger.debug("publishing mask_model output")
except Exception as e:
logger.error(e)
logger.error(traceback.format_exc())
\ No newline at end of file
from edge_engine.streamio.videostream.fps import FPS
from edge_engine.streamio.videostream.nvgstreamer import NVGstreamer
from edge_engine.streamio.videostream.simplevideostream import SimpleVideoStream
from edge_engine.streamio.videostream.threadedvideostream import ThreadedVideoStream
from edge_engine.streamio.videostream.bkp_filevideostream import FileVideoStream
\ No newline at end of file
# import the necessary packages
from threading import Thread
import sys
import cv2
import time
# 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
class FileVideoStream:
def __init__(self,stream_config, transform=None):
# initialize the file video stream along with the boolean
# used to indicate if the thread should be stopped or not
self.transform = transform
self.stream_config =stream_config
# initialize the queue used to store frames read from
# the video file
self.build_pipeline()
def start(self):
# start a thread to read frames from the file video stream
self.thread.start()
return self
def build_cv_obj(self):
self.stream = cv2.VideoCapture(self.stream_config["uri"])
self.stopped = False
def build_pipeline(self):
self.build_cv_obj()
if "queueSize" not in self.stream_config:
self.stream_config["queueSize"] =128
self.Q = Queue(maxsize=int(self.stream_config["queueSize"]))
# intialize thread
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
def is_opened(self):
return self.stream.isOpened()
def update(self):
# keep looping infinitely
while True:
# if the thread indicator variable is set, stop the
# thread
if self.stopped:
break
# otherwise, ensure the queue has room in it
if not self.Q.full():
# read the next frame from the file
(grabbed, frame) = self.stream.read()
# if the `grabbed` boolean is `False`, then we have
# reached the end of the video file
if grabbed is False or frame is None:
#self.stopped = True
self.build_cv_obj()
continue
# if there are transforms to be done, might as well
# do them on producer thread before handing back to
# consumer thread. ie. Usually the producer is so far
# ahead of consumer that we have time to spare.
#
# Python is not parallel but the transform operations
# are usually OpenCV native so release the GIL.
#
# Really just trying to avoid spinning up additional
# native threads and overheads of additional
# producer/consumer queues since this one was generally
# idle grabbing frames.
if self.transform:
frame = self.transform(frame)
# add the frame to the queue
self.Q.put(frame)
else:
time.sleep(0.1) # Rest for 10ms, we have a full queue
self.stream.release()
def read(self):
# return next frame in the queue
return self.Q.get()
# Insufficient to have consumer use while(more()) which does
# not take into account if the producer has reached end of
# file stream.
def running(self):
return self.more() or not self.stopped
def more(self):
# return True if there are still frames in the queue. If stream is not stopped, try to wait a moment
tries = 0
while self.Q.qsize() == 0 and not self.stopped and tries < 5:
time.sleep(0.1)
tries += 1
return self.Q.qsize() > 0
def stop(self):
# indicate that the thread should be stopped
self.stopped = True
# wait until stream resources are released (producer thread might be still grabbing frame)
self.thread.join()
\ No newline at end of file
# import the necessary packages
from threading import Thread
import sys
import cv2
import time
# 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
class FileVideoStream:
def __init__(self, stream_config, transform=None):
# initialize the file video stream along with the boolean
# used to indicate if the thread should be stopped or not
self.transform = transform
self.stream_config = stream_config
# initialize the queue used to store frames read from
# the video file
self.build_pipeline()
def start(self):
# start a thread to read frames from the file video stream
self.thread.start()
return self
def build_cv_obj(self):
self.stream = cv2.VideoCapture(self.stream_config["uri"])
self.stopped = False
def build_pipeline(self):
self.build_cv_obj()
if "queueSize" not in self.stream_config:
self.stream_config["queueSize"] = 128
self.Q = Queue(maxsize=int(self.stream_config["queueSize"]))
# intialize thread
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
def is_opened(self):
return self.stream.isOpened()
def update(self):
# keep looping infinitely
count = 0
while True:
# if the thread indicator variable is set, stop the
# thread
if self.stopped:
break
# otherwise, ensure the queue has room in it
if not self.Q.full():
# read the next frame from the file
(grabbed, frame) = self.stream.read()
# if the `grabbed` boolean is `False`, then we have
# reached the end of the video file
if grabbed is False or frame is None:
# self.stopped = True
count = 0
self.build_cv_obj()
continue
# if there are transforms to be done, might as well
# do them on producer thread before handing back to
# consumer thread. ie. Usually the producer is so far
# ahead of consumer that we have time to spare.
#
# Python is not parallel but the transform operations
# are usually OpenCV native so release the GIL.
#
# Really just trying to avoid spinning up additional
# native threads and overheads of additional
# producer/consumer queues since this one was generally
# idle grabbing frames.
if self.transform:
frame = self.transform(frame)
# add the frame to the queue
self.Q.put((frame, count))
count = count+1
else:
time.sleep(0.1) # Rest for 10ms, we have a full queue
self.stream.release()
def read(self):
# return next frame in the queue
return self.Q.get()
# Insufficient to have consumer use while(more()) which does
# not take into account if the producer has reached end of
# file stream.
def running(self):
return self.more() or not self.stopped
def more(self):
# return True if there are still frames in the queue. If stream is not stopped, try to wait a moment
tries = 0
while self.Q.qsize() == 0 and not self.stopped and tries < 5:
time.sleep(0.1)
tries += 1
return self.Q.qsize() > 0
def stop(self):
# indicate that the thread should be stopped
self.stopped = True
# wait until stream resources are released (producer thread might be still grabbing frame)
self.thread.join()
# import the necessary packages
import datetime
class FPS:
def __init__(self):
# store the start time, end time, and total number of frames
# that were examined between the start and end intervals
self._start = None
self._end = None
self._numFrames = 0
def start(self):
# start the timer
self._start = datetime.datetime.now()
return self
def stop(self):
# stop the timer
self._end = datetime.datetime.now()
def update(self):
# increment the total number of frames examined during the
# start and end intervals
self._numFrames += 1
def elapsed(self):
# return the total number of seconds between the start and
# end interval
return (self._end - self._start).total_seconds()
def fps(self):
# compute the (approximate) frames per second
return self._numFrames / self.elapsed()
import cv2
class NVGstreamer:
def __init__(self, buildconfig):
self.width = 480
self.height = 640
self.latency = 0
self.framerate = "30/1"
self.fformat = "BGRx"
self.BUILD_CONFIG = {
"width": self.width,
"height": self.height,
"latency": self.latency,
"framerate": self.framerate,
"format": self.fformat,
"gstreamer": True
}
self.BUILD_CONFIG.update(buildconfig)
def open_cam_rtsp(self):
gst_str = ('rtspsrc location={uri} latency={latency} ! '
'rtph264depay ! h264parse ! omxh264dec ! '
'nvvidconv ! videorate ! '
'video/x-raw, width=(int){width}, height=(int){height}, '
'format=(string){format}, framerate=(fraction){framerate} ! '
'videoconvert ! appsink').format(**self.BUILD_CONFIG)
print(gst_str)
return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
def open_cam_usb(self):
# We want to set width and height here, otherwise we could just do:
# return cv2.VideoCapture(dev)
gst_str = ('v4l2src device=/dev/video{uri} ! '
'video/x-raw, width=(int){width}, height=(int){height}, '
'format=(string){format}, framerate=(fraction){framerate} ! '
'videoconvert ! appsink').format(**self.BUILD_CONFIG)
print(gst_str)
return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
def open_cam_onboard(self):
# On versions of L4T prior to 28.1, add 'flip-method=2' into gst_str
gst_str = ('nvcamerasrc ! '
'video/x-raw(memory:NVMM), '
'width=(int)2592, height=(int)1458, '
'format=(string)I420 ! '
'nvvidconv ! videorate ! '
'video/x-raw, width=(int){width}, height=(int){height}, '
'format=(string){format}, framerate=(fraction){framerate} !'
'videoconvert ! appsink').format(**self.BUILD_CONFIG)
print(gst_str)
return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
def custom_pipeline(self):
gst_str = "{customGstPipelineString}".format(**self.BUILD_CONFIG)
print(gst_str)
return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
def build_pipeline(self):
if self.BUILD_CONFIG["gStreamer"]!=True:
if self.BUILD_CONFIG["sourceType"] == "usbcam":
self.cap = cv2.VideoCapture(int(self.BUILD_CONFIG["uri"]))
else:
self.cap = cv2.VideoCapture(self.BUILD_CONFIG["uri"])
elif self.BUILD_CONFIG["sourceType"] == "rtsp":
self.cap = self.open_cam_rtsp()
elif self.BUILD_CONFIG["sourceType"] == "usbcam":
self.cap = self.open_cam_usb()
elif self.BUILD_CONFIG["sourceType"] == "onboard":
self.cap = self.open_cam_onboard()
elif self.BUILD_CONFIG["sourceType"] == "customPipeline":
self.cap = self.custom_pipeline()
else:
raise ValueError("unimplemented source {}".format(self.BUILD_CONFIG["sourceType"]))
def get_stream(self):
return self.cap
from edge_engine.common.logsetup import logger
from edge_engine.streamio.videostream import NVGstreamer
class SimpleVideoStream:
def __init__(self, stream_config, name="SimpleVideoStream"):
self.stream_config = stream_config
self.build_pipeline()
(self.grabbed, self.frame) = self.stream.read()
self.name = name
def build_pipeline(self):
self.gstreamer = NVGstreamer(self.stream_config)
self.gstreamer.build_pipeline()
self.stream = self.gstreamer.get_stream()
def start(self):
logger.info("Starting video stream ")
if self.stream.isOpened():
self.grabbed, self.frame = self.stream.read()
if self.grabbed is False:
logger.error("Empty Frame !!!! ")
logger.error("Error opening Capture !!!! ")
self.build_pipeline()
return self
else:
logger.error("Error opening Capture !!!! ")
self.build_pipeline()
def is_opened(self):
return self.stream.isOpened()
def read(self):
# return the frame most recently read
if self.stream.isOpened():
self.grabbed, self.frame = self.stream.read()
if self.grabbed is False:
logger.error("Empty Frame !!!! ")
raise ValueError("Empty Frame !!!! ")
return self.frame
else:
logger.error("Error opening Capture !!!! ")
raise ValueError("Error opening Capture !!!! ")
def stop(self):
if self.stream.isOpened():
self.stream.release()
# import the necessary packages
from threading import Thread
import time
from edge_engine.streamio.videostream import NVGstreamer
from edge_engine.common.logsetup import logger
class ThreadedVideoStream:
def __init__(self, stream_config, name="ThreadedVideoStream"):
# initialize the video camera stream and read the first frame
# from the stream
self.stream_config = stream_config
self.build_pipeline()
# self.stream = stream
(self.grabbed, self.frame) = self.stream.read()
# initialize the thread name
self.name = name
# initialize the variable used to indicate if the thread should
# be stopped
self.stopped = False
def build_pipeline(self):
self.gstreamer = NVGstreamer(self.stream_config)
self.gstreamer.build_pipeline()
self.stream = self.gstreamer.get_stream()
def start(self):
# start the thread to read frames from the video stream
t = Thread(target=self.update, name=self.name, args=())
t.daemon = True
t.start()
return self
def update(self):
# keep looping infinitely until the thread is stopped
while True:
# if the thread indicator variable is set, stop the thread
if self.stopped:
return
# otherwise, read the next frame from the stream
(self.grabbed, self.frame) = self.stream.read()
if self.grabbed is False or self.frame is None:
logger.error("Empty Frame !!!! ")
logger.error("Error opening Capture !!!! ")
self.build_pipeline()
def read(self):
# return the frame most recently read
return self.frame
def stop(self):
# indicate that the thread should be stopped
self.stopped = True
time.sleep(0.2)
self.stream.release()
# Copyright 2019 KnowledgeLens pvt Ltd.
VERSION = '0.0.1.alpha'
File added
......@@ -6,8 +6,6 @@ from datetime import datetime
from pymongo import MongoClient
from copy import deepcopy
import json
def licence_validator(payload):
try:
dt = parser.parse(payload['valid_till'])
......@@ -31,20 +29,22 @@ def get_config_from_mongo(mongo_uri, dbname, basecollection,
return config
def load_conf(config, mongo_uri, dbname):
def load_conf(config,mongo_uri, dbname):
mongo = MongoClient(mongo_uri)
db = mongo[dbname]
pub_configs = []
for conf in config['pubConfigs']:
if conf["type"].lower() in ["mqtt", "mongo", ]:
key = conf["key"]
value = conf["value"]
if conf["type"].lower() in ["mqtt","mongo",]:
key= conf["key"]
value=conf["value"]
collection = conf["conectionCollection"]
pub_conf = db[collection].find_one({key: value}, {"_id": False})
pub_conf.update(conf)
pub_configs.append(pub_conf)
else:
else :
pub_configs.append(conf)
config['pubConfigs'] = pub_configs
......@@ -52,6 +52,7 @@ def load_conf(config, mongo_uri, dbname):
return config
# """
# {
# "MONGO_URI": "mongodb://192.168.3.220:21017",
......@@ -71,14 +72,14 @@ BASE_LOG_PATH = os.environ.get('BASE_LOG_PATH',
if not os.path.isdir(BASE_LOG_PATH):
os.mkdir(BASE_LOG_PATH)
CONFIG_ENV = json.loads(os.environ.get('config', default=None))
CONFIG_ENV = json.loads(os.environ.get('config', default=None))
sys.stdout.write("config->{} \n".format(json.dumps(CONFIG_ENV)))
MONGO_URI = CONFIG_ENV.get('MONGO_URI', None)
MONGO_DATABASE = CONFIG_ENV.get('MONGO_DATABASE', None)
MONGO_COLLECTION = CONFIG_ENV.get('MONGO_COLLECTION', None)
MONGO_KEY = CONFIG_ENV.get('MONGO_KEY', None)
MONGO_VALUE = CONFIG_ENV.get('MONGO_VALUE', None)
print(CONFIG_ENV)
MONGO_VALUE = CONFIG_ENV.get('MONGO_VALUE',None)
if MONGO_URI == None \
or MONGO_DATABASE is None \
or MONGO_COLLECTION is None \
......@@ -86,23 +87,19 @@ if MONGO_URI == None \
or MONGO_VALUE is None:
sys.stderr.write("invalid mongo config \n")
sys.exit(1)
state = os.environ.get('state',default='prod')
if state == 'dev':
with open('Edge_Config.json') as f:
EDGE_CONFIG = json.load(f)
else:
EDGE_CONFIG = get_config_from_mongo(
mongo_uri=MONGO_URI,
dbname=MONGO_DATABASE, basecollection=MONGO_COLLECTION,
key=MONGO_KEY, value=MONGO_VALUE
)
DEVICE_ID = EDGE_CONFIG["deviceId"]
EDGE_CONFIG = get_config_from_mongo(
mongo_uri=MONGO_URI,
dbname=MONGO_DATABASE, basecollection=MONGO_COLLECTION,
key=MONGO_KEY, value=MONGO_VALUE
)
DEVICE_ID = EDGE_CONFIG["deviceId"]
if EDGE_CONFIG is None:
sys.stderr.write("invalid EDGE_CONFIG config \n")
sys.exit(1)
EDGE_CONFIG = load_conf(EDGE_CONFIG, mongo_uri=MONGO_URI,
dbname=MONGO_DATABASE)
DATA_PATH = EDGE_CONFIG["inputConf"].get('dataPath', os.path.join(os.getcwd(), "data".format()))
EDGE_CONFIG=load_conf(EDGE_CONFIG, mongo_uri=MONGO_URI,
dbname=MONGO_DATABASE)
DATA_PATH = EDGE_CONFIG["inputConf"].get('dataPath',os.path.join(os.getcwd(), "data".format()))
sys.stderr.write("Loading data from {} \n".format(DATA_PATH))
sys.stderr.write("Loading data from {} \n".format(DATA_PATH))
\ No newline at end of file
......@@ -40,7 +40,8 @@ BASE_LOG_PATH = os.environ.get('BASE_LOG_PATH',
if not os.path.isdir(BASE_LOG_PATH):
os.mkdir(BASE_LOG_PATH)
DATA_PATH = os.environ.get('BASE_DATA_PATH', __config.get('CLIENT-CONFIG', 'basepath', fallback=os.path.normpath(
os.getcwd() + '{}data'.format(os.sep))))
sys.stdout.write("Data base path {} \n".format(DATA_PATH))
......
import os, time
from minio import Minio
# from minio.error import ResponseError
from edge_engine.common.logsetup import logger
......@@ -90,4 +89,4 @@ class MinioClient:
# MINIO_IP = '192.168.3.220:29000'
# LOCAL_DATA_PATH = "F:/GDrive Data/Downloads"
# obj = MinioClient(SECRET_KEY, ACCESS_KEY, BUCKET_NAME, LOCAL_DATA_PATH, MINIO_IP)
# obj.upload()
\ No newline at end of file
# obj.upload()
......@@ -3,29 +3,27 @@ from edge_engine.common.config import EDGE_CONFIG
from edge_engine.streamio.datastream import MQTT
from edge_engine.streamio.datastream import VideoOutputStream
from edge_engine.streamio.datastream import FrameOutputStream
from edge_engine.streamio.datastream import FFMPEGOutputStream, OPENCVOutputStream
from edge_engine.streamio.datastream import FFMPEGOutputStream
from edge_engine.streamio.datastream import MongoDataStreamOut
from edge_engine.streamio.videostream import ThreadedVideoStream
from edge_engine.streamio.videostream import FileVideoStream
from edge_engine.streamio.datastream import DummyPublisher
from edge_engine.streamio.frameProcessor import FrameProcessor
from edge_engine.common.minio_server import MinioClient
import json
from threading import Thread
import os
class Pubs():
def __init__(self):
self.mqtt_pub = DummyPublisher(name="MQTT")
self.frame_write = DummyPublisher(name="FRAME")
self.video_write = DummyPublisher(name="VIDEO")
self.mongo_write = DummyPublisher(name="MONGO")
self.rtp_write = DummyPublisher(name="RTP")
self.mqtt_pub = None
self.frame_write = None
self.video_write = None
self.mongo_write = None
self.rtp_write = None
self.build_pubs()
if 'minioConfig' in EDGE_CONFIG.keys() and \
isinstance(EDGE_CONFIG["minioConfig"], dict):
if 'minioConfig' in EDGE_CONFIG.keys() and \
isinstance(EDGE_CONFIG["minioConfig"],dict):
self.minio_thread = self.start_minio(EDGE_CONFIG["minioConfig"])
@staticmethod
......@@ -39,7 +37,6 @@ class Pubs():
def build_pubs(self):
logger.info("building publishers ")
state = os.environ.get('state', 'prod')
for conf in EDGE_CONFIG["pubConfigs"]:
if conf["type"].upper() == "MQTT":
self.mqtt_pub = MQTT(broker=conf["broker"], topic=conf["topic"], port=conf["port"]
......@@ -69,12 +66,8 @@ class Pubs():
password=conf["password"],
publish_hook=None)
elif conf["type"].upper() == "RTP":
self.rtp_write = FFMPEGOutputStream(conf["ffmpegCmd"], conf["RTPEndpoint"], publish_hook=None)
elif conf["type"].upper() == "OPENCV":
logger.info('Dev Testing, Video output will be loaded on new window')
self.rtp_write = OPENCVOutputStream()
self.rtp_write = FFMPEGOutputStream(conf["ffmpegCmd"], conf["RTPEndpoint"]
, publish_hook=None)
else:
logger.error("Unsupported publisher {}".format(conf["type"]))
......
......@@ -3,6 +3,4 @@ from edge_engine.streamio.datastream.mongodatastreamout import MongoDataStreamOu
from edge_engine.streamio.datastream.frameoutputstream import FrameOutputStream
from edge_engine.streamio.datastream.videooutputstream import VideoOutputStream
from edge_engine.streamio.datastream.mqttstream import MQTT
from edge_engine.streamio.datastream.ffmpegdata_streamout import FFMPEGOutputStream
from edge_engine.streamio.datastream.dummyouputstreamer import DummyPublisher
from edge_engine.streamio.datastream.opencvimshowout import OPENCVOutputStream
\ No newline at end of file
from edge_engine.streamio.datastream.ffmpegdata_streamout import FFMPEGOutputStream
\ No newline at end of file
from edge_engine.common.logsetup import logger
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
class DummyPublisher(DataStreamWrapper):
def __init__(self, name):
super().__init__()
self.name = name
def publish(self, x):
logger.warn(f"{self.name} Publisher is not configured but you are using it !!!!!!!!!")
from edge_engine.streamio.datastream.datastreamwrapper import DataStreamWrapper
import subprocess as sp
import cv2
class OPENCVOutputStream(DataStreamWrapper):
def __init__(self):
super().__init__()
def publish(self, x):
cv2.imshow('Dev Test', x['frame'])
key = cv2.waitKey(1)
# Copyright 2019 KnowledgeLens pvt Ltd.
VERSION = '1.0.0.alpha'
VERSION = '0.0.1.alpha'
This diff is collapsed.
2037e91b-5127-4bfb-867e-e8dfdaf788531673876778.875812.avi
7da72f97-f6ef-4541-9c27-c654581a47861673876810.1505582.avi
1e846e2a-9454-46a6-9e5e-0f2942fecddd1673876840.7609582.avi
2bf8e0b4-c669-4ec9-875a-c306e1a7cafc1673918679.660369.avi
6b069622-408f-4b08-b65f-42628832ae0f1673918710.2025747.avi
ef38a9a9-9e5c-461d-ab5b-e047a9bb23b11673918927.7348251.avi
4d97cde4-fa41-4ae4-86b8-d811f6b96a111673918958.1766603.avi
2548de5a-716d-4296-9aa8-72875fdfed0a1673918988.5155804.avi
5830b368-7a89-473b-95d2-88c25426d57c1673919018.9897242.avi
f61c730f-59c9-4c5b-8b80-beedb7d93a0d1673919049.2783659.avi
f625b670-f3dc-44ab-bdac-1bb073bf1e1a1673919079.727069.avi
a179becb-f3df-42e6-a0f6-bf999862c48b1673919110.3672595.avi
a1055d17-dbe0-42fe-9a5a-7cc877e863f01673919140.8465016.avi
25f68c42-d2b0-4d31-a651-1f7bd828e5a31673919171.1900787.avi
42f7b82a-ee30-49df-86fe-f8acfdb41d5f1673919201.623807.avi
926d531b-f9a3-4545-8f10-72232c1a19581673919232.0070171.avi
5a8bc7ec-0840-45e2-b823-9251df6ed4521673919262.2924252.avi
ef149507-10b0-49a5-8dd2-4d35ae3f540b1673937257.0850854.webm
1e12fad8-e319-4c4a-8a59-e3b60fc839641673937501.7711918.webm
f3b958af-f280-43aa-96c5-b1aa40f8a32a1673937635.0289881.webm
62054c4f-8d28-4153-ab01-f91c3b5d7c0b1673937672.4400358.webm
a74a3eb0-a2cb-4a1e-acea-588308006ace1673937870.293142.webm
b6271369-49b9-4834-bfe9-f256fb0437da1673938017.9071586.webm
80850154-1686-4b9a-a078-53c828bfd5911673938137.0431178.webm
920e0bd3-ff9c-4651-8c29-73f55da676bf1673938688.2525978.webm
3682bdcc-7345-4a8b-bbc5-cbdc90e27b961673938795.913603.webm
8d1daf45-b7a3-4f76-be72-791a9049be591673938826.3939579.webm
fb179339-7261-49cf-91f6-fcfca68c126a1673938856.883514.webm
e334b338-ac05-4e8f-abef-85c06861cc941673938887.3769703.webm
289d80a9-7a7a-4248-bc3e-ad12f94d3b401673939458.6783032.webm
81818b70-df7d-4a54-8fc0-919bf2d186e91673939548.079672.webm
0163846d-1c7a-4e47-8a21-f4343064b6341673944845.2525587.webm
23c579f3-7527-49a1-b3f1-4f2a112a3cc11673944875.549665.webm
53ba7ebb-d82b-41fd-a7e7-3102d197b0611673944905.8529074.webm
2c6ef734-7a71-4e5d-a82a-4d1298b1becb1673944936.2374694.webm
1c577a66-416d-451b-b017-1a2ebbb5f5321673944966.7960153.webm
20a7f8b3-da8d-446b-b9d6-09d1f01df0561673944997.252341.webm
cba5d9e8-2138-4a53-b845-600ffd9ac6c41673945027.7105763.webm
9d5f41b2-ddf6-4f21-9d0d-e0891e84d4921673945058.0353796.webm
3291b3cf-0b04-48f8-993a-c754176c6ca81673945088.4803202.webm
20a8f4c9-c315-4f3b-b4c7-5028856290ce1673945118.7755.webm
13159e47-a9e3-46c2-a611-24eda50329171673945149.1806812.webm
4667ce2e-598f-4974-9568-2523a03937cf1674613867.1548927.webm
427204c0-7231-47d2-a754-f6495db4dee61674614099.3403118.webm
93dd7783-f0d3-448f-8939-f1279ca908851674614129.876808.webm
341bd053-6817-4d90-a935-0d28c69707201674614160.6690917.webm
1d4fb86c-d147-4b43-a9c3-34d8d1c29cf01674614191.5612426.webm
eae32a35-16aa-4411-a0a5-453a090e3aee1674614222.4885771.webm
4eabe757-497e-476d-83ba-f99d6e0677051674614253.061201.webm
ed6e86fb-391f-4f81-94e8-ce04aca0a93f1674614442.5539196.webm
cbb8ecea-5a6b-4303-9464-dc1acacf10891674614473.4363682.webm
0f4aa969-1ae3-4e6d-b524-29a9e29fe3851674614504.0250866.webm
c01ae836-21f3-4c75-aa7e-9bc89a8534b71673869481.9821734.avi
e609d866-f8ea-45e1-87fd-4698be8211391673869513.4192338.avi
0a17a6fe-fe55-4e0e-8bb0-b9ab3c8b16001673869544.4394276.avi
9fdfd021-adcb-4776-b5ec-97632250a3df1673869575.249049.avi
cbf9542a-f9fe-4c2f-90ca-b4d1c9ecf2211673869605.9451807.avi
numpy==1.23.1
pymongo
opencv-python
numpy
cachetools
# yolov5processor~=1.1.1
minio
python-dateutil==2.8.2
paho-mqtt==1.5.1
pyyaml==5.4.1
pyjwt==2.1.0
six>=1.5
\ No newline at end of file
expiringdict
Cython
matplotlib
numpy
pillow
PyYAML
scipy>=1.4.1
tensorboard
tqdm
torch==1.9.0
torchvision==0.10.0
pandas
seaborn
scikit-learn==0.22.2
\ No newline at end of file
from.ppe import Ppe
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -13,9 +13,9 @@ if MAIN_OS_VARIABLE is None:
MONGO_URI = MAIN_OS_VARIABLE.get('MONGO_URI')
MONGO_SERVICE_DB = MAIN_OS_VARIABLE.get('MONGO_DB')
MONGO_SERVICE_COLL = MAIN_OS_VARIABLE.get('MONGO_COLL')
PASS_KEY = MAIN_OS_VARIABLE.get('PASS_KEY')
MONGO_DB_OBJ = MongoClient(MONGO_URI)[MONGO_SERVICE_DB]
HOST_CONFIG = MONGO_DB_OBJ[MONGO_SERVICE_COLL].find_one({'configId': 'hostConfig'}).get('config')
APP_MONGO_COLLECTION = MONGO_DB_OBJ[MONGO_SERVICE_COLL].find_one({'configId': 'appMongoConfig'}).get('config')
JANUS_CONFIG = MONGO_DB_OBJ[MONGO_SERVICE_COLL].find_one({'configId': 'janusConfig'}).get('config')
class ModelConstants:
sink_layer = {'cls': 'cls_branch_concat_1/concat', 'bbox': 'loc_branch_concat_1/concat'}
model_detector_pth = "./data/model/face_mask_detection.xml"
id2class = {0: 'Mask', 1: 'No Mask'}
id2bool = {0: True, 1: False}
exec_net_device_name = 'CPU'
fallback_initial_temperature = 98.3
net_precision = 'FP32'
\ No newline at end of file
class JanusDeploymentConstants:
JANUS_DEPLOYMENT_COLLECTION = "janusDeploymentConfigurations"
DEPLOYMENT_ID = 'deploymentId'
EXTRA_FIELDS_KEY = 'extra_fields'
LINE_COORDINATES = ['x1', 'y1', 'x2', 'y2']
COUNT_BAGS_FLAG = 'count_bags'
ALIGNMENT_KEY = 'alignment'
VERTICAL = 'vertical'
HORIZONTAL = 'horizontal'
MODEL_KEY = 'model'
DIRECTION_KEY = 'direction'
class CameraConstants:
videortpmap="VP8/90000"
videopt=96
threads=3
gStreamer = False
eventType = 'deploy'
created_by = 'user_6501'
event_status = 'pending'
deploymentTypeCreate = 'upgrade_and_deploy'
deploymentTypeRemove = 'remove'
pipeline_internal = {}
pipeline_category = "ai"
thread = 1
job_id = "pipeline_129"
deployment_key = 'deploymentId'
pipeline_deployment_type = 'docker'
docker_deployment_type = 'single'
command_eventtype = 'command'
command_type = 'docker'
restart_command = "restart_container"
stop_command = "stop_container"
start_command = "start_container"
import cv2
from edge_engine.ai.model.modelwraper import ModelWrapper
from edge_engine.common.logsetup import logger
from yolov5processor.infer import ExecuteInference
from scripts.utils.infocenter import InfoCenter
class PPEDetection(ModelWrapper):
def __init__(self, config, pubs, device_id):
super().__init__()
self.config = config['config']
self.rtp = pubs.rtp_write
self.ic = InfoCenter(device_id=device_id)
self.model = ExecuteInference(
weight="assets/ppe_6_class.pt",
confidence=0.6,
img_size=416,
gpu=False
)
self.prev_emit = None
self.validate_emit = True
self.validate_emit_count = 0
def _pre_process(self, x):
"""
Do preprocessing here, if any
:param x: payload
:return: payload
"""
return x
def _post_process(self, x):
"""
Apply post processing here, if any
:param x: payload
:return: payload
"""
self.rtp.publish(x)
return x
def validate_and_emit(self, msg, frame):
if self.validate_emit:
if self.prev_emit == msg:
self.validate_emit_count += 1
if self.validate_emit_count == 5:
logger.info(msg)
# self.ic.send_payload(frame=frame,
# person_count=1,
# message=msg,
# alert_sound="sound_1")
else:
self.prev_emit = msg
self.validate_emit_count = 0
def _predict(self, x):
"""Implement core mask_model inference code here"""
try:
print(x)
frame = x['frame']
prediction = self.model.predict(frame)
cv2.circle(frame, (350, 100), 2, (255, 255, 255), 2)
cv2.circle(frame, (925, 100), 2, (255, 255, 255), 2)
prediction = [each for each in prediction if each['points'][0] > 350 and each['points'][2] < 925]
person_count = len([each['class'] for each in prediction if each['class'] == 'Person'])
vest_count = len([each['class'] for each in prediction if each['class'] == 'Vest'])
hh_count = len([each['class'] for each in prediction if 'HH-' in each['class']])
msg = ""
if person_count > vest_count and person_count > hh_count:
msg = "PPE is Missing"
self.validate_and_emit(msg=msg, frame=frame)
elif person_count > vest_count:
msg = "Vest is Missing"
self.validate_and_emit(msg=msg, frame=frame)
elif person_count > hh_count:
msg = "Hardhat is Missing"
self.validate_and_emit(msg=msg, frame=frame)
elif person_count:
msg = "PPE Detected!"
self.validate_and_emit(msg=msg, frame=frame)
# logger.info(msg)
for det in prediction:
color = (0, 0, 255)
if msg == 'PPE Detected!':
color = (0, 255, 0)
cv2.rectangle(frame, (det['points'][0], det['points'][1]), (det['points'][2], det['points'][3]),
color, 2)
detection_class = det['class']
if det['class'].startswith('HH'):
detection_class = 'Hard Hat'
cv2.putText(frame, detection_class,
(det['points'][0], det['points'][3] - 10), cv2.FONT_HERSHEY_SIMPLEX,
1, color, 2, cv2.LINE_AA)
cv2.imshow('frame', cv2.resize(frame, (960, 540)))
if cv2.waitKey(1) & 0xFF == ord('q'):
import sys
sys.exit(0)
x['frame'] = cv2.resize(frame, (self.config.get('FRAME_WIDTH'), self.config.get('FRAME_HEIGHT')))
return x
except Exception as e:
logger.error(f"Error: {e}", exc_info=True)
x['frame'] = cv2.resize(x['frame'], (self.config.get('FRAME_WIDTH'), self.config.get('FRAME_HEIGHT')))
return x
import cv2, json
from edge_engine.ai.model.modelwraper import ModelWrapper
from edge_engine.common.logsetup import logger
# from yolov5processor.infer import ExecuteInference
from scripts.utils.infocenter import InfoCenter
class PPEDetection(ModelWrapper):
def __init__(self, config, pubs, device_id):
super().__init__()
self.config = config['config']
self.rtp = pubs.rtp_write
self.ic = InfoCenter(device_id=device_id)
self.dets = json.loads(open('assets/ppe.json', 'r').read())
self.prev_emit = None
self.validate_emit = True
self.validate_emit_count = 0
def _pre_process(self, x):
"""
Do preprocessing here, if any
:param x: payload
:return: payload
"""
return x
def _post_process(self, x):
"""
Apply post processing here, if any
:param x: payload
:return: payload
"""
self.rtp.publish(x)
return x
def validate_and_emit(self, msg, frame):
if self.validate_emit:
if self.prev_emit == msg:
self.validate_emit_count += 1
if self.validate_emit_count == 5:
logger.info(msg)
self.ic.send_payload(frame=frame,
person_count=1,
message=msg,
alert_sound="sound_1")
else:
self.prev_emit = msg
self.validate_emit_count = 0
def _predict(self, x):
"""Implement core mask_model inference code here"""
try:
frame = x['frame']
frameId = x['frameId']
# prediction = self.model.predict(frame)
prediction, frames = self.dets[int(frameId)][str(frameId)]['detections'], frame
prediction = [each for each in prediction if each['points'][0] > 350 and each['points'][2] < 925]
person_count = len([each['class'] for each in prediction if each['class'] == 'Person'])
vest_count = len([each['class'] for each in prediction if each['class'] == 'Vest'])
hh_count = len([each['class'] for each in prediction if 'HH-' in each['class']])
msg = ""
if person_count > vest_count and person_count > hh_count:
msg = "PPE is Missing"
self.validate_and_emit(msg=msg, frame=frame)
elif person_count > vest_count:
msg = "Vest is Missing"
self.validate_and_emit(msg=msg, frame=frame)
elif person_count > hh_count:
msg = "Hardhat is Missing"
self.validate_and_emit(msg=msg, frame=frame)
elif person_count:
msg = "PPE Detected!"
self.validate_and_emit(msg=msg, frame=frame)
# logger.info(msg)
for det in prediction:
color = (0, 0, 255)
if msg == 'PPE Detected!':
color = (0, 255, 0)
cv2.rectangle(frame, (det['points'][0], det['points'][1]), (det['points'][2], det['points'][3]),
color, 2)
detection_class = det['class']
if det['class'].startswith('HH'):
detection_class = 'Hard Hat'
cv2.putText(frame, detection_class,
(det['points'][0], det['points'][3] - 10), cv2.FONT_HERSHEY_SIMPLEX,
1, color, 2, cv2.LINE_AA)
# cv2.imshow('frame', cv2.resize(frame, (960, 540)))
# if cv2.waitKey(1) & 0xFF == ord('q'):
# import sys
# sys.exit(0)
x['frame'] = cv2.resize(frame, (self.config.get('FRAME_WIDTH'), self.config.get('FRAME_HEIGHT')))
return x
except Exception as e:
logger.error(f"Error: {e}", exc_info=True)
x['frame'] = cv2.resize(x['frame'], (self.config.get('FRAME_WIDTH'), self.config.get('FRAME_HEIGHT')))
return x
from edge_engine.ai.model.modelwraper import ModelWrapper
import cv2
import base64
class LoopBackModel(ModelWrapper):
def __init__(self, pubs, path=None, ):
super().__init__(path)
self.mqtt = pubs.mqtt_pub
def _pre_process(self, x):
return x
def _post_process(self, x):
image = cv2.imencode('.jpg', x['frame'])[1].tostring()
image = 'data:image/jpeg;base64,' + base64.b64encode(image).decode("utf-8")
x['frame'] = image
self.mqtt.publish(x)
return x
def _predict(self, x):
return x
def predict(self, x):
return super().predict(x)
This diff is collapsed.
# import the necessary packages
from scipy.spatial import distance as dist
from collections import OrderedDict
import numpy as np
from edge_engine.common.logsetup import logger
class CentroidTracker():
def __init__(self, maxDisappeared=50):
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict()
self.disappeared = OrderedDict()
# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared
def register(self, centroid):
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = {'has_print': False, 'centroid': centroid}
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1
def deregister(self, objectID):
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]
def update(self, rects):
# check to see if the list of input bounding box rectangles
# is empty
if len(rects) == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list(self.disappeared.keys()):
self.disappeared[objectID] += 1
# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister(objectID)
# return early as there are no centroids or tracking info
# to update
return self.objects
# initialize an array of input centroids for the current frame
inputCentroids = np.zeros((len(rects), 2), dtype="int")
# loop over the bounding box rectangles
for (i, (startX, startY, endX, endY)) in enumerate(rects):
# use the bounding box coordinates to derive the centroid
cX = int((startX + endX) / 2.0)
cY = int((startY + endY) / 2.0)
inputCentroids[i] = (cX, cY)
# if we are currently not tracking any objects take the input
# centroids and register each of them
if len(self.objects) == 0:
for i in range(0, len(inputCentroids)):
self.register(inputCentroids[i])
# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list(self.objects.keys())
objectCentroids = [e['centroid'] for e in self.objects.values()]
# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
# logger.info(f"OBC --> {objectCentroids}")
try:
D = dist.cdist(np.array(objectCentroids), inputCentroids)
except Exception as e:
logger.info(f"objectCentroids --> {objectCentroids}")
logger.info(f"inputCentroids --> {inputCentroids}")
logger.exception(e)
# in order to perform this matching we must (1) find the
# smallest value in each row and then (2) sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min(axis=1).argsort()
# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin(axis=1)[rows]
# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set()
usedCols = set()
# loop over the combination of the (row, column) index
# tuples
for (row, col) in zip(rows, cols):
# if we have already examined either the row or
# column value before, ignore it
# val
if row in usedRows or col in usedCols:
continue
# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID]['centroid'] = inputCentroids[col]
self.disappeared[objectID] = 0
# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add(row)
usedCols.add(col)
# compute both the row and column index we have NOT yet
# examined
unusedRows = set(range(0, D.shape[0])).difference(usedRows)
unusedCols = set(range(0, D.shape[1])).difference(usedCols)
# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1
# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister(objectID)
# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register(inputCentroids[col])
# return the set of trackable objects
return self.objects
from scripts.common.constants import JanusDeploymentConstants
from scripts.common.config import MONGO_DB_OBJ, APP_MONGO_COLLECTION
import cv2
from edge_engine.common.logsetup import logger
#from scripts.common.config import MONGO_DB_OBJ, APP_MONGO_COLLECTION
#from scripts.common.constants import JanusDeploymentConstants
class Utilities:
@classmethod
def get_extra_fields(
cls,
device_id,
):
_janus_deployment = MONGO_DB_OBJ[
APP_MONGO_COLLECTION.get(JanusDeploymentConstants.JANUS_DEPLOYMENT_COLLECTION)].find_one(
{JanusDeploymentConstants.DEPLOYMENT_ID: device_id}).get(
JanusDeploymentConstants.EXTRA_FIELDS_KEY)
if _janus_deployment is None:
raise ValueError("Janus deployment configuration is not found/corrupted")
_key_dictionary = dict()
for each_field in _janus_deployment:
_key_dictionary[each_field['key']] = each_field['value']
return _key_dictionary
@classmethod
def get_direction(
cls,
device_id,
):
logger.debug("Getting the direction from DB")
return MONGO_DB_OBJ[APP_MONGO_COLLECTION.get(JanusDeploymentConstants.JANUS_DEPLOYMENT_COLLECTION)].find_one(
{JanusDeploymentConstants.DEPLOYMENT_ID: device_id}).get(
JanusDeploymentConstants.DIRECTION_KEY)
@classmethod
def set_direction(
cls,
device_id: str,
direction: bool,
):
logger.debug("Updating the direction in DB")
updated_values = {"$set": {JanusDeploymentConstants.DIRECTION_KEY: direction}}
MONGO_DB_OBJ[APP_MONGO_COLLECTION.get(JanusDeploymentConstants.JANUS_DEPLOYMENT_COLLECTION)].update_one(
{JanusDeploymentConstants.DEPLOYMENT_ID: device_id}, updated_values)
@classmethod
def draw_circles_on_frame(
cls,
frame,
point,
radius=3,
color=(255, 255, 255),
thickness=1,
):
"""
draw circle on the objects
:param radius: radius of the circle
:param frame: frame to draw on
:param point: co-ordinate to draw on
:param color: color of the circle
:param thickness: thickness of the circle
:return: frame
"""
return cv2.circle(frame, tuple(point), radius, color, thickness)
@classmethod
def resize_to_64_64(
cls,
frame,
):
"""
resize the from
:param frame: frame
:return: frame
"""
return cv2.resize(frame, (64, 64))
def get_extra_fields(device_id):
# _janus_deployment = [
# {
# "type": "number",
# "key": "x1",
# "value": 1000
# },
# {
# "type": "number",
# "key": "y1",
# "value": 0
# },
# {
# "type": "number",
# "key": "x2",
# "value": 1001
# },
# {
# "type": "number",
# "key": "y2",
# "value": 720
# },
# {
# "type": "dropdown",
# "key": "alignment",
# "value": "vertical"
# }
# ]
_janus_deployment = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get(JanusDeploymentConstants.JANUS_DEPLOYMENT_COLLECTION)]. \
find_one({JanusDeploymentConstants.DEPLOYMENT_ID: device_id}).get(JanusDeploymentConstants.EXTRA_FIELDS_KEY)
if _janus_deployment is None:
raise ValueError("Janus deployment configuration is not found/corrupted")
_key_dictionary = dict()
for each_field in _janus_deployment:
_key_dictionary[each_field['key']] = each_field['value']
return _key_dictionary
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 20 14:51:33 2017
@author: kyleguan
"""
import numpy as np
import cv2
np.seterr(divide='ignore', invalid='ignore')
class Box:
def __init__(self):
self.x, self.y = float(), float()
self.w, self.h = float(), float()
self.c = float()
self.prob = float()
def overlap(x1, w1, x2, w2):
l1 = x1 - w1 / 2.;
l2 = x2 - w2 / 2.;
left = max(l1, l2)
r1 = x1 + w1 / 2.;
r2 = x2 + w2 / 2.;
right = min(r1, r2)
return right - left;
def box_intersection(a, b):
w = overlap(a.x, a.w, b.x, b.w);
h = overlap(a.y, a.h, b.y, b.h);
if w < 0 or h < 0: return 0;
area = w * h;
return area;
def box_union(a, b):
i = box_intersection(a, b);
u = a.w * a.h + b.w * b.h - i;
return u;
def box_iou(a, b):
return box_intersection(a, b) / box_union(a, b);
def box_iou2(a, b):
'''
Helper funciton to calculate the ratio between intersection and the union of
two boxes a and b
a[0], a[1], a[2], a[3] <-> left, up, right, bottom
'''
w_intsec = np.maximum(0, (np.minimum(a[2], b[2]) - np.maximum(a[0], b[0])))
h_intsec = np.maximum(0, (np.minimum(a[3], b[3]) - np.maximum(a[1], b[1])))
s_intsec = w_intsec * h_intsec
s_a = (a[2] - a[0]) * (a[3] - a[1])
s_b = (b[2] - b[0]) * (b[3] - b[1])
return float(s_intsec) / (s_a + s_b - s_intsec)
def convert_to_pixel(box_yolo, img, crop_range):
'''
Helper function to convert (scaled) coordinates of a bounding box
to pixel coordinates.
Example (0.89361443264143803, 0.4880486045564924, 0.23544462956491041,
0.36866588651069609)
crop_range: specifies the part of image to be cropped
'''
box = box_yolo
imgcv = img
[xmin, xmax] = crop_range[0]
[ymin, ymax] = crop_range[1]
h, w, _ = imgcv.shape
# Calculate left, top, width, and height of the bounding box
left = int((box.x - box.w / 2.) * (xmax - xmin) + xmin)
top = int((box.y - box.h / 2.) * (ymax - ymin) + ymin)
width = int(box.w * (xmax - xmin))
height = int(box.h * (ymax - ymin))
# Deal with corner cases
if left < 0: left = 0
if top < 0: top = 0
# Return the coordinates (in the unit of the pixels)
box_pixel = np.array([left, top, width, height])
return box_pixel
def convert_to_cv2bbox(bbox, img_dim=(1280, 720)):
'''
Helper fucntion for converting bbox to bbox_cv2
bbox = [left, top, width, height]
bbox_cv2 = [left, top, right, bottom]
img_dim: dimension of the image, img_dim[0]<-> x
img_dim[1]<-> y
'''
left = np.maximum(0, bbox[0])
top = np.maximum(0, bbox[1])
right = np.minimum(img_dim[0], bbox[0] + bbox[2])
bottom = np.minimum(img_dim[1], bbox[1] + bbox[3])
return (left, top, right, bottom)
def draw_box_label(id, img, bbox_cv2, box_color=(0, 255, 255), show_label=True):
'''
Helper funciton for drawing the bounding boxes and the labels
bbox_cv2 = [left, top, right, bottom]
'''
# box_color= (0, 255, 255)
font = cv2.FONT_HERSHEY_SIMPLEX
font_size = 0.7
font_color = (0, 0, 0)
left, top, right, bottom = bbox_cv2[1], bbox_cv2[0], bbox_cv2[3], bbox_cv2[2]
# Draw the bounding box
cv2.rectangle(img, (left, top), (right, bottom), box_color, 4)
# centroid = [int(left+((right - left)/2)), int(top+((bottom - top)/2))]
if show_label:
# Draw a filled box on top of the bounding box (as the background for the labels)
cv2.rectangle(img, (left - 2, top - 45), (right + 2, top), box_color, -1, 1)
# Output the labels that show the x and y coordinates of the bounding box center.
text_x = 'id=' + str(id)
cv2.putText(img, text_x, (left, top - 25), font, font_size, font_color, 1, cv2.LINE_AA)
text_y = 'y=' + str((top + bottom) / 2)
# cv2.putText(img, text_y, (left, top - 5), font, font_size, font_color, 1, cv2.LINE_AA)
return img
from edge_engine.common.logsetup import logger
import cv2
def draw_circles_on_frame(frame, point, radius=3, color=(255, 255, 255), thickness=1):
"""
draw circle on the objects
:param radius: radius of the circle
:param frame: frame to draw on
:param point: co-ordinate to draw on
:param color: color of the circle
:param thickness: thickness of the circle
:return: frame
"""
logger.debug("Drawing circle centroid on the frame")
return cv2.circle(frame, tuple(point), radius, color, thickness)
def resize_to_64_64(frame):
"""
resize the from
:param frame: frame
:return: frame
"""
logger.debug("Resizing the frame to 64 x 64")
return cv2.resize(frame, (64, 64))
\ No newline at end of file
import cv2
import time
import base64
from uuid import uuid1
import os
from datetime import datetime
from cachetools import cached, TTLCache
from requests import post
from uuid import uuid1
from urllib.parse import urljoin
from edge_engine.common.logsetup import logger
from scripts.common.config import MONGO_DB_OBJ, APP_MONGO_COLLECTION
TTL = 5
class InfoCenter:
def __init__(self, device_id):
self.device_id = device_id
self.attendance_event_collection = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('eventLogCollection')]
self.camera_configuration = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('cameraConfigurationCollection')]
self.ttl_check = NotificationFilter()
def get_camera_name(
self,
device_id: str
) -> str:
camera_mapping_json = self.camera_configuration.find_one(
{
'decommissioned': False,
'cameraId': device_id
},
{
"_id": 0
})
if camera_mapping_json:
return camera_mapping_json['cameraName']
return 'iLens Camera'
def send_payload(
self,
frame,
label='ppe',
bg_color="#474520",
font_color="#FFFF00",
alert_sound=None,
message="",
person_count=0
):
if self.ttl_check.check_rpt(message):
frame = cv2.resize(frame, (64, 64))
payload = {
"deviceId": self.device_id,
"message": message,
"frame": 'data:image/jpeg;base64,' + base64.b64encode(
cv2.imencode('.jpg', frame)[1].tostring()).decode("utf-8"),
"activity": label,
"bg_color": bg_color,
"font_color": font_color,
"alert_sound": alert_sound,
"person_count": person_count}
self.insert_attendance_event_to_mongo(payload)
def insert_attendance_event_to_mongo(self, data):
try:
input_data = {
"eventId": str(uuid1()).split('-')[0],
"cameraId": data['deviceId'],
"cameraName": self.get_camera_name(data['deviceId']),
"timestamp": datetime.now(),
"frame": data['frame'],
"eventtype": "Intrusion Detection",
"bg_color": data["bg_color"],
"font_color": data["font_color"],
"intrusion_message": data["message"],
"alert_sound": data["alert_sound"],
"person_count": data["person_count"],
"app": data["activity"]
}
logger.debug("Pushing to Mongo..")
self.attendance_event_collection.insert(input_data)
except Exception as e:
logger.error(f"Exception occurred: {e}", exc_info=True)
class NotificationFilter(object):
def __init__(self, ttl_value=3):
"""init function
"""
global TTL
TTL = ttl_value
self.TTL = ttl_value
self.face_id_cache = {}
def _update_cache(self, name):
"""updates the cache with a name
Args:
name (str): Name of the person
"""
self.face_id_cache[name] = time.time()
def check_rpt(self, name):
"""Returns a boolean if the notification center has to be notified
or not
Args:
name (str): name of person identified
Returns:
notify (bool): True if notification to be sent False if the
notification is not to be sent
"""
self._clean_up_cache()
if name is None:
notify = False
else:
is_present = self.face_id_cache.get(name, -1)
if is_present == -1:
notify = True
self._update_cache(name)
else:
notify = False
return notify
@cached(cache=TTLCache(maxsize=1024, ttl=TTL))
def _clean_up_cache(self):
"""Cleans up the cached name at regular interval
"""
key_to_delete = []
for key, value in self.face_id_cache.items():
if time.time() - value >= self.TTL:
key_to_delete.append(key)
for key in key_to_delete:
del self.face_id_cache[key]
class MongoLogger:
def __init__(self):
self.attendance_event_collection = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('eventLogCollection')]
self.camera_configuration = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('cameraConfigurationCollection')]
self.camera_mapping_json = self.get_all_cameras()
def get_all_cameras(self):
camera_mapping_json = self.camera_configuration.find({'decommissioned': False}, {"_id": 0})
camera_json = {}
for each in camera_mapping_json:
camera_json[each['cameraId']] = each['cameraName']
return camera_json
@staticmethod
def update_count_api():
asset_id = os.environ.get('asset_id')
asset_hierarchy = os.environ.get('asset_hierarchy')
count_update_endpoint = os.environ.get('count_update_endpoint')
if asset_id is not None and count_update_endpoint is not None and asset_hierarchy is not None:
response = post(url=count_update_endpoint, json=dict(asset_hierarchy=asset_hierarchy, count_increment=1, asset_id=asset_id),
timeout=5)
if response.status_code != 200:
logger.warning(
"Value not updated in cards!. Invalid response from Update Count API: {}".format(response.content))
else:
logger.warning("Either asset_id, asset_hierarchy or count_update_endpoint is not set!."
" Not updating the cards API!")
def insert_attendance_event_to_mongo(self, data):
try:
input_data = {
"eventId": str(uuid1()).split('-')[0],
"cameraId": "4",
"cameraName": self.camera_mapping_json.get(data['deviceId'], "Thermal Camera"),
"timestamp": datetime.now(),
"frame": data['frame'],
"eventtype": data["message"],
"bg_color": data["bg_color"],
"font_color": data["font_color"],
"intrusion_message": data["event_type"],
"alert_sound": data["alert_sound"],
"logged_activity": data["activity"],
"frame_id": data["frame_id"]}
if os.environ.get('app') is not None:
input_data['app'] = os.environ.get('app')
logger.info("Pushing to Mongo..")
self.attendance_event_collection.insert_one(input_data)
self.update_count_api()
except Exception as e:
logger.exception(e)
from datetime import datetime
from scripts.common.config import MONGO_DB_OBJ
class ModelCountTracker:
def __init__(
self,
device_id,
) -> None:
self.device_id = device_id
self.count_tracker = None
self._reset_tracker()
def _reset_tracker(self):
self.count_tracker = list()
def __call__(
self,
conf: float,
) -> None:
self.count_tracker.append(
{
"time": datetime.now(),
"deviceId": self.device_id,
"count_confidence": conf
})
if len(self.count_tracker) >= 10:
self.insert_to_mongo(self.count_tracker)
self._reset_tracker()
@staticmethod
def insert_to_mongo(
payload: list,
collection_name: str = "model_count_tracker"
) -> None:
MONGO_DB_OBJ[collection_name].insert_many(payload)
class ModelTracker:
def __init__(
self,
device_id,
) -> None:
self.device_id = device_id
self.model_tracker = None
self._reset_tracker()
def _reset_tracker(self):
self.model_tracker = list()
def __call__(
self,
conf: float,
) -> None:
self.model_tracker.append(
{
"time": datetime.now(),
"deviceId": self.device_id,
"model_confidence": conf
})
if len(self.model_tracker) >= 500:
self.insert_to_mongo(self.model_tracker)
self._reset_tracker()
@staticmethod
def insert_to_mongo(
payload: list,
collection_name: str = "model_confidence_tracker"
) -> None:
MONGO_DB_OBJ[collection_name].insert_many(payload)
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import numpy as np
from numpy import dot
from scipy.linalg import inv, block_diag
class Tracker(): # class for Kalman Filter based tracker
def __init__(self):
# Initialize parametes for tracker (history)
self.id = 0 # tracker's id
self.box = [] # list to store the coordinates for a bounding box
self.hits = 0 # number of detection matches
self.no_losses = 0 # number of unmatched tracks (track loss)
# Initialize parameters for Kalman Filtering
# The state is the (x, y) coordinates of the detection box
# state: [up, up_dot, left, left_dot, down, down_dot, right, right_dot]
# or[up, up_dot, left, left_dot, height, height_dot, width, width_dot]
self.x_state = []
self.dt = 1. # time interval
# Process matrix, assuming constant velocity model
self.F = np.array([[1, self.dt, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, self.dt, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, self.dt, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, self.dt],
[0, 0, 0, 0, 0, 0, 0, 1]])
# Measurement matrix, assuming we can only measure the coordinates
self.H = np.array([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0]])
# Initialize the state covariance
self.L = 100.0
self.P = np.diag(self.L * np.ones(8))
# Initialize the process covariance
self.Q_comp_mat = np.array([[self.dt ** 4 / 2., self.dt ** 3 / 2.],
[self.dt ** 3 / 2., self.dt ** 2]])
self.Q = block_diag(self.Q_comp_mat, self.Q_comp_mat,
self.Q_comp_mat, self.Q_comp_mat)
# Initialize the measurement covariance
self.R_ratio = 1.0 / 16.0
self.R_diag_array = self.R_ratio * np.array([self.L, self.L, self.L, self.L])
self.R = np.diag(self.R_diag_array)
def update_R(self):
R_diag_array = self.R_ratio * np.array([self.L, self.L, self.L, self.L])
self.R = np.diag(R_diag_array)
def kalman_filter(self, z):
'''
Implement the Kalman Filter, including the predict and the update stages,
with the measurement z
'''
x = self.x_state
# Predict
x = dot(self.F, x)
self.P = dot(self.F, self.P).dot(self.F.T) + self.Q
# Update
S = dot(self.H, self.P).dot(self.H.T) + self.R
K = dot(self.P, self.H.T).dot(inv(S)) # Kalman gain
y = z - dot(self.H, x) # residual
x += dot(K, y)
self.P = self.P - dot(K, self.H).dot(self.P)
self.x_state = x.astype(int) # convert to integer coordinates
# (pixel values)
def predict_only(self):
'''
Implment only the predict stage. This is used for unmatched detections and
unmatched tracks
'''
x = self.x_state
# Predict
x = dot(self.F, x)
self.P = dot(self.F, self.P).dot(self.F.T) + self.Q
self.x_state = x.astype(int)
if __name__ == "__main__":
import matplotlib.pyplot as plt
import glob
import helpers
# Creat an instance
trk = Tracker()
# Test R_ratio
trk.R_ratio = 1.0 / 16
# Update measurement noise covariance matrix
trk.update_R()
# Initial state
x_init = np.array([390, 0, 1050, 0, 513, 0, 1278, 0])
x_init_box = [x_init[0], x_init[2], x_init[4], x_init[6]]
# Measurement
z = np.array([399, 1022, 504, 1256])
trk.x_state = x_init.T
trk.kalman_filter(z.T)
# Updated state
x_update = trk.x_state
x_updated_box = [x_update[0], x_update[2], x_update[4], x_update[6]]
print('The initial state is: ', x_init)
print('The measurement is: ', z)
print('The update state is: ', x_update)
# Visualize the Kalman filter process and the
# impact of measurement nosie convariance matrix
images = [plt.imread(file) for file in glob.glob('./test_images/*.jpg')]
img = images[3]
plt.figure(figsize=(10, 14))
helpers.draw_box_label(img, x_init_box, box_color=(0, 255, 0))
ax = plt.subplot(3, 1, 1)
plt.imshow(img)
plt.title('Initial: ' + str(x_init_box))
helpers.draw_box_label(img, z, box_color=(255, 0, 0))
ax = plt.subplot(3, 1, 2)
plt.imshow(img)
plt.title('Measurement: ' + str(z))
helpers.draw_box_label(img, x_updated_box)
ax = plt.subplot(3, 1, 3)
plt.imshow(img)
plt.title('Updated: ' + str(x_updated_box))
plt.show()
import typer
app = typer.Typer()
@app.command()
def hello(name: str):
typer.echo(f"Hello {name}")
@app.command()
def goodbye(name: str, formal: bool = False):
if formal:
typer.echo(f"Goodbye Ms. {name}. Have a good day.")
else:
typer.echo(f"Bye {name}!")
if __name__ == "__main__":
app()
\ No newline at end of file
from os import environ
environ["config"] = '{"MONGO_URI": "mongodb://admin:iLens!8989@192.168.0.220:21017", "MONGO_DATABASE": "ilens_wps", ' \
'"MONGO_DB": "ilens_wps","MONGO_COLLECTION": "janusDeployment", "MONGO_KEY": "deploymentId", ' \
'"MONGO_VALUE": "1b180a0e", "MONGO_SERVICE_COLL": "serviceConfiguration", "MONGO_COLL": ' \
'"serviceConfiguration" } '
import unittest
from edge_engine.edge_processor import Pubs
from edge_engine.common.config import EDGE_CONFIG
from scripts.cement_counter import CementBagCounter
class TestCementBagCounter(unittest.TestCase):
def test__pre_process(self):
self.assertEqual(CementBagCounter(config=EDGE_CONFIG, model_config=EDGE_CONFIG["modelConfig"], pubs=Pubs(),
device_id=EDGE_CONFIG['deviceId'])._pre_process("5"), '5')
This diff is collapsed.
# Define hooks for code formations
# Will be applied on any updated commit files if a user has installed and linked commit hook
default_language_version:
python: python3.8
# Define bot property if installed via https://github.com/marketplace/pre-commit-ci
ci:
autofix_prs: true
autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions'
autoupdate_schedule: monthly
# submodules: true
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
# - id: end-of-file-fixer
- id: trailing-whitespace
- id: check-case-conflict
- id: check-yaml
- id: check-toml
- id: pretty-format-json
- id: check-docstring-first
- repo: https://github.com/asottile/pyupgrade
rev: v2.38.2
hooks:
- id: pyupgrade
name: Upgrade code
args: [ --py37-plus ]
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
hooks:
- id: isort
name: Sort imports
- repo: https://github.com/pre-commit/mirrors-yapf
rev: v0.32.0
hooks:
- id: yapf
name: YAPF formatting
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.16
hooks:
- id: mdformat
name: MD formatting
additional_dependencies:
- mdformat-gfm
- mdformat-black
exclude: "README.md|README_cn.md"
- repo: https://github.com/asottile/yesqa
rev: v1.4.0
hooks:
- id: yesqa
- repo: https://github.com/PyCQA/flake8
rev: 5.0.4
hooks:
- id: flake8
name: PEP8
## Contributing to YOLOv5 🚀
We love your input! We want to make contributing to YOLOv5 as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing a new feature
- Becoming a maintainer
YOLOv5 works so well due to our combined community effort, and for every small improvement you contribute you will be
helping push the frontiers of what's possible in AI 😃!
## Submitting a Pull Request (PR) 🛠️
Submitting a PR is easy! This example shows how to submit a PR for updating `requirements.txt` in 4 steps:
### 1. Select File to Update
Select `requirements.txt` to update by clicking on it in GitHub.
<p align="center"><img width="800" alt="PR_step1" src="https://user-images.githubusercontent.com/26833433/122260847-08be2600-ced4-11eb-828b-8287ace4136c.png"></p>
### 2. Click 'Edit this file'
Button is in top-right corner.
<p align="center"><img width="800" alt="PR_step2" src="https://user-images.githubusercontent.com/26833433/122260844-06f46280-ced4-11eb-9eec-b8a24be519ca.png"></p>
### 3. Make Changes
Change `matplotlib` version from `3.2.2` to `3.3`.
<p align="center"><img width="800" alt="PR_step3" src="https://user-images.githubusercontent.com/26833433/122260853-0a87e980-ced4-11eb-9fd2-3650fb6e0842.png"></p>
### 4. Preview Changes and Submit PR
Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch**
for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose
changes** button. All done, your PR is now submitted to YOLOv5 for review and approval 😃!
<p align="center"><img width="800" alt="PR_step4" src="https://user-images.githubusercontent.com/26833433/122260856-0b208000-ced4-11eb-8e8e-77b6151cbcc3.png"></p>
### PR recommendations
To allow your work to be integrated as seamlessly as possible, we advise you to:
- ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update
your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally.
<p align="center"><img width="751" alt="Screenshot 2022-08-29 at 22 47 15" src="https://user-images.githubusercontent.com/26833433/187295893-50ed9f44-b2c9-4138-a614-de69bd1753d7.png"></p>
- ✅ Verify all YOLOv5 Continuous Integration (CI) **checks are passing**.
<p align="center"><img width="751" alt="Screenshot 2022-08-29 at 22 47 03" src="https://user-images.githubusercontent.com/26833433/187296922-545c5498-f64a-4d8c-8300-5fa764360da6.png"></p>
- ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase
but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee
## Submitting a Bug Report 🐛
If you spot a problem with YOLOv5 please submit a Bug Report!
For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few
short guidelines below to help users provide what we need in order to get started.
When asking a question, people will be better able to provide help if you provide **code** that they can easily
understand and use to **reproduce** the problem. This is referred to by community members as creating
a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). Your code that reproduces
the problem should be:
-**Minimal** – Use as little code as possible that still produces the same problem
-**Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself
-**Reproducible** – Test the code you're about to provide to make sure it reproduces the problem
In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code
should be:
-**Current** – Verify that your code is up-to-date with current
GitHub [master](https://github.com/ultralytics/yolov5/tree/master), and if necessary `git pull` or `git clone` a new
copy to ensure your problem has not already been resolved by previous commits.
-**Unmodified** – Your problem must be reproducible without any modifications to the codebase in this
repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️.
If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛
**Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and providing
a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) to help us better
understand and diagnose your problem.
## License
By contributing, you agree that your contributions will be licensed under
the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment