Merge branch 'dev'

This commit is contained in:
ori agranat
2019-10-08 14:17:11 +03:00
60 changed files with 20931 additions and 257 deletions

View File

@@ -10,23 +10,13 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-java:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxathena:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxraspbian:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxx86-64:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:windowsx86-64:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cameraserver:cameraserver-java:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-java:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxathena:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxraspbian:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxx86-64:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:windowsx86-64:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.wpiutil:wpiutil-java:2019.4.1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2019.opencv:opencv-java:3.4.4-5" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2019.opencv:opencv-jni:windowsx86-64:3.4.4-5" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2019.opencv:opencv-jni:linuxx86-64:3.4.4-5" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2019.opencv:opencv-jni:linuxathena:3.4.4-5" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2019.opencv:opencv-jni:linuxraspbian:3.4.4-5" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cameraserver:cameraserver-java:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-java:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:osxx86-64:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxraspbian:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxx86-64:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:windowsx86-64:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.wpiutil:wpiutil-java:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: io.javalin:javalin:3.4.1" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.3.31" level="project" />
@@ -66,13 +56,13 @@
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxx86-64:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:osxx86-64:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:windowsx86-64:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cameraserver:cameraserver-java:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-java:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:osxx86-64:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxraspbian:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxx86-64:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:windowsx86-64:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.wpiutil:wpiutil-java:2019.4.1-176-ga5650b9" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cameraserver:cameraserver-java:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-java:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:osxx86-64:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxraspbian:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxx86-64:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:windowsx86-64:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.wpiutil:wpiutil-java:2019.4.1-200-g2271570" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-java:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:linuxaarch64bionic:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:linuxraspbian:3.4.7-1" level="project" />

View File

@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.chameleon-vision.main</groupId>
<artifactId>chameleon-vision</artifactId>
<version>1.1.0-BETA</version>
<version>1.1.3-BETA</version>
<build>
<plugins>
<!--setup for java jdk 12-->
@@ -116,37 +116,37 @@
<dependency>
<groupId>edu.wpi.first.cscore</groupId>
<artifactId>cscore-java</artifactId>
<version>2019.4.1-200-g2271570</version>
<version>2019.4.1-213-g56d782b</version>
</dependency>
<!--frc cscore interface libs-->
<dependency>
<groupId>edu.wpi.first.cscore</groupId>
<artifactId>cscore-jni</artifactId>
<version>2019.4.1-200-g2271570</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>linuxaarch64bionic</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.cscore</groupId>
<artifactId>cscore-jni</artifactId>
<version>2019.4.1-200-g2271570</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>linuxraspbian</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.cscore</groupId>
<artifactId>cscore-jni</artifactId>
<version>2019.4.1-200-g2271570</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>linuxx86-64</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.cscore</groupId>
<artifactId>cscore-jni</artifactId>
<version>2019.4.1-200-g2271570</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>osxx86-64</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.cscore</groupId>
<artifactId>cscore-jni</artifactId>
<version>2019.4.1-200-g2271570</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>windowsx86-64</classifier>
</dependency>
@@ -154,39 +154,39 @@
<dependency>
<groupId>edu.wpi.first.cameraserver</groupId>
<artifactId>cameraserver-java</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
</dependency>
<!--frc network table java libs-->
<dependency>
<groupId>edu.wpi.first.ntcore</groupId>
<artifactId>ntcore-java</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
</dependency>
<!--frc network tables interface libs-->
<dependency>
<groupId>edu.wpi.first.ntcore</groupId>
<artifactId>ntcore-jni</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>osxx86-64</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.ntcore</groupId>
<artifactId>ntcore-jni</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>linuxraspbian</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.ntcore</groupId>
<artifactId>ntcore-jni</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>linuxx86-64</classifier>
</dependency>
<dependency>
<groupId>edu.wpi.first.ntcore</groupId>
<artifactId>ntcore-jni</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
<classifier>windowsx86-64</classifier>
</dependency>
@@ -194,7 +194,7 @@
<dependency>
<groupId>edu.wpi.first.wpiutil</groupId>
<artifactId>wpiutil-java</artifactId>
<version>2019.4.1-176-ga5650b9</version>
<version>2019.4.1-213-g56d782b</version>
</dependency>
<!-- WPI OpenCV for all supported platforms -->

View File

