Merge branch 'dev' into 'master'

v2 final

See merge request oriagranat9/Chameleon-Vision!8
This commit is contained in:
ori agranat
2019-08-28 21:16:37 +00:00
26 changed files with 302 additions and 208 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ Python/app/handlers/__pycache__/
\.vscode/
backend/settings/
/.vscode/

70
.vscode/launch.json vendored
View File

@@ -1,70 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File (Integrated Terminal)",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
},
{
"name": "Python: Remote Attach",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
]
},
{
"name": "Python: Module",
"type": "python",
"request": "launch",
"module": "enter-your-module-name-here",
"console": "integratedTerminal"
},
{
"name": "Python: Django",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/manage.py",
"console": "integratedTerminal",
"args": [
"runserver",
"--noreload",
"--nothreading"
],
"django": true
},
{
"name": "Python: Flask",
"type": "python",
"request": "launch",
"module": "flask",
"env": {
"FLASK_APP": "app.py"
},
"args": [
"run",
"--no-debugger",
"--no-reload"
],
"jinja": true
},
{
"name": "Python: Current File (External Terminal)",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "externalTerminal"
}
]
}

150
README.md
View File

@@ -1,84 +1,154 @@
# Chameleon-Vision
a free software for FRC teams to use for vision proccesing on their robots
a free software for FRC teams to use for vision proccesing on their robots
## getting started
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
### Prerequisites
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.7 and above
- opencv 3.4.5
- tornado web framework
- robotpy-cscore
- pynetworktables
- pymq
#### frontend
- vue.js
- vuex
- vue-router
- less and less-loader
- iView
- vue-native-websocket
#### frontend
- vue.js
- vuex
- vue-router
- less and less-loader
- iView
- vue-native-websocket
### installing
### installing
#### for the backend
1. sudo apt-get update
1. sudo apt-get update
2. apt-get dist-upgrade
3. sudo apt-get 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 (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
9. cd ~/opencv-${OPENCV_VERSION}/
10. mkdir build
11. cd build
12. cmake -D BUILD_SHARED_LIBS=ON -D BUILD_opencv_python3=ON ..
13. make -j $(python3 -c 'import multiprocessing as mp; print(int(mp.cpu_count() * 1.5))')
14. make install
15. ldconfig
16. pip3 install robotpy-cscore pyzmq tornado
6. sudo apt-get install python3-opencv
7. pip3 install robotpy-cscore
8. pip3 install pyzmq
9. pip3 install tornado
to run the backend:
```
sudo python3 Main.py
```
if backed gets suck or no camera are recognized after a crash do:
```
sudo pkill -9 python3
```
#### compiling:
in order to compile the program for runtime run: (still needs to install dependencies)
```
python3 -m nuitka --follow-imports Main.py
```
#### for the frontend
1. sudo apt-get install nodejs npm
2. cd chameleon-client
2. cd chameleon-client
3. sudo npm install
4. sudo npm install @vue/cli
to run the front end you can open the cli ui by:
```
vue ui
```
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
to run the front end you can open the cli ui by:
```
vue ui
```
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
main docs can be found at [google docs](https://docs.google.com/document/d/1qDuwHtpIPJfyXGIL8PJG89LZwRWbn2J9f-5g19lWL9U/edit?usp=sharing)
## Authors
* **Sagi Frimer** - *initial work* - websocket, settings manager, UI
* **Ori Agranat** - *main coder* - vision loop , UI, websocket, networktables
* **Sagi Frimer** - *initial work* - websocket, settings manager, UI
* **Ori Agranat** - *main coder* - vision loop , UI, websocket, networktables
## Acknowledgments
* the [robotpy project](https://github.com/robotpy) and mainly the cscore libs
* basically all of stackoverflow
* basically all of stackoverflow

View File

@@ -1,4 +1,3 @@
from datetime import timedelta
from networktables import NetworkTables
import tornado.ioloop
import logging
@@ -7,7 +6,6 @@ from app.classes.SettingsManager import SettingsManager
from tornado.options import options
import threading
import asyncio
from app.handlers.SocketHandler import send_all_async
from app.handlers.CameraHander import CameraHandler
@@ -18,13 +16,10 @@ 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()

View File

@@ -2,9 +2,11 @@ import os
import json
import cv2
import cscore
import subprocess
from cscore._cscore import VideoMode
from .Singleton import Singleton
from .Exceptions import PipelineAlreadyExistsException, NoCameraConnectedException
from ..handlers.IPHandler import ChangeIP
class SettingsManager(metaclass=Singleton):
@@ -27,7 +29,7 @@ class SettingsManager(metaclass=Singleton):
"area": [0, 100],
"ratio": [0, 20],
"extent": [0, 100],
"is_binary": "Normal",
"is_binary": 0,
"sort_mode": "Largest",
"target_group": 'Single',
"target_intersection": 'Up',
@@ -39,7 +41,8 @@ class SettingsManager(metaclass=Singleton):
"connection_type": "DHCP",
"ip": "",
"gateway": "",
"hostname": "",
"netmask": "",
"hostname": "Chameleon-Vision",
"curr_camera": "",
"curr_pipeline": ""
}
@@ -48,6 +51,9 @@ class SettingsManager(metaclass=Singleton):
self.settings_path = os.path.join(os.getcwd(), "settings")
self.cams_path = os.path.join(self.settings_path, "cams")
self._init_general_settings()
ChangeIP(connection_type=self.general_settings['connection_type'], hostname=self.general_settings['hostname'],
ip=self.general_settings['ip'],
netmask=self.general_settings['netmask'], gateway=self.general_settings['gateway'])
self._init_cameras_info()
self._init_usb_cameras()
self._init_cameras()
@@ -72,13 +78,10 @@ class SettingsManager(metaclass=Singleton):
# Initiate our camera's settings
def _init_cameras(self):
for cam_name in self.usb_cameras_info:
cam = self.usb_cameras_info[cam_name]
if os.path.exists(os.path.join(self.cams_path, cam.name + '.json')):
with open(os.path.join(self.cams_path, cam.name + '.json'), 'r') as camera:
if os.path.exists(os.path.join(self.cams_path, cam_name + '.json')):
with open(os.path.join(self.cams_path, cam_name + '.json'), 'r') as camera:
self.cams[cam_name] = json.load(camera)
if len(self.cams[cam.name]["pipelines"]) == 0:
if len(self.cams[cam_name]["pipelines"]) == 0:
self.create_new_pipeline(cam_name=cam_name)
else:
self.create_new_cam(cam_name)
@@ -188,11 +191,12 @@ class SettingsManager(metaclass=Singleton):
def change_general_settings_values(self, dic):
for key in dic['change_general_settings_values']:
if self.default_general_settings[key]:
if key in self.default_general_settings.keys():
self.general_settings[key] = dic['change_general_settings_values'][key]
self.settings_manager.save_settings()
#after all values has been set change settings
self.change_general_settings()
self.save_settings()
subprocess.call(['reboot'])
# after all values has been set change settings
# Creators
@@ -255,7 +259,5 @@ class SettingsManager(metaclass=Singleton):
with open(os.path.join(self.settings_path, 'settings.json'), 'w+') as setting_file:
json.dump(self.general_settings, setting_file)
def change_general_settings(self):
pass

View File

@@ -37,29 +37,37 @@ class CameraHandler:
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):
def change_camera_values(pipeline):
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)
if value in self.settings_manager.cams[self.cam_name]['pipelines'].keys():
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)
else:
self.table.putString('Pipeline', self.settings_manager.cams_curr_pipeline[self.cam_name])
def mode_listener(table, key, value, is_new):
change_camera_values({
'brightness': 25,
'exposure': 15
})
if value:
change_camera_values({
'brightness': 25,
'exposure': 15
})
else:
change_camera_values(pipeline)
#setting up network table
self.table = NetworkTables.getTable("/Chameleon-Vision/" + self.cam_name)
#init values for pipeline and driver mode
self.table.putString('Pipeline', self.settings_manager.cams_curr_pipeline[self.cam_name])
self.table.putBoolean('Driver_Mode', False)
self.table.addEntryListenerEx(pipeline_listener, key="Pipeline",
flags=networktables.NetworkTablesInstance.NotifyFlags.UPDATE)
self.table.addEntryListenerEx(mode_listener, key="Driver_Mode",
@@ -101,8 +109,8 @@ class CameraHandler:
# 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)
self.table.putNumber('time_stamp', self.nt_data['time_stamp'])
self.table.putNumber('fps', self.nt_data['fps'])
# if the selected camera in ui is this cam send the point to the ui
except:
pass
@@ -132,11 +140,13 @@ class CameraHandler:
#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
pipeline=pipeline,
driver_mode=self.table.getBoolean('Driver_Mode', False)
), zmq.SNDMORE)
socket.send_pyobj(self.image)
socket.send_pyobj((self.time_stamp,self.image))
self.p_image = socket.recv_pyobj()
self.nt_data = socket.recv_json()
@@ -174,49 +184,62 @@ class CameraHandler:
while True:
obj = socket.recv_json()
image = socket.recv_pyobj()
curr_pipeline = obj["pipeline"]
curr_pipeline = obj['pipeline']
driver_mode = obj['driver_mode']
time_stamp, image = socket.recv_pyobj()
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:
if not driver_mode:
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)
else:
res = image
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
fps=fps,
time_stamp=time_stamp
))
counter += 1
if (time.time() - start_time) > x:

