Initial commit

This commit is contained in:
Henri Gros 2024-06-28 14:08:49 +02:00
commit 9f12627649
17 changed files with 4047 additions and 0 deletions

View file

@ -0,0 +1,164 @@
#include "esp_camera.h"
#include <WiFi.h>
//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
// Partial images will be transmitted if image exceeds buffer size
//
// You must select partition scheme from the board menu that has at least 3MB APP space.
// Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
// seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well
// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM
//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM
#include "camera_pins.h"
// ===========================
// Enter your WiFi credentials
// ===========================
const char* ssid = "RPI Henri";
IPAddress staticIP(192, 168, 0, 152);
IPAddress gateway(192, 168, 0, 0);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 0, 0);
void startCameraServer();
void setupLedFlash(int pin);
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;how can i open multiple files at the same time in python
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // for streaming
//config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
// Best option for face detection/recognition
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
sensor_t * s = esp_camera_sensor_get();
// initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_vflip(s, 1); // flip it back
s->set_brightness(s, 1); // up the brightness just a bit
s->set_saturation(s, -2); // lower the saturation
}
// drop down frame size for higher initial frame rate
// if(config.pixel_format == PIXFORMAT_JPEG){
// s->set_framesize(s, FRAMESIZE_QVGA);
// }
#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
#endif
#if defined(CAMERA_MODEL_ESP32S3_EYE)
s->set_vflip(s, 1);
#endif
// Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM)
setupLedFlash(LED_GPIO_NUM);
#endif
if (WiFi.config(staticIP, gateway, subnet, dns, dns) == false) {
Serial.println("Configuration failed.");
}
// WiFi.begin(ssid, password);
WiFi.begin(ssid);
WiFi.setSleep(false);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
startCameraServer();
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}
void loop() {
// Do nothing. Everything is done in another task by the web server
delay(10000);
}

1394
ESP_sources/app_httpd.cpp Normal file

File diff suppressed because it is too large Load diff

1571
ESP_sources/camera_index.h Normal file

File diff suppressed because it is too large Load diff

317
ESP_sources/camera_pins.h Normal file
View file

@ -0,0 +1,317 @@
#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_ESP_EYE)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#define LED_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 22
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_M5STACK_WIDE)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 22
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#define LED_GPIO_NUM 2
#elif defined(CAMERA_MODEL_M5STACK_ESP32CAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_M5STACK_UNITCAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// 4 for flash led or 33 for normal led
#define LED_GPIO_NUM 4
#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL)
#define PWDN_GPIO_NUM 0
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_XIAO_ESP32S3)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 10
#define SIOD_GPIO_NUM 40
#define SIOC_GPIO_NUM 39
#define Y9_GPIO_NUM 48
#define Y8_GPIO_NUM 11
#define Y7_GPIO_NUM 12
#define Y6_GPIO_NUM 14
#define Y5_GPIO_NUM 16
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 17
#define Y2_GPIO_NUM 15
#define VSYNC_GPIO_NUM 38
#define HREF_GPIO_NUM 47
#define PCLK_GPIO_NUM 13
#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD)
// The 18 pin header on the board has Y5 and Y3 swapped
#define USE_BOARD_HEADER 0
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM 33
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 19
#define Y7_GPIO_NUM 21
#define Y6_GPIO_NUM 39
#if USE_BOARD_HEADER
#define Y5_GPIO_NUM 13
#else
#define Y5_GPIO_NUM 35
#endif
#define Y4_GPIO_NUM 14
#if USE_BOARD_HEADER
#define Y3_GPIO_NUM 35
#else
#define Y3_GPIO_NUM 13
#endif
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 40
#define SIOD_GPIO_NUM 17
#define SIOC_GPIO_NUM 18
#define Y9_GPIO_NUM 39
#define Y8_GPIO_NUM 41
#define Y7_GPIO_NUM 42
#define Y6_GPIO_NUM 12
#define Y5_GPIO_NUM 3
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 47
#define Y2_GPIO_NUM 13
#define VSYNC_GPIO_NUM 21
#define HREF_GPIO_NUM 38
#define PCLK_GPIO_NUM 11
#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD)
// The 18 pin header on the board has Y5 and Y3 swapped
#define USE_BOARD_HEADER 0
#define PWDN_GPIO_NUM 1
#define RESET_GPIO_NUM 2
#define XCLK_GPIO_NUM 42
#define SIOD_GPIO_NUM 41
#define SIOC_GPIO_NUM 18
#define Y9_GPIO_NUM 16
#define Y8_GPIO_NUM 39
#define Y7_GPIO_NUM 40
#define Y6_GPIO_NUM 15
#if USE_BOARD_HEADER
#define Y5_GPIO_NUM 12
#else
#define Y5_GPIO_NUM 13
#endif
#define Y4_GPIO_NUM 5
#if USE_BOARD_HEADER
#define Y3_GPIO_NUM 13
#else
#define Y3_GPIO_NUM 12
#endif
#define Y2_GPIO_NUM 14
#define VSYNC_GPIO_NUM 38
#define HREF_GPIO_NUM 4
#define PCLK_GPIO_NUM 3
#elif defined(CAMERA_MODEL_ESP32S3_EYE)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 15
#define SIOD_GPIO_NUM 4
#define SIOC_GPIO_NUM 5
#define Y2_GPIO_NUM 11
#define Y3_GPIO_NUM 9
#define Y4_GPIO_NUM 8
#define Y5_GPIO_NUM 10
#define Y6_GPIO_NUM 12
#define Y7_GPIO_NUM 18
#define Y8_GPIO_NUM 17
#define Y9_GPIO_NUM 16
#define VSYNC_GPIO_NUM 6
#define HREF_GPIO_NUM 7
#define PCLK_GPIO_NUM 13
#elif defined(CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3) || defined(CAMERA_MODEL_DFRobot_Romeo_ESP32S3)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 45
#define SIOD_GPIO_NUM 1
#define SIOC_GPIO_NUM 2
#define Y9_GPIO_NUM 48
#define Y8_GPIO_NUM 46
#define Y7_GPIO_NUM 8
#define Y6_GPIO_NUM 7
#define Y5_GPIO_NUM 4
#define Y4_GPIO_NUM 41
#define Y3_GPIO_NUM 40
#define Y2_GPIO_NUM 39
#define VSYNC_GPIO_NUM 6
#define HREF_GPIO_NUM 42
#define PCLK_GPIO_NUM 5
#else
#error "Camera model not selected"
#endif

