Files
yair a7a776fb58 feat: adapt linescan scripts to use uv and proper rollover-based file saving
- Updated launch_with_signal.py with PEP 723 metadata for uv compatibility
- Added day/night mode presets with command-line arguments
- Implemented proper rollover-only file saving via Python/PIL callbacks
- Removed multifilesink from pipeline (was saving every frame incorrectly)
- Added funny auto-generated output directory names (e.g., fuzzy-photon)
- Updated rollover_example.py to follow same pattern with uv support
- Updated rollover_example.c to demonstrate signal detection without file saving
- Updated launch_with_capture.ps1 to remove incorrect multifilesink usage
- All scripts now save files ONLY on rollover events, not every frame
- Pipeline simplified: camera -> linescan -> display (files saved in callback)
2025-11-18 19:39:51 +02:00

216 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GStreamer Linescan Plugin
## Overview
The `linescan` plugin simulates a line scan camera by extracting a single row or column of pixels from each input frame and stacking them to create a line scan image over time. This is particularly useful for analyzing fast-moving objects captured with high frame rate cameras (typically 200-750 fps).
## Features
- **Horizontal mode**: Extracts a single row from each frame and stacks them vertically
- **Vertical mode**: Extracts a single column from each frame and stacks them horizontally
- **Configurable line selection**: Choose which row/column to extract, or use the middle automatically
- **Configurable output size**: Set the number of lines to accumulate before wrapping around
- **Supports multiple pixel formats**: GRAY8, GRAY16_LE, GRAY16_BE, RGB, BGR, BGRA, RGBx
## Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `direction` | enum | horizontal | Direction to extract line: `horizontal` (row) or `vertical` (column) |
| `line-index` | int | -1 | Index of row/column to extract (-1 for middle of image) |
| `output-size` | int | 800 | Number of lines to accumulate (width for horizontal mode, height for vertical mode) |
## Signals
### `rollover`
```c
void user_function (GstElement *linescan,
GstBuffer *buffer,
gpointer user_data)
```
Emitted when the buffer position wraps around to 0 after accumulating `output-size` lines. The `buffer` parameter contains the completed line scan image at the moment of rollover.
**Parameters:**
- `linescan`: The linescan element emitting the signal
- `buffer`: The completed line scan buffer (read-only, contains full image)
- `user_data`: User data set when the signal handler was connected
**Use cases:**
- Save completed line scan images to disk automatically
- Process completed frames (e.g., run image analysis)
- Trigger external actions when a scan cycle completes
- Capture periodic snapshots during continuous operation
## Usage Examples
### Basic Horizontal Line Scan (Extract Row 100)
```bash
gst-launch-1.0 videotestsrc ! \
linescan direction=horizontal line-index=100 output-size=800 ! \
videoconvert ! autovideosink
```
### Vertical Line Scan (Extract Middle Column)
```bash
gst-launch-1.0 videotestsrc ! \
linescan direction=vertical line-index=-1 output-size=600 ! \
videoconvert ! autovideosink
```
### High-Speed Camera Line Scan
```bash
gst-launch-1.0 idsueyesrc framerate=500 ! \
videocrop bottom=3 ! \
linescan direction=horizontal line-index=50 output-size=1000 ! \
videoconvert ! autovideosink
```
### Save Line Scan to File
```bash
gst-launch-1.0 idsueyesrc config-file=config.ini framerate=200 ! \
linescan direction=horizontal output-size=2000 ! \
videoconvert ! \
pngenc ! filesink location=linescan.png
```
### Capturing Frames on Rollover (Using Signal)
The `rollover` signal fires when the buffer wraps around, allowing you to capture completed frames:
**Python example** (`rollover_example.py`):
```python
#!/usr/bin/env python3
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
frame_counter = 0
def on_rollover(linescan, buffer, filesink):
global frame_counter
filename = f"linescan_{frame_counter:04d}.raw"
print(f"Rollover! Saving to: {filename}")
filesink.set_property('location', filename)
frame_counter += 1
Gst.init(None)
pipeline = Gst.parse_launch(
"videotestsrc pattern=ball ! "
"linescan direction=horizontal line-index=100 output-size=400 ! "
"tee name=t "
"t. ! queue ! videoconvert ! autovideosink "
"t. ! queue ! filesink name=fsink location=init.raw"
)
linescan = pipeline.get_by_name("linescan")
filesink = pipeline.get_by_name("fsink")
linescan.connect("rollover", on_rollover, filesink)
pipeline.set_state(Gst.State.PLAYING)
# ... run main loop ...
```
**Alternative: Using multifilesink with tee** (no signal needed):
```bash
# Automatically saves each output frame with incrementing counter
gst-launch-1.0 videotestsrc pattern=ball ! \
linescan direction=horizontal line-index=100 output-size=400 ! \
tee name=t \
t. ! queue ! videoconvert ! autovideosink \
t. ! queue ! multifilesink location="frame_%04d.raw" max-files=100
```
**Real-world example with IDS uEye camera:**
```powershell
# PowerShell script (see launch_with_capture.ps1)
$env:GST_DEBUG="linescan:5"
gst-launch-1.0 idsueyesrc config-file=ini/roi-night.ini `
exposure=5.25 framerate=200 gain=42 name=cam device-id=2 ! `
intervalometer enabled=true camera-element=cam `
ramp-rate=vslow update-interval=1000 gain-max=52 log-file=timelapse.csv ! `
videocrop bottom=3 ! queue ! `
linescan direction=vertical output-size=1900 ! `
tee name=t `
t. ! queue ! videoconvert ! autovideosink `
t. ! queue ! multifilesink location="linescan_%04d.raw" max-files=100
```
See examples:
- [`rollover_example.py`](rollover_example.py) - Basic rollover signal demo
- [`launch_with_signal.py`](launch_with_signal.py) - Full IDS camera pipeline with signal
- [`launch_with_capture.ps1`](launch_with_capture.ps1) - PowerShell script with multifilesink
## How It Works
### Horizontal Mode (default)
1. Extracts one horizontal row from each input frame
2. The row is determined by `line-index` (or middle if -1)
3. Each extracted row is stacked vertically to build the output image
4. Output dimensions: `output-size` (width) × `input_height` (height)
5. When the buffer fills up (after `input_height` frames), it wraps around and starts overwriting from the top
### Vertical Mode
1. Extracts one vertical column from each input frame
2. The column is determined by `line-index` (or middle if -1)
3. Each extracted column is stacked horizontally to build the output image
4. Output dimensions: `input_width` (width) × `output-size` (height)
5. When the buffer fills up (after `input_width` frames), it wraps around and starts overwriting from the left
## Typical Use Cases
1. **Conveyor Belt Inspection**: Capture a continuous image of objects moving on a conveyor belt
2. **High-Speed Object Analysis**: Analyze fast-moving objects frame-by-frame at high framerates
3. **Barcode/Text Reading**: Extract a horizontal line across moving barcodes or text
4. **Web Inspection**: Continuous inspection of paper, textile, or other web materials
5. **Sports Analysis**: Track trajectory or movement patterns of fast-moving objects
## Pipeline Tips
### For Best Results
- Use a high framerate camera (200-750 fps recommended)
- Ensure consistent object motion
- Adjust `line-index` to capture the region of interest
- Set `output-size` based on expected duration or object size
- Use `videocrop` before linescan if needed to reduce processing
### Common Pipeline Patterns
```bash
# Pattern 1: Crop + Linescan + Display
camera ! videocrop ! linescan ! videoconvert ! autovideosink
# Pattern 2: Linescan + Encode + Save
camera ! linescan ! videoconvert ! x264enc ! mp4mux ! filesink
# Pattern 3: Linescan + Network Stream
camera ! linescan ! videoconvert ! jpegenc ! multipartmux ! tcpserversink
```
## Performance Considerations
- The plugin maintains an internal buffer equal to the full output image size
- Memory usage = `output_width × output_height × bytes_per_pixel`
- Processing overhead is minimal (single memcpy per frame)
- No frame buffering - processes each frame immediately
## Troubleshooting
### "Could not link" errors
- Ensure videocrop or other upstream elements provide fixed caps
- Try adding `videoconvert` before linescan if needed
### Line index out of range
- Check that `line-index` is less than input height (horizontal) or width (vertical)
- Use `-1` to automatically select the middle
### Wrapping/Rolling effect
- This is normal when the buffer fills up
- Adjust `output-size` to match your capture duration needs
## See Also
- [intervalometer](../intervalometer/README.md) - Auto-exposure control
- [rollingsum](../rollingsum/README.md) - Moving window sum detection
- [GStreamer Documentation](https://gstreamer.freedesktop.org/documentation/)