diff --git a/.idea/misc.xml b/.idea/misc.xml index e122dea..cbec6ae 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index ee1f9a5..08c91db 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,11 +4,14 @@ - - + + + + + + - @@ -33,53 +36,47 @@ "associatedIndex": 8 } - - - + - { + "keyToString": { + "Application.GraphicsProgram.executor": "Run", + "Application.Main.executor": "Run", + "Application.Tracker.executor": "Run", + "Downloaded.Files.Path.Enabled": "false", + "Repository.Attach.Annotations": "false", + "Repository.Attach.JavaDocs": "false", + "Repository.Attach.Sources": "false", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "com.codeium.enabled": "true", + "git-widget-placeholder": "master", + "kotlin-language-version-configured": "true", + "last_opened_file_path": "C:/Users/paul3/OneDrive/Dokumente/Studium BME/Semester 3/Interaktion/opencv/build/java/opencv-4100.jar", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "project.structure.last.edited": "Libraries", + "project.structure.proportion": "0.15", + "project.structure.side.proportion": "0.24022989", + "vue.rearranger.settings.migration": "true" } -}]]> +} + + + + + - - - - + + + + + + @@ -113,9 +117,9 @@ - - - - - - - - - @@ -183,13 +155,8 @@ - \ No newline at end of file diff --git a/Welcome0.png b/Welcome0.png new file mode 100644 index 0000000..ffdca99 Binary files /dev/null and b/Welcome0.png differ diff --git a/Welcome1.png b/Welcome1.png new file mode 100644 index 0000000..b5aeebc Binary files /dev/null and b/Welcome1.png differ diff --git a/Welcome2.png b/Welcome2.png new file mode 100644 index 0000000..bff852f Binary files /dev/null and b/Welcome2.png differ diff --git a/Welcome3.png b/Welcome3.png new file mode 100644 index 0000000..3063a5a Binary files /dev/null and b/Welcome3.png differ diff --git a/src/main/java/CamPuffer.java b/src/main/java/CamPuffer.java index 8f7fc49..889d683 100644 --- a/src/main/java/CamPuffer.java +++ b/src/main/java/CamPuffer.java @@ -11,7 +11,7 @@ public class CamPuffer implements Runnable { static { try { - System.load("C:\\Users\\david\\Documents\\Uni\\GTCar\\opencv\\build\\java\\x64\\opencv_java4100.dll"); + System.load("C:\\Users\\paul3\\OneDrive\\Dokumente\\Studium BME\\Semester 3\\Interaktion\\GTCar V3\\opencv\\build\\java\\x64\\opencv_java4100.dll"); System.out.println("OpenCV manuell geladen!"); } catch (UnsatisfiedLinkError e) { System.err.println("Fehler beim Laden der OpenCV-Bibliothek: " + e.getMessage()); @@ -74,7 +74,7 @@ public class CamPuffer implements Runnable { if (System.currentTimeMillis() - lastGcTime > 1000) { System.gc(); // Triggern des Garbage Collectors lastGcTime = System.currentTimeMillis(); - System.out.println("Garbage Collection durchgeführt."); + //System.out.println("Garbage Collection durchgeführt."); } } } finally { @@ -98,9 +98,7 @@ public class CamPuffer implements Runnable { public Mat getCurrentMat() { synchronized (frameBuffer) { if (!frameBuffer.isEmpty()) { - Mat resizedFrame = new Mat(); - Imgproc.resize(frameBuffer.pollLast().clone(), resizedFrame, new Size(1792, 1024)); - return resizedFrame; // Rückgabe des neuesten Frames + return frameBuffer.pollLast().clone(); // Rückgabe des neuesten Frames } } return new Mat(); // Rückgabe eines leeren Frames, falls der Puffer leer ist diff --git a/src/main/java/GameLoop.java b/src/main/java/GameLoop.java index a3577f3..9addfb0 100644 --- a/src/main/java/GameLoop.java +++ b/src/main/java/GameLoop.java @@ -1,15 +1,21 @@ +import org.opencv.highgui.HighGui; import processing.core.PApplet; -import java.awt.Point; + +import java.awt.*; import java.util.ArrayList; import java.util.List; +import static java.lang.Thread.sleep; + public class GameLoop { int activePlayer = 0; - private final int CAM = 1; // Kamera-ID (0 für Webcam, 1 für andere Cams) - private final int EXP = -9; // Belichtungszeit (idealerweise: 0) + private final int CAM = 0; // Kamera-ID (0 für Webcam, 1 für andere Cams) + private final int EXP = -8; // Belichtungszeit (idealerweise: 0) private final int FPS = 20; // FPS - private final int THV = 245; // Threshold + private final int THV = 240; + + private final int TRAIL_LENGTH = 50; ImgAnalyzer tracker; CamPuffer camPuffer; @@ -22,22 +28,23 @@ public class GameLoop { Player player2; public GameLoop(){ - player1 = new Player(0, "192.168.1.1", 9000); - player2 = new Player(1, "192.168.1.2", 9000); + player1 = new Player(0, TRAIL_LENGTH); + player2 = new Player(1, TRAIL_LENGTH); camPuffer = new CamPuffer(CAM, EXP, FPS, THV); Thread pufferThread = new Thread(camPuffer); pufferThread.start(); - tracker = new ImgAnalyzer(camPuffer, THV); - Thread trackerThread = new Thread(tracker::run); - trackerThread.start(); - - /*graphics = new GraphicsProgram(player1, player2); + graphics = new GraphicsProgram(); String[] args = {"GraphicsProgram"}; PApplet.runSketch(args, graphics); + tracker = new ImgAnalyzer(camPuffer, THV, graphics); + Thread trackerThread = new Thread(tracker::run); + trackerThread.start(); + + /* gl = new GameLogic(); String[] args_ = {"GameLogic"}; PApplet.runSketch(args_, gl); */ @@ -46,55 +53,23 @@ public class GameLoop { } private void run(){ + while(camPuffer.getCurrentMat().elemSize() == 0){ + System.out.println("Camera booting up"); + try { + sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + graphics.nextGameState(); + //Hier kommt Morphing rein + graphics.nextGameState(); while(true){ - //communicate(); - Point p1 = tracker.getP1(); - //System.out.println("Player 1 is at " + p1.x + " and " + p1.y); - Point p2 = tracker.getP2(); - //System.out.println("Player 2 is at " + p2.x + " and " + p2.y); - - /*player1.setKoords(p1.x, p1.y); - player2.setKoords(p2.x, p2.y); - - if(gl.doCheckExtern(player2.getTrail(), p1)){ //Check Position von P1 mit Spur von P2 - System.out.println("Spieler 1 hat verloren"); - break; - } - - if(gl.doCheckExtern(player1.getTrail(), p2)){ //Check Position von P2 mit Spur von P1 - System.out.println("Spieler 2 hat verloren"); - break; - } */ - - //draw(); - - try{ - wait(50); - } - catch (Exception e){ - } } } private void communicate() { //offen für Auto Kommunikation } - - /*private List track(){ - Point p1 = tracker.getP1(); - Point p2 = tracker.getP2(); - System.out.println(p1.x); - - player1.setKoords(p1.x, p1.y); - player2.setKoords(p2.x, p2.y); - - List output = new ArrayList<>(); - output.add(0, p1); - output.add(1, p2); - return output; - }*/ - - private void draw(){ - } } \ No newline at end of file diff --git a/src/main/java/GraphicsProgram.java b/src/main/java/GraphicsProgram.java index 6aca883..d1bb1c1 100644 --- a/src/main/java/GraphicsProgram.java +++ b/src/main/java/GraphicsProgram.java @@ -2,16 +2,28 @@ import processing.core.PApplet; import processing.core.PImage; import java.util.LinkedList; -import java.util.Queue; +import java.util.List; public class GraphicsProgram extends PApplet { - private Queue playerTrails = new LinkedList<>(); + private LinkedList player1Trail = new LinkedList<>(); // Liste für Spieler 1 + private LinkedList player2Trail = new LinkedList<>(); // Liste für Spieler 2 + + private final int TRAIL_LENGTH = 150; + private int trailCounter = 17; + + private int distanceTh = 100; + + private int gameState = 0; //0 für Welcome, 1 für Morphing, 2 für Game, 3 für Gameover + + private float startingTime = System.currentTimeMillis(); PImage img1; PImage img2; PImage backgroundImage; + LinkedList cameraLoadingImages = new LinkedList<>(); + public static void main(String[] args) { PApplet.main("GraphicsProgram"); } @@ -26,38 +38,124 @@ public class GraphicsProgram extends PApplet { img1 = loadImage("TrailBlue.png"); img2 = loadImage("TrailRed.png"); + + cameraLoadingImages.add(loadImage("Welcome0.png")); + cameraLoadingImages.add(loadImage("Welcome1.png")); + cameraLoadingImages.add(loadImage("Welcome2.png")); + cameraLoadingImages.add(loadImage("Welcome3.png")); } public void draw() { - image(backgroundImage, 0, 0); // Hintergrund zeichnen - - - int particleSizeP1 = 30; - int particleSizeP2 = 30; - - - - // Kopie von trailPlayer1 erstellen und durch die Kopie iterieren - for (int[] koordinates : new LinkedList<>(playerTrails)) { - int x1 = koordinates[0]; - int y1 = koordinates[1]; - int x2 = koordinates[2]; - int y2 = koordinates[3]; - - fill(0, 0, 255); - rect(x1, y1, particleSizeP1, particleSizeP1); - //image(img1, x1, y1, particleSizeP1, particleSizeP1); - - fill(255, 0, 0); - rect(x2, y2, particleSizeP2, particleSizeP2); - //image(img2, x2, y2, particleSizeP2, particleSizeP2); - - + if (gameState == 0) { + drawWelcome(); + } + if (gameState == 1) { + setUpMorphing(); + } + if (gameState == 2) { + gameScreen(); + } + if (gameState == 3) { + gameOverScreen(); } - } - public void updateTrail(Queue trails){ - this.playerTrails = trails; + public void drawWelcome() { + int waitingTime = (int) (System.currentTimeMillis() / 1000); + switch (waitingTime % 4) { + case 0: + image(cameraLoadingImages.get(0), 0, 0); + break; + case 1: + image(cameraLoadingImages.get(1), 0, 0); + break; + case 2: + image(cameraLoadingImages.get(2), 0, 0); + break; + case 3: + image(cameraLoadingImages.get(3), 0, 0); + } } -} + + private void setUpMorphing() { + } + + private void gameScreen() { + image(backgroundImage, 0, 0); // Hintergrund zeichnen + strokeWeight(20); // Linienstärke festlegen + // Linien für Spieler 1 zeichnen + stroke(0, 0, 255); // Blau + drawTrail(player1Trail, 1); + // Linien für Spieler 2 zeichnen + stroke(255, 0, 0); // Rot + drawTrail(player2Trail, 2); + } + + private void gameOverScreen() { + } + + public void nextGameState() { + gameState++; + } + + // Methode, um Linien für eine gegebene Trail-Liste zu zeichnen + private void drawTrail(LinkedList trail, int player) { + if (trail.size() < 4) return; // Mindestens 2 Punkte nötig, um Linien zu zeichnen + + for (int i = 0; i < trail.size() - 1; i++) { + if (player == 1){ + stroke(170-(255/trail.size() * i),0,255/2 + (255/trail.size() * i)/2); + } else if (player == 2){ + stroke(255, 170-(255/trail.size() * i), 0); + } + int[] current = new int[2]; + try { + current = trail.get(i); + } catch (NullPointerException e) { + System.out.println("Index 1 out of bounds"); + continue; + } + + int[] next = new int[2]; + try { + next = trail.get(i + 1); + } catch (NullPointerException e) { + System.out.println("Index 2 out of bounds"); + continue; + } + + // Null-Check für die Punkte + if (current != null && next != null) { + if (current[0] - next[0] > -distanceTh && current[0] - next[0] < distanceTh && current[1] - next[1] > -distanceTh && current[1] - next[1] < distanceTh) { + line(current[0], current[1], next[0], next[1]); + } + } + } + } + + + // Methode zum Aktualisieren der Trails für beide Spieler + public void updateTrail(int x1, int y1, int x2, int y2) { + if (x1 >= 0 && y1 >= 0) { + addToTrail(player1Trail, x1, y1); + } + if (x2 >= 0 && y2 >= 0) { + addToTrail(player2Trail, x2, y2); + } + } + + // Methode zum Hinzufügen eines Punktes zur Trail-Liste und Begrenzung auf 20 Einträge + private void addToTrail(LinkedList trail, int x, int y) { + if (trailCounter % 7 == 0) { + if (x >= 0 && y >= 0) { + trail.add(new int[]{x, y}); + if (trail.size() > TRAIL_LENGTH) { + trail.removeFirst(); + } + } + } + trailCounter++; + } + + +} \ No newline at end of file diff --git a/src/main/java/ImgAnalyzer.java b/src/main/java/ImgAnalyzer.java index 7f84393..9223ed9 100644 --- a/src/main/java/ImgAnalyzer.java +++ b/src/main/java/ImgAnalyzer.java @@ -6,11 +6,8 @@ import org.opencv.imgproc.Moments; import org.opencv.videoio.Videoio; import processing.core.PApplet; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import java.awt.Point; -import java.util.Queue; public class ImgAnalyzer { @@ -19,19 +16,17 @@ public class ImgAnalyzer { private Point currentPositionP1 = new Point(0, 0); private Point currentPositionP2 = new Point(0, 0); Queue trails = new LinkedList<>(); - private final int TRAIL_LENGTH = 200; + private final int TRAIL_LENGTH = 90; private final CamPuffer camPuffer; private GraphicsProgram playerGraphics; - public ImgAnalyzer(CamPuffer cP, int threshold) { + public ImgAnalyzer(CamPuffer cP, int threshold, GraphicsProgram graphicsProgram) { THV = threshold; camPuffer = cP; System.loadLibrary(Core.NATIVE_LIBRARY_NAME); - playerGraphics = new GraphicsProgram(); - String[] args ={"GraphicsProgram"}; - PApplet.runSketch(args, playerGraphics); + playerGraphics = graphicsProgram; } public static void main(String[] args) { @@ -39,6 +34,7 @@ public class ImgAnalyzer { } public void run() { + /* while (camPuffer.getCurrentMat().elemSize() == 0) { System.out.println("Warten auf das erste Bild..."); try { @@ -48,6 +44,7 @@ public class ImgAnalyzer { return; } } + */ Mat currentImg = new Mat(); Mat grayFrame = new Mat(); @@ -88,11 +85,21 @@ public class ImgAnalyzer { if(trails.size() > TRAIL_LENGTH){ trails.poll(); } - System.out.println(trails.size()); - playerGraphics.updateTrail(trails); - playerGraphics.draw(); - + playerGraphics.updateTrail(currentPositionP1.x, currentPositionP1.y, currentPositionP2.x, currentPositionP2.y); + //playerGraphics.draw(); } + + /*org.opencv.core.Point pp1 = new org.opencv.core.Point(currentPositionP1.x, currentPositionP1.y); + Imgproc.circle(currentImg, pp1, 10, new Scalar(255,0,0), -1); + + org.opencv.core.Point pp2 = new org.opencv.core.Point(currentPositionP2.x, currentPositionP2.y); + Imgproc.circle(currentImg, pp2, 10, new Scalar(0,0,255), -1); + + if(currentImg.elemSize() != 0) { + + HighGui.imshow("el thunfisch", currentImg); + + } */ } } @@ -103,24 +110,42 @@ public class ImgAnalyzer { // Finde Konturen Imgproc.findContours(thresholdFrame, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); - // Sortiere Konturen nach Fläche (absteigend) - contours.sort((c1, c2) -> Double.compare(Imgproc.contourArea(c2), Imgproc.contourArea(c1))); - - // Speichere die Positionen der zwei größten Konturen + // Liste für die Positionen und zugehörige Pixelanzahl List positions = new ArrayList<>(); + List whitePixelCounts = new ArrayList<>(); - for (int i = 0; i < Math.min(contours.size(), 2); i++) { - Moments moments = Imgproc.moments(contours.get(i)); + for (MatOfPoint contour : contours) { + Moments moments = Imgproc.moments(contour); if (moments.get_m00() != 0) { + // Berechne den Mittelpunkt der Kontur int cx = (int) (moments.get_m10() / moments.get_m00()); int cy = (int) (moments.get_m01() / moments.get_m00()); + + // Berechne die Anzahl der weißen Pixel in der Kontur + Mat mask = Mat.zeros(thresholdFrame.size(), CvType.CV_8UC1); + Imgproc.drawContours(mask, List.of(contour), 0, new Scalar(255), -1); // Fülle die Kontur mit Weiß + double whitePixels = Core.sumElems(mask).val[0] / 255.0; // Summe der Pixelwerte durch 255 (1 Pixel = 255) + + // Speichere Position und Pixelanzahl positions.add(new Point(cx, cy)); + whitePixelCounts.add(whitePixels); } } - //Check - return positions; + + // Sortiere die Positionen basierend auf der Anzahl weißer Pixel (absteigend) + List sortedPositions = new ArrayList<>(); + while (!whitePixelCounts.isEmpty()) { + int maxIndex = whitePixelCounts.indexOf(Collections.max(whitePixelCounts)); + sortedPositions.add(positions.get(maxIndex)); + positions.remove(maxIndex); + whitePixelCounts.remove(maxIndex); + } + + // Gib die Positionen der zwei größten Konturen zurück + return sortedPositions.subList(0, Math.min(sortedPositions.size(), 2)); } + public synchronized Point getP1() { return currentPositionP1; } diff --git a/src/main/java/Player.java b/src/main/java/Player.java index f74f8b1..95dab42 100644 --- a/src/main/java/Player.java +++ b/src/main/java/Player.java @@ -7,20 +7,13 @@ public class Player { private final int ID; private int x; private int y; - - private String name = "Thunfisch"; + private final int TRAIL_LENGTH; Queue trail = new LinkedList<>(); - ArduinoCommunication arduinoCommunicator; - - - - private final int TRAIL_LENGTH = 30; - // Konstruktor - public Player(int id, String finalIpAddress, int finalPortNr) { + public Player(int id, int trailLength) { this.ID = id; - arduinoCommunicator = new ArduinoCommunication(finalIpAddress, finalPortNr); + this.TRAIL_LENGTH = trailLength; trail.add(new int[]{0,0}); } @@ -32,8 +25,7 @@ public class Player { return y; } - - //fügt 2 Koordinaten zum Trail hinzu nd verhindert, dass dieser zulang wird + //fügt 2 Koordinaten zum Trail hinzu und verhindert, dass dieser zu lang wird public void setKoords(int x, int y){ addToTrail(x,y); this.x = x; @@ -47,20 +39,9 @@ public class Player { } } - public Queue getTrail(){ return trail; } - - public void sendToCar(int light, double steer, double speed){ - arduinoCommunicator.sendMessage(light, steer, speed); - } - - - //gibt aktuelle Position aus - public void printPosition() { - System.out.println(trail); - } }