View file

@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x3d0000,
fr, data, , 0x3e0000, 0x20000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x3d0000
5 fr data 0x3e0000 0x20000

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# Stage: Stéréovision sur ESP32
Ce dépot contient les sources python pour le tracking ainsi que celles pour les ESP32 et le modèle 3D de l'étui qui permet de les maintenir en place.

BIN
models/Holder V4.stl Normal file

Binary file not shown.

View file

@ -0,0 +1,42 @@
# Python sources for object tracking
## Installation
### With Nix
```bash
nix-shell
```
### Without Nix
requirements : Conda
```bash
conda create --yes -q -n stage python=3.10 -c conda-forge
conda activate stage
conda install --yes -f conda-requirements.txt -c conda-forge
```
## Usage
Tracking:
```bash
python tracking.py
```
verify on a benchmarck of pictures
```bash
python verify.py
```
Graph results:
```bash
python graphing.py results.csv
```
Graph frametime:
```bash
python frametime.py
```

View file

@ -0,0 +1,7 @@
opencv
ultralytics
numpy
pytorch
torchvision
ffmpeg
lap

View file

@ -0,0 +1,5 @@
import pandas as pd
def read_table(path):
df=pd.read_csv(path)
return df.shape[0], df["percent"], df["angle"]

View file

@ -0,0 +1,31 @@
import matplotlib.pyplot as plt
def plot_graph(file_path):
# Read the file and extract the floats
with open(file_path, 'r') as file:
values1 = []
values2 = []
values3 = []
for line in file:
float1, float2, float3 = map(float, line.strip().split())
values1.append(float1)
values2.append(float2)
values3.append(float3)
# Generate x-axis values (assuming each float pair is a data point)
x_values = list(range(1, len(values1) + 1))
# Plot the graph
plt.plot(x_values, values1, label='requete')
plt.plot(x_values, values2, label='traitement') # Plot the graph
plt.plot(x_values, values3, label='total')
plt.title('Temps pour traiter une image')
plt.xlabel("numero de l'image")
plt.ylabel('temps (s)')
plt.grid(True)
plt.legend()
plt.xlim(left=0)
plt.ylim(bottom=0)
plt.show()
plot_graph("frametime.txt")

View file

