From 662e10d1a40821bcf9fecaf46f7766e8d6ea808c Mon Sep 17 00:00:00 2001 From: Simon Milvert Date: Wed, 10 Feb 2021 21:19:53 +0100 Subject: [PATCH] start with poetry --- water_meter/detect_circle.py | 15 +++--- water_meter/detect_hsv.py | 16 +++++-- water_meter/read_stram.py | 2 + water_meter/src/__init__.py | 1 + water_meter/src/water_meter/__init__.py | 0 water_meter/src/{ => water_meter}/config.yml | 0 water_meter/src/{ => water_meter}/helpers.py | 15 +++--- water_meter/src/{ => water_meter}/main.py | 40 ++++++++-------- water_meter/src/{ => water_meter}/mqtt.py | 3 +- water_meter/src/{ => water_meter}/water.py | 20 ++++---- .../src/{ => water_meter}/water_meter.py | 46 +++++++++++-------- 11 files changed, 91 insertions(+), 67 deletions(-) create mode 100755 water_meter/src/water_meter/__init__.py rename water_meter/src/{ => water_meter}/config.yml (100%) rename water_meter/src/{ => water_meter}/helpers.py (66%) rename water_meter/src/{ => water_meter}/main.py (50%) rename water_meter/src/{ => water_meter}/mqtt.py (90%) rename water_meter/src/{ => water_meter}/water.py (83%) rename water_meter/src/{ => water_meter}/water_meter.py (87%) diff --git a/water_meter/detect_circle.py b/water_meter/detect_circle.py index 468abea..7684aa2 100755 --- a/water_meter/detect_circle.py +++ b/water_meter/detect_circle.py @@ -11,7 +11,7 @@ image = cv2.imread('capture.png') # Create a window cv2.namedWindow('image') -# dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None) + # Create trackbars for color change # Hue is from 0-179 for Opencv cv2.createTrackbar('dp', 'image', 0, 300, nothing) @@ -33,7 +33,7 @@ cv2.setTrackbarPos('maxRadius', 'image', 50) dp = minDist = param1 = param2 = minRadius = maxRadius = 0 pdp = pminDist = pparam1 = pparam2 = pminRadius = pmaxRadius = 0 -while (1): +while True: # Get current positions of all trackbars dp = cv2.getTrackbarPos('dp', 'image') minDist = cv2.getTrackbarPos('minDist', 'image') @@ -44,16 +44,17 @@ while (1): img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gradient = cv2.HOUGH_GRADIENT - circles = cv2.HoughCircles(img, gradient, dp/100.0, minDist, - param1=param1, param2=param2, minRadius=minRadius, - maxRadius=maxRadius) + circles = cv2.HoughCircles(img, gradient, dp/100.0, minDist, param1=param1, + param2=param2, minRadius=minRadius, + maxRadius=maxRadius) # Print if there is a change in HSV value if ((pdp != dp) | (pminDist != minDist) | (pparam1 != param1) | ( pparam2 != param2) | (pminRadius != minRadius) | ( pmaxRadius != maxRadius)): - print("dp: {}, minDist: {}, param1: {}, param2: {}, minRadius: {}, maxRadius: {}" - .format(dp, minDist, param1, param2, minRadius, maxRadius)) + print(f"dp: {dp}, minDist: {minDist}, param1: {param1}, " + f"param2: {param2}, minRadius: {minRadius}, " + f"maxRadius: {maxRadius}") pdp = dp pminDist = minDist pparam1 = param1 diff --git a/water_meter/detect_hsv.py b/water_meter/detect_hsv.py index 223c7e6..ca6fc31 100755 --- a/water_meter/detect_hsv.py +++ b/water_meter/detect_hsv.py @@ -1,9 +1,12 @@ import cv2 import numpy as np + def nothing(x): + print(x) pass + # Load image image = cv2.imread('capture.png') @@ -28,7 +31,7 @@ cv2.setTrackbarPos('VMax', 'image', 255) hMin = sMin = vMin = hMax = sMax = vMax = 0 phMin = psMin = pvMin = phMax = psMax = pvMax = 0 -while(1): +while True: # Get current positions of all trackbars hMin = cv2.getTrackbarPos('HMin', 'image') sMin = cv2.getTrackbarPos('SMin', 'image') @@ -47,8 +50,15 @@ while(1): result = cv2.bitwise_and(image, image, mask=mask) # Print if there is a change in HSV value - if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ): - print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax)) + if( + (phMin != hMin) | + (psMin != sMin) | + (pvMin != vMin) | + (phMax != hMax) | + (psMax != sMax) | + (pvMax != vMax)): + print(f"(hMin = {hMin} , sMin = {sMin}, vMin = {vMin}), " + f"(hMax = {hMax}, sMax = {sMax}, vMax = {vMax})") phMin = hMin psMin = sMin pvMin = vMin diff --git a/water_meter/read_stram.py b/water_meter/read_stram.py index 9494864..175f076 100755 --- a/water_meter/read_stram.py +++ b/water_meter/read_stram.py @@ -1,5 +1,6 @@ import cv2 + def get_video(): camera = cv2.VideoCapture() camera.open('http://10.0.0.22:81') @@ -12,5 +13,6 @@ def get_video(): cv2.waitKey(1) pass + if __name__ == '__main__': get_video() diff --git a/water_meter/src/__init__.py b/water_meter/src/__init__.py index e69de29..3f5c4a7 100755 --- a/water_meter/src/__init__.py +++ b/water_meter/src/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1.0" diff --git a/water_meter/src/water_meter/__init__.py b/water_meter/src/water_meter/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/water_meter/src/config.yml b/water_meter/src/water_meter/config.yml similarity index 100% rename from water_meter/src/config.yml rename to water_meter/src/water_meter/config.yml diff --git a/water_meter/src/helpers.py b/water_meter/src/water_meter/helpers.py similarity index 66% rename from water_meter/src/helpers.py rename to water_meter/src/water_meter/helpers.py index 28e2ada..f47006d 100755 --- a/water_meter/src/helpers.py +++ b/water_meter/src/water_meter/helpers.py @@ -1,6 +1,5 @@ - import yaml -import logging + def get_config(config_filepath: str) -> dict: with open(config_filepath) as f: @@ -9,14 +8,14 @@ def get_config(config_filepath: str) -> dict: def create_logger(): - import multiprocessing, logging + import multiprocessing + import logging logger = multiprocessing.get_logger() logger.setLevel(logging.INFO) - formatter = logging.Formatter(\ - '[%(asctime)s| %(levelname)s| %(message)s') - import os, os.path - if not os.path.exists("logs/"): - os.makedirs("logs/") + formatter = logging.Formatter('[%(asctime)s| %(levelname)s| %(message)s') + import os.path + if not os.path.exists("logs"): + os.makedirs("logs") handler = logging.FileHandler('logs/water.log') handler.setFormatter(formatter) diff --git a/water_meter/src/main.py b/water_meter/src/water_meter/main.py similarity index 50% rename from water_meter/src/main.py rename to water_meter/src/water_meter/main.py index 4f54cc3..6822b9e 100755 --- a/water_meter/src/main.py +++ b/water_meter/src/water_meter/main.py @@ -1,12 +1,12 @@ import os import time +from queue import Queue from threading import Thread -from src.helpers import get_config, create_logger -from src.mqtt import get_mqtt_client -from src.water import ReportAmount, Water -from src.water_meter import WaterMeter -from queue import Queue +from src.water_meter.helpers import get_config, create_logger +from src.water_meter.mqtt import get_mqtt_client +from src.water_meter.water import ReportAmount +from src.water_meter.water_meter import WaterMeter CONFIG_FILE_PATH = os.getenv("MQTT_CAMERA_CONFIG", "./config.yml") CONFIG = get_config(CONFIG_FILE_PATH) @@ -16,15 +16,17 @@ MQTT_PORT = CONFIG["mqtt"]["port"] def producer(): - logger = create_logger() - logger.info("From producer") - water_meter = WaterMeter('http://10.0.0.22:81', img='capture_4.png', debug=False) + logger_producer = create_logger() + logger_producer.info("From producer") + water_meter = WaterMeter('http://10.0.0.22:81', + img='capture_4.png', + debug=False) water_meter.loop(q) def consumer(): - logger = create_logger() - logger.info("From consumer") + logger_consumer = create_logger() + logger_consumer.info("From consumer") evaluator = ReportAmount(client, topic='water_meter/litre') while True: water = q.get(True) @@ -32,28 +34,28 @@ def consumer(): def main(): - client = get_mqtt_client() - client.connect(MQTT_BROKER, port=MQTT_PORT) time.sleep(5) while True: from random import randrange value = randrange(10) - client.publish('water_meter/litre', 1) + client.publish('water_meter/litre', value) time.sleep(3) def main2(): - producer() consumer_thread = Thread(target=consumer) consumer_thread.daemon = True consumer_thread.start() + producer() + + +logger = create_logger() +logger.info("From main") +q = Queue() +client = get_mqtt_client() +client.connect(MQTT_BROKER, port=MQTT_PORT) if __name__ == '__main__': - logger = create_logger() - logger.info("From main") - q = Queue() - client = get_mqtt_client() - client.connect(MQTT_BROKER, port=MQTT_PORT) main2() diff --git a/water_meter/src/mqtt.py b/water_meter/src/water_meter/mqtt.py similarity index 90% rename from water_meter/src/mqtt.py rename to water_meter/src/water_meter/mqtt.py index 36aa008..11a7c27 100755 --- a/water_meter/src/mqtt.py +++ b/water_meter/src/water_meter/mqtt.py @@ -2,9 +2,10 @@ Some boilerplate code to handle MQTT. """ import os + from paho.mqtt import client as mqtt -from src.helpers import get_config +from src.water_meter.helpers import get_config CONFIG_FILE_PATH = os.getenv("MQTT_CAMERA_CONFIG", "./config.yml") CONFIG = get_config(CONFIG_FILE_PATH) diff --git a/water_meter/src/water.py b/water_meter/src/water_meter/water.py similarity index 83% rename from water_meter/src/water.py rename to water_meter/src/water_meter/water.py index 966078e..9dc90cb 100755 --- a/water_meter/src/water.py +++ b/water_meter/src/water_meter/water.py @@ -1,9 +1,11 @@ -from dataclasses import dataclass import time -from threading import Thread +from dataclasses import dataclass from queue import Queue +from threading import Thread + from .helpers import create_logger + @dataclass class Water: percent_of_a_litre: int @@ -15,6 +17,7 @@ def coroutine(fn): v = fn(*args, **kwargs) v.send(None) return v + return wrapper @@ -45,20 +48,19 @@ class ReportAmount: self.logger.info(f"New litre, publish, amount: {self.litre}") self.last_send_timestamp = water.timestamp self.current_state = self.reported - #print(f"REPORT: Percentage is {percentage}, time {water.timestamp}") + # print(f"REPORT: Percentage is {percentage}, time {water.timestamp}") @coroutine def _reported(self): while True: water = yield percentage = water.percent_of_a_litre - time_diff = water.timestamp - self.last_send_timestamp + # time_diff = water.timestamp - self.last_send_timestamp if percentage > 25: self.current_state = self.redo - # print(f"REPORTED: Wait until percentage is 50, {percentage}" + # print(f"REPORTED: Wait until percentage is 50, {percentage}" # f", timediff: {time_diff}") - @coroutine def _redo(self): while True: @@ -67,7 +69,6 @@ class ReportAmount: if percentage < 20: print("Change to report") self.current_state = self.report - #print(f"REDO: Percentage is {percentage}, time {water.timestamp}") def producer(): @@ -77,7 +78,7 @@ def producer(): def consumer(): - evaluator = ReportAmount() + evaluator = ReportAmount(None, topic='water_meter/litre') while True: water = q.get(True) evaluator.send(water) @@ -95,6 +96,3 @@ if __name__ == '__main__': t1.start() q.join() - - - diff --git a/water_meter/src/water_meter.py b/water_meter/src/water_meter/water_meter.py similarity index 87% rename from water_meter/src/water_meter.py rename to water_meter/src/water_meter/water_meter.py index c7ac95a..248fab8 100755 --- a/water_meter/src/water_meter.py +++ b/water_meter/src/water_meter/water_meter.py @@ -1,14 +1,13 @@ import math -import sys import time import cv2 -import os -import numpy as np import imutils +import numpy as np from scipy.spatial import distance as dist -from .water import Water + from .helpers import create_logger +from .water import Water class WaterMeter(object): @@ -43,6 +42,7 @@ class WaterMeter(object): img = cv2.imread(self.img) self.get_degree(img) + # noinspection PyUnusedLocal def loop(self, queue): bad_frame = 0 while not self._quit: @@ -62,7 +62,7 @@ class WaterMeter(object): ret, current_frame = self.cap.read() # the connection broke, or the stream came to an end if (not ret) or (current_frame is None): - # ToDo Logging error frame + self.logger.error("Bad frame") bad_frame += 1 continue else: @@ -87,6 +87,7 @@ class WaterMeter(object): cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.putText(current_frame, f"%: {self.percent}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.imshow("Degree", current_frame) cv2.waitKey(1) @@ -99,8 +100,7 @@ class WaterMeter(object): def get_degree(self, frame): img = frame dials = self.find_circle(img) - # Init value out of range - deg = -1 + dial_one_litre = [] if not dials: return -1, img @@ -174,8 +174,15 @@ class WaterMeter(object): except cv2.error: return None # Find suitable hsv number by running detect_hsv.py - lower_red_hue = self.create_hue_mask(hsv, [0, 100, 100], [10, 255, 255]) - higher_red_hue = self.create_hue_mask(hsv, [170, 80, 110], [179, 255, 255]) + lower_red_hue = self.create_hue_mask(hsv, + [0, 100, 100], + [10, 255, 255] + ) + + higher_red_hue = self.create_hue_mask(hsv, + [170, 80, 110], + [179, 255, 255] + ) mask = cv2.bitwise_or(lower_red_hue, higher_red_hue) needle = cv2.GaussianBlur(mask, (5, 5), 0) @@ -187,7 +194,7 @@ class WaterMeter(object): def get_contours(self, img, org): ret, thresh = cv2.threshold(img, 127, 255, 0) contours = cv2.findContours(thresh, cv2.RETR_TREE, - cv2.CHAIN_APPROX_SIMPLE) + cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(contours) try: c = max(cnts, key=cv2.contourArea) @@ -232,11 +239,11 @@ class WaterMeter(object): height, width, _ = cut.shape for (x, y) in extreme_points: - D = dist.euclidean((x, y), (int(height/2), int(width/2))) + distance = dist.euclidean((x, y), (int(height/2), int(width/2))) if not length_from_centre: - length_from_centre = {'x': x, 'y': y, 'distance': D} - elif D > length_from_centre['distance']: - length_from_centre = {'x': x, 'y': y, 'distance': D} + length_from_centre = {'x': x, 'y': y, 'distance': distance} + elif distance > length_from_centre['distance']: + length_from_centre = {'x': x, 'y': y, 'distance': distance} if self.debug: cv2.line(cut, (length_from_centre['x'], length_from_centre['y']), @@ -259,8 +266,11 @@ class WaterMeter(object): self.percent = sum(self.percent_list) / len(self.percent_list) self.percent = round(self.percent * 100) -if __name__ == '__main__': - water_meter = WaterMeter('http://10.0.0.22:81', img='capture_4.png', debug=False) - water_meter.loop() - #water_meqter.read() + +if __name__ == '__main__': + water_meter = WaterMeter('http://10.0.0.22:81', + img='capture_4.png', + debug=False) + water_meter.loop() + # water_meqter.read()