-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
102 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,110 +1,96 @@ | ||
import os | ||
import json | ||
from PIL import Image | ||
from src.digitizer import Digitizer | ||
from src.routing import IdentifierConverter | ||
from src.draw import draw_objects | ||
from src.file_storage import FileStorage | ||
from io import BytesIO | ||
from glob import glob | ||
from flask import Flask, request | ||
from flask import Flask, request, send_file | ||
|
||
model = 'models/yolov8-detect-20240229.onnx' | ||
data_dir = 'data/' | ||
|
||
digitizer = Digitizer(model) | ||
storage = FileStorage(data_dir) | ||
|
||
app = Flask(__name__) | ||
app.url_map.converters['identifier'] = IdentifierConverter | ||
|
||
@app.route('/digitize', methods=['POST']) | ||
def digitize(): | ||
value, _, _ = _detect() | ||
decimals = request.args.get('decimals', default=0, type=int) | ||
threshold = request.args.get('threshold', default=0.7, type=float) | ||
|
||
image = Image.open(BytesIO(request.get_data())) | ||
value, _ = digitizer.detect(image, decimals, threshold) | ||
|
||
if value is None: | ||
return 'No reading found', 400 | ||
|
||
json_data = json.dumps({'value': value}) | ||
|
||
return json_data, 200, {'Content-Type': 'application/json'} | ||
return json.dumps({'value': value}), 200, {'Content-Type': 'application/json'} | ||
|
||
@app.route('/meter/<identifier:meter_id>', methods=['POST']) | ||
def update_meter(meter_id): | ||
value, objects, image = _detect() | ||
decimals = request.args.get('decimals', default=0, type=int) | ||
threshold = request.args.get('threshold', default=0.7, type=float) | ||
max_increase = request.args.get('max_increase', default=float('inf'), type=float) | ||
|
||
image = Image.open(BytesIO(request.get_data())) | ||
value, objects = digitizer.detect(image, decimals, threshold) | ||
|
||
if value is None: | ||
return 'No reading found', 400 | ||
|
||
json_file = os.path.join(data_dir, f'{meter_id}.json') | ||
max_increase = request.args.get('max_increase', default=float('inf'), type=float) | ||
|
||
if os.path.exists(json_file): | ||
with open(json_file, 'r') as f: | ||
data = json.load(f) | ||
if value < data['value']: | ||
try: | ||
old_value = storage.read_value(meter_id) | ||
|
||
if value < old_value: | ||
return 'Reading is lower than previous', 400 | ||
if value - data['value'] > max_increase: | ||
if value - old_value > max_increase: | ||
return 'Reading increased too much', 400 | ||
except FileNotFoundError: | ||
# no old value | ||
pass | ||
|
||
json_data = json.dumps({'value': value}) | ||
|
||
with open(json_file, 'w') as f: | ||
f.write(json_data) | ||
|
||
image.save(os.path.join(data_dir, f'{meter_id}.jpg')) | ||
|
||
draw_objects(image, objects) | ||
|
||
image.save(os.path.join(data_dir, f'{meter_id}_result.jpg')) | ||
result_image = image.copy() | ||
draw_objects(result_image, objects) | ||
|
||
storage.store(meter_id, value, image, result_image) | ||
|
||
return json_data, 200, {'Content-Type': 'application/json'} | ||
return json.dumps({'value': value}), 200, {'Content-Type': 'application/json'} | ||
|
||
@app.route('/meter/<identifier:meter_id>', methods=['GET']) | ||
def show_meter(meter_id): | ||
return _send_file(f'{meter_id}.json', 'application/json') | ||
try: | ||
value = storage.read_value(meter_id) | ||
return json.dumps({'value': value}), 200, {'Content-Type': 'application/json'} | ||
except FileNotFoundError: | ||
return 'Meter not found', 404 | ||
|
||
@app.route('/meter/<identifier:meter_id>/image', methods=['GET']) | ||
def meter_image(meter_id): | ||
return _send_file(f'{meter_id}.jpg', 'image/jpeg') | ||
try: | ||
data = storage.read_image_data(meter_id) | ||
return data, 200, {'Content-Type': 'image/jpeg'} | ||
except FileNotFoundError: | ||
return 'Meter not found', 404 | ||
|
||
@app.route('/meter/<identifier:meter_id>/image_result', methods=['GET']) | ||
def meter_image_result(meter_id): | ||
return _send_file(f'{meter_id}_result.jpg', 'image/jpeg') | ||
@app.route('/meter/<identifier:meter_id>/result_image', methods=['GET']) | ||
def meter_result_image(meter_id): | ||
try: | ||
data = storage.read_result_image_data(meter_id) | ||
return data, 200, {'Content-Type': 'image/jpeg'} | ||
except FileNotFoundError: | ||
return 'Meter not found', 404 | ||
|
||
@app.route('/meter/<identifier:meter_id>/reset', methods=['GET']) | ||
def reset_meter(meter_id): | ||
for file in glob(f'{data_dir}{meter_id}.*'): | ||
os.remove(file) | ||
|
||
value = request.args.get('value', default=None, type=float) | ||
storage.remove(meter_id) | ||
|
||
if value is not None: | ||
json_data = json.dumps({'value': value}) | ||
json_file = os.path.join(data_dir, f'{meter_id}.json') | ||
with open(json_file, 'w') as f: | ||
f.write(json_data) | ||
blank_image = Image.new('RGB', (1, 1)) | ||
storage.store(meter_id, value, blank_image, blank_image) | ||
|
||
return 'Meter reset', 200 | ||
|
||
def _detect(): | ||
decimals = request.args.get('decimals', default=0, type=int) | ||
threshold = request.args.get('threshold', default=0.7, type=float) | ||
data = request.get_data() | ||
image = Image.open(BytesIO(data)) | ||
reading, objects = digitizer.detect(image, threshold) | ||
|
||
if len(reading): | ||
value = float(reading) / (10 ** decimals) | ||
else: | ||
value = None | ||
|
||
return value, objects, image | ||
|
||
def _send_file(file_name, content_type): | ||
path = os.path.join(data_dir, file_name) | ||
|
||
if not os.path.exists(path): | ||
return 'Meter not found', 404 | ||
|
||
data = open(path, 'rb').read() | ||
|
||
return data, 200, {'Content-Type': content_type} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import json | ||
import os | ||
|
||
class FileStorage: | ||
def __init__(self, path): | ||
self.path = path | ||
|
||
def store(self, meter_id, value, image, result_image): | ||
self._write_data(f'{meter_id}.json', {'value': value}) | ||
self._write_image(f'{meter_id}.jpg', image) | ||
self._write_image(f'{meter_id}_result.jpg', result_image) | ||
|
||
def read_value(self, meter_id): | ||
return self._read_data(f'{meter_id}.json')['value'] | ||
|
||
def read_image_data(self, meter_id): | ||
return self._read_image_data(f'{meter_id}.jpg') | ||
|
||
def read_result_image_data(self, meter_id): | ||
return self._read_image_data(f'{meter_id}_result.jpg') | ||
|
||
def remove(self, meter_id): | ||
files = [f'{meter_id}.json', f'{meter_id}.jpg', f'{meter_id}_result.jpg'] | ||
for file in files: | ||
path = os.path.join(self.path, file) | ||
if os.path.exists(path): | ||
os.remove(path) | ||
|
||
def _write_data(self, name, data): | ||
with open(os.path.join(self.path, name), 'w') as f: | ||
json.dump(data, f) | ||
|
||
def _read_data(self, name): | ||
with open(os.path.join(self.path, name), 'r') as f: | ||
return json.load(f) | ||
|
||
def _write_image(self, name, image): | ||
with open(os.path.join(self.path, name), 'wb') as f: | ||
image.save(f, 'JPEG') | ||
|
||
def _read_image_data(self, name): | ||
return open(os.path.join(self.path, name), 'rb').read() |