@ -0,0 +1,45 @@
# Graphing script
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import sys
# Read csv path
args = sys.argv
path = args[1]
# open csv
df = pd.read_csv(path)
print(df)
# compute the error
df["dr1m1"] = abs(df["r1m1"] - df["reel"])
df["dr2m1"] = abs(df["r2m1"] - df["reel"])
df["dr3m1"] = abs(df["r3m1"] - df["reel"])
df["dr4m1"] = abs(df["r4m1"] - df["reel"])
# Plotting the distance seen vs real
plt.plot(df["reel"], df["reel"], label="Real")
plt.plot(df["reel"], df["r1m1"], label="r1m1")
plt.plot(df["reel"], df["r2m1"], label="r2m1")
plt.plot(df["reel"], df["r3m1"], label="r3m1")
plt.plot(df["reel"], df["r4m1"], label="r4m1")
plt.xlabel("Distance (m)")
plt.ylabel("Distance (m)")
plt.title("Real vs Seen Distance")
plt.legend()
plt.show()
# Plotting the error over distance
# plt.plot(df["reel"], df["dr1m1"], label="r1m1")
# plt.plot(df["reel"], df["dr2m1"], label="r2m1")
# plt.plot(df["reel"], df["dr3m1"], label="r3m1")
plt.plot(df["reel"], df["dr4m1"], label="r4m1")
plt.xlabel("Distance (m)")
plt.ylabel("Error (m)")
plt.title("Tracking Error over Distance")
plt.legend()
plt.show()

View file

@ -0,0 +1,10 @@
reel,r1m1,r1m2,r2m1,r2m2,r3m1,r4m1
2,1.92,1.72,1.8,1.72,2.02,2.21
2.5,2.42,2.16,2.3,2.11,2.59,2.84
3,3,2.6,2.78,2.53,3.16,3.49
3.5,3.59,2.98,3.32,2.99,3.8,4.14
4,4.24,3.45,3.94,3.29,4.43,4.84
4.5,5.12,3.5,4.5,3.77,5.12,5.63
5,5.63,4.14,5.1,4.27,5.83,6.25
5.5,6.32,4.9,5.67,4.7,6.55,7.10
6,7,5.19,6.32,5.1,,7.93
1 reel r1m1 r1m2 r2m1 r2m2 r3m1 r4m1
2 2 1.92 1.72 1.8 1.72 2.02 2.21
3 2.5 2.42 2.16 2.3 2.11 2.59 2.84
4 3 3 2.6 2.78 2.53 3.16 3.49
5 3.5 3.59 2.98 3.32 2.99 3.8 4.14
6 4 4.24 3.45 3.94 3.29 4.43 4.84
7 4.5 5.12 3.5 4.5 3.77 5.12 5.63
8 5 5.63 4.14 5.1 4.27 5.83 6.25
9 5.5 6.32 4.9 5.67 4.7 6.55 7.10
10 6 7 5.19 6.32 5.1 7.93

View file

@ -0,0 +1,28 @@
{ pkgs ? import <nixpkgs> {}}:
let
fhs = pkgs.buildFHSUserEnv {
name = "my-fhs-environment";
targetPkgs = _: [
pkgs.micromamba
pkgs.zlib
pkgs.libGL
pkgs.glib
pkgs.python310
pkgs.pkg-config
];
profile = ''
set -e
eval "$(micromamba shell hook --shell=posix)"
export MAMBA_ROOT_PREFIX=${builtins.getEnv "PWD"}/.mamba
if ! test -d $MAMBA_ROOT_PREFIX/envs/m2; then
micromamba create --yes -q -n m2 python=3.10 -c conda-forge
fi
micromamba activate m2
micromamba install --yes -f conda-requirements.txt -c conda-forge
set +e
'';
};
in fhs.env

View file

