Skip to content

Commit 5da8d13

Browse files
Merge pull request #8 from 5sControl/dev
Dev
2 parents 82f2d7a + 299d99b commit 5da8d13

23 files changed

+259
-211
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ __pycache__
77
.vscode/
88
build/
99
cmake-build-debug/
10-
idle_models/weights/
10+
idle_model/weights/

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
# algorithms-python
1+
# algorithms-python
2+
3+
```bash
4+
docker build ./idle_models -t 5scontrol/idle_python_server:v-.-.-
5+
docker build . -t 5scontrol/idle_python:v-.-.-
6+
7+
docker run --network host --rm 5scontrol/idle_python_server:v-.-.-
8+
docker run --network host --rm 5scontrol/idle_python:v-.-.-
9+
```

confs/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .load_configs import load_configs
2+
configs = load_configs()

confs/configs.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
{
2-
"classes": [
3-
77
4-
],
52
"wait_time": 10,
63
"threshold": 100
74
}

confs/load_configs.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import json
2+
import os
23

34

4-
with open("confs/configs.json", "r") as conf:
5-
configs = json.load(conf)
6-
CONF_THRES = configs.get("conf_thres")
7-
IOU_THRES = configs.get("iou_thres")
8-
MODEL_PATH = configs.get("model_path")
9-
CLASSES = configs.get("classes")
10-
WAIT_TIME = configs.get("wait_time")
11-
THRESHOLD = configs.get("threshold")
5+
def load_configs() -> dict:
6+
with open("confs/configs.json", "r") as conf:
7+
configs = json.load(conf)
8+
return configs

connection/IdleReporter.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import os
2+
import time
3+
import logging
4+
import requests
5+
import datetime
6+
import uuid
7+
import cv2
8+
import numpy as np
9+
10+
11+
class IdleReporter:
12+
def __init__(self, images_folder: str, server_url: str, wait_time: int, logger: logging.Logger) -> None:
13+
self.images_folder = images_folder
14+
self.server_url = server_url
15+
self.wait_time = wait_time
16+
self.logger = logger
17+
os.makedirs(self.images_folder, exist_ok=True)
18+
19+
def _save_image(self, image: np.array) -> str:
20+
save_photo_url = f'{self.images_folder}/' + str(uuid.uuid4()) + '.jpg'
21+
cv2.imwrite(save_photo_url, image)
22+
return save_photo_url
23+
24+
def create_report(self, image: np.array, start_tracking_time: datetime.time) -> dict:
25+
time.sleep(self.wait_time)
26+
stop_tracking_time = str(datetime.datetime.now())
27+
saved_image_name = self._save_image(image)
28+
report_for_send = {
29+
'camera': self.images_folder.split('/')[1],
30+
'algorithm': 'idle_control',
31+
'start_tracking': start_tracking_time,
32+
'stop_tracking': stop_tracking_time,
33+
'photos': [{'image': saved_image_name, 'date': start_tracking_time}],
34+
'violation_found': True,
35+
}
36+
return report_for_send
37+
38+
def send_report(self, report: dict) -> None:
39+
try:
40+
self.logger.info(str(report))
41+
requests.post(
42+
url=f'{self.server_url}:80/api/reports/report-with-photos/', json=report
43+
)
44+
except Exception as exc:
45+
self.logger.error(f"Cannot send report. Following error raised: {str(exc)}")
46+
47+