@@ -1,15 +1,18 @@
package com.chameleonvision;
import com.chameleonvision.network.NetworkManager;
import com.chameleonvision.settings.Platform;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.util.Utilities;
import com.chameleonvision.vision.camera.CameraManager;
import com.chameleonvision.vision.process.VisionProcess;
import com.chameleonvision.web.Server;
import edu.wpi.cscore.CameraServerCvJNI;
import edu.wpi.cscore.CameraServerJNI;
import edu.wpi.first.networktables.LogMessage;
import edu.wpi.first.networktables.NetworkTableInstance;
import java.io.IOException;
import java.util.function.Consumer;
public class Main {
@@ -17,14 +20,31 @@ public class Main {
private static final String NT_SERVERMODE_KEY = "--nt-servermode"; // no args for this setting
private static final String NT_CLIENTMODESERVER_KEY = "--nt-client-server"; // expects String representing an IP address (hostnames will be rejected!)
private static final String NETWORK_MANAGE_KEY = "--unmanage-network"; // no args for this setting
private static final String IGNORE_ROOT = "--ignore-root"; // no args for this setting
private static final int DEFAULT_PORT = 8888;
private static int webserverPort = DEFAULT_PORT;
private static boolean ntServerMode = false;
private static boolean manageNetwork = true;
private static boolean ignoreRoot = false;
private static String ntClientModeServer = null;
private static class NTLogger implements Consumer<LogMessage> {
private boolean hasReportedConnectionFailure = false;
@Override
public void accept(LogMessage logMessage) {
if (!hasReportedConnectionFailure && logMessage.message.contains("timed out")) {
System.err.println("NT Connection has failed!");
hasReportedConnectionFailure = true;
}
}
}
public static final Platform CurrentPlatform = Platform.getCurrentPlatform();
private static void handleArgs(String[] args) {
for (int i = 0; i < args.length; i++) {
var key = args[i].toLowerCase();
@@ -43,6 +63,7 @@ public class Main {
break;
case NT_SERVERMODE_KEY:
case NETWORK_MANAGE_KEY:
case IGNORE_ROOT:
// nothing
}
@@ -77,29 +98,53 @@ public class Main {
case NETWORK_MANAGE_KEY:
manageNetwork = false;
break;
case IGNORE_ROOT:
ignoreRoot = true;
}
}
}
public static void main(String[] args) {
if (CurrentPlatform.equals(Platform.UNSUPPORTED)) {
System.err.printf("Sorry, this platform is not supported. Give these details to the developers.\n%s\n", CurrentPlatform.toString());
return;
} else {
System.out.printf("Starting Chameleon Vision on platform %s\n", CurrentPlatform.toString());
}
handleArgs(args);
if (!CurrentPlatform.isRoot()) {
if (ignoreRoot) {
// TODO: should we do this?
// manageNetwork = false;
System.out.println("Ignoring root, network will not be managed!");
} else {
System.err.println("This program must be run as root!");
return;
}
}
// Attempt to load the JNI Libraries
try {
if (CurrentPlatform.equals(Platform.LINUX_ARM64))
CameraServerJNI.forceLoad();
CameraServerCvJNI.forceLoad();
} catch (IOException e) {
var errorStr = SettingsManager.getCurrentPlatform().equals(SettingsManager.Platform.UNSUPPORTED) ? "Unsupported platform!" : "Failed to load JNI Libraries!";
var errorStr = CurrentPlatform.equals(Platform.UNSUPPORTED) ? "Unsupported platform!" : "Failed to load JNI Libraries!";
throw new RuntimeException(errorStr);
}
if (CameraManager.initializeCameras()) {
SettingsManager.initialize(manageNetwork);
SettingsManager.initialize();
NetworkManager.initialize(manageNetwork);
CameraManager.initializeThreads();
if (ntServerMode) {
System.out.println("Starting NT Server");
NetworkTableInstance.getDefault().startServer();
} else {
NetworkTableInstance.getDefault().addLogger(new NTLogger(), 0, 255); // to hide error messages
if (ntClientModeServer != null) {
NetworkTableInstance.getDefault().startClient(ntClientModeServer);
} else {

View File

@@ -0,0 +1,82 @@
package com.chameleonvision.network;
import com.chameleonvision.settings.NetworkSettings;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.util.ShellExec;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class LinuxNetworking extends SysNetworking {
private ShellExec shell = new ShellExec(true, true);
@Override
public boolean setDHCP() {
String[] clearArgs = { "addr", "flush", "dev", networkInterface.name };
try {
int clearRetCode = shell.execute("ip", clearArgs);
int dhcpRetCode = shell.execute("dhclient", networkInterface.name);
return clearRetCode == 0 && dhcpRetCode == 0;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
@Override
public boolean setHostname(String newHostname) {
String[] setHostnameArgs = { "set-hostname", newHostname };
try {
var setHostnameRetCode = shell.execute("hostnamectl", setHostnameArgs);
return setHostnameRetCode == 0;
} catch(Exception e) {
e.printStackTrace();
return false;
}
}
@Override
public boolean setStatic(String ipAddress, String netmask, String gateway, String broadcast) {
try {
String[] clearArgs = { "addr", "flush", "dev", networkInterface.name };
String[] setIPArgs = { "addr", "add", String.format("%s/%s", ipAddress, netmask), "broadcast", broadcast, "dev", networkInterface.name };
String[] setGatewayArgs = { "route", "replace", "default", "via", gateway, "dev", networkInterface.name };
int clearRetCode = shell.execute("ip", clearArgs);
int setIPRetCode = shell.execute("ip", setIPArgs);
int setGatewayRetCode = shell.execute("ip", setGatewayArgs);
return clearRetCode == 0 && setIPRetCode == 0 && setGatewayRetCode == 0;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
@Override
public List<java.net.NetworkInterface> getNetworkInterfaces() throws SocketException {
List<java.net.NetworkInterface> netInterfaces;
try {
netInterfaces = Collections.list(java.net.NetworkInterface.getNetworkInterfaces());
} catch (SocketException e) {
return null;
}
List<java.net.NetworkInterface> goodInterfaces = new ArrayList<>();
for (var netInterface : netInterfaces) {
if (netInterface.getDisplayName().contains("lo")) continue;
if (!netInterface.isUp()) continue;
goodInterfaces.add(netInterface);
}
return goodInterfaces;
}
}

View File

@@ -0,0 +1,7 @@
package com.chameleonvision.network;
public enum NetworkIPMode {
DHCP,
STATIC,
UNKNOWN
}

View File

@@ -0,0 +1,57 @@
package com.chameleonvision.network;
import com.chameleonvision.settings.GeneralSettings;
import java.net.InetAddress;
import java.net.InterfaceAddress;
public class NetworkInterface {
public final String name;
public final String displayName;
public final String IPAddress;
public final String Netmask;
public final String Gateway;
public final String Broadcast;
public NetworkInterface(java.net.NetworkInterface inetface, InterfaceAddress ifaceAddress) {
name = inetface.getName();
displayName = inetface.getDisplayName();
var inetAddress = ifaceAddress.getAddress();
IPAddress = inetAddress.getHostAddress();
Netmask = getIPv4LocalNetMask(ifaceAddress);
// TODO: hack to "get" gateway, this is gross and bad, pls fix
var splitIPAddr = IPAddress.split("\\.");
splitIPAddr[3] = "1";
Gateway = String.join(".", splitIPAddr);
splitIPAddr[3] = "255";
Broadcast = String.join(".", splitIPAddr);
}
private static String getIPv4LocalNetMask(InterfaceAddress interfaceAddress) {
var netPrefix = interfaceAddress.getNetworkPrefixLength();
try {
// Since this is for IPv4, it's 32 bits, so set the sign value of
// the int to "negative"...
int shiftby = (1<<31);
// For the number of bits of the prefix -1 (we already set the sign bit)
for (int i = netPrefix - 1; i > 0; i--) {
// Shift the sign right... Java makes the sign bit sticky on a shift...
// So no need to "set it back up"...
shiftby = (shiftby >> 1);
}
// Transform the resulting value in xxx.xxx.xxx.xxx format, like if
/// it was a standard address...
String maskString = ((shiftby >> 24) & 255) + "." + ((shiftby >> 16) & 255) + "." + ((shiftby >> 8) & 255) + "." + (shiftby & 255);
// Return the address thus created...
return maskString;
// return InetAddress.getByName(maskString);
}
catch(Exception e) {
e.printStackTrace();
}
// Something went wrong here...
return null;
}
}

View File

@@ -0,0 +1,126 @@
package com.chameleonvision.network;
import com.chameleonvision.settings.NetworkSettings;
import com.chameleonvision.settings.Platform;
import com.chameleonvision.settings.SettingsManager;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class NetworkManager {
private NetworkManager() {}
protected static SysNetworking networking;
protected static NetworkInterface botInterface = null;
private static boolean isManaged = false;
public static void initialize(boolean manage) {
isManaged = manage;
if (!isManaged) {
return;
}
Platform platform = Platform.getCurrentPlatform();
if (platform.isLinux()) {
networking = new LinuxNetworking();
} else if (platform.isWindows()) {
// networking = new WindowsNetworking();
System.out.println("Windows networking is not yet supported. Running unmanaged.");
return;
}
if (networking == null) {
throw new RuntimeException("Failed to detect platform!");
}
List<java.net.NetworkInterface> interfaces = new ArrayList<>();
List<NetworkInterface> goodInterfaces = new ArrayList<>();
try {
interfaces = networking.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
}
var teamBytes = NetworkSettings.GetTeamNumberIPBytes(SettingsManager.GeneralSettings.team_number);
if (interfaces.size() > 0) {
for (var inetface : interfaces) {
for (var inetfaceAddr : inetface.getInterfaceAddresses()) {
var rawAddr = inetfaceAddr.getAddress().getAddress();
if (rawAddr.length > 4) continue;
if (rawAddr[1] == teamBytes[0] && rawAddr[2] == teamBytes[1]) {
goodInterfaces.add(new NetworkInterface(inetface, inetfaceAddr));
}
}
}
if (goodInterfaces.size() == 0) {
isManaged = false;
System.err.println("No valid network interfaces found! Staying unmanaged.");
return;
}
botInterface = goodInterfaces.get(0);
networking.setNetworkInterface(botInterface);
} else {
isManaged = false;
System.err.println("No valid network interfaces found! Staying unmanaged.");
return;
}
if(!loadFromGeneralSettings()) {
isManaged = false;
System.err.println("Failed to load network settings. Staying unmanaged!");
}
}
private static boolean loadFromGeneralSettings() {
if (!isManaged) {
return true;
}
var genSettings = SettingsManager.GeneralSettings;
boolean isStatic = genSettings.connection_type.toLowerCase().equals("static");
if (isStatic) {
var splitIPAddr = genSettings.ip.split("\\.");
splitIPAddr[3] = "255";
var broadcast = String.join(".", splitIPAddr);
if (!setStatic(genSettings.ip, genSettings.netmask, genSettings.gateway, broadcast)) {
return false;
}
} else {
if (!setDHCP()) {
return false;
}
}
return setHostname(genSettings.hostname);
}
private static boolean setDHCP() {
if (!isManaged) {
return true;
}
return networking.setDHCP();
}
private static boolean setStatic(String ipAddress, String netmask, String gateway, String broadcast) {
if (!isManaged) {
return true;
}
return networking.setStatic(ipAddress, netmask, gateway, broadcast);
}
private static boolean setHostname(String hostname) {
if (!isManaged) {
return true;
}
return networking.setHostname(hostname);
}
}

View File

@@ -0,0 +1,37 @@
package com.chameleonvision.network;
import com.chameleonvision.util.ShellExec;
import java.io.IOException;
import java.net.SocketException;
import java.util.List;
import java.util.Scanner;
public abstract class SysNetworking {
NetworkInterface networkInterface;
ShellExec shell = new ShellExec(true, true);
public String getHostname() {
try {
var retCode = shell.execute("hostname", null, true);
if (retCode == 0) {
while(!shell.isOutputCompleted()) {}
return shell.getOutput();
} else {
return null;
}
} catch (IOException e) {
return null;
}
}
public void setNetworkInterface(NetworkInterface networkInterface) {
this.networkInterface = networkInterface;
}
public abstract boolean setDHCP();
public abstract boolean setHostname(String hostname);
public abstract boolean setStatic(String ipAddress, String netmask, String gateway, String broadcast);
public abstract List<java.net.NetworkInterface> getNetworkInterfaces() throws SocketException;
}

View File

@@ -0,0 +1,57 @@
package com.chameleonvision.network;
import com.chameleonvision.settings.NetworkSettings;
import com.chameleonvision.settings.SettingsManager;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class WindowsNetworking extends SysNetworking {
@Override
public boolean setDHCP() {
return false;
}
@Override
public boolean setHostname(String newHostname) {
var currentHostname = getHostname();
if (getHostname() == null) {
return false;
}
String command = String.format("wmic computersystem where name=\"%s\" call rename name=\"%s\"", currentHostname, newHostname);
try {
var process = Runtime.getRuntime().exec(command);
var returnCode = process.waitFor();
return returnCode == 0;
} catch(Exception e) {
return false;
}
}
@Override
public boolean setStatic(String ipAddress, String netmask, String gateway, String broadcast) {
return false;
}
@Override
public List<java.net.NetworkInterface> getNetworkInterfaces() throws SocketException {
var netInterfaces = Collections.list(java.net.NetworkInterface.getNetworkInterfaces());
List<java.net.NetworkInterface> goodInterfaces = new ArrayList<>();
for (var netInterface : netInterfaces) {
if (netInterface.getDisplayName().toLowerCase().contains("bluetooth")) continue;
if (netInterface.getDisplayName().toLowerCase().contains("virtual")) continue;
if (netInterface.getDisplayName().toLowerCase().contains("loopback")) continue;
if (!netInterface.isUp()) continue;
goodInterfaces.add(netInterface);
}
return goodInterfaces;
}
}

View File

@@ -1,4 +1,4 @@
package com.chameleonvision.vision;
package com.chameleonvision.settings;
public class GeneralSettings {
public int team_number = 1577;

View File

@@ -1,9 +1,12 @@
package com.chameleonvision.settings;
import java.net.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import com.chameleonvision.util.Utilities;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
public class NetworkSettings {
@@ -51,20 +54,26 @@ public class NetworkSettings {
}
}
public static byte[] GetTeamNumberIPBytes(int teamNumber) {
return new byte[]{(byte) (teamNumber / 100), (byte) (teamNumber % 100)};
}
public static String getAdapter() {
try {//TODO fix windows get adapter
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets)) {
Enumeration<InetAddress> ee = netint.getInetAddresses();
for (InetAddress addr : Collections.list(ee))
if (addr instanceof Inet4Address)
if ((addr.getAddress()[0] & 0xFF) == 192 && (addr.getAddress()[1] & 0xFF) == 168) {
if (addr instanceof Inet4Address) {
var addrString = addr.toString();
if ((addr.getAddress()[0] & 0xFF) == 10 && (addr.getAddress()[1] & 0xFF) == 168) {
System.out.println("found robot network interface at " + netint.getName() + " ip: " + addr.getHostAddress());
return netint.getName();
}
}
}
} catch (SocketException e) {
System.err.println("Socket exception while trying to find current ip");
System.err.println("Socket exception while trying to find current IP");
}
return "";
}

View File

@@ -0,0 +1,97 @@
package com.chameleonvision.settings;
import com.chameleonvision.util.ShellExec;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public enum Platform {
WINDOWS_64("Windows x64"),
LINUX_64("Linux x64"),
LINUX_RASPBIAN("Linux Raspbian"),
LINUX_ARM64("Linux ARM64"),
MACOS_64("Mac OS x64"),
UNSUPPORTED("Unsupported Platform");
public final String value;
Platform(String value) {
this.value = value;
}
private static final String OS_NAME = System.getProperty("os.name");
private static final String OS_ARCH = System.getProperty("os.arch");
public boolean isWindows() {
return this == WINDOWS_64;
}
public boolean isLinux() {
return this == LINUX_64 || this == LINUX_RASPBIAN || this == LINUX_ARM64;
}
public boolean isMac() {
return this == MACOS_64;
}
private static ShellExec shell = new ShellExec(true, false);
public boolean isRoot() {
if (isLinux() || isMac()) {
try {
shell.execute("id", null, true, "-u");
} catch (IOException e) {
e.printStackTrace();
}
while (!shell.isOutputCompleted()) {}
if (shell.getExitCode() == 0) {
var out = shell.getOutput();
out = out.split("\n")[0];
return out.equals("0");
}
} else if (isWindows()) {
return true;
} else {
return true;
}
return false;
}
private static boolean isRaspbian() {
try (BufferedReader reader = Files.newBufferedReader(Paths.get("/etc/os-release"))) {
String value = reader.readLine();
return value.contains("Raspbian");
} catch (IOException ex) {
return false;
}
}
public static Platform getCurrentPlatform() {
if (OS_NAME.contains("Windows")) {
if (OS_ARCH.equals("amd64")) return Platform.WINDOWS_64;
}
if (OS_NAME.contains("Linux")) {
if (OS_ARCH.equals("amd64")) return Platform.LINUX_64;
if (isRaspbian()) return Platform.LINUX_RASPBIAN;
if (OS_ARCH.contains("aarch")) return Platform.LINUX_ARM64;
}
if (OS_NAME.contains("Mac")) {
if (OS_ARCH.equals("amd64")) return Platform.MACOS_64;
}
System.out.printf("Unknown Platform! OS: %s, Architecture: %s", OS_NAME, OS_ARCH);
return Platform.UNSUPPORTED;
}
public String toString() {
if (this.equals(UNSUPPORTED)) {
return String.format("Unknown Platform. OS: %s, Architecture: %s", OS_NAME, OS_ARCH);
} else {
return this.value;
}
}
}

View File

@@ -1,7 +1,7 @@
package com.chameleonvision.settings;
import com.chameleonvision.FileHelper;
import com.chameleonvision.vision.GeneralSettings;
import com.chameleonvision.network.NetworkManager;
import com.chameleonvision.util.FileHelper;
import com.chameleonvision.vision.camera.CameraManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -15,21 +15,22 @@ import java.nio.file.Paths;
public class SettingsManager {
public static final Path SettingsPath = Paths.get(System.getProperty("user.dir"), "settings");
public static com.chameleonvision.vision.GeneralSettings GeneralSettings;
public static com.chameleonvision.settings.GeneralSettings GeneralSettings;
private SettingsManager() {}
public static void initialize(boolean manageNetwork) {
public static void initialize() {
initGeneralSettings();
if (manageNetwork) {
NetworkSettings netSettings = new NetworkSettings();
netSettings.hostname = GeneralSettings.hostname;
netSettings.gateway = GeneralSettings.gateway;
netSettings.netmask = GeneralSettings.netmask;
netSettings.connectionType = GeneralSettings.connection_type;
netSettings.ip = GeneralSettings.ip;
netSettings.run();
}
// if (manageNetwork) {
// NetworkSettings netSettings = new NetworkSettings();
// netSettings.hostname = GeneralSettings.hostname;
// netSettings.gateway = GeneralSettings.gateway;
// netSettings.netmask = GeneralSettings.netmask;
// netSettings.connectionType = GeneralSettings.connection_type;
// netSettings.ip = GeneralSettings.ip;
// netSettings.run();
// }
var allCameras = CameraManager.getAllCamerasByName();
if (!allCameras.containsKey(GeneralSettings.curr_camera) && allCameras.size() > 0) {
var cam = allCameras.entrySet().stream().findFirst().get().getValue();
@@ -38,49 +39,10 @@ public class SettingsManager {
}
}
public enum Platform {
WINDOWS_64("Windows x64"),
LINUX_64("Linux x64"),
LINUX_RASPBIAN("Linux Raspbian"),
LINUX_AARCH64("Linux ARM 64bit"),
MACOS_64("Mac OS x64"),
UNSUPPORTED("Unsupported Platform");
public final String value;
Platform(String value) {
this.value = value;
}
}
public static Platform getCurrentPlatform() {
var osName = System.getProperty("os.name");
var osArch = System.getProperty("os.arch");
if (osName.contains("Windows")) {
if (osArch.equals("amd64")) return Platform.WINDOWS_64;
return Platform.UNSUPPORTED;
}
if (osName.contains("Linux")) {
if (osArch.equals("amd64")) return Platform.LINUX_64;
if (osArch.contains("rasp")) return Platform.LINUX_RASPBIAN;
if (osArch.contains("aarch")) return Platform.LINUX_64;
return Platform.UNSUPPORTED;
}
if (osName.contains("Mac")) {
if (osArch.equals("amd64")) return Platform.MACOS_64;
return Platform.UNSUPPORTED;
}
return Platform.UNSUPPORTED;
}
private static void initGeneralSettings() {
FileHelper.CheckPath(SettingsPath);
try {
GeneralSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(), "settings.json").toString()), com.chameleonvision.vision.GeneralSettings.class);
GeneralSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(), "settings.json").toString()), com.chameleonvision.settings.GeneralSettings.class);
} catch (FileNotFoundException e) {
GeneralSettings = new GeneralSettings();
}

View File

@@ -1,4 +1,4 @@
package com.chameleonvision;
package com.chameleonvision.util;
import java.io.IOException;
import java.nio.file.Files;

View File

@@ -1,15 +1,24 @@
package com.chameleonvision.Handler;
package com.chameleonvision.util;
import java.lang.Math;
import org.apache.commons.math3.util.FastMath;
public class MathHandler {
MathHandler(){}
MathHandler() {}
public static double sigmoid(double x){
double bias = 0;
double a = 5;
double b = -0.05;
double k = 200;
if (x < 50){
bias = -1.338;
}
return ((k / (1 + Math.pow(Math.E,(a + (b * x))))) + bias);
}
public static double toSlope(double angle){
return FastMath.atan(FastMath.toRadians(angle - 90));
}
}

View File

@@ -1,4 +1,4 @@
package com.chameleonvision;
package com.chameleonvision.util;
public class MemoryManager {

View File

@@ -0,0 +1,151 @@
package com.chameleonvision.util;
import java.io.*;
/**
* Execute external process and optionally read output buffer.
*/
public class ShellExec {
private int exitCode;
private boolean readOutput, readError;
private StreamGobbler errorGobbler, outputGobbler;
public ShellExec() {
this(false, false);
}
public ShellExec(boolean readOutput, boolean readError) {
this.readOutput = readOutput;
this.readError = readError;
}
/**
* Execute a command in current folder, and wait for process to end
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
* @param args 0..n command line arguments
* @return process exit code
*/
public int execute(String command, String... args) throws IOException {
return execute(command, null, true, args);
}
/**
* Execute a command.
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
* @param workdir working directory or NULL to use command folder
* @param wait wait for process to end
* @param args 0..n command line arguments
* @return process exit code
*/
public int execute(String command, String workdir, boolean wait, String...args) throws IOException {
String[] cmdArr;
if (args != null && args.length > 0) {
cmdArr = new String[1+args.length];
cmdArr[0] = command;
System.arraycopy(args, 0, cmdArr, 1, args.length);
} else {
cmdArr = new String[] { command };
}
ProcessBuilder pb = new ProcessBuilder(cmdArr);
File workingDir = (workdir==null ? new File(command).getParentFile() : new File(workdir) );
pb.directory(workingDir);
Process process = pb.start();
// Consume streams, older jvm's had a memory leak if streams were not read,
// some other jvm+OS combinations may block unless streams are consumed.
errorGobbler = new StreamGobbler(process.getErrorStream(), readError);
outputGobbler = new StreamGobbler(process.getInputStream(), readOutput);
errorGobbler.start();
outputGobbler.start();
exitCode = 0;
if (wait) {
try {
process.waitFor();
exitCode = process.exitValue();
} catch (InterruptedException ignored) { }
}
return exitCode;
}
public int getExitCode() {
return exitCode;
}
public boolean isOutputCompleted() {
return (outputGobbler != null && outputGobbler.isCompleted());
}
public boolean isErrorCompleted() {
return (errorGobbler != null && errorGobbler.isCompleted());
}
public String getOutput() {
return (outputGobbler != null ? outputGobbler.getOutput() : null);
}
public String getError() {
return (errorGobbler != null ? errorGobbler.getOutput() : null);
}
//********************************************
//********************************************
/**
* StreamGobbler reads inputstream to "gobble" it.
* This is used by Executor class when running
* a commandline applications. Gobblers must read/purge
* INSTR and ERRSTR process streams.
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
*/
@SuppressWarnings("WeakerAccess")
private class StreamGobbler extends Thread {
private InputStream is;
private StringBuilder output;
private volatile boolean completed; // mark volatile to guarantee a thread safety
public StreamGobbler(InputStream is, boolean readStream) {
this.is = is;
this.output = (readStream ? new StringBuilder(256) : null);
}
public void run() {
completed = false;
try {
String NL = System.getProperty("line.separator", "\r\n");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null) {
if (output != null)
output.append(line).append(NL);
}
} catch (IOException ex) {
// ex.printStackTrace();
}
completed = true;
}
/**
* Get inputstream buffer or null if stream
* was not consumed.
* @return
*/
public String getOutput() {
return (output != null ? output.toString() : null);
}
/**
* Is input stream completed.
* @return
*/
public boolean isCompleted() {
return completed;
}
}
}

View File

@@ -1,5 +1,8 @@
package com.chameleonvision.util;
import java.util.ArrayList;
import java.util.List;
public class Utilities {
private Utilities() {}
@@ -8,4 +11,30 @@ public class Utilities {
return ip.matches(PATTERN);
}
public static List<Byte> getDigitBytes(int num) {
List<Byte> digits = new ArrayList<>();
collectDigitBytes(num, digits);
return digits;
}
private static void collectDigitBytes(int num, List<Byte> digits) {
if (num / 10 > 0) {
collectDigitBytes( num / 10, digits);
}
digits.add((byte) (num % 10));
}
public static List<Integer> getDigits(int num) {
List<Integer> digits = new ArrayList<Integer>();
collectDigits(num, digits);
return digits;
}
private static void collectDigits(int num, List<Integer> digits) {
if(num / 10 > 0) {
collectDigits(num / 10, digits);
}
digits.add(num % 10);
}
}

View File

@@ -1,13 +1,11 @@
package com.chameleonvision.vision.camera;
import com.chameleonvision.CameraException;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.settings.Platform;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.web.ServerHandler;
import edu.wpi.cscore.*;
import edu.wpi.first.cameraserver.CameraServer;
import org.opencv.core.Mat;
import org.springframework.core.env.Environment;
import java.util.Arrays;
import java.util.HashMap;
@@ -18,7 +16,7 @@ public class Camera {
private static final double DEFAULT_FOV = 60.8;
private static final int MINIMUM_FPS = 30;
private static final int MINIMUM_WIDTH = 320;
private static final int MINIMUM_HEIGHT = 240;
private static final int MINIMUM_HEIGHT = 200;
private static final int MAX_INIT_MS = 1500;
public final String name;
@@ -67,12 +65,11 @@ public class Camera {
this.pipelines = pipelines;
// set up video modes according to minimums
if (SettingsManager.getCurrentPlatform() == SettingsManager.Platform.WINDOWS_64 && !UsbCam.isConnected()) {
if (Platform.getCurrentPlatform() == Platform.WINDOWS_64 && !UsbCam.isConnected()) {
System.out.print("Waiting on camera... ");
long initTimeout = System.nanoTime();
while(!UsbCam.isConnected())
{
//TODO add a time sleep, can wait only so long before giving up
if (((System.nanoTime() - initTimeout) / 1e6 ) >= MAX_INIT_MS) {
break;
}
@@ -81,7 +78,7 @@ public class Camera {
System.out.printf("Camera initialized in %.2fms\n", initTimeMs);
}
var trueVideoModes = UsbCam.enumerateVideoModes();
availableVideoModes = Arrays.stream(trueVideoModes).filter(v -> v.fps >= MINIMUM_FPS && v.width >= MINIMUM_WIDTH && v.height >= MINIMUM_HEIGHT && v.pixelFormat == VideoMode.PixelFormat.kYUYV).toArray(VideoMode[]::new);
availableVideoModes = Arrays.stream(trueVideoModes).filter(v -> v.fps >= MINIMUM_FPS && v.width >= MINIMUM_WIDTH && v.height >= MINIMUM_HEIGHT).toArray(VideoMode[]::new);
if (availableVideoModes.length == 0) {
System.err.println("Camera not supported!");
throw new RuntimeException(new CameraException(CameraException.CameraExceptionType.BAD_CAMERA));

View File

@@ -1,4 +1,4 @@
package com.chameleonvision;
package com.chameleonvision.vision.camera;
public class CameraException extends Exception {
public enum CameraExceptionType {
@@ -19,7 +19,7 @@ public class CameraException extends Exception {
}
}
public CameraException(CameraExceptionType camExceptionType) {
CameraException(CameraExceptionType camExceptionType) {
super(camExceptionType.toString());
}
}

View File

@@ -1,9 +1,7 @@
package com.chameleonvision.vision.camera;
import com.chameleonvision.CameraException;
import com.chameleonvision.FileHelper;
import com.chameleonvision.util.FileHelper;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.GeneralSettings;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.process.VisionProcess;
import com.google.gson.Gson;
@@ -15,7 +13,6 @@ import org.opencv.videoio.VideoCapture;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -121,7 +118,7 @@ public class CameraManager {
public static List<String> getResolutionList() throws CameraException {
if (!SettingsManager.GeneralSettings.curr_camera.equals("")) {
return Arrays.stream(CameraManager.getCamera(SettingsManager.GeneralSettings.curr_camera).getAvailableVideoModes())
.map(res -> String.format("%s X %s at %s fps", res.width, res.height, res.fps)).collect(Collectors.toList());
.map(res -> String.format("%s X %s at %s fps using %s ", res.width, res.height, res.fps, res.pixelFormat.toString())).collect(Collectors.toList());
}
throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
}

View File

@@ -1,93 +1,103 @@
package com.chameleonvision.vision.process;
import com.chameleonvision.vision.camera.CameraValues;
import com.chameleonvision.Handler.MathHandler;
import com.chameleonvision.util.MathHandler;
import org.apache.commons.math3.util.FastMath;
import org.jetbrains.annotations.NotNull;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgproc.Moments;
import java.util.*;
@SuppressWarnings("WeakerAccess")
public class CVProcess {
private final CameraValues CamVals;
private HashMap<String, Integer> TargetGrouping = new HashMap<>() {{
private final CameraValues cameraValues;
private HashMap<String, Integer> targetGrouping = new HashMap<>() {{
put("Single", 1);
put("Dual", 2);
put("Triple", 3);
put("Quadruple", 4);
put("Quintuple", 5);
}};
private Mat Kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
private Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
private Size blur = new Size(1,1);
private Mat hsvImage = new Mat();
private List<MatOfPoint> FoundContours = new ArrayList<>();
private List<MatOfPoint> foundContours = new ArrayList<>();
private Mat binaryMat = new Mat();
private List<MatOfPoint> FilteredContours = new ArrayList<>();
private Comparator<RotatedRect> SortByCentermostComparator = Comparator.comparingDouble(this::calcDistance);
private List<RotatedRect> FinalCountours = new ArrayList<>();
private Mat intersectMatA = new Mat();
private Mat intersectMatB = new Mat();
private List<MatOfPoint> filteredContours = new ArrayList<>();
private Comparator<RotatedRect> sortByCentermostComparator = Comparator.comparingDouble(this::calcDistance);
private Comparator<MatOfPoint> sortByMomentsX = Comparator.comparingDouble(this::calcMomentsX);
private List<RotatedRect> finalCountours = new ArrayList<>();
private MatOfPoint2f intersectMatA = new MatOfPoint2f();
private MatOfPoint2f intersectMatB = new MatOfPoint2f();
CVProcess(CameraValues camVals) {
CamVals = camVals;
CVProcess(CameraValues cameraValues) {
this.cameraValues = cameraValues;
}
void HSVThreshold(Mat srcImage, Mat dst, @NotNull Scalar hsvLower, @NotNull Scalar hsvUpper, boolean shouldErode, boolean shouldDilate) {
void hsvThreshold(Mat srcImage, Mat dst, @NotNull Scalar hsvLower, @NotNull Scalar hsvUpper, boolean shouldErode, boolean shouldDilate) {
Imgproc.cvtColor(srcImage, hsvImage, Imgproc.COLOR_RGB2HSV, 3);
Imgproc.blur(hsvImage, hsvImage, blur);
Core.inRange(hsvImage, hsvLower, hsvUpper, dst);
if (shouldErode) {
Imgproc.erode(dst, dst, Kernel);
Imgproc.erode(dst, dst, kernel);
}
if (shouldDilate) {
Imgproc.dilate(dst, dst, Kernel);
Imgproc.dilate(dst, dst, kernel);
}
hsvImage.release();
}
List<MatOfPoint> FindContours(Mat src) {
List<MatOfPoint> findContours(Mat src) {
src.copyTo(binaryMat);
FoundContours.clear();
Imgproc.findContours(binaryMat, FoundContours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_L1);
foundContours.clear();
Imgproc.findContours(binaryMat, foundContours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_L1);
binaryMat.release();
return FoundContours;
return foundContours;
}
List<MatOfPoint> FilterContours(List<MatOfPoint> InputContours, List<Integer> area, List<Double> ratio, List<Integer> extent) {
for (MatOfPoint Contour : InputContours) {
List<MatOfPoint> filterContours(List<MatOfPoint> inputContours, List<Integer> area, List<Double> ratio, List<Integer> extent) {
for (MatOfPoint Contour : inputContours) {
try {
double contourArea = Imgproc.contourArea(Contour);
double minArea = (MathHandler.sigmoid(area.get(0)) * CamVals.ImageArea) / 100;
double maxArea = (MathHandler.sigmoid(area.get(1)) * CamVals.ImageArea) / 100;
if (contourArea <= minArea || contourArea >= maxArea) {
double AreaRatio = (contourArea / cameraValues.ImageArea)*100;
double minArea = (MathHandler.sigmoid(area.get(0)));
double maxArea = (MathHandler.sigmoid(area.get(1)));
if (AreaRatio < minArea || AreaRatio > maxArea) {
continue;
}
var rect = Imgproc.minAreaRect(new MatOfPoint2f(Contour.toArray()));
var targetFullness = contourArea;
double minExtent = (double) (extent.get(0) * rect.size.area())/ 100;
double minExtent = (double) (extent.get(0) * rect.size.area()) / 100;
double maxExtent = (double) (extent.get(1) * rect.size.area()) / 100;
if (targetFullness <= minExtent || contourArea >= maxExtent) {
continue;
}
double aspectRatio = rect.size.width / rect.size.height;//TODO i think aspectRatio is inverted
Rect bb = Imgproc.boundingRect(Contour);
double aspectRatio = (bb.width / bb.height);
if (aspectRatio < ratio.get(0) || aspectRatio > ratio.get(1)) {
continue;
}
FilteredContours.add(Contour);
filteredContours.add(Contour);
} catch (Exception e) {
System.err.println("Error while filtering contours");
e.printStackTrace();
}
}
return FilteredContours;
return filteredContours;
}
private double calcDistance(RotatedRect rect) {
return FastMath.sqrt(FastMath.pow(CamVals.CenterX - rect.center.x, 2) + FastMath.pow(CamVals.CenterY - rect.center.y, 2));
return FastMath.sqrt(FastMath.pow(cameraValues.CenterX - rect.center.x, 2) + FastMath.pow(cameraValues.CenterY - rect.center.y, 2));
}
RotatedRect SortTargetsToOne(List<RotatedRect> inputRects, String sortMode) {
private double calcMomentsX(MatOfPoint c){
Moments m = Imgproc.moments(c);
return (m.get_m10()/m.get_m00());
}
RotatedRect sortTargetsToOne(List<RotatedRect> inputRects, String sortMode) {
switch (sortMode) {
case "Largest":
return Collections.max(inputRects, Comparator.comparing(rect -> rect.size.area()));
@@ -102,22 +112,23 @@ public class CVProcess {
case "Rightmost":
return Collections.max(inputRects, Comparator.comparing(rect -> rect.center.x));
case "Centermost":
return Collections.min(inputRects, SortByCentermostComparator);
return Collections.min(inputRects, sortByCentermostComparator);
default:
return inputRects.get(0); // default to whatever the first contour is, but this should never happen
}
}
List<RotatedRect> GroupTargets(List<MatOfPoint> InputContours, String IntersectionPoint, String TargetGroup) {
FinalCountours.clear();
if (!TargetGroup.equals("Single")) {
for (var i = 0; i < InputContours.size(); i++) {
List<Point> FinalContourList = new ArrayList<>(InputContours.get(i).toList());
for (var c = 0; c < (TargetGrouping.get(TargetGroup) - 1); c++) {
List<RotatedRect> groupTargets(List<MatOfPoint> inputContours, String intersectionPoint, String targetGroup) {
finalCountours.clear();
if (!targetGroup.equals("Single")) {
inputContours.sort(sortByMomentsX);
for (var i = 0; i < inputContours.size(); i++) {
List<Point> FinalContourList = new ArrayList<>(inputContours.get(i).toList());
for (var c = 0; c < (targetGrouping.get(targetGroup) - 1); c++) {
try {
MatOfPoint firstContour = InputContours.get(i + c);
MatOfPoint secondContour = InputContours.get(i + c + 1);
if (IsIntersecting(firstContour, secondContour, IntersectionPoint)) {
MatOfPoint firstContour = inputContours.get(i + c);
MatOfPoint secondContour = inputContours.get(i + c + 1);
if (isIntersecting(firstContour, secondContour, intersectionPoint)) {
FinalContourList.addAll(secondContour.toList());
}
else{
@@ -130,7 +141,7 @@ public class CVProcess {
contour.fromList(FinalContourList);
if (contour.cols() != 0 && contour.rows() != 0) {
RotatedRect rect = Imgproc.minAreaRect(contour);
FinalCountours.add(rect);
finalCountours.add(rect);
}
} catch (IndexOutOfBoundsException e) {
FinalContourList.clear();
@@ -140,41 +151,37 @@ public class CVProcess {
}
} else {
for (MatOfPoint inputContour : InputContours) {
for (MatOfPoint inputContour : inputContours) {
MatOfPoint2f contour = new MatOfPoint2f();
contour.fromArray(inputContour.toArray());
if (contour.cols() != 0 && contour.rows() != 0) {
RotatedRect rect = Imgproc.minAreaRect(contour);
FinalCountours.add(rect);
finalCountours.add(rect);
}
}
}
return FinalCountours;
return finalCountours;
}
private boolean IsIntersecting(MatOfPoint ContourOne, MatOfPoint ContourTwo, String IntersectionPoint) {
private boolean isIntersecting(MatOfPoint ContourOne, MatOfPoint ContourTwo, String IntersectionPoint) {
if (IntersectionPoint.equals("None")) {
return true;
}
try {
Imgproc.fitLine(ContourOne, intersectMatA, Imgproc.CV_DIST_L2, 0, 0.01, 0.01);
Imgproc.fitLine(ContourTwo, intersectMatB, Imgproc.CV_DIST_L2, 0, 0.01, 0.01);
double vxA = intersectMatA.get(0, 0)[0];
double vyA = intersectMatA.get(1, 0)[0];
double x0A = intersectMatA.get(2, 0)[0];
double y0A = intersectMatA.get(3, 0)[0];
double mA = vyA / vxA;
double vxB = intersectMatB.get(0, 0)[0];
double vyB = intersectMatB.get(1, 0)[0];
double x0B = intersectMatB.get(2, 0)[0];
double y0B = intersectMatB.get(3, 0)[0];
double mB = vyB / vxB;
double bA = y0A - (mA*x0A);
double bB = y0B - (mB*x0B);
intersectMatA.fromArray(ContourOne.toArray());
intersectMatB.fromArray(ContourTwo.toArray());
RotatedRect a = Imgproc.fitEllipse(intersectMatA);
RotatedRect b = Imgproc.fitEllipse(intersectMatB);
double mA = MathHandler.toSlope(a.angle);
double mB = MathHandler.toSlope(b.angle);
double x0A = a.center.x;
double y0A = a.center.y;
double x0B = b.center.x;
double y0B = b.center.y;
double intersectionX = ((mA * x0A) - y0A - (mB * x0B) + y0B )/ (mA - mB);
double intersectionY = (mA * (intersectionX - x0A)) + y0A;
double massX = intersectionX + 1;
double massY = intersectionY + ((mA + bA + mB +bB) / 2);
double massX = (x0A + x0B) / 2;
double massY = (y0A + y0B) / 2;
switch (IntersectionPoint) {
case "Up": {
if (intersectionY < massY) {

View File

@@ -3,7 +3,6 @@ package com.chameleonvision.vision.process;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.camera.Camera;
import com.chameleonvision.web.Server;
import com.chameleonvision.web.ServerHandler;
import edu.wpi.cscore.VideoException;
import edu.wpi.first.networktables.*;
@@ -31,14 +30,15 @@ public class VisionProcess implements Runnable {
private Pipeline currentPipeline;
private CVProcess cvProcess;
// pipeline process items
private List<MatOfPoint> FoundContours = new ArrayList<>();
private List<MatOfPoint> FilteredContours = new ArrayList<>();
private List<RotatedRect> GroupedContours = new ArrayList<>();
private List<MatOfPoint> foundContours = new ArrayList<>();
private List<MatOfPoint> filteredContours = new ArrayList<>();
private List<RotatedRect> groupedContours = new ArrayList<>();
private Mat cameraInputMat = new Mat();
private Mat hsvThreshMat = new Mat();
private Mat streamOutputMat = new Mat();
private Scalar contourRectColor = new Scalar(255, 0, 0);
private long TimeStamp = 0;
private Scalar BoxRectColor = new Scalar(0, 0, 233);
private long timeStamp = 0;
public VisionProcess(Camera processCam) {
camera = processCam;
@@ -53,8 +53,8 @@ public class VisionProcess implements Runnable {
ntDistanceEntry = ntTable.getEntry("distance");
ntTimeStampEntry = ntTable.getEntry("timestamp");
ntValidEntry = ntTable.getEntry("is_valid");
ntDriverModeEntry.addListener(this::DriverModeListener, EntryListenerFlags.kUpdate);
ntPipelineEntry.addListener(this::PipelineListener, EntryListenerFlags.kUpdate);
ntDriverModeEntry.addListener(this::driverModeListener, EntryListenerFlags.kUpdate);
ntPipelineEntry.addListener(this::pipelineListener, EntryListenerFlags.kUpdate);
ntDriverModeEntry.setBoolean(false);
ntPipelineEntry.setNumber(camera.getCurrentPipelineIndex());
@@ -63,7 +63,7 @@ public class VisionProcess implements Runnable {
cameraProcess = new CameraProcess(camera);
}
private void DriverModeListener(EntryNotification entryNotification) {
private void driverModeListener(EntryNotification entryNotification) {
if (entryNotification.value.getBoolean()) {
camera.setExposure(25);
camera.setBrightness(15);
@@ -74,7 +74,7 @@ public class VisionProcess implements Runnable {
}
}
private void PipelineListener(EntryNotification entryNotification) {
private void pipelineListener(EntryNotification entryNotification) {
var ntPipelineIndex = (int) entryNotification.value.getDouble();
if (camera.getPipelines().containsKey(ntPipelineIndex)) {
// camera.setEntryNotification.value.getString());
@@ -104,20 +104,29 @@ public class VisionProcess implements Runnable {
List<MatOfPoint> drawnContour = new ArrayList<>();
Point[] vertices = new Point[4];
contourRect.points(vertices);
drawnContour.add(new MatOfPoint(vertices));
MatOfPoint contour = new MatOfPoint(vertices);
drawnContour.add(contour);
Rect box = Imgproc.boundingRect(contour);
Imgproc.drawContours(inputMat, drawnContour, 0, contourRectColor, 3);
Imgproc.circle(inputMat, contourRect.center, 3, contourRectColor);
Imgproc.rectangle(inputMat,new Point(box.x, box.y), new Point((box.x + box.width),(box.y + box.height)), BoxRectColor,2);
}
private void updateNetworkTables(PipelineResult pipelineResult) {
ntValidEntry.setBoolean(pipelineResult.IsValid);
if (pipelineResult.IsValid) {
ntValidEntry.setBoolean(true);
ntYawEntry.setNumber(pipelineResult.Yaw);
ntPitchEntry.setNumber(pipelineResult.Pitch);
ntDistanceEntry.setNumber(pipelineResult.Area);
ntTimeStampEntry.setNumber(timeStamp);
NetworkTableInstance.getDefault().flush();
} else {
ntYawEntry.setNumber(0.0);
ntPitchEntry.setNumber(0.0);
ntDistanceEntry.setNumber(0.0);
ntTimeStampEntry.setNumber(timeStamp);
ntValidEntry.setBoolean(false);
}
ntTimeStampEntry.setNumber(TimeStamp);
}
private PipelineResult runVisionProcess(Mat inputImage, Mat outputImage) {
@@ -136,20 +145,20 @@ public class VisionProcess implements Runnable {
Scalar hsvLower = new Scalar(currentPipeline.hue.get(0), currentPipeline.saturation.get(0), currentPipeline.value.get(0));
Scalar hsvUpper = new Scalar(currentPipeline.hue.get(1), currentPipeline.saturation.get(1), currentPipeline.value.get(1));
cvProcess.HSVThreshold(inputImage, hsvThreshMat, hsvLower, hsvUpper, currentPipeline.erode, currentPipeline.dilate);
cvProcess.hsvThreshold(inputImage, hsvThreshMat, hsvLower, hsvUpper, currentPipeline.erode, currentPipeline.dilate);
if (currentPipeline.is_binary == 1) {
Imgproc.cvtColor(hsvThreshMat, outputImage, Imgproc.COLOR_GRAY2BGR, 3);
} else {
inputImage.copyTo(outputImage);
}
FoundContours = cvProcess.FindContours(hsvThreshMat);
if (FoundContours.size() > 0) {
FilteredContours = cvProcess.FilterContours(FoundContours, currentPipeline.area, currentPipeline.ratio, currentPipeline.extent);
if (FilteredContours.size() > 0) {
GroupedContours = cvProcess.GroupTargets(FilteredContours, currentPipeline.target_intersection, currentPipeline.target_group);
if (GroupedContours.size() > 0) {
var finalRect = cvProcess.SortTargetsToOne(GroupedContours, currentPipeline.sort_mode);
foundContours = cvProcess.findContours(hsvThreshMat);
if (foundContours.size() > 0) {
filteredContours = cvProcess.filterContours(foundContours, currentPipeline.area, currentPipeline.ratio, currentPipeline.extent);
if (filteredContours.size() > 0) {
groupedContours = cvProcess.groupTargets(filteredContours, currentPipeline.target_intersection, currentPipeline.target_group);
if (groupedContours.size() > 0) {
var finalRect = cvProcess.sortTargetsToOne(groupedContours, currentPipeline.sort_mode);
// System.out.printf("Largest Contour Area: %.2f\n", finalRect.size.area());
pipelineResult.RawPoint = finalRect;
pipelineResult.IsValid = true;
@@ -188,9 +197,9 @@ public class VisionProcess implements Runnable {
while (!Thread.interrupted()) {
startTime = System.nanoTime();
if ((startTime - lastFrameEndNanosec) * 1e-6 >= 1000.0 / maxFps + 3) { // 3 additional fps to allow for overhead
FoundContours.clear();
FilteredContours.clear();
GroupedContours.clear();
foundContours.clear();
filteredContours.clear();
groupedContours.clear();
// update FPS for ui only every 0.5 seconds
if ((startTime - fpsLastTime) * 1e-6 >= 500) {
@@ -204,7 +213,7 @@ public class VisionProcess implements Runnable {
currentPipeline = camera.getCurrentPipeline();
// start fps counter right before grabbing input frame
TimeStamp = cameraProcess.getLatestFrame(cameraInputMat);
timeStamp = cameraProcess.getLatestFrame(cameraInputMat);
if (cameraInputMat.cols() == 0 && cameraInputMat.rows() == 0) {
continue;
}

View File

@@ -1,11 +1,8 @@
package com.chameleonvision.web;
import com.chameleonvision.CameraException;
import com.chameleonvision.vision.camera.CameraException;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.camera.Camera;
import com.chameleonvision.vision.camera.CameraManager;
import com.google.gson.JsonArray;
import edu.wpi.cscore.VideoException;
import io.javalin.websocket.WsCloseContext;
import io.javalin.websocket.WsConnectContext;

View File

@@ -0,0 +1,2 @@
> 1%
last 2 versions

View File

@@ -0,0 +1,17 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
parserOptions: {
parser: 'babel-eslint'
}
}

21
New client/chameleon-client/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,29 @@
# chameleon-client
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

18481
New client/chameleon-client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
{
"name": "chameleon-client",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^2.6.5",
"material-design-icons-iconfont": "^5.0.1",
"vue": "^2.6.10",
"vue-native-websocket": "^2.0.13",
"vue-router": "^3.0.3",
"vuetify": "^2.0.0",
"vuex": "^3.0.1"
},
"devDependencies": {
"@mdi/font": "^4.4.95",
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-service": "^3.11.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"sass": "^1.17.4",
"sass-loader": "^7.1.0",
"vue-cli-plugin-vuetify": "^0.6.3",
"vue-template-compiler": "^2.6.10",
"vuetify-loader": "^1.2.2"
}
}

View File

@@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

View File

@@ -0,0 +1,336 @@
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxFIzIFKw.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxMIzIFKw.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxEIzIFKw.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxLIzIFKw.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxHIzIFKw.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxGIzIFKw.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url(https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgVxIIzI.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmYUtfBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,18 @@
<!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.0">
<link rel="icon" href="<%= BASE_URL %>favicon.png">
<title>Chameleon Vision</title>
<link rel="stylesheet" href="<%= BASE_URL %>Roboto.css">
</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>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -0,0 +1,86 @@
<template>
<v-app>
<v-app-bar app clipped-left dark>
<img class="imgClass" src="./assets/logo.png">
<v-toolbar-title id="title">Chameleon Vision</v-toolbar-title>
<div class="flex-grow-1"></div>
<v-toolbar-items>
<v-tabs dark height="64" slider-color="#4baf62">
<v-tab to="Vision">Vision</v-tab>
<v-tab to="Settings">Settings</v-tab>
</v-tabs>
</v-toolbar-items>
</v-app-bar>
<v-content>
<v-container fluid fill-height>
<v-layout>
<v-flex>
<router-view></router-view>
</v-flex>
</v-layout>
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
name: 'App',
components: {
},
methods:{
handleMessage(key,val){
switch(key){
default:{
this.$store.commit(key,value);
}
}
}
},
data: () => ({
}),
created(){
this.$options.sockets.onmessage = (data) =>{
try{
let message = JSON.parse(data.data);
for(let prop in message){
if(message.hasOwnProperty(prop)){
this.handleMessage(prop,message[prop]);
}
}
}
catch{
console.error('error: ' + data.data);
}
}
}
};
</script>
<style>
html{
overflow-y: hidden !important;
}
.imgClass{
width: auto;
height: 58px;
vertical-align: middle;
padding-right: 5px;
}
.tabClass{
color: #4baf62;
}
.container{
background-color: #212121;
padding: 0!important;
}
#title{
color:#4baf62;
}
span{
color: white;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -0,0 +1,31 @@
<template>
<div>
<v-tooltip :right="right" :bottom="!right" nudge-right="10">
<template v-slot:activator="{ on }">
<v-icon @click="handleClick" v-on="on" :color="color">{{text}}</v-icon>
</template>
<span>{{tooltip}}</span>
</v-tooltip>
</div>
</template>
<script>
export default {
name: 'Icon',
props:['color','tooltip','text','right'],
data() {
return {
}
},
methods:{
handleClick(){
this.$emit('click');
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,38 @@
<template>
<div>
<v-row align="center">
<v-col :cols="2">
<span>{{name}}</span>
</v-col>
<v-col>
<v-text-field dark v-model="localValue" class="mt-0 pt-0" hide-details single-line :disabled="disabled"></v-text-field>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: 'Input',
props:['name','value','disabled'],
data() {
return {
}
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value);
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,38 @@
<template>
<div>
<v-row align="center">
<v-col :cols="2">
<span>{{name}}</span>
</v-col>
<v-col>
<v-text-field dark v-model="localValue" class="mt-0 pt-0" hide-details single-line type="number" style="width: 70px"></v-text-field>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: 'NumberInput',
props:['name','value'],
data() {
return {
}
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value);
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,33 @@
<template>
<div>
<v-radio-group row v-model="localValue" dark :mandatory="true">
<v-radio color="#4baf62" v-for="(name,index) in list" :label="name" v-bind:key="index" :value="index"></v-radio>
</v-radio-group>
</div>
</template>
<script>
export default {
name: 'Radio',
props:['value','list'],
data() {
return {
}
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value);
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,45 @@
<template>
<div>
<v-row align="center">
<v-col :cols="2">
<span>{{name}}</span>
</v-col>
<v-col :cols="10">
<v-range-slider v-model="localValue" :max="max" :min="min" hide-details class="align-center" dark color="#4baf62" :step="step">
<template v-slot:prepend>
<v-text-field v-model="localValue[0]" class="mt-0 pt-0" hide-details single-line type="number" style="width: 50px" :step="step"></v-text-field>
</template>
<template v-slot:append>
<v-text-field v-model="localValue[1]" class="mt-0 pt-0" hide-details single-line type="number" style="width: 50px" :step="step"></v-text-field>
</template>
</v-range-slider>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: 'RangeSlider',
props:['name','min','max','value','step'],
data() {
return {
}
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value)
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,45 @@
<template>
<div>
<v-row align="center">
<v-col :cols="3">
<span>{{name}}</span>
</v-col>
<v-col :cols="9">
<v-select v-model="localValue" :items="indexList" item-text="name" item-value="index" dark color="#4baf62" item-color="green" dense :disabled="disabled"></v-select>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: 'Select',
props:['list','name','value','disabled'],
data() {
return {
}
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value)
}
},
indexList(){
let list = []
for(let i=0 ; i<this.list.length; i++){
list.push({
name:this.list[i],
index:i});
}
return list;
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,44 @@
<template>
<div>
<v-row align="center">
<v-col :cols="2">
<span>{{name}}</span>
</v-col>
<v-col :cols="10">
<v-slider v-model="localValue" dark class="align-center" :max="max" :min="min" hide-details color="#4baf62" :step="step">
<template v-slot:append>
<v-text-field dark v-model="localValue" class="mt-0 pt-0" hide-details single-line type="number" style="width: 50px" :step="step"></v-text-field>
</template>
</v-slider>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: 'Slider',
props:['min','max','name','value','step'],
data() {
return {
}
},
methods:{
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value)
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,38 @@
<template>
<div>
<v-row align="center">
<v-col :cols="2">
<span>{{name}}</span>
</v-col>
<v-col>
<v-switch v-model="localValue" color="#4baf62"></v-switch>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: 'CVSwitch',
props:['name','value'],
data() {
return {
}
},
computed:{
localValue:{
get(){
return this.value;
},
set(value){
this.$emit('input',value)
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,15 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify';
import VueNativeSock from 'vue-native-websocket';
Vue.config.productionTip = false;
// Vue.use(VueNativeSock,'ws://' + location.host + '/websocket',{format: 'json'});
Vue.use(VueNativeSock,'ws://'+location.hostname+':8888/websocket',{format:'JSON'});
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')

View File

@@ -0,0 +1,13 @@
import '@mdi/font/css/materialdesignicons.css';
import 'material-design-icons-iconfont/dist/material-design-icons.css'
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
Vue.use(Vuetify);
export default new Vuetify({
icons: {
}
});

View File

@@ -0,0 +1,27 @@
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
function lazyLoad(view){
return() => import(`@/views/${view}.vue`)
}
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
redirect:'/Vision'
},
{
path: '/Vision',
name: 'Vision',
component: lazyLoad('Camera')
},
{
path: '/Settings',
name: 'Settings',
component: lazyLoad('Settings')
}
]
})

View File

@@ -0,0 +1,62 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const set = key => (state,val) =>{
state[key] = val
};
export default new Vuex.Store({
state: {
settings:{},
pipeline:{
Exposure:0,
Brightness:0,
Orientation:0,
Hue:[0,15],
Saturation:[0,15],
Value:[0,25],
Erode:false,
Dilate:false,
Area:[0,12],
Ratio:[0,12],
Extent:[0,12],
TargetGrouping:0,
TargetIntersection:0,
SortMode:0
},
cameraSettings:{},
resolutionList:[],
port:1181,
currentCameraIndex:0,
currentPipelineIndex:0,
cameraList:[],
pipelinelist:[],
point:{}
},
mutations: {
settings: set('settings'),
pipeline: set('pipeline'),
cameraSettings: set('cameraSettings'),
resolutionList: set('resolutionList'),
port: set('port'),
currentCameraIndex: set('currentCameraIndex'),
currentPipelineIndex: set('currentPipelineIndex'),
cameraList: set('cameraList'),
pipelinelist: set('cameraList'),
point:set('point')
},
actions: {
settings: state => state.settings,
pipeline: state => state.pipeline,
cameraSettings: state =>state.cameraSettings,
resolutionList: state =>state.resolutionList,
port: state =>state.port,
currentCameraIndex: state =>state.currentCameraIndex,
currentPipelineIndex: state =>state.currentPipelineIndex,
cameraList: state =>state.cameraList,
pipelinelist: state =>state.pipelinelist,
point: state =>state.point,
}
})

View File

@@ -0,0 +1,192 @@
<template>
<div>
<div>
<v-row align="center">
<v-col :cols="3" class="colsClass">
<div style="padding-left:30px">
<CVselect name="Camera" v-model="currentCameraIndex" :list="cameraList"></CVselect>
</div>
</v-col>
<v-col :cols="1">
<CVicon color="white" text="edit" tooltip="Edit camera name"></CVicon>
</v-col>
<v-col :cols="3" class="colsClass">
<CVselect name="Pipeline" :list="pipelineList" v-model="currentPipelineIndex"></CVselect>
</v-col>
<v-col :cols="1" class="colsClass">
<v-menu offset-y dark auto>
<template v-slot:activator="{ on }">
<v-icon color="white" @click="test" v-on="on">menu</v-icon>
</template>
<v-list dense>
<v-list-item @click="test">
<v-list-item-title>
<CVicon color="white" :right="true" text="edit" tooltip="Edit pipeline name"></CVicon>
</v-list-item-title>
</v-list-item>
<v-list-item @click="test">
<v-list-item-title>
<CVicon color="white" :right="true" text="add" tooltip="Add new pipeline"></CVicon>
</v-list-item-title>
</v-list-item>
<v-list-item @click="test">
<v-list-item-title>
<CVicon color="red darken-2" :right="true" text="delete" tooltip="Delete pipeline"></CVicon>
</v-list-item-title>
</v-list-item>
<v-list-item @click="test">
<v-list-item-title>
<CVicon color="white" :right="true" text="mdi-content-copy" tooltip="Duplicate pipeline"></CVicon>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
</v-row>
</div>
<v-row>
<v-col cols="6" class="colsClass">
<v-tabs fixed-tabs background-color="#212121" dark height="50" slider-color="#4baf62" v-model="selectedTab">
<v-tab>Input</v-tab>
<v-tab>Threshold</v-tab>
<v-tab>Contours</v-tab>
<v-tab>Output</v-tab>
</v-tabs>
<div style="padding-left:30px">
<component v-model="pipeline" :is="selectedComponent"></component>
</div>
</v-col>
<v-col cols="6" class="colsClass">
<div>
<v-tabs background-color="#212121" dark height="50" slider-color="#4baf62" centered style="padding-bottom:10px">
<v-tab>Normal</v-tab>
<v-tab>Threshold</v-tab>
</v-tabs>
<div class="videoClass">
<img :src="steamAdress">
</div>
<h5 id="Point">{{point}}</h5>
</div>
</v-col>
</v-row>
</div>
</template>
<script>
import InputTab from './CameraViewes/InputTab'
import ThresholdTab from './CameraViewes/ThresholdTab'
import ContoursTab from './CameraViewes/ContoursTab'
import OutputTab from './CameraViewes/OutputTab'
import CVselect from '../components/cv-select'
import CVicon from '../components/cv-icon'
export default {
name: 'CameraTab',
components:{
InputTab,
ThresholdTab,
ContoursTab,
OutputTab,
CVselect,
CVicon
},
methods:{
test(){
}
},
data() {
return {
selectedTab:0,
}
},
computed:{
selectedComponent(){
switch(this.selectedTab){
case 0:
return "InputTab";
case 1:
return "ThresholdTab";
case 2:
return "ContoursTab";
case 3:
return "OutputTab";
}
},
point:{
get:function(){
let p = this.$store.state.point.calulated;
if(p !== undefined){
return ("Pitch: " + parseFloat(p['pitch']).toFixed(2) + " Yaw: " + parseFloat(p['yaw']).toFixed(2) + " FPS: " + parseFloat(p['fps']).toFixed(2))
} else{
return undefined;
}
}
},
currentCameraIndex:{
get(){
return this.$store.state.currentCameraIndex;
},
set(value){
this.$store.commit('currentCameraIndex',value);
}
},
currentPipelineIndex:{
get(){
return this.$store.state.currentPipelineIndex;
},
set(value){
this.$store.commit('currentPipelineIndex',value);
}
},
cameraList:{
get(){
return this.$store.state.cameraList;
},
set(value){
this.$store.commit('cameraList',value);
}
},
pipelineList:{
get(){
return this.$store.state.pipelinelist;
},
set(value){
this.$store.commit('pipelinelist',value);
}
},
pipeline:{
get(){
return this.$store.state.pipeline;
},
set(value){
this.$store.commit('pipeline',value);
}
},
steamAdress: {
get: function(){
return "http://"+location.hostname + ":"+ this.$store.state.port +"/stream.mjpg";
}
},
}
}
</script>
<style scoped>
.colsClass{
padding: 0 !important;
}
.videoClass{
text-align: center;
}
.videoClass img{
height: auto !important;
width: 75%;
vertical-align: middle;
}
#Point{
padding-top: 5px;
text-align: center;
color: #f4f4f4;
}
</style>

View File

@@ -0,0 +1,39 @@
<template>
<div>
<CVrangeSlider v-model="value.Area" name="Area" :min="0" :max="100" :step="0.1"></CVrangeSlider>
<CVrangeSlider v-model="value.Ratio" name="Ratio (W/H)" :min="0" :max="100" :step="0.1"></CVrangeSlider>
<CVrangeSlider v-model="value.Extent" name="Extent" :min="0" :max="100"></CVrangeSlider>
<CVselect name="Target Group" :list="['Single','Dual','Triple','Quadruple','Quintuple']" v-model="value.TargetGrouping"></CVselect>
<CVselect name="Target Intersection" :list="['None','Up','Down','Left','Right']" :disabled="isDisabled" v-model="value.TargetIntersection"></CVselect>
</div>
</template>
<script>
import CVrangeSlider from '../../components/cv-range-slider'
import CVselect from '../../components/cv-select'
export default {
name: 'Contours',
props:['value'],
components:{
CVrangeSlider,
CVselect
},
data() {
return {
}
},
computed:{
isDisabled(){
if(this.value.TargetGrouping === 0){
return true;
}
return false;
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,37 @@
<template>
<div>
<CVslider name="Exposure" v-model="value.Exposure" :min="0" :max="100"></CVslider>
<CVslider name="Brightness" v-model="value.Brightness" :min="0" :max="100"></CVslider>
<CVselect name="Orientation" v-model="value.Orientation" :list="['Normal','Inverted']"></CVselect>
</div>
</template>
<script>
import CVslider from '../../components/cv-slider'
import rangeSlider from '../../components/cv-range-slider'
import CVselect from '../../components/cv-select'
import CVswitch from '../../components/cv-switch'
export default {
name: 'Input',
props:['value'],
components:{
CVslider,
rangeSlider,
CVselect,
CVswitch
},
data() {
return {
t:0,
a:1
}
},
methods:{
},
computed:{}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,37 @@
<template>
<div>
<CVselect name="SortMode" v-model="value.SortMode" :list="['Largest','Smallest','Highest','Lowest','Rightmost','Leftmost','Closest']"></CVselect>
<span>Calibrate:</span><v-divider dark color="white"></v-divider>
<v-row align="center" justify="start">
<v-col style="padding-right:0px" :cols="3">
<v-btn small color="#4baf62">Take Point A</v-btn>
</v-col>
<v-col style="margin-left:0px" :cols="3">
<v-btn small color="#4baf62">Take Point B</v-btn>
</v-col>
<v-col>
<v-btn small color="yellow darken-3">Clear All Points</v-btn>
</v-col>
</v-row>
</div>
</template>
<script>
import CVselect from '../../components/cv-select'
export default {
name: 'Output',
props:['value'],
components:{
CVselect
},
data() {
return {
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,32 @@
<template>
<div>
<CVrangeSlider v-model="value.Hue" name="Hue" :min="0" :max="180"></CVrangeSlider>
<CVrangeSlider v-model="value.Saturation" name="Saturation" :min="0" :max="255"></CVrangeSlider>
<CVrangeSlider v-model="value.Value" name="Value" :min="0" :max="255"></CVrangeSlider>
<CVswitch v-model="value.Erode" name="Erode"></CVswitch>
<CVswitch v-model="value.Dilate" name="Dilate"></CVswitch>
</div>
</template>
<script>
import CVrangeSlider from '../../components/cv-range-slider'
import CVswitch from '../../components/cv-switch'
export default {
name: 'Threshold',
props:['value'],
components:{
CVrangeSlider,
CVswitch
},
data() {
return {
}
},
computed:{
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,67 @@
<template>
<div>
<v-row align="center">
<v-col cols="6" class="colsClass">
<v-tabs fixed-tabs background-color="#212121" dark height="50" slider-color="#4baf62" v-model="selectedTab">
<v-tab to="">General</v-tab>
<v-tab to="">Cameras</v-tab>
</v-tabs>
<div style="padding-left:30px">
<component :is="selectedComponent"></component>
</div>
</v-col>
<v-col v-show="selectedTab === 1" class="colsClass">
<div class="videoClass">
<img :src="steamAdress">
</div>
</v-col>
</v-row>
</div>
</template>
<script>
import General from './SettingsViewes/General'
import Cameras from './SettingsViewes/Cameras'
export default {
name: 'SettingsTab',
components:{
General,
Cameras,
},
data() {
return {
selectedTab:0,
}
},
computed:{
selectedComponent(){
switch(this.selectedTab){
case 0:
return "General";
case 1:
return "Cameras";
}
},
steamAdress: {
get: function(){
return "http://"+location.hostname + ":"+ this.$store.state.port +"/stream.mjpg";
}
},
}
}
</script>
<style scoped>
.videoClass{
text-align: center;
}
.videoClass img{
height: auto !important;
width: 75%;
vertical-align: middle;
}
.colsClass{
padding: 0 !important;
}
</style>

View File

@@ -0,0 +1,62 @@
<template>
<div>
<CVselect name="Camera" :list="cameraList"></CVselect>
<CVselect name="Resulotion" v-model="cameraSettings.resolution" :list="resolutionList"></CVselect>
<CVselect name="Stream Resulotion" v-model="cameraSettings.streamResolution" :list="['1:1','1:2','1:4','1:6']"></CVselect>
<CVnumberinput name="Diagonal FOV" v-model="cameraSettings.fov" ></CVnumberinput>
<v-btn style="margin-top:10px" small color="#4baf62">Save Camera Settings</v-btn>
</div>
</template>
<script>
import CVselect from '../../components/cv-select'
import CVnumberinput from '../../components/cv-number-input'
export default {
name: 'CameraSettings',
components:{
CVselect,
CVnumberinput
},
data() {
return {
}
},
computed:{
currentCameraIndex:{
get(){
return this.$store.state.currentCameraIndex;
},
set(value){
this.$store.commit('currentCameraIndex',value);
}
},
cameraList:{
get(){
return this.$store.state.cameraList;
},
set(value){
this.$store.commit('cameraList',value);
}
},
resolutionList:{
get(){
return this.$store.state.resolutionList;
}
},
cameraSettings:{
get(){
return this.$store.state.cameraSettings;
},
set(value){
this.$store.commit('cameraSettings',value);
}
},
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -0,0 +1,52 @@
<template>
<div>
<CVnumberinput name="Team Number"></CVnumberinput>
<CVradio v-model="settings.connectionType" :list="['DHCP','Static']"></CVradio>
<v-divider color="white"></v-divider>
<CVinput name="IP" v-model="settings.ip" :disabled="isDisabled"></CVinput>
<CVinput name="NetMask" v-model="settings.netmask" :disabled="isDisabled"></CVinput>
<CVinput name="Gateway" v-model="settings.gateway" :disabled="isDisabled"></CVinput>
<v-divider color="white"></v-divider>
<CVinput name="Hostname" v-model="settings.hostname"></CVinput>
<v-btn style="margin-top:10px" small color="#4baf62">Save General Settings</v-btn>
</div>
</template>
<script>
import CVnumberinput from '../../components/cv-number-input'
import CVradio from '../../components/cv-radio'
import CVinput from '../../components/cv-input'
export default {
name: 'General',
components:{
CVnumberinput,
CVradio,
CVinput
},
data() {
return {
}
},
computed:{
isDisabled(){
if(this.settings.connectionType === 0){
return true;
}
return false;
},
settings:{
get(){
return this.$store.state.settings;
},
set(value){
this.$store.commit('settings',value);
}
}
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -985,7 +985,8 @@
"@types/q": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw=="
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
"@vue/babel-helper-vue-jsx-merge-props": {
"version": "1.0.0",
@@ -1887,6 +1888,7 @@
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
@@ -1931,6 +1933,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
@@ -2434,7 +2437,8 @@
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
@@ -2744,6 +2748,7 @@
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@@ -2939,6 +2944,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
"integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
"dev": true,
"requires": {
"@types/q": "^1.5.1",
"chalk": "^2.4.1",
@@ -2974,6 +2980,7 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -2981,7 +2988,8 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"color-string": {
"version": "1.5.3",
@@ -3458,6 +3466,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz",
"integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==",
"dev": true,
"requires": {
"boolbase": "^1.0.0",
"css-what": "^2.1.2",
@@ -3468,7 +3477,8 @@
"css-select-base-adapter": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==",
"dev": true
},
"css-selector-tokenizer": {
"version": "0.7.1",
@@ -3525,6 +3535,7 @@
"version": "1.0.0-alpha.33",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.33.tgz",
"integrity": "sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w==",
"dev": true,
"requires": {
"mdn-data": "2.0.4",
"source-map": "^0.5.3"
@@ -3539,7 +3550,8 @@
"css-what": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
"dev": true
},
"cssesc": {
"version": "2.0.0",
@@ -3628,6 +3640,7 @@
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz",
"integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==",
"dev": true,
"requires": {
"css-tree": "1.0.0-alpha.29"
},
@@ -3636,6 +3649,7 @@
"version": "1.0.0-alpha.29",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz",
"integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==",
"dev": true,
"requires": {
"mdn-data": "~1.1.0",
"source-map": "^0.5.3"
@@ -3644,7 +3658,8 @@
"mdn-data": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz",
"integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA=="
"integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==",
"dev": true
}
}
},
@@ -3740,6 +3755,7 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"dev": true,
"requires": {
"object-keys": "^1.0.12"
}
@@ -3925,6 +3941,7 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz",
"integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==",
"dev": true,
"requires": {
"domelementtype": "^2.0.1",
"entities": "^2.0.0"
@@ -3933,7 +3950,8 @@
"domelementtype": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==",
"dev": true
}
}
},
@@ -3945,7 +3963,8 @@
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"dev": true
},
"domhandler": {
"version": "2.4.2",
@@ -3960,6 +3979,7 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"dev": true,
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
@@ -4097,7 +4117,8 @@
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==",
"dev": true
},
"errno": {
"version": "0.1.7",
@@ -4129,6 +4150,7 @@
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
"integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.0",
"function-bind": "^1.1.1",
@@ -4142,6 +4164,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
"integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
@@ -4157,7 +4180,8 @@
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"eslint": {
"version": "5.16.0",
@@ -4634,7 +4658,8 @@
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esquery": {
"version": "1.0.1",
@@ -5590,10 +5615,10 @@
"bundled": true,
"optional": true,
"requires": {
"deep-extend": "0.6.0",
"ini": "1.3.5",
"minimist": "1.2.0",
"strip-json-comments": "2.0.1"
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"dependencies": {
"minimist": {
@@ -5728,7 +5753,8 @@
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"functional-red-black-tree": {
"version": "1.0.1",
@@ -5888,6 +5914,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
@@ -5912,12 +5939,14 @@
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"has-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
"dev": true
},
"has-value": {
"version": "1.0.0",
@@ -6528,7 +6557,8 @@
"is-callable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
"dev": true
},
"is-ci": {
"version": "1.2.1",
@@ -6574,7 +6604,8 @@
"is-date-object": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"dev": true
},
"is-descriptor": {
"version": "0.1.6",
@@ -6695,6 +6726,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
"dev": true,
"requires": {
"has": "^1.0.1"
}
@@ -6724,6 +6756,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
"integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
"dev": true,
"requires": {
"has-symbols": "^1.0.0"
}
@@ -6830,6 +6863,7 @@
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -7257,7 +7291,8 @@
"mdn-data": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA=="
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
"dev": true
},
"media-typer": {
"version": "0.3.0",
@@ -7708,6 +7743,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
"dev": true,
"requires": {
"boolbase": "~1.0.0"
}
@@ -7772,7 +7808,8 @@
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true
},
"object-visit": {
"version": "1.0.1",
@@ -7798,6 +7835,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
"integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.5.1"
@@ -7815,6 +7853,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz",
"integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
@@ -8941,7 +8980,8 @@
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
"dev": true
},
"qs": {
"version": "6.5.2",
@@ -9458,7 +9498,8 @@
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
"schema-utils": {
"version": "0.4.7",
@@ -10017,7 +10058,8 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"sshpk": {
"version": "1.16.1",
@@ -10047,7 +10089,8 @@
"stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
"dev": true
},
"stackframe": {
"version": "1.0.4",
@@ -10239,6 +10282,7 @@
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
@@ -10249,18 +10293,11 @@
"integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
"dev": true
},
"svg-to-vue": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/svg-to-vue/-/svg-to-vue-0.4.0.tgz",
"integrity": "sha512-g/ZHtEFf4QDsDtTk9tuYX/MJ2HESTUBMTkuLoffQGQ3xMtlmD9Ec4YyTgmMkP1P8QJtWWu2FiGdOnlKaXc/X/Q==",
"requires": {
"svgo": "^1.1.1"
}
},
"svgo": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz",
"integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==",
"dev": true,
"requires": {
"chalk": "^2.4.1",
"coa": "^2.0.2",
@@ -10736,7 +10773,8 @@
"unquote": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
"integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ="
"integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=",
"dev": true
},
"unset-value": {
"version": "1.0.0",
@@ -10877,6 +10915,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
"integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"object.getownpropertydescriptors": "^2.0.3"
@@ -13660,8 +13699,7 @@
},
"minimist": {
"version": "0.0.8",
"bundled": true,
"optional": true
"bundled": true
},
"minipass": {
"version": "2.2.4",
@@ -17840,15 +17878,6 @@
"loader-utils": "^1.0.2"
}
},
"vue-svg-loader": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/vue-svg-loader/-/vue-svg-loader-0.12.0.tgz",
"integrity": "sha512-pg8H6iKCj+DAC7FZuxdfGJMHiFpJPv/YyoN1M7Iqlf+Hu4eU6Q/W/sEFx978syQA+aOx0NXrp+uQUAajqQvXbQ==",
"requires": {
"loader-utils": "^1.2.3",
"svg-to-vue": "^0.4.0"
}
},
"vue-template-compiler": {
"version": "2.6.10",
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz",

0
chameleon-client/src/assets/logo.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -1,17 +1,17 @@
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import iView from 'iview';
import router from "./routes";
import '../theme/index.less';
import VueNativeSock from 'vue-native-websocket';
import locale from 'iview/dist/locale/en-US';
import {store} from './store'
import {store} from './store';
Vue.use(VueRouter);
Vue.use(iView , { locale });
Vue.use(VueNativeSock,'ws://'+location.hostname+':8888/websocket',{format:'JSON'});
Vue.config.productionTip = false
Vue.config.productionTip = false;
new Vue({
router,