@ -0,0 +1,257 @@
import cv2
import urllib.request
import requests
import numpy as np
import math
import pandas as pd
import asyncio
import time
import os
import glob
from core_functions import read_table
from ultralytics import YOLO
def read_image_from_url(url):
try:
req = urllib.request.urlopen(url)
img_arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
return cv2.imdecode(img_arr, -1)
except Exception as _:
print("URL Error")
exit(1)
def read_image_from_fs(path):
return cv2.imread(path)
async def analyze(model, img, name):
# Run YOLOv8 tracking on the frame, persisting tracks between frames
# results = model(img, conf=conf, classes=classes)
# results = model.track(img, conf=conf, classes=classes, persist=True)
results = model.track(img, conf=conf, classes=classes, persist=True, max_det=1, imgsz=1600)
if draw:
# Visualize the results on the frame
annotated_frame = results[0].plot()
# Display the annotated frame
cv2.imshow(name, annotated_frame)
# Gather the coordinates of the box
boxes = results[0].boxes
if len(boxes) == 0:
print("No objects detected in " + name)
return -1, -1
x1, _, x2, _ = boxes.xyxyn[0].numpy()
x = (x1 + x2) / 2
width = x2 - x1
return x, width
def interpolate(ratio):
# N = 9
# cal_ratio = [0.06, 0.18, 0.28, 0.39, 0.49, 0.60, 0.70, 0.82, 0.92]
# cal_angledeg = [-25.27, -19.20, -13.46, -6.68, -0.58, 6.40, 12.37, 18.86, 24.24]
N, cal_ratio, cal_angledeg = read_table("configs/config4.csv")
if trace:
print(f"Interpolate {ratio}")
for i in range(1, N):
ratiomin = cal_ratio[i - 1]
ratiomax = cal_ratio[i]
anglemin = cal_angledeg[i - 1]
anglemax = cal_angledeg[i]
if ratiomin <= ratio < ratiomax:
if trace:
print(f" i={i}, Ratio[{i - 1}]={ratiomin}, Ratio[{i}]={ratiomax}")
print(f" i={i}, Angledeg[{i - 1}]={anglemin}, Angledeg[{i}]={anglemax}")
deltay = anglemax - anglemin
deltax = ratiomax - ratiomin
slope = deltay / deltax
if trace:
print(f" deltax={deltax}, deltay={deltay}, slope={slope}°/m")
delta = ratio - ratiomin
angle = anglemin + slope * delta
if trace:
print(f" delta={delta}, angle={angle}°")
return angle
print(f"Error: unable to interpolate {ratio}")
exit(0)
def estimate(leftd, rightd, alphar, betar, widthr, width):
alphadeg, betadeg, thetadeg = 0.0, 0.0, 0.0
alpharad, betarad, thetarad = 0.0, 0.0, 0.0
alphatan, betatan, thetatan = 0.0, 0.0, 0.0
gammadeg, gammarad, gammatan = 0.0, 0.0, 0.0
distance = 0.0
if trace:
print("Estimation")
# interpolate to get angles
alphadeg = -interpolate(alphar)
if trace:
print(f" interpolate: alphar={alphar} (ratio) -> alphadeg={alphadeg}°")
betadeg = interpolate(betar)
if trace:
print(f"interpolate: betar={betar} (ratio) -> betadeg={betadeg}°")
gammadeg = interpolate(0.5 + widthr)
if trace:
print(f"interpolate: widthr={widthr} (ratio) -> gammadeg={gammadeg}°")
# convert to radians
alpharad = math.radians(alphadeg)
if trace:
print(f"to radians: alphadeg={alphadeg} -> alpharad={alpharad}")
betarad = math.radians(betadeg)
if trace:
print(f"to radians: betadeg={betadeg} -> betarad={betarad}")
# get tan
alphatan = math.tan(alpharad)
betatan = math.tan(betarad)
if trace:
print(f"tan(): alphatan={alphatan}, betatan={betatan}")
# (x, y)
y = (leftd + rightd) / (alphatan + betatan)
x = y * alphatan - leftd
if trace:
print(f"position: x={x}, y={y}")
# (distance, angle)
distance_1 = math.sqrt(x * x + y * y)
thetatan = x / y
thetarad = math.atan(thetatan)
thetadeg = math.degrees(thetarad)
print(f"distance={distance_1}, thetatan={thetatan}, theta={thetadeg}, thetarad={thetarad}")
# print(f"distance = {distance}")
gammarad = math.radians(gammadeg)
gammatan = math.tan(gammarad)
distance_2 = width / gammatan
print(f"distance={distance_2}, gammatan={gammatan}, gamma={gammadeg}, gammarad={gammarad}")
return distance_1, distance_2, thetadeg
async def get_image_stream(cap):
ret, img = cap.read()
if not ret:
print("Error: Unable to read frame.")
exit()
return img
async def get_images_stream(l_cap, r_cap, l_imgs_buffer, r_imgs_buffer, n_image):
current_img = n_image % 2
l_img = await l_imgs_buffer[current_img]
r_img = await r_imgs_buffer[current_img]
l_imgs_buffer[current_img] = asyncio.create_task(get_image_stream(l_cap))
r_imgs_buffer[current_img] = asyncio.create_task(get_image_stream(r_cap))
return l_img, r_img
def init_stream(url):
# Set quality
requests.get(url + "/control?var=framesize&val=13")
# requests.get(url + "/control?var=framesize&val=8")
# Open stream
stream_url = url + ":81/stream"
print(stream_url)
cap = cv2.VideoCapture(stream_url)
if not cap.isOpened():
print("Error: Unable to open the stream.")
exit()
return cap
async def main():
print("Loading models")
l_model = YOLO('yolov8n.pt')
r_model = YOLO('yolov8n.pt')
l_model()
r_model()
print("Init streams")
l_cap = init_stream(l_url)
r_cap = init_stream(r_url)
ti1 = asyncio.create_task(get_image_stream(l_cap))
ti2 = asyncio.create_task(get_image_stream(r_cap))
n_images = -1
results = (0, 0, 0)
l_img_save = None
r_img_save = None
print("Loop start")
init_time = time.time()
with open("frametime.txt", 'w') as file:
while True:
n_images += 1
st_request = time.time()
l_img = await ti1
r_img = await ti2
ti1 = asyncio.create_task(get_image_stream(l_cap))
ti2 = asyncio.create_task(get_image_stream(r_cap))
dt_request = time.time() - st_request
print(f"imgs read in {dt_request}")
st_analyze = time.time()
t1 = asyncio.create_task(analyze(l_model, l_img, "left"))
t2 = asyncio.create_task(analyze(r_model, r_img, "right"))
lx, l_width = await t1
rx, r_width = await t2
if cv2.waitKey(1) & 0xFF == ord("q"):
break
if n_images == 100:
break
width = (l_width + r_width) / 2
if lx != -1 and rx != -1:
results = estimate(0, 0.72, lx, rx, width, obj_size)
l_img_save = l_img
r_img_save = r_img
dt_analyze = time.time() - st_analyze
print(f"analyse done in {dt_analyze}")
dt_total = time.time() - st_request
print(f"total time {dt_total}")
file.write(f"{dt_request} {dt_analyze} {dt_total}\n")
print("\n\n\n")
l_cap.release()
r_cap.release()
cv2.destroyAllWindows()
print("\n\n\n")
total_time = time.time() - init_time
print(f"total time {total_time}")
print(f"avrg time {total_time / n_images}")
print(f"resutlts {results}")
folder_path = 'imgs/'
num_files = len(glob.glob(os.path.join(folder_path, '*'))) / 2
cv2.imwrite(folder_path + str(num_files) + "_left.png", l_img_save)
cv2.imwrite(folder_path + str(num_files) + "_right.png", r_img_save)
print("done saving")
draw = True;
trace = False;
# classes = None
# classes = [32] # Sport ball
classes = [39] # Sport ball
# classes = [64] # Mouse
conf = 0.05
obj_size = 0.08
l_url = "http://192.168.0.151"
r_url = "http://192.168.0.152"
asyncio.run(main())

