mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-26 01:51:40 +00:00
Merge branch 'dev' into dev
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,3 +9,5 @@ Python/app/__pycache__/
|
||||
Python/app/handlers/__pycache__/
|
||||
|
||||
\.vscode/
|
||||
|
||||
backend/settings/
|
||||
|
||||
10
README.md
10
README.md
@@ -7,7 +7,7 @@ These instructions will get you a copy of the project up and running on your loc
|
||||
|
||||
so in order to run this project we will need to install python in order to run the backend and node.js with vue.js in order to run the fronted
|
||||
#### backend
|
||||
- python 3.6 and above
|
||||
- python 3.7 and above
|
||||
- opencv 3.4.5
|
||||
- tornado web framework
|
||||
- robotpy-cscore
|
||||
@@ -29,7 +29,7 @@ so in order to run this project we will need to install python in order to run t
|
||||
2. apt-get dist-upgrade
|
||||
3. sudo apt-get upgrade
|
||||
4. sudo apt-get install python3-pip python3-dev cmake zip unzip build-essential git libnss-mdns --fix-missing
|
||||
5. sudo pip3 install numpy
|
||||
5. sudo pip3 install numpy (if on raspberry pi do "sudo apt-get install python3-numpy")
|
||||
6. OPENCV_VERSION=3.4.5
|
||||
7. wget -O opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip
|
||||
8. unzip opencv.zip
|
||||
@@ -65,7 +65,11 @@ of you can auto serve the ui by
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
## Hardware
|
||||
this is important when choosing your sbc it is more important to have a good usb controller that a good cpu
|
||||
on the odroid xu4 which is very fast i have got many bottlenecks from the usb controller and many times making the program crach
|
||||
#### networking
|
||||
it is very important to install Bonjour
|
||||
|
||||
|
||||
## docs
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
from datetime import timedelta
|
||||
from networktables import NetworkTables
|
||||
import tornado.ioloop
|
||||
import logging
|
||||
from app.ChameleonVisionApp import ChameleonApplication
|
||||
from app.classes.SettingsManager import SettingsManager
|
||||
from tornado.options import options
|
||||
from app.handlers.VisionHandler import VisionHandler
|
||||
import threading
|
||||
import asyncio
|
||||
from app.handlers.SocketHandler import send_all_async
|
||||
from app.handlers.CameraHander import CameraHandler
|
||||
|
||||
|
||||
def run_server():
|
||||
@@ -15,15 +18,24 @@ def run_server():
|
||||
print(f"Serving on port {options.port}")
|
||||
app.listen(options.port)
|
||||
tornado.ioloop.IOLoop.current().start()
|
||||
tornado.ioloop.IOLoop.instance().add_timeout(timedelta(seconds=1),
|
||||
send_all_async)
|
||||
|
||||
|
||||
def run():
|
||||
NetworkTables.startClientTeam(team=settings_manager.general_settings.get("team_number", 1577))
|
||||
# NetworkTables.initialize("localhost")
|
||||
port = 5550
|
||||
for cam_name in settings_manager.usb_cameras:
|
||||
CameraHandler(cam_name, port).run()
|
||||
port += 1
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
SettingsManager()
|
||||
|
||||
VisionHandler().run()
|
||||
settings_manager = SettingsManager()
|
||||
run()
|
||||
server_thread = threading.Thread(target=run_server)
|
||||
server_thread.start()
|
||||
|
||||
while True:
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import os
|
||||
|
||||
from .handlers.MainHandler import MainHandler
|
||||
from .handlers.SocketHandler import ChameleonWebSocket
|
||||
from tornado.options import define
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
class PipelineAlreadyExistsException(Exception):
|
||||
|
||||
def __init__(self, pipe_name):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import socket
|
||||
import os
|
||||
import json
|
||||
import cv2
|
||||
|
||||
225
backend/app/handlers/CameraHander.py
Normal file
225
backend/app/handlers/CameraHander.py
Normal file
@@ -0,0 +1,225 @@
|
||||
import math
|
||||
import cv2
|
||||
import numpy
|
||||
from cscore import CameraServer
|
||||
from app.classes.SettingsManager import SettingsManager
|
||||
from ..handlers.SocketHandler import send_all_async
|
||||
from multiprocessing import Process
|
||||
import threading
|
||||
import zmq
|
||||
import asyncio
|
||||
import time
|
||||
from networktables import NetworkTables
|
||||
import networktables
|
||||
from .VisionHandler import VisionHandler
|
||||
|
||||
|
||||
class CameraHandler:
|
||||
def __init__(self, cam_name, port):
|
||||
#settings vars up for vision loop
|
||||
self.cs = CameraServer.getInstance()
|
||||
self.settings_manager = SettingsManager()
|
||||
self.vision_handler = VisionHandler()
|
||||
self.port = port
|
||||
self.cam_name = cam_name
|
||||
self.image = None
|
||||
self.p_image = None
|
||||
self.table = None
|
||||
self.nt_data = {'valid': False}
|
||||
self.time_stamp = 0
|
||||
|
||||
def run(self):
|
||||
#starting main thread
|
||||
threading.Thread(target=self.thread_proc).start()
|
||||
|
||||
def thread_proc(self):
|
||||
self.settings_manager.cams_curr_pipeline[self.cam_name] = "pipeline0"
|
||||
pipeline = self.settings_manager.cams[self.cam_name]["pipelines"][self.settings_manager.cams_curr_pipeline[self.cam_name]]
|
||||
FOV = self.settings_manager.cams[self.cam_name]["FOV"]
|
||||
|
||||
def change_camera_values(pipline):
|
||||
self.settings_manager.usb_cameras[self.cam_name].setBrightness(pipeline['brightness'])
|
||||
self.settings_manager.usb_cameras[self.cam_name].setExposureManual(pipeline['exposure'])
|
||||
self.settings_manager.usb_cameras[self.cam_name].setWhiteBalanceAuto()
|
||||
|
||||
def pipeline_listener(table, key, value, is_new):
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
self.settings_manager.cams_curr_pipeline[self.cam_name] = value
|
||||
change_camera_values(pipeline)
|
||||
if self.cam_name == self.settings_manager.general_settings['curr_camera']:
|
||||
self.settings_manager.general_settings['curr_pipeline'] = value
|
||||
update_settings = self.settings_manager.get_curr_pipeline()
|
||||
update_settings['curr_pipeline'] = self.settings_manager.general_settings["curr_pipeline"]
|
||||
send_all_async(update_settings)
|
||||
|
||||
def mode_listener(table, key, value, is_new):
|
||||
change_camera_values({
|
||||
'brightness': 25,
|
||||
'exposure': 15
|
||||
})
|
||||
#setting up network table
|
||||
self.table = NetworkTables.getTable("/Chameleon-Vision/" + self.cam_name)
|
||||
self.table.putString('Pipeline', self.settings_manager.cams_curr_pipeline[self.cam_name])
|
||||
self.table.addEntryListenerEx(pipeline_listener, key="Pipeline",
|
||||
flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE)
|
||||
self.table.addEntryListenerEx(mode_listener, key="Driver_Mode",
|
||||
flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE)
|
||||
|
||||
# getting video from current camera
|
||||
cv_sink = self.cs.getVideo(camera=self.settings_manager.usb_cameras[self.cam_name])
|
||||
|
||||
width = self.settings_manager.cams[self.cam_name]["video_mode"]["width"]
|
||||
height = self.settings_manager.cams[self.cam_name]["video_mode"]["height"]
|
||||
|
||||
# setting up a video server for camera
|
||||
cv_publish = self.cs.putVideo(name=self.cam_name, width=width, height=height)
|
||||
# saving camera port in cam name dict for usage in client
|
||||
self.settings_manager.cams_port[self.cam_name] = self.cs._sinks['serve_' + self.cam_name].getPort()
|
||||
|
||||
# setting up a zmq connection to the opencv subprocess
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.PAIR)
|
||||
socket.bind('tcp://*:%s' % str(self.port))
|
||||
|
||||
# starting the process with initial values
|
||||
p = Process(target=self.camera_process, args=(self.cam_name, self.port, FOV))
|
||||
p.start()
|
||||
|
||||
change_camera_values(pipeline)
|
||||
|
||||
def _publish_thread():
|
||||
#getting image values and publishing process image and data
|
||||
self.image = numpy.zeros(shape=(width, height, 3), dtype=numpy.uint8)
|
||||
self.p_image = self.image
|
||||
while True:
|
||||
try:
|
||||
self.time_stamp, self.image = cv_sink.grabFrame(self.image)
|
||||
cv_publish.putFrame(self.p_image)
|
||||
self.table.putBoolean('valid', self.nt_data['valid'])
|
||||
# check if point is valid
|
||||
if self.nt_data['valid']:
|
||||
# send the point using network tables
|
||||
self.table.putNumber('pitch', self.nt_data['pitch'])
|
||||
self.table.putNumber('yaw', self.nt_data['yaw'])
|
||||
self.table.putNumber('fps', self.nt_data['fps'])
|
||||
self.table.putNumber('time_stamp', self.time_stamp)
|
||||
# if the selected camera in ui is this cam send the point to the ui
|
||||
except:
|
||||
pass
|
||||
|
||||
def _socket_thread():
|
||||
#publishing to websocket at slower interval
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
if self.settings_manager.general_settings['curr_camera'] == self.cam_name:
|
||||
try:
|
||||
send_all_async({
|
||||
'raw_point': self.nt_data['raw_point'],
|
||||
'point': {
|
||||
'pitch': self.nt_data['pitch'],
|
||||
'yaw': self.nt_data['yaw'],
|
||||
'fps': self.nt_data['fps']
|
||||
}
|
||||
})
|
||||
except:
|
||||
pass
|
||||
|
||||
threading.Thread(target=_publish_thread).start()
|
||||
threading.Thread(target=_socket_thread).start()
|
||||
|
||||
while True:
|
||||
#sending and reciving data from opencv sub process
|
||||
pipeline = self.settings_manager.cams[self.cam_name]["pipelines"][
|
||||
self.settings_manager.cams_curr_pipeline[self.cam_name]]
|
||||
socket.send_json(dict(
|
||||
pipeline=pipeline
|
||||
), zmq.SNDMORE)
|
||||
|
||||
socket.send_pyobj(self.image)
|
||||
self.p_image = socket.recv_pyobj()
|
||||
self.nt_data = socket.recv_json()
|
||||
|
||||
def camera_process(self, cam_name, port, FOV):
|
||||
from fractions import Fraction
|
||||
#calc fov
|
||||
diagonalView = math.radians(FOV)
|
||||
|
||||
width = self.settings_manager.cams[cam_name]["video_mode"]["width"]
|
||||
height = self.settings_manager.cams[cam_name]["video_mode"]["height"]
|
||||
centerX = (width / 2) - .5
|
||||
centerY = (height / 2) - .5
|
||||
cam_area = width * height
|
||||
|
||||
aspect_fraction = Fraction(width, height)
|
||||
horizontal_ratio = aspect_fraction.numerator
|
||||
vertical_ratio = aspect_fraction.denominator
|
||||
|
||||
horizontalView = math.atan(math.tan(diagonalView / 2) * (horizontal_ratio / diagonalView)) * 2
|
||||
verticalView = math.atan(math.tan(diagonalView / 2) * (vertical_ratio / diagonalView)) * 2
|
||||
|
||||
H_FOCAL_LENGTH = width / (2 * math.tan((horizontalView / 2)))
|
||||
V_FOCAL_LENGTH = height / (2 * math.tan((verticalView / 2)))
|
||||
#setting up zmq socket
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.PAIR)
|
||||
socket.connect('tcp://localhost:%s' % str(port))
|
||||
#setting up filter countours class
|
||||
filter_contours = self.vision_handler.Filter_Contours(center_x=centerX, center_y=centerY)
|
||||
|
||||
x = 1
|
||||
counter = 0
|
||||
start_time = time.time()
|
||||
fps = 0
|
||||
|
||||
while True:
|
||||
obj = socket.recv_json()
|
||||
image = socket.recv_pyobj()
|
||||
curr_pipeline = obj["pipeline"]
|
||||
if curr_pipeline['orientation'] == "Inverted":
|
||||
M = cv2.getRotationMatrix2D((width / 2, height / 2), 180, 1)
|
||||
image = cv2.warpAffine(image, M, (width, height))
|
||||
hsv_image = self.vision_handler._hsv_threshold(curr_pipeline["hue"],
|
||||
curr_pipeline["saturation"], curr_pipeline["value"],
|
||||
image, curr_pipeline["erode"], curr_pipeline["dilate"])
|
||||
# if table.getBoolean("Driver_Mode", False):
|
||||
contours = self.vision_handler.find_contours(hsv_image)
|
||||
filtered_contours = filter_contours.filter_contours(input_contours=contours, area=curr_pipeline['area'],
|
||||
ratio=curr_pipeline['ratio'],
|
||||
extent=curr_pipeline['extent'],
|
||||
sort_mode=curr_pipeline['sort_mode'], cam_area=cam_area,
|
||||
target_grouping=curr_pipeline['target_group'],
|
||||
target_intersection=
|
||||
curr_pipeline['target_intersection'])
|
||||
final_contour = self.vision_handler.output_contour(filtered_contours)
|
||||
try:
|
||||
center = final_contour[0]
|
||||
center_x = (center[1] - curr_pipeline['B']) / curr_pipeline["M"]
|
||||
center_y = (center[0] * curr_pipeline["M"]) + curr_pipeline["B"]
|
||||
pitch = self.vision_handler.calculate_pitch(pixel_y=center[1], center_y=center_y, v_focal_length=V_FOCAL_LENGTH)
|
||||
yaw = self.vision_handler.calculate_yaw(pixel_x=center[0], center_x=center_x, h_focal_length=H_FOCAL_LENGTH)
|
||||
valid = True
|
||||
except IndexError:
|
||||
center = None
|
||||
pitch = None
|
||||
yaw = None
|
||||
valid = False
|
||||
|
||||
if curr_pipeline['is_binary']:
|
||||
draw_image = hsv_image
|
||||
else:
|
||||
draw_image = image
|
||||
res = self.vision_handler.draw_image(input_image=draw_image, contour=final_contour)
|
||||
socket.send_pyobj(res)
|
||||
socket.send_json(dict(
|
||||
pitch=pitch,
|
||||
yaw=yaw,
|
||||
valid=valid,
|
||||
raw_point=center,
|
||||
fps=fps
|
||||
))
|
||||
counter += 1
|
||||
if (time.time() - start_time) > x:
|
||||
fps = (counter / (time.time() - start_time))
|
||||
counter = 0
|
||||
start_time = time.time()
|
||||
@@ -1,12 +1,10 @@
|
||||
import asyncio
|
||||
|
||||
import tornado.websocket
|
||||
import json
|
||||
from ..classes.Exceptions import NoCameraConnectedException
|
||||
from ..classes.SettingsManager import SettingsManager
|
||||
|
||||
|
||||
web_socket_clients = []
|
||||
web_socket_clients = set()
|
||||
|
||||
|
||||
def send_all_async(message):
|
||||
@@ -18,6 +16,7 @@ def send_all_async(message):
|
||||
|
||||
|
||||
class ChameleonWebSocket(tornado.websocket.WebSocketHandler):
|
||||
|
||||
actions = {}
|
||||
|
||||
set_this_camera_settings = ["exposure", "brightness"]
|
||||
@@ -38,7 +37,7 @@ class ChameleonWebSocket(tornado.websocket.WebSocketHandler):
|
||||
def open(self):
|
||||
self.send_full_settings()
|
||||
if self not in web_socket_clients:
|
||||
web_socket_clients.append(self)
|
||||
web_socket_clients.add(self)
|
||||
|
||||
print("WebSocket opened")
|
||||
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
import asyncio
|
||||
import time
|
||||
|
||||
from networktables import NetworkTables
|
||||
import networktables
|
||||
import cv2
|
||||
import numpy
|
||||
from cscore import CameraServer
|
||||
from app.classes.SettingsManager import SettingsManager
|
||||
from ..classes.Singleton import Singleton
|
||||
from multiprocessing import Process
|
||||
import threading
|
||||
import zmq
|
||||
import math
|
||||
from enum import Enum, unique
|
||||
from ..handlers.SocketHandler import send_all_async
|
||||
|
||||
|
||||
class VisionHandler(metaclass=Singleton):
|
||||
class VisionHandler():
|
||||
def __init__(self):
|
||||
self.kernel = numpy.ones((5, 5), numpy.uint8)
|
||||
|
||||
@@ -243,193 +231,3 @@ class VisionHandler(metaclass=Singleton):
|
||||
def calculate_yaw(self, pixel_x, center_x, h_focal_length):
|
||||
yaw = math.degrees(math.atan((pixel_x - center_x) / h_focal_length))
|
||||
return yaw
|
||||
|
||||
def run(self):
|
||||
NetworkTables.startClientTeam(team=SettingsManager.general_settings.get("team_number", 1577))
|
||||
# NetworkTables.initialize("localhost")
|
||||
|
||||
cs = CameraServer.getInstance()
|
||||
port = 5550
|
||||
|
||||
for cam_name in SettingsManager().usb_cameras:
|
||||
threading.Thread(target=self.thread_proc, args=(cs, cam_name, port)).start()
|
||||
port += 1
|
||||
|
||||
def thread_proc(self, cs, cam_name, port=5557):
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
SettingsManager.cams_curr_pipeline[cam_name] = "pipeline0"
|
||||
pipeline = SettingsManager().cams[cam_name]["pipelines"][SettingsManager.cams_curr_pipeline[cam_name]]
|
||||
FOV = SettingsManager().cams[cam_name]["FOV"]
|
||||
|
||||
def change_camera_values(pipline):
|
||||
SettingsManager.usb_cameras[cam_name].setBrightness(pipeline['brightness'])
|
||||
SettingsManager.usb_cameras[cam_name].setExposureManual(pipeline['exposure'])
|
||||
SettingsManager.usb_cameras[cam_name].setWhiteBalanceAuto()
|
||||
|
||||
def pipeline_listener(table, key, value, is_new):
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
SettingsManager.cams_curr_pipeline[cam_name] = value
|
||||
change_camera_values(pipeline)
|
||||
if cam_name == SettingsManager().general_settings['curr_camera']:
|
||||
SettingsManager().general_settings['curr_pipeline'] = value
|
||||
update_settings = SettingsManager().get_curr_pipeline()
|
||||
update_settings['curr_pipeline'] = SettingsManager().general_settings["curr_pipeline"]
|
||||
send_all_async(update_settings)
|
||||
|
||||
def mode_listener(table, key, value, is_new):
|
||||
change_camera_values({
|
||||
'brightness': 25,
|
||||
'exposure': 15
|
||||
})
|
||||
|
||||
table = NetworkTables.getTable("/Chameleon-Vision/" + cam_name)
|
||||
table.putString('Pipeline', SettingsManager.cams_curr_pipeline[cam_name])
|
||||
table.addEntryListenerEx(pipeline_listener, key="Pipeline",
|
||||
flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE)
|
||||
table.addEntryListenerEx(mode_listener, key="Driver_Mode",
|
||||
flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE)
|
||||
#gettings video from curent camera
|
||||
cv_sink = cs.getVideo(camera=SettingsManager.usb_cameras[cam_name])
|
||||
|
||||
width = SettingsManager().cams[cam_name]["video_mode"]["width"]
|
||||
height = SettingsManager().cams[cam_name]["video_mode"]["height"]
|
||||
|
||||
image = numpy.zeros(shape=(width, height, 3), dtype=numpy.uint8)
|
||||
|
||||
#setting up a video server for camera
|
||||
cv_publish = cs.putVideo(name=cam_name, width=width, height=height)
|
||||
# saving camera port in cam name dict for usage in client
|
||||
SettingsManager().cams_port[cam_name] = cs._sinks['serve_'+cam_name].getPort()
|
||||
|
||||
#setting up a zmq connection to the opencv subprocess
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.PAIR)
|
||||
socket.bind('tcp://*:%s' % str(port))
|
||||
|
||||
#starting the process with inital values
|
||||
p = Process(target=self.camera_process, args=(cam_name, port, FOV))
|
||||
p.start()
|
||||
|
||||
change_camera_values(pipeline)
|
||||
|
||||
while True:
|
||||
pipeline = SettingsManager().cams[cam_name]["pipelines"][SettingsManager.cams_curr_pipeline[cam_name]]
|
||||
_, image = cv_sink.grabFrame(image)
|
||||
socket.send_json(dict(
|
||||
pipeline=pipeline
|
||||
), zmq.SNDMORE)
|
||||
|
||||
socket.send_pyobj(image)
|
||||
p_image = socket.recv_pyobj()
|
||||
nt_data = socket.recv_json()
|
||||
table.putBoolean('valid', nt_data['valid'])
|
||||
# check if point is valid
|
||||
|
||||
# print(nt_data['fps'])
|
||||
|
||||
if nt_data['valid']:
|
||||
#send the point using network tables
|
||||
table.putNumber('pitch', nt_data['pitch'])
|
||||
table.putNumber('yaw', nt_data['yaw'])
|
||||
#if the selected camera in ui is this cam send the point to the ui
|
||||
|
||||
if SettingsManager().general_settings['curr_camera'] == cam_name:
|
||||
try:
|
||||
if nt_data['raw_point'] is not None:
|
||||
send_all_async({
|
||||
'raw_point': nt_data['raw_point'],
|
||||
'point': {
|
||||
'pitch': nt_data['pitch'],
|
||||
'yaw': nt_data['yaw'],
|
||||
'fps': nt_data['fps']
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
print(e)
|
||||
#send the image to the camera server
|
||||
|
||||
cv_publish.putFrame(p_image)
|
||||
|
||||
def camera_process(self, cam_name, port, FOV):
|
||||
from fractions import Fraction
|
||||
|
||||
diagonalView = math.radians(FOV) #needs to be implemented in client
|
||||
|
||||
width = SettingsManager().cams[cam_name]["video_mode"]["width"]
|
||||
height = SettingsManager().cams[cam_name]["video_mode"]["height"]
|
||||
centerX = (width / 2) - .5
|
||||
centerY = (height / 2) - .5
|
||||
cam_area = width * height
|
||||
|
||||
aspect_fraction = Fraction(width,height)
|
||||
horizontal_ratio = aspect_fraction.numerator
|
||||
vertical_ratio = aspect_fraction.denominator
|
||||
|
||||
horizontalView = math.atan(math.tan(diagonalView/2) * (horizontal_ratio / diagonalView)) * 2
|
||||
verticalView = math.atan(math.tan(diagonalView/2) * (vertical_ratio / diagonalView)) * 2
|
||||
|
||||
H_FOCAL_LENGTH = width / (2*math.tan((horizontalView/2)))
|
||||
V_FOCAL_LENGTH = height / (2*math.tan((verticalView/2)))
|
||||
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.PAIR)
|
||||
socket.connect('tcp://localhost:%s' % str(port))
|
||||
filter_contours = self.Filter_Contours(center_x=centerX, center_y=centerY)
|
||||
x = 1
|
||||
counter = 0
|
||||
start_time = time.time()
|
||||
fps = 0
|
||||
while True:
|
||||
obj = socket.recv_json()
|
||||
image = socket.recv_pyobj()
|
||||
curr_pipeline = obj["pipeline"]
|
||||
if curr_pipeline['orientation'] == "Inverted":
|
||||
M = cv2.getRotationMatrix2D((width / 2, height / 2), 180, 1)
|
||||
image = cv2.warpAffine(image, M, (width, height))
|
||||
hsv_image = self._hsv_threshold(curr_pipeline["hue"],
|
||||
curr_pipeline["saturation"], curr_pipeline["value"],
|
||||
image, curr_pipeline["erode"], curr_pipeline["dilate"])
|
||||
# if table.getBoolean("Driver_Mode", False):
|
||||
contours = self.find_contours(hsv_image)
|
||||
filtered_contours = filter_contours.filter_contours(input_contours=contours, area=curr_pipeline['area'],
|
||||
ratio=curr_pipeline['ratio'],
|
||||
extent=curr_pipeline['extent'],
|
||||
sort_mode=curr_pipeline['sort_mode'], cam_area=cam_area,
|
||||
target_grouping=curr_pipeline['target_group'],
|
||||
target_intersection=
|
||||
curr_pipeline['target_intersection'])
|
||||
final_contour = self.output_contour(filtered_contours)
|
||||
try:
|
||||
center = final_contour[0]
|
||||
center_x = (center[1] - curr_pipeline['B']) / curr_pipeline["M"]
|
||||
center_y = (center[0] * curr_pipeline["M"]) + curr_pipeline["B"]
|
||||
pitch = self.calculate_pitch(pixel_y=center[1], center_y=center_y, v_focal_length=V_FOCAL_LENGTH)
|
||||
yaw = self.calculate_yaw(pixel_x=center[0], center_x=center_x, h_focal_length=H_FOCAL_LENGTH)
|
||||
valid = True
|
||||
except IndexError:
|
||||
center = None
|
||||
pitch = None
|
||||
yaw = None
|
||||
valid = False
|
||||
|
||||
if curr_pipeline['is_binary']:
|
||||
draw_image = hsv_image
|
||||
else:
|
||||
draw_image = image
|
||||
res = self.draw_image(input_image=draw_image, contour=final_contour)
|
||||
socket.send_pyobj(res)
|
||||
socket.send_json(dict(
|
||||
pitch=pitch,
|
||||
yaw=yaw,
|
||||
valid=valid,
|
||||
raw_point=center,
|
||||
fps=fps
|
||||
))
|
||||
counter += 1
|
||||
if (time.time() - start_time) > x:
|
||||
fps = (counter / (time.time() - start_time))
|
||||
counter = 0
|
||||
start_time = time.time()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"pipelines": {"pipeline0": {"exposure": 50, "brightness": 15, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": 0, "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline1": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": 0, "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline2": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline3": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline4": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline5": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline6": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline7": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline8": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline9": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": 0, "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}}, "path": "/dev/v4l/by-path/pci-0000:02:03.0-usb-0:1:1.0-video-index0", "video_mode": {"fps": 187, "width": 320, "height": 240, "pixel_format": "kYUYV"}, "resolution": 0, "FOV": 60.8}
|
||||
{"pipelines": {"pipeline0": {"exposure": 50, "brightness": 15, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": true, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": 0, "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline1": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": 0, "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline2": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline3": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline4": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline5": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline6": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline7": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline8": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": "Normal", "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}, "pipeline9": {"exposure": 50, "brightness": 50, "orientation": "Normal", "hue": [0, 100], "saturation": [0, 100], "value": [0, 100], "erode": false, "dilate": false, "area": [0, 100], "ratio": [0, 20], "extent": [0, 100], "is_binary": 0, "sort_mode": "Largest", "target_group": "Single", "target_intersection": "Up", "M": 1, "B": 0}}, "path": "/dev/v4l/by-path/pci-0000:02:03.0-usb-0:1:1.0-video-index0", "video_mode": {"fps": 187, "width": 320, "height": 240, "pixel_format": "kYUYV"}, "resolution": 0, "FOV": 60.8}
|
||||
Reference in New Issue
Block a user