View File

@@ -0,0 +1,49 @@
import subprocess
import netifaces
class ChangeIP:
def __init__(self, connection_type, ip, netmask, gateway, hostname):
adapter = self.find_adapter()
if adapter is not None:
self.shutdown_adapter(adapter)
if connection_type == "DHCP":
self.change_to_dhcp(adapter=adapter)
elif connection_type == "Static":
self.change_to_static(adapter=adapter, ip=ip, netmask=netmask, gateway=gateway)
self.start_adapter(adapter)
else:
print("not connected to robot radio cannot set ip")
self.change_hostname(hostname=hostname)
@staticmethod
def change_to_dhcp(adapter):
subprocess.call(['dhclient',"-r", adapter])
@staticmethod
def change_to_static(adapter, ip, netmask, gateway):
subprocess.call(['ifconfig', adapter, ip, 'netmask', netmask])
subprocess.call(['route', 'add', 'default', 'gw', gateway, adapter])
@staticmethod
def shutdown_adapter(adapter):
subprocess.call(['ifconfig', adapter, 'down'])
@staticmethod
def start_adapter(adapter):
subprocess.call(['ifconfig', adapter, 'up'])
@staticmethod
def find_adapter():
for i_name in netifaces.interfaces():
interface = netifaces.ifaddresses(i_name)[netifaces.AF_INET][0]
address = interface['addr'].split('.')[0]
if address == "10":
return str(i_name)
@staticmethod
def change_hostname(hostname):
subprocess.call(['hostnamectl', 'set-hostname', hostname])