168
tracking_sources/verif.py Normal file
View file

@ -0,0 +1,168 @@
import os
import cv2
import math
from core_functions import read_table
from ultralytics import YOLO
import matplotlib.pyplot as plt
def analyze(model, img, name):
# Run YOLOv8 tracking on the frame, persisting tracks between frames
# results = model(img, conf=conf, classes=classes)
# results = model.track(img, conf=conf, classes=classes, persist=True)
results = model.track(img, conf=0.05, classes=[39], persist=True, max_det=1, imgsz=1600)
# Gather the coordinates of the box
boxes = results[0].boxes
if len(boxes) == 0:
print("No objects detected in " + name)
return -1, -1
x1, _, x2, _ = boxes.xyxyn[0].numpy()
x = (x1 + x2) / 2
width = x2 - x1
return x, width
def interpolate(ratio):
# N = 9
# cal_ratio = [0.06, 0.18, 0.28, 0.39, 0.49, 0.60, 0.70, 0.82, 0.92]
# cal_angledeg = [-25.27, -19.20, -13.46, -6.68, -0.58, 6.40, 12.37, 18.86, 24.24]
N, cal_ratio, cal_angledeg = read_table("configs/config4.csv")
print(cal_angledeg)
if trace:
print(f"Interpolate {ratio}")
for i in range(1, N):
ratiomin = cal_ratio[i - 1]
ratiomax = cal_ratio[i]
anglemin = cal_angledeg[i - 1]
anglemax = cal_angledeg[i]
if ratiomin <= ratio < ratiomax:
if trace:
print(f" i={i}, Ratio[{i - 1}]={ratiomin}, Ratio[{i}]={ratiomax}")
print(f" i={i}, Angledeg[{i - 1}]={anglemin}, Angledeg[{i}]={anglemax}")
deltay = anglemax - anglemin
deltax = ratiomax - ratiomin
slope = deltay / deltax
if trace:
print(f" deltax={deltax}, deltay={deltay}, slope={slope}°/m")
delta = ratio - ratiomin
angle = anglemin + slope * delta
if trace:
print(f" delta={delta}, angle={angle}°")
return angle
print(f"Error: unable to interpolate {ratio}")
exit(0)
def estimate(leftd, rightd, alphar, betar, widthr, width):
alphadeg, betadeg, thetadeg = 0.0, 0.0, 0.0
alpharad, betarad, thetarad = 0.0, 0.0, 0.0
alphatan, betatan, thetatan = 0.0, 0.0, 0.0
gammadeg, gammarad, gammatan = 0.0, 0.0, 0.0
distance = 0.0
if trace:
print("Estimation")
# interpolate to get angles
alphadeg = -interpolate(alphar)
if trace:
print(f" interpolate: alphar={alphar} (ratio) -> alphadeg={alphadeg}°")
betadeg = interpolate(betar)
if trace:
print(f"interpolate: betar={betar} (ratio) -> betadeg={betadeg}°")
gammadeg = interpolate(0.5 + widthr)
if trace:
print(f"interpolate: widthr={widthr} (ratio) -> gammadeg={gammadeg}°")
# convert to radians
alpharad = math.radians(alphadeg)
if trace:
print(f"to radians: alphadeg={alphadeg} -> alpharad={alpharad}")
betarad = math.radians(betadeg)
if trace:
print(f"to radians: betadeg={betadeg} -> betarad={betarad}")
# get tan
alphatan = math.tan(alpharad)
betatan = math.tan(betarad)
if trace:
print(f"tan(): alphatan={alphatan}, betatan={betatan}")
# (x, y)
y = (leftd + rightd) / (alphatan + betatan)
x = y * alphatan - leftd
if trace:
print(f"position: x={x}, y={y}")
# (distance, angle)
distance_1 = math.sqrt(x * x + y * y)
thetatan = x / y
thetarad = math.atan(thetatan)
thetadeg = math.degrees(thetarad)
print(f"distance={distance_1}, thetatan={thetatan}, theta={thetadeg}, thetarad={thetarad}")
# print(f"distance = {distance}")
gammarad = math.radians(gammadeg)
gammatan = math.tan(gammarad)
distance_2 = width / gammatan
print(f"distance={distance_2}, gammatan={gammatan}, gamma={gammadeg}, gammarad={gammarad}")
return distance_1, distance_2, thetadeg
trace = False
folder_path = "imgs/"
model = YOLO('yolov8n.pt')
image_files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f)) and f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.tif'))]
# Sort the image files to maintain a consistent order
image_files.sort()
dist = [2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6]
t_results = []
# Iterate over the images in pairs
for i in range(0, len(image_files), 2):
# Check if there are at least two images remaining
if i + 1 < len(image_files):
img1_path = os.path.join(folder_path, image_files[i])
img2_path = os.path.join(folder_path, image_files[i + 1])
# Read the images
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# Process the images (example: print their names)
print(f'Processing images: {image_files[i]} and {image_files[i + 1]}')
lx, l_width = analyze(model, img1, "left")
rx, r_width = analyze(model, img2, "right")
width = (l_width + r_width) / 2
results = estimate(0, 0.72, lx, rx, width, 0.08)
print("\n\n\n")
t_results.append(results[0])
# (Optional) Display the images
cv2.imshow('Image 1', img1)
cv2.imshow('Image 2', img2)
else:
# If there's an odd number of images, the last one will be left without a pair
print(f'Single image left without a pair: {image_files[i]}')
print("results")
print(t_results)
errors = [abs(dist[i]-t_results[i]) for i in range(len(dist))]
print("errors")
print(errors)
cv2.waitKey(0) # Wait for a key press to close the images
cv2.destroyAllWindows()
# Plotting the error over distance
# plt.plot(df["reel"], df["dr1m1"], label="r1m1")
# plt.plot(df["reel"], df["dr2m1"], label="r2m1")
# plt.plot(df["reel"], df["dr3m1"], label="r3m1")
plt.plot(dist, errors)
plt.xlabel("Distance (m)")
plt.ylabel("Error (m)")
plt.title("Tracking Error over Distance")
plt.legend()
plt.show()

BIN
tracking_sources/yolov8n.pt Normal file

Binary file not shown.