connection/ImageHTTPExtractor.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import httplib2
2+
import logging
3+
import datetime
4+
import numpy as np
5+
import cv2
6+
from typing import Tuple, Union
7+
8+
9+
class ImageHTTPExtractor:
10+
def __init__(self, server_url: str, logger: logging.Logger, **credentials) -> None:
11+
self.http_connection = httplib2.Http(".cache")
12+
self.http_connection.add_credentials(credentials.get("username"), credentials.get("password"))
13+
self.logger = logger
14+
self.server_url = server_url
15+
16+
def get_snapshot(self) -> Tuple[Union[cv2.Mat, None], Union[datetime.time, None]]:
17+
try:
18+
curr_time = datetime.datetime.now()
19+
response, content = self.http_connection.request(
20+
self.server_url,
21+
"GET",
22+
body="foobar"
23+
)
24+
nparr = np.frombuffer(content, np.uint8)
25+
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
26+
return img, curr_time
27+
except Exception as exc:
28+
self.logger.error(f"Cannot retrieve image. Following error raised - {exc}")
29+
return None, None
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import requests
2+
import numpy as np
3+
from logging import Logger
4+
from PIL import Image
5+
import io
6+
7+
8+
PORT = 5001
9+
10+
11+
class ModelPredictionsReceiver:
12+
def __init__(self, server_url: str, logger: Logger) -> None:
13+
self.server_url = server_url
14+
self.logger = logger
15+
16+
@staticmethod
17+
def _convert_image2bytes(image: np.array, format='PNG') -> io.BytesIO:
18+
pil_image = Image.fromarray(image)
19+
img_byte_arr = io.BytesIO()
20+
pil_image.save(img_byte_arr, format=format)
21+
img_byte_arr.seek(0)
22+
return img_byte_arr
23+
24+
def _predict(self, img: np.array) -> np.array:
25+
try:
26+
response = requests.post(
27+
f"{self.server_url}:{PORT}/predict",
28+
files={
29+
"image": ("image", self._convert_image2bytes(img), "image/png")
30+
}
31+
)
32+
response.raise_for_status()
33+
return np.array(response.json().get("coordinates"))
34+
except Exception as exc:
35+
self.logger.critical("Cannot send request to model server. Error - {}".format(exc))
36+
return np.array([])
37+
38+
def predict(self, img: np.array) -> np.array:
39+
imgs = [
40+
img[:img.shape[0] // 2, :, :],
41+
img[img.shape[0] // 2:, :, :]
42+
]
43+
preds = [self._predict(imgs[0]), self._predict(imgs[1])]
44+
if len(preds[1]):
45+
preds[1][:, 1] += img.shape[0] // 2
46+
preds[1][:, 3] += img.shape[0] // 2
47+
result = np.append(*preds)
48+
if len(result.shape) == 1:
49+
result = np.expand_dims(result, 0)
50+
return result

connection/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .IdleReporter import IdleReporter
2+
from .ImageHTTPExtractor import ImageHTTPExtractor
3+
from .ModelPredictionsReceiver import ModelPredictionsReceiver

functional.py

Lines changed: 0 additions & 95 deletions
This file was deleted.
File renamed without changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import torch
2+
import numpy as np
3+
import torch
4+
from ultralytics import YOLO
5+
6+
7+
class IdleObjectDetectionModel:
8+
def __init__(self, path: str, conf_thresh, iou_thresh, classes) -> None:
9+
self.model = YOLO(path)
10+
self.conf_thresh = conf_thresh
11+
self.iou_thresh = iou_thresh
12+
self.classes = classes
13+
14+
@torch.no_grad()
15+
def __call__(self, img: np.array) -> np.array:
16+
output = self.model(
17+
source=img,
18+
conf=self.conf_thresh,
19+
iou=self.iou_thresh,
20+
max_det=600,
21+
classes=self.classes,
22+
verbose=False
23+
)[0].boxes
24+
return output.xyxy
File renamed without changes.

idle_models/configs/confs.json renamed to idle_model/configs/confs.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
67
44
],
55
"iou_thres": 0.5,
6-
"conf_thres": 0.65,
7-
"model_path": "./weights",
6+
"conf_thres": 0.8,
7+
"model_path": "weights/yolov8l.pt",
88
"port": 5001
99
}

idle_model/configs/load_configs.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import json
2+
3+
4+
with open("configs/confs.json", "r") as conf:
5+
configs = json.load(conf)
6+
CONF_THRES = configs.get("conf_thres")
7+
IOU_THRES = configs.get("iou_thres")
8+
MODEL_PATH = configs.get("model_path")
9+
CLASSES = configs.get("classes")
10+
PORT = configs.get("port")

idle_models/requirements.txt renamed to idle_model/requirements.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@ PyYAML==6.0
99
requests==2.27.1
1010
Flask==2.2.2
1111
colorlog==4.8.0
12-
transformers==4.28.1
13-
timm==0.6.13
12+
ultralytics==8.0.136

idle_models/IdleObjectDetectionModel.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

idle_models/configs/load_configs.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)