Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
595 changes: 404 additions & 191 deletions adapters.py

Large diffs are not rendered by default.

29 changes: 18 additions & 11 deletions config/config_v20_defaults.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Configuration file."""


CONFIG_VERSION = "2.2.1"
CONFIG_VERSION = "2.2.2"


# ======================================================================================================================
Expand Down Expand Up @@ -91,6 +91,7 @@
CONTINUE_PREVIOUS_PATH = False
PREVIOUS_PATH_POINTS_FILE = "path_points.dat"
PREVIOUS_PATH_INDEX_FILE = "path_index.txt"
PREVIOUS_GNSS_INDEX_FILE = "path_gnss_index.txt"

#Cyril covid
ORIGIN_AVERAGE_SAMPLES = 8
Expand Down Expand Up @@ -623,22 +624,28 @@
# ======================================================================================================================
# CAMERA SETTINGS
# ======================================================================================================================
CAMERA_W = 1920
CAMERA_H = 1080
APPLY_IMAGE_CROPPING = False
CAMERA_BACKEND = "auto" # "auto" | "aravis" | "imx219"
#- "auto": try Aravis first, fallback to IMX219 if no camera found
#- "aravis": force Aravis backend
#- "imx219": force Jetson IMX219 backend "gstreamer", "v4l2", "auto"
CAMERA_BINNING_H = 2
CAMERA_BINNING_V = 2
CAMERA_W = 2160//CAMERA_BINNING_H#2592//CAMERA_BINNING_H
CAMERA_H = 1216//CAMERA_BINNING_V#1944//CAMERA_BINNING_V
APPLY_IMAGE_CROPPING = True
CROP_W_FROM = 0
CROP_W_TO = 1920
CROP_H_FROM = 0
CROP_H_TO = 1080
CAMERA_FRAMERATE = 16
CAMERA_FLIP_METHOD = 0
SCENE_CENTER_X = 1000
SCENE_CENTER_Y = 980
ONE_MM_IN_PX = 3.2
CAMERA_FRAMERATE = 30
CAMERA_FLIP_METHOD = 2 # 0=none, 1=counterclockwise, 2=rotate 180, 3=clockwise, 4=horizontal flip, 5=upside down flip, 6=transpose, 7=transverse
SCENE_CENTER_X = CAMERA_W//2
SCENE_CENTER_Y = 1944//2//2
ONE_MM_IN_PX = 2.9
ISP_DIGITAL_GAIN_RANGE_FROM = 4
ISP_DIGITAL_GAIN_RANGE_TO = 4
GAIN_RANGE_FROM = 4
GAIN_RANGE_TO = 4
GAIN_RANGE_FROM = 12
GAIN_RANGE_TO = 12
EXPOSURE_TIME_RANGE_FROM = 660000
EXPOSURE_TIME_RANGE_TO = 660000
AE_LOCK = True
Expand Down
74 changes: 50 additions & 24 deletions detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def detect(self, image, disable_frame_show=False):

if config.FRAME_SHOW and not disable_frame_show:

t1 = time.time()
#t1 = time.time()

#img = draw_boxes(image, plant_boxes)
img = image
Expand All @@ -184,19 +184,19 @@ def detect(self, image, disable_frame_show=False):

#print(time.time() - t1)

if not YoloDarknetDetector.WEBSTREAM:
template_dir = os.path.abspath('./liveMain')
app = Flask("webstreaming", template_folder=template_dir)
CORS(app)
app.add_url_rule('/', view_func=webstreaming.index)
app.add_url_rule('/video_feed', view_func=webstreaming.video_feed)
# if not YoloDarknetDetector.WEBSTREAM:
# template_dir = os.path.abspath('./liveMain')
# app = Flask("webstreaming", template_folder=template_dir)
# CORS(app)
# app.add_url_rule('/', view_func=webstreaming.index)
# app.add_url_rule('/video_feed', view_func=webstreaming.video_feed)

logging.getLogger('werkzeug').disabled = True
os.environ['WERKZEUG_RUN_MAIN'] = 'true'
# logging.getLogger('werkzeug').disabled = True
# os.environ['WERKZEUG_RUN_MAIN'] = 'true'

YoloDarknetDetector.webStream = Process(target=app.run, args=("0.0.0.0",8888,False))
YoloDarknetDetector.webStream.start()
YoloDarknetDetector.WEBSTREAM = True
# YoloDarknetDetector.webStream = Process(target=app.run, args=("0.0.0.0",8888,False))
# YoloDarknetDetector.webStream.start()
# YoloDarknetDetector.WEBSTREAM = True

return plant_boxes

Expand Down Expand Up @@ -286,7 +286,7 @@ def detect(self, image, disable_frame_show=False):

if config.FRAME_SHOW and not disable_frame_show:

t1 = time.time()
#t1 = time.time()

#img = draw_boxes(image, plant_boxes)
img = image
Expand All @@ -306,19 +306,19 @@ def detect(self, image, disable_frame_show=False):

#print(time.time() - t1)

if not YoloTRTDetector.WEBSTREAM:
template_dir = os.path.abspath('./liveMain')
app = Flask("webstreaming", template_folder=template_dir)
CORS(app)
app.add_url_rule('/', view_func=webstreaming.index)
app.add_url_rule('/video_feed', view_func=webstreaming.video_feed)
# if not YoloTRTDetector.WEBSTREAM:
# template_dir = os.path.abspath('./liveMain')
# app = Flask("webstreaming", template_folder=template_dir)
# CORS(app)
# app.add_url_rule('/', view_func=webstreaming.index)
# app.add_url_rule('/video_feed', view_func=webstreaming.video_feed)

logging.getLogger('werkzeug').disabled = True
os.environ['WERKZEUG_RUN_MAIN'] = 'true'
# logging.getLogger('werkzeug').disabled = True
# os.environ['WERKZEUG_RUN_MAIN'] = 'true'

YoloTRTDetector.webStream = Process(target=app.run, args=("0.0.0.0",8888,False))
YoloTRTDetector.webStream.start()
YoloTRTDetector.WEBSTREAM = True
# YoloTRTDetector.webStream = Process(target=app.run, args=("0.0.0.0",8888,False))
# YoloTRTDetector.webStream.start()
# YoloTRTDetector.WEBSTREAM = True

return plant_boxes

Expand Down Expand Up @@ -353,8 +353,34 @@ def _allocate_buffers(self, engine):
outputs.append(HostDeviceMem(host_mem, device_mem))

return inputs, outputs, bindings, stream

def letterbox_fast(self, img, target_size=(416, 416)):
ih, iw = img.shape[:2]
h, w = target_size

scale = min(w / iw, h / ih)
nw, nh = int(iw * scale), int(ih * scale)

# Resize
img_resized = cv.resize(img, (nw, nh), interpolation=cv.INTER_LINEAR)

# Padding avec copyMakeBorder (plus rapide)
top = (h - nh) // 2
bottom = h - nh - top
left = (w - nw) // 2
right = w - nw - left

img_padded = cv.copyMakeBorder(
img_resized,
top, bottom, left, right,
cv.BORDER_CONSTANT,
value=[114, 114, 114]
)

return img_padded, scale, (left, top)

def _preprocess(self, image):
#processed_image = self.letterbox_fast(image, (self.__width, self.__height))[0]
processed_image = cv.resize(image, (self.__width, self.__height))
processed_image = cv.cvtColor(processed_image, cv.COLOR_BGR2RGB)
processed_image = processed_image.transpose((2, 0, 1)).astype(np.float32)
Expand Down
2 changes: 1 addition & 1 deletion extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ExtractionManagerV3:

def __init__(self,
smoothie: adapters.SmoothieAdapter,
camera: adapters.CameraAdapterIMX219_170,
camera: adapters.CameraAdapterInterface,
logger_full: utility.Logger,
data_collector: datacollection.DataCollector,
image_saver: utility.ImageSaver,
Expand Down
67 changes: 67 additions & 0 deletions index_webrtc.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>Aravis WebRTC Stream</title>
<style>
body {
background: #111;
color: #eee;
font-family: sans-serif;
text-align: center;
}

video {
width: 90vw;
height: auto;
margin-top: 2vh;
border-radius: 10px;
background: #000;
}
</style>
</head>

<body>
<h2>📡 Live Stream from Jetson / Aravis</h2>
<video id="video" autoplay playsinline></video>
<p id="status">Connecting...</p>

<script>
const pc = new RTCPeerConnection();
const video = document.getElementById("video");
const status = document.getElementById("status");

pc.ontrack = e => {
video.srcObject = e.streams[0];
status.textContent = "✅ Connected – live stream active";
};

async function start() {
try {
// create offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);

// send offer to Jetson server
const jetsonHost = window.location.hostname;
const response = await fetch(`http://${jetsonHost}:8080/offer`, {
method: "POST",
body: JSON.stringify(pc.localDescription),
headers: { "Content-Type": "application/json" }
});

// receive answer
const answer = await response.json();
await pc.setRemoteDescription(answer);
} catch (err) {
console.error(err);
status.textContent = "❌ Connection failed: " + err;
}
}

start();
</script>
</body>

</html>
14 changes: 8 additions & 6 deletions liveMain/webstreaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ def rescale_frame(frame, percent=75):

def generate():
sharedMemory = posix_ipc.SharedMemory(config.SHARED_MEMORY_NAME_DETECTED_FRAME)

sharedMem = mmap(fileno=sharedMemory.fd, length=0)
sharedMemory.close_fd()

if config.APPLY_IMAGE_CROPPING:
img_w = config.CROP_W_TO - config.CROP_W_FROM
img_h = config.CROP_H_TO - config.CROP_H_FROM
else:
img_w = config.CAMERA_W
img_h = config.CAMERA_H
# if config.APPLY_IMAGE_CROPPING:
# img_w = config.CROP_W_TO - config.CROP_W_FROM
# img_h = config.CROP_H_TO - config.CROP_H_FROM
# else:

img_w = config.CAMERA_W
img_h = config.CAMERA_H

sharedArray = np.ndarray((img_h, img_w, 3), dtype=np.uint8, buffer=sharedMem)

Expand Down
4 changes: 2 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def move_to_point_and_extract(coords_from_to: list,
gps: adapters.GPSUbloxAdapter,
vesc_engine: adapters.VescAdapterV4,
smoothie: adapters.SmoothieAdapter,
camera: adapters.CameraAdapterIMX219_170,
camera: adapters.CameraAdapterInterface,
periphery_det: detection.YoloOpenCVDetection,
precise_det: detection.YoloOpenCVDetection,
logger_full: utility.Logger,
Expand Down Expand Up @@ -2162,7 +2162,7 @@ def main():
config.VESC_STOPPER_CHECK_FREQ, logger_full) as vesc_engine, \
adapters.SmoothieAdapter(smoothie_address) as smoothie, \
adapters.GPSUbloxAdapter(config.GPS_PORT, config.GPS_BAUDRATE, config.GPS_POSITIONS_TO_KEEP) as gps, \
adapters.CameraAdapterIMX219_170(config.CROP_W_FROM, config.CROP_W_TO, config.CROP_H_FROM,
adapters.CameraAdapterManager(config.CROP_W_FROM, config.CROP_W_TO, config.CROP_H_FROM,
config.CROP_H_TO, config.CV_ROTATE_CODE,
config.ISP_DIGITAL_GAIN_RANGE_FROM,
config.ISP_DIGITAL_GAIN_RANGE_TO,
Expand Down
Loading