View File

@@ -48,8 +48,8 @@ class ChameleonWebSocket(tornado.websocket.WebSocketHandler):
for key in message_dic:
self.actions.get(key, self.actions["change_pipeline_values"])(message_dic)
print(message)
except:
print("crash " + message)
except Exception as e:
print("crash " + e)
def on_close(self):
self.settings_manager.save_settings()

View File

@@ -10,17 +10,16 @@ class VisionHandler():
def _hsv_threshold(self, hue: list, saturation: list, value: list, img: numpy.ndarray, is_erode: bool,
is_dilate: bool):
blur = cv2.blur(img, (3, 3))
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
lower = numpy.array([hue[0], saturation[0], value[0]])
upper = numpy.array([hue[1], saturation[1], value[1]])
thresh = cv2.inRange(hsv, lower, upper)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
thresh = cv2.inRange(hsv, (hue[0], saturation[0], value[0]), (hue[1], saturation[1], value[1]))
erode_img = cv2.erode(thresh, kernel=self.kernel, iterations=is_erode)
dilate_img = cv2.dilate(erode_img, kernel=self.kernel, iterations=is_dilate)
return dilate_img
def find_contours(self, binary_img: numpy.ndarray):
_, contours, _ = cv2.findContours(binary_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
_,contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
return contours
class Filter_Contours:
@@ -192,24 +191,14 @@ class VisionHandler():
sorted_contours = []
return sorted_contours
@unique
class Region(Enum):
UP_MOST = 0
RIGHT_MOST = 1
DOWN_MOST = 2
LEFT_MOST = 3
CENTER_MOST = 4
def output_contour(self, sorted_contours):
if len(sorted_contours) > 0:
selected_contour = sorted_contours[0]
rect = cv2.minAreaRect(selected_contour)
else:
return []
# crosshair_calibration function to "put" camera in the middle
return rect
def draw_image(self, input_image, contour):
if len(input_image.shape)<3:
input_image = cv2.cvtColor(input_image, cv2.COLOR_GRAY2RGB)
@@ -224,7 +213,6 @@ class VisionHandler():
def calculate_pitch(self, pixel_y, center_y, v_focal_length):
pitch = math.degrees(math.atan((pixel_y - center_y) / v_focal_length))
# Just stopped working have to do this:
pitch *= -1
return pitch

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 221 KiB

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Chameleon Vision</title><link href=/css/app.bd8aa8d9.css rel=preload as=style><link href=/js/app.d1ab8cb6.js rel=preload as=script><link href=/js/chunk-vendors.a3ecb371.js rel=preload as=script><link href=/css/app.bd8aa8d9.css rel=stylesheet></head><body><noscript><strong>We're sorry but Chameleon Vision doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.a3ecb371.js></script><script src=/js/app.d1ab8cb6.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Chameleon Vision</title><link href=/css/app.bd8aa8d9.css rel=preload as=style><link href=/js/app.894d02a9.js rel=preload as=script><link href=/js/chunk-vendors.a3ecb371.js rel=preload as=script><link href=/css/app.bd8aa8d9.css rel=stylesheet></head><body><noscript><strong>We're sorry but Chameleon Vision doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.a3ecb371.js></script><script src=/js/app.894d02a9.js></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,4 @@
tornado
pyzmq
robotpy-cscore
robotpy-cscore
netifaces

View File

@@ -1 +0,0 @@
{"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}

View File

@@ -1 +0,0 @@
{"pipelines": {"pipeline0": {"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"}}, "path": "/dev/v4l/by-path/pci-0000:02:03.0-usb-0:2:1.0-video-index0", "video_mode": {"fps": 30, "width": 640, "height": 480, "pixel_format": "kYUYV"}, "resolution": 0, "FOV": 60.8}

View File

@@ -1 +0,0 @@
{"team_number": 1567, "connection_type": "DHCP", "ip": "", "gateway": "", "hostname": "Chameleon-Vision", "curr_camera": "USB Camera-B4.09.24.1", "curr_pipeline": "pipeline0"}

BIN
chameleon-client/public/favicon.ico Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 221 KiB

BIN
chameleon-client/src/assets/logo.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -25,6 +25,14 @@
<Input v-model="ip" size="small" :disabled="isConnection"></Input>
</Col>
</row>
<row type="flex" justify="start" align="middle" class="spacing">
<Col span="4">
<h4>Netmask:</h4>
</Col>
<Col span="10">
<Input v-model="netmask" size="small" :disabled="isConnection"></Input>
</Col>
</row>
<row type="flex" justify="start" align="middle" class="spacing">
<Col span="4">
<h4>Gateway:</h4>
@@ -39,7 +47,6 @@
</Col>
<Col span="10">
<Input v-model="hostname" size="small">
<span slot="prepend">http://Chameleon-Vision</span>
<span slot="append">.local</span>
</Input>
</Col>
@@ -74,6 +81,7 @@
'team_number':this.team_number,
'connection_type':this.connection_type,
'ip':this.ip,
'netmask':this.netmask,
'gateway':this.gateway,
'hostname':this.hostname}});
}
@@ -103,6 +111,14 @@
this.$store.commit('ip',value);
}
},
netmask:{
get: function(){
return this.$store.state.netmask;
},
set: function(value){
this.$store.commit('netmask',value);
}
},
gateway:{
get: function(){
return this.$store.state.gateway;
@@ -120,7 +136,7 @@
}
},
isConnection: function(){
if(this.connectionType == "DHCP"){
if(this.connection_type == "DHCP"){
return true
} else{
return false

View File

@@ -30,14 +30,15 @@ export const store = new Vuex.Store({
area:[0,100],
ratio:[0,20],
extent:[0,100],
sort_mode:'Largest', //
target_group:'Single', //
target_intersection:'Up', //
sort_mode:'Largest',
target_group:'Single',
target_intersection:'Up',
//Settings
team_number:0,
connection_type:"DHCP",
ip:0,
gateWay:0,
ip:"",
gateway:"",
netmask:"",
hostname:"",
//live info
port:1181,
@@ -68,7 +69,8 @@ export const store = new Vuex.Store({
team_number: set('team_number'),
connection_type: set('connection_type'),
ip: set('ip'),
gateWay : set('gateway'),
netmask: set('netmask'),
gateway : set('gateway'),
hostname : set('hostname'),
is_binary: set('is_binary'),
cameraList : set('cameraList'),
@@ -99,7 +101,8 @@ export const store = new Vuex.Store({
team_number: state => state.teamValue,
connection_type: state => state.connectionType,
ip: state => state.ip,
gateWay: state => state.gateWay,
netmask: state => state.netmask,
gateway: state => state.gateway,
hostname: state => state.hostName,
is_binary: state => state.is_binary,
cameraList: state => state.cameraList,

10
install.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
apt-get update
apt-get dist-upgrade
apt-get upgrade
apt-get install python3-pip python3-dev cmake zip unzip build-essential git libnss-mdns --fix-missing
apt-get install python3-numpy
apt-get install python3-opencv
pip3 install robotpy-cscore
pip3 install pyzmq
pip3 install tornado