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