init commit
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -137,3 +137,5 @@ dist
|
||||
# Vite logs files
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
/videos/*
|
||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"python.analysis.extraPaths": [
|
||||
"./python demo"
|
||||
]
|
||||
}
|
||||
146
01README.md
Normal file
146
01README.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# GigE Camera Image Capture
|
||||
|
||||
This project provides simple Python scripts to connect to a GigE camera and capture images using the provided SDK.
|
||||
|
||||
## Files Overview
|
||||
|
||||
### Demo Files (provided with camera)
|
||||
- `python demo/mvsdk.py` - Main SDK wrapper library
|
||||
- `python demo/grab.py` - Basic image capture example
|
||||
- `python demo/cv_grab.py` - OpenCV-based continuous capture
|
||||
- `python demo/cv_grab_callback.py` - Callback-based capture
|
||||
- `python demo/readme.txt` - Original demo documentation
|
||||
|
||||
### Custom Scripts
|
||||
- `camera_capture.py` - Standalone script to capture 10 images with 200ms intervals
|
||||
- `test.ipynb` - Jupyter notebook with the same functionality
|
||||
- `images/` - Directory where captured images are saved
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic camera detection** - Finds and connects to available GigE cameras
|
||||
- **Configurable capture** - Currently set to capture 10 images with 200ms intervals
|
||||
- **Both mono and color support** - Automatically detects camera type
|
||||
- **Timestamped filenames** - Images saved with date/time stamps
|
||||
- **Error handling** - Robust error handling for camera operations
|
||||
- **Cross-platform** - Works on Windows and Linux (with appropriate image flipping)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.x
|
||||
- OpenCV (`cv2`)
|
||||
- NumPy
|
||||
- Matplotlib (for Jupyter notebook display)
|
||||
- GigE camera SDK (MVSDK) - included in `python demo/` directory
|
||||
|
||||
## Usage
|
||||
|
||||
### Option 1: Standalone Script
|
||||
|
||||
Run the standalone Python script:
|
||||
|
||||
```bash
|
||||
python camera_capture.py
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Initialize the camera SDK
|
||||
2. Detect available cameras
|
||||
3. Connect to the first camera found
|
||||
4. Configure camera settings (manual exposure, continuous mode)
|
||||
5. Capture 10 images with 200ms intervals
|
||||
6. Save images to the `images/` directory
|
||||
7. Clean up and close the camera
|
||||
|
||||
### Option 2: Jupyter Notebook
|
||||
|
||||
Open and run the `test.ipynb` notebook:
|
||||
|
||||
```bash
|
||||
jupyter notebook test.ipynb
|
||||
```
|
||||
|
||||
The notebook provides the same functionality but with:
|
||||
- Step-by-step execution
|
||||
- Detailed explanations
|
||||
- Visual display of the last captured image
|
||||
- Better error reporting
|
||||
|
||||
## Camera Configuration
|
||||
|
||||
The scripts are configured with the following default settings:
|
||||
|
||||
- **Trigger Mode**: Continuous capture (mode 0)
|
||||
- **Exposure**: Manual, 30ms
|
||||
- **Output Format**:
|
||||
- Monochrome cameras: MONO8
|
||||
- Color cameras: BGR8
|
||||
- **Image Processing**: Automatic ISP processing from RAW to RGB/MONO
|
||||
|
||||
## Output
|
||||
|
||||
Images are saved in the `images/` directory with the following naming convention:
|
||||
```
|
||||
image_XX_YYYYMMDD_HHMMSS_mmm.jpg
|
||||
```
|
||||
|
||||
Where:
|
||||
- `XX` = Image number (01-10)
|
||||
- `YYYYMMDD_HHMMSS_mmm` = Timestamp with milliseconds
|
||||
|
||||
Example: `image_01_20250722_140530_123.jpg`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **"No camera was found!"**
|
||||
- Check camera connection (Ethernet cable)
|
||||
- Verify camera power
|
||||
- Check network settings (camera and PC should be on same subnet)
|
||||
- Ensure camera drivers are installed
|
||||
|
||||
2. **"CameraInit Failed"**
|
||||
- Camera might be in use by another application
|
||||
- Check camera permissions
|
||||
- Try restarting the camera or PC
|
||||
|
||||
3. **"Failed to capture image"**
|
||||
- Check camera settings
|
||||
- Verify sufficient lighting
|
||||
- Check exposure settings
|
||||
|
||||
4. **Images appear upside down**
|
||||
- This is handled automatically on Windows
|
||||
- Linux users may need to adjust the flip settings
|
||||
|
||||
### Network Configuration
|
||||
|
||||
For GigE cameras, ensure:
|
||||
- Camera and PC are on the same network segment
|
||||
- PC network adapter supports Jumbo frames (recommended)
|
||||
- Firewall allows camera communication
|
||||
- Sufficient network bandwidth
|
||||
|
||||
## Customization
|
||||
|
||||
You can modify the scripts to:
|
||||
|
||||
- **Change capture count**: Modify the range in the capture loop
|
||||
- **Adjust timing**: Change the `time.sleep(0.2)` value
|
||||
- **Modify exposure**: Change the exposure time parameter
|
||||
- **Change output format**: Modify file format and quality settings
|
||||
- **Add image processing**: Insert processing steps before saving
|
||||
|
||||
## SDK Reference
|
||||
|
||||
The camera SDK (`mvsdk.py`) provides extensive functionality:
|
||||
|
||||
- Camera enumeration and initialization
|
||||
- Image capture and processing
|
||||
- Parameter configuration (exposure, gain, etc.)
|
||||
- Trigger modes and timing
|
||||
- Image format conversion
|
||||
- Error handling
|
||||
|
||||
Refer to the original SDK documentation for advanced features.
|
||||
191
VIDEO_RECORDER_README.md
Normal file
191
VIDEO_RECORDER_README.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Camera Video Recorder
|
||||
|
||||
A Python script for recording videos from GigE cameras using the provided SDK with custom exposure and gain settings.
|
||||
|
||||
## Features
|
||||
|
||||
- **List all available cameras** - Automatically detects and displays all connected cameras
|
||||
- **Custom camera settings** - Set exposure time to 1ms and gain to 3.5x (or custom values)
|
||||
- **Video recording** - Record videos in AVI format with timestamp filenames
|
||||
- **Live preview** - Test camera functionality with live preview mode
|
||||
- **Interactive menu** - User-friendly menu system for all operations
|
||||
- **Automatic cleanup** - Proper resource management and cleanup
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.x
|
||||
- OpenCV (`cv2`)
|
||||
- NumPy
|
||||
- Camera SDK (mvsdk) - included in `python demo` directory
|
||||
- GigE camera connected to the system
|
||||
|
||||
## Installation
|
||||
|
||||
1. Ensure your GigE camera is connected and properly configured
|
||||
2. Make sure the `python demo` directory with `mvsdk.py` is present
|
||||
3. Install required Python packages:
|
||||
```bash
|
||||
pip install opencv-python numpy
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run the script:
|
||||
```bash
|
||||
python camera_video_recorder.py
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Display a welcome message and feature overview
|
||||
2. List all available cameras
|
||||
3. Let you select a camera (if multiple are available)
|
||||
4. Allow you to set custom exposure and gain values
|
||||
5. Present an interactive menu with options
|
||||
|
||||
### Menu Options
|
||||
|
||||
1. **Start Recording** - Begin video recording with timestamp filename
|
||||
2. **List Camera Info** - Display detailed camera information
|
||||
3. **Test Camera (Live Preview)** - View live camera feed without recording
|
||||
4. **Exit** - Clean up and exit the program
|
||||
|
||||
### Default Settings
|
||||
|
||||
- **Exposure Time**: 1.0ms (1000 microseconds)
|
||||
- **Gain**: 3.5x
|
||||
- **Video Format**: AVI with XVID codec
|
||||
- **Frame Rate**: 30 FPS
|
||||
- **Output Directory**: `videos/` (created automatically)
|
||||
|
||||
### Recording Controls
|
||||
|
||||
- **Start Recording**: Select option 1 from the menu
|
||||
- **Stop Recording**: Press 'q' in the preview window
|
||||
- **Video Files**: Saved as `videos/camera_recording_YYYYMMDD_HHMMSS.avi`
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
camera_video_recorder.py # Main script
|
||||
python demo/
|
||||
mvsdk.py # Camera SDK wrapper
|
||||
(other demo files)
|
||||
videos/ # Output directory (created automatically)
|
||||
camera_recording_*.avi # Recorded video files
|
||||
```
|
||||
|
||||
## Script Features
|
||||
|
||||
### CameraVideoRecorder Class
|
||||
|
||||
- `list_cameras()` - Enumerate and display available cameras
|
||||
- `initialize_camera()` - Set up camera with custom exposure and gain
|
||||
- `start_recording()` - Initialize video writer and begin recording
|
||||
- `stop_recording()` - Stop recording and save video file
|
||||
- `record_loop()` - Main recording loop with live preview
|
||||
- `cleanup()` - Proper resource cleanup
|
||||
|
||||
### Key Functions
|
||||
|
||||
- **Camera Detection**: Automatically finds all connected GigE cameras
|
||||
- **Settings Validation**: Checks and clamps exposure/gain values to camera limits
|
||||
- **Frame Processing**: Handles both monochrome and color cameras
|
||||
- **Windows Compatibility**: Handles frame flipping for Windows systems
|
||||
- **Error Handling**: Comprehensive error handling and user feedback
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
Camera Video Recorder
|
||||
====================
|
||||
This script allows you to:
|
||||
- List all available cameras
|
||||
- Record videos with custom exposure (1ms) and gain (3.5x) settings
|
||||
- Save videos with timestamps
|
||||
- Stop recording anytime with 'q' key
|
||||
|
||||
Found 1 camera(s):
|
||||
0: GigE Camera Model (GigE) - SN: 12345678
|
||||
|
||||
Using camera: GigE Camera Model
|
||||
|
||||
Camera Settings:
|
||||
Enter exposure time in ms (default 1.0): 1.0
|
||||
Enter gain value (default 3.5): 3.5
|
||||
|
||||
Initializing camera with:
|
||||
- Exposure: 1.0ms
|
||||
- Gain: 3.5x
|
||||
|
||||
Camera type: Color
|
||||
Set exposure time: 1000.0μs
|
||||
Set analog gain: 3.50x (range: 1.00 - 16.00)
|
||||
Camera started successfully
|
||||
|
||||
==================================================
|
||||
Camera Video Recorder Menu
|
||||
==================================================
|
||||
1. Start Recording
|
||||
2. List Camera Info
|
||||
3. Test Camera (Live Preview)
|
||||
4. Exit
|
||||
|
||||
Select option (1-4): 1
|
||||
|
||||
Started recording to: videos/camera_recording_20241223_143022.avi
|
||||
Frame size: (1920, 1080), FPS: 30.0
|
||||
Press 'q' to stop recording...
|
||||
Recording... Press 'q' in the preview window to stop
|
||||
|
||||
Recording stopped!
|
||||
Saved: videos/camera_recording_20241223_143022.avi
|
||||
Frames recorded: 450
|
||||
Duration: 15.2 seconds
|
||||
Average FPS: 29.6
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **"No cameras found!"**
|
||||
- Check camera connection
|
||||
- Verify camera power
|
||||
- Ensure network configuration for GigE cameras
|
||||
|
||||
2. **"SDK initialization failed"**
|
||||
- Verify `python demo/mvsdk.py` exists
|
||||
- Check camera drivers are installed
|
||||
|
||||
3. **"Camera initialization failed"**
|
||||
- Camera may be in use by another application
|
||||
- Try disconnecting and reconnecting the camera
|
||||
|
||||
4. **Recording issues**
|
||||
- Ensure sufficient disk space
|
||||
- Check write permissions in the output directory
|
||||
|
||||
### Performance Tips
|
||||
|
||||
- Close other applications using the camera
|
||||
- Ensure adequate system resources (CPU, RAM)
|
||||
- Use SSD storage for better write performance
|
||||
- Adjust frame rate if experiencing dropped frames
|
||||
|
||||
## Customization
|
||||
|
||||
You can modify the script to:
|
||||
- Change video codec (currently XVID)
|
||||
- Adjust target frame rate
|
||||
- Modify output filename format
|
||||
- Add additional camera settings
|
||||
- Change preview window size
|
||||
|
||||
## Notes
|
||||
|
||||
- Videos are saved in the `videos/` directory with timestamp filenames
|
||||
- The script handles both monochrome and color cameras automatically
|
||||
- Frame flipping is handled automatically for Windows systems
|
||||
- All resources are properly cleaned up on exit
|
||||
291
camera_capture.py
Normal file
291
camera_capture.py
Normal file
@@ -0,0 +1,291 @@
|
||||
# coding=utf-8
|
||||
"""
|
||||
Simple GigE Camera Capture Script
|
||||
Captures 10 images every 200 milliseconds and saves them to the images directory.
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import numpy as np
|
||||
import cv2
|
||||
import platform
|
||||
from datetime import datetime
|
||||
import sys
|
||||
|
||||
sys.path.append("./python demo")
|
||||
import mvsdk
|
||||
|
||||
|
||||
def is_camera_ready_for_capture():
|
||||
"""
|
||||
Check if camera is ready for capture.
|
||||
Returns: (ready: bool, message: str, camera_info: object or None)
|
||||
"""
|
||||
try:
|
||||
# Initialize SDK
|
||||
mvsdk.CameraSdkInit(1)
|
||||
|
||||
# Enumerate cameras
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
if len(DevList) < 1:
|
||||
return False, "No cameras found", None
|
||||
|
||||
DevInfo = DevList[0]
|
||||
|
||||
# Check if already opened
|
||||
try:
|
||||
if mvsdk.CameraIsOpened(DevInfo):
|
||||
return False, f"Camera '{DevInfo.GetFriendlyName()}' is already opened by another process", DevInfo
|
||||
except:
|
||||
pass # Some cameras might not support this check
|
||||
|
||||
# Try to initialize
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
|
||||
|
||||
# Quick capture test
|
||||
try:
|
||||
# Basic setup
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
|
||||
# Try to get one frame with short timeout
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 500) # 0.5 second timeout
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# Success - close and return
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
return True, f"Camera '{DevInfo.GetFriendlyName()}' is ready for capture", DevInfo
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
if e.error_code == mvsdk.CAMERA_STATUS_TIME_OUT:
|
||||
return False, "Camera timeout - may be busy or not streaming properly", DevInfo
|
||||
else:
|
||||
return False, f"Camera capture test failed: {e.message}", DevInfo
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
if e.error_code == mvsdk.CAMERA_STATUS_DEVICE_IS_OPENED:
|
||||
return False, f"Camera '{DevInfo.GetFriendlyName()}' is already in use", DevInfo
|
||||
elif e.error_code == mvsdk.CAMERA_STATUS_ACCESS_DENY:
|
||||
return False, f"Access denied to camera '{DevInfo.GetFriendlyName()}'", DevInfo
|
||||
else:
|
||||
return False, f"Camera initialization failed: {e.message}", DevInfo
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Camera check failed: {str(e)}", None
|
||||
|
||||
|
||||
def get_camera_ranges(hCamera):
|
||||
"""
|
||||
Get the available ranges for camera settings
|
||||
"""
|
||||
try:
|
||||
# Get exposure time range
|
||||
exp_min, exp_max, exp_step = mvsdk.CameraGetExposureTimeRange(hCamera)
|
||||
print(f"Exposure time range: {exp_min:.1f} - {exp_max:.1f} μs (step: {exp_step:.1f})")
|
||||
|
||||
# Get analog gain range
|
||||
gain_min, gain_max, gain_step = mvsdk.CameraGetAnalogGainXRange(hCamera)
|
||||
print(f"Analog gain range: {gain_min:.2f} - {gain_max:.2f}x (step: {gain_step:.3f})")
|
||||
|
||||
return (exp_min, exp_max, exp_step), (gain_min, gain_max, gain_step)
|
||||
except Exception as e:
|
||||
print(f"Could not get camera ranges: {e}")
|
||||
return None, None
|
||||
|
||||
|
||||
def capture_images(exposure_time_us=2000, analog_gain=1.0):
|
||||
"""
|
||||
Main function to capture images from GigE camera
|
||||
|
||||
Parameters:
|
||||
- exposure_time_us: Exposure time in microseconds (default: 2000 = 2ms)
|
||||
- analog_gain: Analog gain multiplier (default: 1.0)
|
||||
"""
|
||||
# Check if camera is ready for capture
|
||||
print("Checking camera availability...")
|
||||
ready, message, camera_info = is_camera_ready_for_capture()
|
||||
|
||||
if not ready:
|
||||
print(f"❌ Camera not ready: {message}")
|
||||
print("\nPossible solutions:")
|
||||
print("- Close any other camera applications (preview software, etc.)")
|
||||
print("- Check camera connection and power")
|
||||
print("- Wait a moment and try again")
|
||||
return False
|
||||
|
||||
print(f"✅ {message}")
|
||||
|
||||
# Initialize SDK (already done in status check, but ensure it's ready)
|
||||
try:
|
||||
mvsdk.CameraSdkInit(1) # Initialize SDK with English language
|
||||
except Exception as e:
|
||||
print(f"SDK initialization failed: {e}")
|
||||
return False
|
||||
|
||||
# Enumerate cameras
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
|
||||
if nDev < 1:
|
||||
print("No camera was found!")
|
||||
return False
|
||||
|
||||
print(f"Found {nDev} camera(s):")
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
print(f"{i}: {DevInfo.GetFriendlyName()} {DevInfo.GetPortType()}")
|
||||
|
||||
# Select camera (use first one if only one available)
|
||||
camera_index = 0 if nDev == 1 else int(input("Select camera index: "))
|
||||
DevInfo = DevList[camera_index]
|
||||
print(f"Selected camera: {DevInfo.GetFriendlyName()}")
|
||||
|
||||
# Initialize camera
|
||||
hCamera = 0
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
|
||||
print("Camera initialized successfully")
|
||||
except mvsdk.CameraException as e:
|
||||
print(f"CameraInit Failed({e.error_code}): {e.message}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Get camera capabilities
|
||||
cap = mvsdk.CameraGetCapability(hCamera)
|
||||
|
||||
# Check if it's a mono or color camera
|
||||
monoCamera = cap.sIspCapacity.bMonoSensor != 0
|
||||
print(f"Camera type: {'Monochrome' if monoCamera else 'Color'}")
|
||||
|
||||
# Get camera ranges
|
||||
exp_range, gain_range = get_camera_ranges(hCamera)
|
||||
|
||||
# Set output format
|
||||
if monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
|
||||
# Set camera to continuous capture mode
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
|
||||
# Set manual exposure with improved control
|
||||
mvsdk.CameraSetAeState(hCamera, 0) # Disable auto exposure
|
||||
|
||||
# Clamp exposure time to valid range
|
||||
if exp_range:
|
||||
exp_min, exp_max, exp_step = exp_range
|
||||
exposure_time_us = max(exp_min, min(exp_max, exposure_time_us))
|
||||
|
||||
mvsdk.CameraSetExposureTime(hCamera, exposure_time_us)
|
||||
print(f"Set exposure time: {exposure_time_us/1000:.1f}ms")
|
||||
|
||||
# Set analog gain
|
||||
if gain_range:
|
||||
gain_min, gain_max, gain_step = gain_range
|
||||
analog_gain = max(gain_min, min(gain_max, analog_gain))
|
||||
|
||||
try:
|
||||
mvsdk.CameraSetAnalogGainX(hCamera, analog_gain)
|
||||
print(f"Set analog gain: {analog_gain:.2f}x")
|
||||
except Exception as e:
|
||||
print(f"Could not set analog gain: {e}")
|
||||
|
||||
# Start camera
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
print("Camera started")
|
||||
|
||||
# Calculate frame buffer size
|
||||
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
|
||||
|
||||
# Allocate frame buffer
|
||||
pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
# Create images directory if it doesn't exist
|
||||
if not os.path.exists("images"):
|
||||
os.makedirs("images")
|
||||
|
||||
print("Starting image capture...")
|
||||
print("Capturing 10 images with 200ms intervals...")
|
||||
|
||||
# Capture 10 images
|
||||
for i in range(10):
|
||||
try:
|
||||
# Get image from camera (timeout: 2000ms)
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 2000)
|
||||
|
||||
# Process the raw image data
|
||||
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
|
||||
|
||||
# Release the raw data buffer
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# Handle Windows image flip (images are upside down on Windows)
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# Convert to numpy array for OpenCV
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
|
||||
# Reshape based on camera type
|
||||
if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth))
|
||||
else:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 3))
|
||||
|
||||
# Generate filename with timestamp
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3] # milliseconds
|
||||
filename = f"images/image_{i+1:02d}_{timestamp}.jpg"
|
||||
|
||||
# Save image using OpenCV
|
||||
success = cv2.imwrite(filename, frame)
|
||||
|
||||
if success:
|
||||
print(f"Image {i+1}/10 saved: {filename} ({FrameHead.iWidth}x{FrameHead.iHeight})")
|
||||
else:
|
||||
print(f"Failed to save image {i+1}/10")
|
||||
|
||||
# Wait 200ms before next capture (except for the last image)
|
||||
if i < 9:
|
||||
time.sleep(0.2)
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
print(f"Failed to capture image {i+1}/10 ({e.error_code}): {e.message}")
|
||||
continue
|
||||
|
||||
print("Image capture completed!")
|
||||
|
||||
# Cleanup
|
||||
mvsdk.CameraAlignFree(pFrameBuffer)
|
||||
|
||||
finally:
|
||||
# Close camera
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
print("Camera closed")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("GigE Camera Image Capture Script")
|
||||
print("=" * 40)
|
||||
print("Note: If images are overexposed, you can adjust the exposure settings:")
|
||||
print("- Lower exposure_time_us for darker images (e.g., 1000-5000)")
|
||||
print("- Lower analog_gain for less amplification (e.g., 0.5-2.0)")
|
||||
print()
|
||||
|
||||
# for cracker
|
||||
# You can adjust these values to fix overexposure:
|
||||
success = capture_images(exposure_time_us=6000, analog_gain=16.0) # 2ms exposure (much lower than default 30ms) # 1x gain (no amplification)
|
||||
# for blower
|
||||
success = capture_images(exposure_time_us=1000, analog_gain=3.5) # 2ms exposure (much lower than default 30ms) # 1x gain (no amplification)
|
||||
|
||||
if success:
|
||||
print("\nCapture completed successfully!")
|
||||
print("Images saved in the 'images' directory")
|
||||
else:
|
||||
print("\nCapture failed!")
|
||||
|
||||
input("Press Enter to exit...")
|
||||
607
camera_status_test.ipynb
Normal file
607
camera_status_test.ipynb
Normal file
@@ -0,0 +1,607 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "intro",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Camera Status and Availability Testing\n",
|
||||
"\n",
|
||||
"This notebook tests various methods to check camera status and availability before attempting to capture images.\n",
|
||||
"\n",
|
||||
"## Key Functions to Test:\n",
|
||||
"- `CameraIsOpened()` - Check if camera is already opened by another process\n",
|
||||
"- `CameraInit()` - Try to initialize and catch specific error codes\n",
|
||||
"- `CameraGetImageBuffer()` - Test actual image capture with timeout\n",
|
||||
"- Error code analysis for different failure scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 46,
|
||||
"id": "imports",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Libraries imported successfully!\n",
|
||||
"Platform: Windows\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Import required libraries\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import time\n",
|
||||
"import numpy as np\n",
|
||||
"import cv2\n",
|
||||
"import platform\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# Add the python demo directory to path to import mvsdk\n",
|
||||
"sys.path.append('./python demo')\n",
|
||||
"import mvsdk\n",
|
||||
"\n",
|
||||
"print(\"Libraries imported successfully!\")\n",
|
||||
"print(f\"Platform: {platform.system()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 47,
|
||||
"id": "error-codes",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Relevant Camera Status Error Codes:\n",
|
||||
"========================================\n",
|
||||
"CAMERA_STATUS_SUCCESS: 0\n",
|
||||
"CAMERA_STATUS_DEVICE_IS_OPENED: -18\n",
|
||||
"CAMERA_STATUS_DEVICE_IS_CLOSED: -19\n",
|
||||
"CAMERA_STATUS_ACCESS_DENY: -45\n",
|
||||
"CAMERA_STATUS_DEVICE_LOST: -38\n",
|
||||
"CAMERA_STATUS_TIME_OUT: -12\n",
|
||||
"CAMERA_STATUS_BUSY: -28\n",
|
||||
"CAMERA_STATUS_NO_DEVICE_FOUND: -16\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Let's examine the relevant error codes from the SDK\n",
|
||||
"print(\"Relevant Camera Status Error Codes:\")\n",
|
||||
"print(\"=\" * 40)\n",
|
||||
"print(f\"CAMERA_STATUS_SUCCESS: {mvsdk.CAMERA_STATUS_SUCCESS}\")\n",
|
||||
"print(f\"CAMERA_STATUS_DEVICE_IS_OPENED: {mvsdk.CAMERA_STATUS_DEVICE_IS_OPENED}\")\n",
|
||||
"print(f\"CAMERA_STATUS_DEVICE_IS_CLOSED: {mvsdk.CAMERA_STATUS_DEVICE_IS_CLOSED}\")\n",
|
||||
"print(f\"CAMERA_STATUS_ACCESS_DENY: {mvsdk.CAMERA_STATUS_ACCESS_DENY}\")\n",
|
||||
"print(f\"CAMERA_STATUS_DEVICE_LOST: {mvsdk.CAMERA_STATUS_DEVICE_LOST}\")\n",
|
||||
"print(f\"CAMERA_STATUS_TIME_OUT: {mvsdk.CAMERA_STATUS_TIME_OUT}\")\n",
|
||||
"print(f\"CAMERA_STATUS_BUSY: {mvsdk.CAMERA_STATUS_BUSY}\")\n",
|
||||
"print(f\"CAMERA_STATUS_NO_DEVICE_FOUND: {mvsdk.CAMERA_STATUS_NO_DEVICE_FOUND}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 48,
|
||||
"id": "status-functions",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Camera Availability Check\n",
|
||||
"==============================\n",
|
||||
"✓ SDK initialized successfully\n",
|
||||
"✓ Found 2 camera(s)\n",
|
||||
" 0: Blower-Yield-Cam (NET-1000M-192.168.1.165)\n",
|
||||
" 1: Cracker-Cam (NET-1000M-192.168.1.167)\n",
|
||||
"\n",
|
||||
"Testing camera 0: Blower-Yield-Cam\n",
|
||||
"✓ Camera is available (not opened by another process)\n",
|
||||
"✓ Camera initialized successfully\n",
|
||||
"✓ Camera closed after testing\n",
|
||||
"\n",
|
||||
"Testing camera 1: Cracker-Cam\n",
|
||||
"✓ Camera is available (not opened by another process)\n",
|
||||
"✓ Camera initialized successfully\n",
|
||||
"✓ Camera closed after testing\n",
|
||||
"\n",
|
||||
"Results for 2 cameras:\n",
|
||||
" Camera 0: AVAILABLE\n",
|
||||
" Camera 1: AVAILABLE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def check_camera_availability():\n",
|
||||
" \"\"\"\n",
|
||||
" Comprehensive camera availability check\n",
|
||||
" \"\"\"\n",
|
||||
" print(\"Camera Availability Check\")\n",
|
||||
" print(\"=\" * 30)\n",
|
||||
" \n",
|
||||
" # Step 1: Initialize SDK\n",
|
||||
" try:\n",
|
||||
" mvsdk.CameraSdkInit(1)\n",
|
||||
" print(\"✓ SDK initialized successfully\")\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"✗ SDK initialization failed: {e}\")\n",
|
||||
" return None, \"SDK_INIT_FAILED\"\n",
|
||||
" \n",
|
||||
" # Step 2: Enumerate cameras\n",
|
||||
" try:\n",
|
||||
" DevList = mvsdk.CameraEnumerateDevice()\n",
|
||||
" nDev = len(DevList)\n",
|
||||
" print(f\"✓ Found {nDev} camera(s)\")\n",
|
||||
" \n",
|
||||
" if nDev < 1:\n",
|
||||
" print(\"✗ No cameras detected\")\n",
|
||||
" return None, \"NO_CAMERAS\"\n",
|
||||
" \n",
|
||||
" for i, DevInfo in enumerate(DevList):\n",
|
||||
" print(f\" {i}: {DevInfo.GetFriendlyName()} ({DevInfo.GetPortType()})\")\n",
|
||||
" \n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"✗ Camera enumeration failed: {e}\")\n",
|
||||
" return None, \"ENUM_FAILED\"\n",
|
||||
" \n",
|
||||
" # Step 3: Check all cameras\n",
|
||||
" camera_results = []\n",
|
||||
" \n",
|
||||
" for i, DevInfo in enumerate(DevList):\n",
|
||||
" print(f\"\\nTesting camera {i}: {DevInfo.GetFriendlyName()}\")\n",
|
||||
" \n",
|
||||
" # Check if camera is already opened\n",
|
||||
" try:\n",
|
||||
" is_opened = mvsdk.CameraIsOpened(DevInfo)\n",
|
||||
" if is_opened:\n",
|
||||
" print(\"✗ Camera is already opened by another process\")\n",
|
||||
" camera_results.append((DevInfo, \"ALREADY_OPENED\"))\n",
|
||||
" continue\n",
|
||||
" else:\n",
|
||||
" print(\"✓ Camera is available (not opened by another process)\")\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠ Could not check if camera is opened: {e}\")\n",
|
||||
" \n",
|
||||
" # Try to initialize camera\n",
|
||||
" try:\n",
|
||||
" hCamera = mvsdk.CameraInit(DevInfo, -1, -1)\n",
|
||||
" print(\"✓ Camera initialized successfully\")\n",
|
||||
" camera_results.append((hCamera, \"AVAILABLE\"))\n",
|
||||
" \n",
|
||||
" # Close the camera after testing\n",
|
||||
" try:\n",
|
||||
" mvsdk.CameraUnInit(hCamera)\n",
|
||||
" print(\"✓ Camera closed after testing\")\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠ Warning: Could not close camera: {e}\")\n",
|
||||
" \n",
|
||||
" except mvsdk.CameraException as e:\n",
|
||||
" print(f\"✗ Camera initialization failed: {e.error_code} - {e.message}\")\n",
|
||||
" \n",
|
||||
" # Analyze specific error codes\n",
|
||||
" if e.error_code == mvsdk.CAMERA_STATUS_DEVICE_IS_OPENED:\n",
|
||||
" camera_results.append((DevInfo, \"DEVICE_OPENED\"))\n",
|
||||
" elif e.error_code == mvsdk.CAMERA_STATUS_ACCESS_DENY:\n",
|
||||
" camera_results.append((DevInfo, \"ACCESS_DENIED\"))\n",
|
||||
" elif e.error_code == mvsdk.CAMERA_STATUS_DEVICE_LOST:\n",
|
||||
" camera_results.append((DevInfo, \"DEVICE_LOST\"))\n",
|
||||
" else:\n",
|
||||
" camera_results.append((DevInfo, f\"INIT_ERROR_{e.error_code}\"))\n",
|
||||
" \n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"✗ Unexpected error during initialization: {e}\")\n",
|
||||
" camera_results.append((DevInfo, \"UNEXPECTED_ERROR\"))\n",
|
||||
" \n",
|
||||
" return camera_results\n",
|
||||
"\n",
|
||||
"# Test the function\n",
|
||||
"camera_results = check_camera_availability()\n",
|
||||
"print(f\"\\nResults for {len(camera_results)} cameras:\")\n",
|
||||
"for i, (camera_info, status) in enumerate(camera_results):\n",
|
||||
" if hasattr(camera_info, 'GetFriendlyName'):\n",
|
||||
" name = camera_info.GetFriendlyName()\n",
|
||||
" else:\n",
|
||||
" name = f\"Camera {i}\"\n",
|
||||
" print(f\" {name}: {status}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 49,
|
||||
"id": "test-capture-availability",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"Testing capture readiness for 2 available camera(s):\n",
|
||||
"\n",
|
||||
"Testing camera 0 capture readiness...\n",
|
||||
"\n",
|
||||
"Testing Camera Capture Readiness\n",
|
||||
"===================================\n",
|
||||
"✓ Camera capabilities retrieved\n",
|
||||
"✓ Camera type: Color\n",
|
||||
"✓ Basic camera configuration set\n",
|
||||
"✓ Camera started\n",
|
||||
"✓ Frame buffer allocated\n",
|
||||
"\n",
|
||||
"Testing image capture...\n",
|
||||
"✓ Image captured successfully: 1280x1024\n",
|
||||
"✓ Image processed and buffer released\n",
|
||||
"✓ Cleanup completed\n",
|
||||
"Capture Ready for Blower-Yield-Cam: True\n",
|
||||
"\n",
|
||||
"Testing camera 1 capture readiness...\n",
|
||||
"\n",
|
||||
"Testing Camera Capture Readiness\n",
|
||||
"===================================\n",
|
||||
"✓ Camera capabilities retrieved\n",
|
||||
"✓ Camera type: Color\n",
|
||||
"✓ Basic camera configuration set\n",
|
||||
"✓ Camera started\n",
|
||||
"✓ Frame buffer allocated\n",
|
||||
"\n",
|
||||
"Testing image capture...\n",
|
||||
"✓ Image captured successfully: 1280x1024\n",
|
||||
"✓ Image processed and buffer released\n",
|
||||
"✓ Cleanup completed\n",
|
||||
"Capture Ready for Cracker-Cam: True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def test_camera_capture_readiness(hCamera):\n",
|
||||
" \"\"\"\n",
|
||||
" Test if camera is ready for image capture\n",
|
||||
" \"\"\"\n",
|
||||
" if not isinstance(hCamera, int):\n",
|
||||
" print(\"Camera not properly initialized, skipping capture test\")\n",
|
||||
" return False\n",
|
||||
" \n",
|
||||
" print(\"\\nTesting Camera Capture Readiness\")\n",
|
||||
" print(\"=\" * 35)\n",
|
||||
" \n",
|
||||
" try:\n",
|
||||
" # Get camera capabilities\n",
|
||||
" cap = mvsdk.CameraGetCapability(hCamera)\n",
|
||||
" print(\"✓ Camera capabilities retrieved\")\n",
|
||||
" \n",
|
||||
" # Check camera type\n",
|
||||
" monoCamera = (cap.sIspCapacity.bMonoSensor != 0)\n",
|
||||
" print(f\"✓ Camera type: {'Monochrome' if monoCamera else 'Color'}\")\n",
|
||||
" \n",
|
||||
" # Set basic configuration\n",
|
||||
" if monoCamera:\n",
|
||||
" mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)\n",
|
||||
" else:\n",
|
||||
" mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)\n",
|
||||
" \n",
|
||||
" mvsdk.CameraSetTriggerMode(hCamera, 0) # Continuous mode\n",
|
||||
" mvsdk.CameraSetAeState(hCamera, 0) # Manual exposure\n",
|
||||
" mvsdk.CameraSetExposureTime(hCamera, 5000) # 5ms exposure\n",
|
||||
" print(\"✓ Basic camera configuration set\")\n",
|
||||
" \n",
|
||||
" # Start camera\n",
|
||||
" mvsdk.CameraPlay(hCamera)\n",
|
||||
" print(\"✓ Camera started\")\n",
|
||||
" \n",
|
||||
" # Allocate buffer\n",
|
||||
" FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)\n",
|
||||
" pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)\n",
|
||||
" print(\"✓ Frame buffer allocated\")\n",
|
||||
" \n",
|
||||
" # Test image capture with short timeout\n",
|
||||
" print(\"\\nTesting image capture...\")\n",
|
||||
" try:\n",
|
||||
" pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 1000) # 1 second timeout\n",
|
||||
" print(f\"✓ Image captured successfully: {FrameHead.iWidth}x{FrameHead.iHeight}\")\n",
|
||||
" \n",
|
||||
" # Process and release\n",
|
||||
" mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)\n",
|
||||
" mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)\n",
|
||||
" print(\"✓ Image processed and buffer released\")\n",
|
||||
" \n",
|
||||
" capture_success = True\n",
|
||||
" \n",
|
||||
" except mvsdk.CameraException as e:\n",
|
||||
" print(f\"✗ Image capture failed: {e.error_code} - {e.message}\")\n",
|
||||
" \n",
|
||||
" if e.error_code == mvsdk.CAMERA_STATUS_TIME_OUT:\n",
|
||||
" print(\" → Camera timeout - may be busy or not streaming\")\n",
|
||||
" elif e.error_code == mvsdk.CAMERA_STATUS_DEVICE_LOST:\n",
|
||||
" print(\" → Device lost - camera disconnected\")\n",
|
||||
" elif e.error_code == mvsdk.CAMERA_STATUS_BUSY:\n",
|
||||
" print(\" → Camera busy - may be used by another process\")\n",
|
||||
" \n",
|
||||
" capture_success = False\n",
|
||||
" \n",
|
||||
" # Cleanup\n",
|
||||
" mvsdk.CameraAlignFree(pFrameBuffer)\n",
|
||||
" print(\"✓ Cleanup completed\")\n",
|
||||
" \n",
|
||||
" return capture_success\n",
|
||||
" \n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"✗ Capture readiness test failed: {e}\")\n",
|
||||
" return False\n",
|
||||
"\n",
|
||||
"# Test capture readiness for available cameras\n",
|
||||
"available_cameras = [(cam, stat) for cam, stat in camera_results if stat == \"AVAILABLE\"]\n",
|
||||
"\n",
|
||||
"if available_cameras:\n",
|
||||
" print(f\"\\nTesting capture readiness for {len(available_cameras)} available camera(s):\")\n",
|
||||
" for i, (camera_handle, status) in enumerate(available_cameras):\n",
|
||||
" if hasattr(camera_handle, 'GetFriendlyName'):\n",
|
||||
" # This shouldn't happen for AVAILABLE cameras, but just in case\n",
|
||||
" print(f\"\\nCamera {i}: Invalid handle\")\n",
|
||||
" continue\n",
|
||||
" \n",
|
||||
" print(f\"\\nTesting camera {i} capture readiness...\")\n",
|
||||
" # Re-initialize the camera for testing since we closed it earlier\n",
|
||||
" try:\n",
|
||||
" # Find the camera info from the original results\n",
|
||||
" DevList = mvsdk.CameraEnumerateDevice()\n",
|
||||
" if i < len(DevList):\n",
|
||||
" DevInfo = DevList[i]\n",
|
||||
" hCamera = mvsdk.CameraInit(DevInfo, -1, -1)\n",
|
||||
" capture_ready = test_camera_capture_readiness(hCamera)\n",
|
||||
" print(f\"Capture Ready for {DevInfo.GetFriendlyName()}: {capture_ready}\")\n",
|
||||
" mvsdk.CameraUnInit(hCamera)\n",
|
||||
" else:\n",
|
||||
" print(f\"Could not re-initialize camera {i}\")\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"Error testing camera {i}: {e}\")\n",
|
||||
"else:\n",
|
||||
" print(\"\\nNo cameras are available for capture testing\")\n",
|
||||
" print(\"Camera statuses:\")\n",
|
||||
" for i, (cam_info, status) in enumerate(camera_results):\n",
|
||||
" if hasattr(cam_info, 'GetFriendlyName'):\n",
|
||||
" name = cam_info.GetFriendlyName()\n",
|
||||
" else:\n",
|
||||
" name = f\"Camera {i}\"\n",
|
||||
" print(f\" {name}: {status}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 50,
|
||||
"id": "comprehensive-check",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"==================================================\n",
|
||||
"COMPREHENSIVE CAMERA CHECK\n",
|
||||
"==================================================\n",
|
||||
"Camera Availability Check\n",
|
||||
"==============================\n",
|
||||
"✓ SDK initialized successfully\n",
|
||||
"✓ Found 2 camera(s)\n",
|
||||
" 0: Blower-Yield-Cam (NET-1000M-192.168.1.165)\n",
|
||||
" 1: Cracker-Cam (NET-1000M-192.168.1.167)\n",
|
||||
"\n",
|
||||
"Testing camera 0: Blower-Yield-Cam\n",
|
||||
"✓ Camera is available (not opened by another process)\n",
|
||||
"✓ Camera initialized successfully\n",
|
||||
"✓ Camera closed after testing\n",
|
||||
"\n",
|
||||
"Testing camera 1: Cracker-Cam\n",
|
||||
"✓ Camera is available (not opened by another process)\n",
|
||||
"✓ Camera initialized successfully\n",
|
||||
"✓ Camera closed after testing\n",
|
||||
"\n",
|
||||
"==================================================\n",
|
||||
"FINAL RESULTS:\n",
|
||||
"Camera Available: False\n",
|
||||
"Capture Ready: False\n",
|
||||
"Status: (34, 'AVAILABLE')\n",
|
||||
"==================================================\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def comprehensive_camera_check():\n",
|
||||
" \"\"\"\n",
|
||||
" Complete camera availability and readiness check\n",
|
||||
" Returns: (available, ready, handle_or_info, status_message)\n",
|
||||
" \"\"\"\n",
|
||||
" # Check availability\n",
|
||||
" handle_or_info, status = check_camera_availability()\n",
|
||||
" \n",
|
||||
" available = status == \"AVAILABLE\"\n",
|
||||
" ready = False\n",
|
||||
" \n",
|
||||
" if available:\n",
|
||||
" # Test capture readiness\n",
|
||||
" ready = test_camera_capture_readiness(handle_or_info)\n",
|
||||
" \n",
|
||||
" # Close camera after testing\n",
|
||||
" try:\n",
|
||||
" mvsdk.CameraUnInit(handle_or_info)\n",
|
||||
" print(\"✓ Camera closed after testing\")\n",
|
||||
" except:\n",
|
||||
" pass\n",
|
||||
" \n",
|
||||
" return available, ready, handle_or_info, status\n",
|
||||
"\n",
|
||||
"# Run comprehensive check\n",
|
||||
"print(\"\\n\" + \"=\" * 50)\n",
|
||||
"print(\"COMPREHENSIVE CAMERA CHECK\")\n",
|
||||
"print(\"=\" * 50)\n",
|
||||
"\n",
|
||||
"available, ready, info, status_msg = comprehensive_camera_check()\n",
|
||||
"\n",
|
||||
"print(\"\\n\" + \"=\" * 50)\n",
|
||||
"print(\"FINAL RESULTS:\")\n",
|
||||
"print(f\"Camera Available: {available}\")\n",
|
||||
"print(f\"Capture Ready: {ready}\")\n",
|
||||
"print(f\"Status: {status_msg}\")\n",
|
||||
"print(\"=\" * 50)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 51,
|
||||
"id": "status-check-function",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"Testing Simple Camera Ready Check:\n",
|
||||
"========================================\n",
|
||||
"Ready: True\n",
|
||||
"Message: Camera 'Blower-Yield-Cam' is ready for capture\n",
|
||||
"Camera: Blower-Yield-Cam\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def is_camera_ready_for_capture():\n",
|
||||
" \"\"\"\n",
|
||||
" Simple function to check if camera is ready for capture.\n",
|
||||
" Returns: (ready: bool, message: str, camera_info: object or None)\n",
|
||||
" \n",
|
||||
" This is the function you can use in your main capture script.\n",
|
||||
" \"\"\"\n",
|
||||
" try:\n",
|
||||
" # Initialize SDK\n",
|
||||
" mvsdk.CameraSdkInit(1)\n",
|
||||
" \n",
|
||||
" # Enumerate cameras\n",
|
||||
" DevList = mvsdk.CameraEnumerateDevice()\n",
|
||||
" if len(DevList) < 1:\n",
|
||||
" return False, \"No cameras found\", None\n",
|
||||
" \n",
|
||||
" DevInfo = DevList[0]\n",
|
||||
" \n",
|
||||
" # Check if already opened\n",
|
||||
" try:\n",
|
||||
" if mvsdk.CameraIsOpened(DevInfo):\n",
|
||||
" return False, f\"Camera '{DevInfo.GetFriendlyName()}' is already opened by another process\", DevInfo\n",
|
||||
" except:\n",
|
||||
" pass # Some cameras might not support this check\n",
|
||||
" \n",
|
||||
" # Try to initialize\n",
|
||||
" try:\n",
|
||||
" hCamera = mvsdk.CameraInit(DevInfo, -1, -1)\n",
|
||||
" \n",
|
||||
" # Quick capture test\n",
|
||||
" try:\n",
|
||||
" # Basic setup\n",
|
||||
" mvsdk.CameraSetTriggerMode(hCamera, 0)\n",
|
||||
" mvsdk.CameraPlay(hCamera)\n",
|
||||
" \n",
|
||||
" # Try to get one frame with short timeout\n",
|
||||
" pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 500) # 0.5 second timeout\n",
|
||||
" mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)\n",
|
||||
" \n",
|
||||
" # Success - close and return\n",
|
||||
" mvsdk.CameraUnInit(hCamera)\n",
|
||||
" return True, f\"Camera '{DevInfo.GetFriendlyName()}' is ready for capture\", DevInfo\n",
|
||||
" \n",
|
||||
" except mvsdk.CameraException as e:\n",
|
||||
" mvsdk.CameraUnInit(hCamera)\n",
|
||||
" if e.error_code == mvsdk.CAMERA_STATUS_TIME_OUT:\n",
|
||||
" return False, \"Camera timeout - may be busy or not streaming properly\", DevInfo\n",
|
||||
" else:\n",
|
||||
" return False, f\"Camera capture test failed: {e.message}\", DevInfo\n",
|
||||
" \n",
|
||||
" except mvsdk.CameraException as e:\n",
|
||||
" if e.error_code == mvsdk.CAMERA_STATUS_DEVICE_IS_OPENED:\n",
|
||||
" return False, f\"Camera '{DevInfo.GetFriendlyName()}' is already in use\", DevInfo\n",
|
||||
" elif e.error_code == mvsdk.CAMERA_STATUS_ACCESS_DENY:\n",
|
||||
" return False, f\"Access denied to camera '{DevInfo.GetFriendlyName()}'\", DevInfo\n",
|
||||
" else:\n",
|
||||
" return False, f\"Camera initialization failed: {e.message}\", DevInfo\n",
|
||||
" \n",
|
||||
" except Exception as e:\n",
|
||||
" return False, f\"Camera check failed: {str(e)}\", None\n",
|
||||
"\n",
|
||||
"# Test the simple function\n",
|
||||
"print(\"\\nTesting Simple Camera Ready Check:\")\n",
|
||||
"print(\"=\" * 40)\n",
|
||||
"\n",
|
||||
"ready, message, camera_info = is_camera_ready_for_capture()\n",
|
||||
"print(f\"Ready: {ready}\")\n",
|
||||
"print(f\"Message: {message}\")\n",
|
||||
"if camera_info:\n",
|
||||
" print(f\"Camera: {camera_info.GetFriendlyName()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "usage-example",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Usage Example\n",
|
||||
"\n",
|
||||
"Here's how you can integrate the camera status check into your capture script:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Before attempting to capture images\n",
|
||||
"ready, message, camera_info = is_camera_ready_for_capture()\n",
|
||||
"\n",
|
||||
"if not ready:\n",
|
||||
" print(f\"Camera not ready: {message}\")\n",
|
||||
" # Handle the error appropriately\n",
|
||||
" return False\n",
|
||||
"\n",
|
||||
"print(f\"Camera ready: {message}\")\n",
|
||||
"# Proceed with normal capture logic\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## Key Findings\n",
|
||||
"\n",
|
||||
"1. **`CameraIsOpened()`** - Checks if camera is opened by another process\n",
|
||||
"2. **`CameraInit()` error codes** - Provide specific failure reasons\n",
|
||||
"3. **Quick capture test** - Verifies camera is actually streaming\n",
|
||||
"4. **Timeout handling** - Detects if camera is busy/unresponsive\n",
|
||||
"\n",
|
||||
"The most reliable approach is to:\n",
|
||||
"1. Check if camera exists\n",
|
||||
"2. Check if it's already opened\n",
|
||||
"3. Try to initialize it\n",
|
||||
"4. Test actual image capture with short timeout\n",
|
||||
"5. Clean up properly"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "cc_pecan",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
439
camera_video_recorder.py
Normal file
439
camera_video_recorder.py
Normal file
@@ -0,0 +1,439 @@
|
||||
# coding=utf-8
|
||||
import cv2
|
||||
import numpy as np
|
||||
import platform
|
||||
import time
|
||||
import threading
|
||||
from datetime import datetime
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Add the python demo directory to path to import mvsdk
|
||||
sys.path.append("python demo")
|
||||
|
||||
import mvsdk
|
||||
|
||||
|
||||
class CameraVideoRecorder:
|
||||
def __init__(self):
|
||||
self.hCamera = 0
|
||||
self.pFrameBuffer = 0
|
||||
self.cap = None
|
||||
self.monoCamera = False
|
||||
self.recording = False
|
||||
self.video_writer = None
|
||||
self.frame_count = 0
|
||||
self.start_time = None
|
||||
|
||||
def list_cameras(self):
|
||||
"""List all available cameras"""
|
||||
try:
|
||||
# Initialize SDK
|
||||
mvsdk.CameraSdkInit(1)
|
||||
except Exception as e:
|
||||
print(f"SDK initialization failed: {e}")
|
||||
return []
|
||||
|
||||
# Enumerate cameras
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
|
||||
if nDev < 1:
|
||||
print("No cameras found!")
|
||||
return []
|
||||
|
||||
print(f"\nFound {nDev} camera(s):")
|
||||
cameras = []
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
camera_info = {"index": i, "name": DevInfo.GetFriendlyName(), "port_type": DevInfo.GetPortType(), "serial": DevInfo.GetSn(), "dev_info": DevInfo}
|
||||
cameras.append(camera_info)
|
||||
print(f"{i}: {camera_info['name']} ({camera_info['port_type']}) - SN: {camera_info['serial']}")
|
||||
|
||||
return cameras
|
||||
|
||||
def initialize_camera(self, dev_info, exposure_ms=1.0, gain=3.5, target_fps=3.0):
|
||||
"""Initialize camera with specified settings"""
|
||||
self.target_fps = target_fps
|
||||
try:
|
||||
# Initialize camera
|
||||
self.hCamera = mvsdk.CameraInit(dev_info, -1, -1)
|
||||
print(f"Camera initialized successfully")
|
||||
|
||||
# Get camera capabilities
|
||||
self.cap = mvsdk.CameraGetCapability(self.hCamera)
|
||||
self.monoCamera = self.cap.sIspCapacity.bMonoSensor != 0
|
||||
print(f"Camera type: {'Monochrome' if self.monoCamera else 'Color'}")
|
||||
|
||||
# Set output format
|
||||
if self.monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(self.hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(self.hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
|
||||
# Calculate RGB buffer size
|
||||
FrameBufferSize = self.cap.sResolutionRange.iWidthMax * self.cap.sResolutionRange.iHeightMax * (1 if self.monoCamera else 3)
|
||||
|
||||
# Allocate RGB buffer
|
||||
self.pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
# Set camera to continuous capture mode
|
||||
mvsdk.CameraSetTriggerMode(self.hCamera, 0)
|
||||
|
||||
# Set manual exposure
|
||||
mvsdk.CameraSetAeState(self.hCamera, 0) # Disable auto exposure
|
||||
exposure_time_us = exposure_ms * 1000 # Convert ms to microseconds
|
||||
|
||||
# Get exposure range and clamp value
|
||||
try:
|
||||
exp_min, exp_max, exp_step = mvsdk.CameraGetExposureTimeRange(self.hCamera)
|
||||
exposure_time_us = max(exp_min, min(exp_max, exposure_time_us))
|
||||
print(f"Exposure range: {exp_min:.1f} - {exp_max:.1f} μs")
|
||||
except Exception as e:
|
||||
print(f"Could not get exposure range: {e}")
|
||||
|
||||
mvsdk.CameraSetExposureTime(self.hCamera, exposure_time_us)
|
||||
print(f"Set exposure time: {exposure_time_us/1000:.1f}ms")
|
||||
|
||||
# Set analog gain
|
||||
try:
|
||||
gain_min, gain_max, gain_step = mvsdk.CameraGetAnalogGainXRange(self.hCamera)
|
||||
gain = max(gain_min, min(gain_max, gain))
|
||||
mvsdk.CameraSetAnalogGainX(self.hCamera, gain)
|
||||
print(f"Set analog gain: {gain:.2f}x (range: {gain_min:.2f} - {gain_max:.2f})")
|
||||
except Exception as e:
|
||||
print(f"Could not set analog gain: {e}")
|
||||
|
||||
# Start camera
|
||||
mvsdk.CameraPlay(self.hCamera)
|
||||
print("Camera started successfully")
|
||||
|
||||
return True
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
print(f"Camera initialization failed({e.error_code}): {e.message}")
|
||||
return False
|
||||
|
||||
def start_recording(self, output_filename=None):
|
||||
"""Start video recording"""
|
||||
if self.recording:
|
||||
print("Already recording!")
|
||||
return False
|
||||
|
||||
if not output_filename:
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_filename = f"video_{timestamp}.avi"
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(output_filename) if os.path.dirname(output_filename) else ".", exist_ok=True)
|
||||
|
||||
# Get first frame to determine video properties
|
||||
try:
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(self.hCamera, 2000)
|
||||
mvsdk.CameraImageProcess(self.hCamera, pRawData, self.pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
|
||||
|
||||
# Handle Windows frame flipping
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(self.pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# Convert to numpy array
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(self.pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
|
||||
if self.monoCamera:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth))
|
||||
# Convert mono to BGR for video writer
|
||||
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
|
||||
else:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 3))
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
print(f"Failed to get initial frame: {e.message}")
|
||||
return False
|
||||
|
||||
# Initialize video writer
|
||||
fourcc = cv2.VideoWriter_fourcc(*"XVID")
|
||||
fps = getattr(self, "target_fps", 3.0) # Use configured FPS or default to 3.0
|
||||
frame_size = (FrameHead.iWidth, FrameHead.iHeight)
|
||||
|
||||
self.video_writer = cv2.VideoWriter(output_filename, fourcc, fps, frame_size)
|
||||
|
||||
if not self.video_writer.isOpened():
|
||||
print(f"Failed to open video writer for {output_filename}")
|
||||
return False
|
||||
|
||||
self.recording = True
|
||||
self.frame_count = 0
|
||||
self.start_time = time.time()
|
||||
self.output_filename = output_filename
|
||||
|
||||
print(f"Started recording to: {output_filename}")
|
||||
print(f"Frame size: {frame_size}, FPS: {fps}")
|
||||
print("Press 'q' to stop recording...")
|
||||
|
||||
return True
|
||||
|
||||
def stop_recording(self):
|
||||
"""Stop video recording"""
|
||||
if not self.recording:
|
||||
print("Not currently recording!")
|
||||
return False
|
||||
|
||||
self.recording = False
|
||||
|
||||
if self.video_writer:
|
||||
self.video_writer.release()
|
||||
self.video_writer = None
|
||||
|
||||
duration = time.time() - self.start_time if self.start_time else 0
|
||||
avg_fps = self.frame_count / duration if duration > 0 else 0
|
||||
|
||||
print(f"\nRecording stopped!")
|
||||
print(f"Saved: {self.output_filename}")
|
||||
print(f"Frames recorded: {self.frame_count}")
|
||||
print(f"Duration: {duration:.1f} seconds")
|
||||
print(f"Average FPS: {avg_fps:.1f}")
|
||||
|
||||
return True
|
||||
|
||||
def record_loop(self):
|
||||
"""Main recording loop"""
|
||||
if not self.recording:
|
||||
return
|
||||
|
||||
print("Recording... Press 'q' in the preview window to stop")
|
||||
|
||||
while self.recording:
|
||||
try:
|
||||
# Get frame from camera
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(self.hCamera, 200)
|
||||
mvsdk.CameraImageProcess(self.hCamera, pRawData, self.pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
|
||||
|
||||
# Handle Windows frame flipping
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(self.pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# Convert to numpy array
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(self.pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
|
||||
if self.monoCamera:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth))
|
||||
frame_bgr = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
|
||||
else:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 3))
|
||||
frame_bgr = frame
|
||||
|
||||
# Write every frame to video (FPS is controlled by video file playback rate)
|
||||
if self.video_writer and self.recording:
|
||||
self.video_writer.write(frame_bgr)
|
||||
self.frame_count += 1
|
||||
|
||||
# Show preview (resized for display)
|
||||
display_frame = cv2.resize(frame_bgr, (640, 480), interpolation=cv2.INTER_LINEAR)
|
||||
|
||||
# Add small delay to control capture rate based on target FPS
|
||||
target_fps = getattr(self, "target_fps", 3.0)
|
||||
time.sleep(1.0 / target_fps)
|
||||
|
||||
# Add recording indicator
|
||||
cv2.putText(display_frame, f"REC - Frame: {self.frame_count}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
|
||||
|
||||
cv2.imshow("Camera Recording - Press 'q' to stop", display_frame)
|
||||
|
||||
# Check for quit key
|
||||
if cv2.waitKey(1) & 0xFF == ord("q"):
|
||||
self.stop_recording()
|
||||
break
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
if e.error_code != mvsdk.CAMERA_STATUS_TIME_OUT:
|
||||
print(f"Camera error: {e.message}")
|
||||
break
|
||||
|
||||
def cleanup(self):
|
||||
"""Clean up resources"""
|
||||
if self.recording:
|
||||
self.stop_recording()
|
||||
|
||||
if self.video_writer:
|
||||
self.video_writer.release()
|
||||
|
||||
if self.hCamera > 0:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
self.hCamera = 0
|
||||
|
||||
if self.pFrameBuffer:
|
||||
mvsdk.CameraAlignFree(self.pFrameBuffer)
|
||||
self.pFrameBuffer = 0
|
||||
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
|
||||
def interactive_menu():
|
||||
"""Interactive menu for camera operations"""
|
||||
recorder = CameraVideoRecorder()
|
||||
|
||||
try:
|
||||
# List available cameras
|
||||
cameras = recorder.list_cameras()
|
||||
if not cameras:
|
||||
return
|
||||
|
||||
# Select camera
|
||||
if len(cameras) == 1:
|
||||
selected_camera = cameras[0]
|
||||
print(f"\nUsing camera: {selected_camera['name']}")
|
||||
else:
|
||||
while True:
|
||||
try:
|
||||
choice = int(input(f"\nSelect camera (0-{len(cameras)-1}): "))
|
||||
if 0 <= choice < len(cameras):
|
||||
selected_camera = cameras[choice]
|
||||
break
|
||||
else:
|
||||
print("Invalid selection!")
|
||||
except ValueError:
|
||||
print("Please enter a valid number!")
|
||||
|
||||
# Get camera settings from user
|
||||
print(f"\nCamera Settings:")
|
||||
try:
|
||||
exposure = float(input("Enter exposure time in ms (default 1.0): ") or "1.0")
|
||||
gain = float(input("Enter gain value (default 3.5): ") or "3.5")
|
||||
fps = float(input("Enter target FPS (default 3.0): ") or "3.0")
|
||||
except ValueError:
|
||||
print("Using default values: exposure=1.0ms, gain=3.5x, fps=3.0")
|
||||
exposure, gain, fps = 1.0, 3.5, 3.0
|
||||
|
||||
# Initialize camera with specified settings
|
||||
print(f"\nInitializing camera with:")
|
||||
print(f"- Exposure: {exposure}ms")
|
||||
print(f"- Gain: {gain}x")
|
||||
print(f"- Target FPS: {fps}")
|
||||
|
||||
if not recorder.initialize_camera(selected_camera["dev_info"], exposure_ms=exposure, gain=gain, target_fps=fps):
|
||||
return
|
||||
|
||||
# Menu loop
|
||||
while True:
|
||||
print(f"\n{'='*50}")
|
||||
print("Camera Video Recorder Menu")
|
||||
print(f"{'='*50}")
|
||||
print("1. Start Recording")
|
||||
print("2. List Camera Info")
|
||||
print("3. Test Camera (Live Preview)")
|
||||
print("4. Exit")
|
||||
|
||||
try:
|
||||
choice = input("\nSelect option (1-4): ").strip()
|
||||
|
||||
if choice == "1":
|
||||
# Start recording
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_file = f"videos/camera_recording_{timestamp}.avi"
|
||||
|
||||
# Create videos directory
|
||||
os.makedirs("videos", exist_ok=True)
|
||||
|
||||
if recorder.start_recording(output_file):
|
||||
recorder.record_loop()
|
||||
|
||||
elif choice == "2":
|
||||
# Show camera info
|
||||
print(f"\nCamera Information:")
|
||||
print(f"Name: {selected_camera['name']}")
|
||||
print(f"Port Type: {selected_camera['port_type']}")
|
||||
print(f"Serial Number: {selected_camera['serial']}")
|
||||
print(f"Type: {'Monochrome' if recorder.monoCamera else 'Color'}")
|
||||
|
||||
elif choice == "3":
|
||||
# Live preview
|
||||
print("\nLive Preview - Press 'q' to stop")
|
||||
preview_loop(recorder)
|
||||
|
||||
elif choice == "4":
|
||||
print("Exiting...")
|
||||
break
|
||||
|
||||
else:
|
||||
print("Invalid option! Please select 1-4.")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nReturning to menu...")
|
||||
continue
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nInterrupted by user")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
recorder.cleanup()
|
||||
print("Cleanup completed")
|
||||
|
||||
|
||||
def preview_loop(recorder):
|
||||
"""Live preview without recording"""
|
||||
print("Live preview mode - Press 'q' to return to menu")
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Get frame from camera
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(recorder.hCamera, 200)
|
||||
mvsdk.CameraImageProcess(recorder.hCamera, pRawData, recorder.pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(recorder.hCamera, pRawData)
|
||||
|
||||
# Handle Windows frame flipping
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(recorder.pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# Convert to numpy array
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(recorder.pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
|
||||
if recorder.monoCamera:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth))
|
||||
frame_bgr = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
|
||||
else:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 3))
|
||||
frame_bgr = frame
|
||||
|
||||
# Show preview (resized for display)
|
||||
display_frame = cv2.resize(frame_bgr, (640, 480), interpolation=cv2.INTER_LINEAR)
|
||||
|
||||
# Add info overlay
|
||||
cv2.putText(display_frame, f"PREVIEW - {FrameHead.iWidth}x{FrameHead.iHeight}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
||||
cv2.putText(display_frame, "Press 'q' to return to menu", (10, display_frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
||||
|
||||
cv2.imshow("Camera Preview", display_frame)
|
||||
|
||||
# Check for quit key
|
||||
if cv2.waitKey(1) & 0xFF == ord("q"):
|
||||
cv2.destroyWindow("Camera Preview")
|
||||
break
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
if e.error_code != mvsdk.CAMERA_STATUS_TIME_OUT:
|
||||
print(f"Camera error: {e.message}")
|
||||
break
|
||||
|
||||
|
||||
def main():
|
||||
print("Camera Video Recorder")
|
||||
print("====================")
|
||||
print("This script allows you to:")
|
||||
print("- List all available cameras")
|
||||
print("- Record videos with custom exposure (1ms), gain (3.5x), and FPS (3.0) settings")
|
||||
print("- Save videos with timestamps")
|
||||
print("- Stop recording anytime with 'q' key")
|
||||
print()
|
||||
|
||||
interactive_menu()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
426
exposure test.ipynb
Normal file
426
exposure test.ipynb
Normal file
@@ -0,0 +1,426 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"id": "ba958c88",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# coding=utf-8\n",
|
||||
"\"\"\"\n",
|
||||
"Test script to help find optimal exposure settings for your GigE camera.\n",
|
||||
"This script captures a single test image with different exposure settings.\n",
|
||||
"\"\"\"\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"sys.path.append(\"./python demo\")\n",
|
||||
"import os\n",
|
||||
"import mvsdk\n",
|
||||
"import numpy as np\n",
|
||||
"import cv2\n",
|
||||
"import platform\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# Add the python demo directory to path\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"id": "23f1dc49",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def test_exposure_settings():\n",
|
||||
" \"\"\"\n",
|
||||
" Test different exposure settings to find optimal values\n",
|
||||
" \"\"\"\n",
|
||||
" # Initialize SDK\n",
|
||||
" try:\n",
|
||||
" mvsdk.CameraSdkInit(1)\n",
|
||||
" print(\"SDK initialized successfully\")\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"SDK initialization failed: {e}\")\n",
|
||||
" return False\n",
|
||||
"\n",
|
||||
" # Enumerate cameras\n",
|
||||
" DevList = mvsdk.CameraEnumerateDevice()\n",
|
||||
" nDev = len(DevList)\n",
|
||||
"\n",
|
||||
" if nDev < 1:\n",
|
||||
" print(\"No camera was found!\")\n",
|
||||
" return False\n",
|
||||
"\n",
|
||||
" print(f\"Found {nDev} camera(s):\")\n",
|
||||
" for i, DevInfo in enumerate(DevList):\n",
|
||||
" print(f\" {i}: {DevInfo.GetFriendlyName()} ({DevInfo.GetPortType()})\")\n",
|
||||
"\n",
|
||||
" # Use first camera\n",
|
||||
" DevInfo = DevList[0]\n",
|
||||
" print(f\"\\nSelected camera: {DevInfo.GetFriendlyName()}\")\n",
|
||||
"\n",
|
||||
" # Initialize camera\n",
|
||||
" try:\n",
|
||||
" hCamera = mvsdk.CameraInit(DevInfo, -1, -1)\n",
|
||||
" print(\"Camera initialized successfully\")\n",
|
||||
" except mvsdk.CameraException as e:\n",
|
||||
" print(f\"CameraInit Failed({e.error_code}): {e.message}\")\n",
|
||||
" return False\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" # Get camera capabilities\n",
|
||||
" cap = mvsdk.CameraGetCapability(hCamera)\n",
|
||||
" monoCamera = cap.sIspCapacity.bMonoSensor != 0\n",
|
||||
" print(f\"Camera type: {'Monochrome' if monoCamera else 'Color'}\")\n",
|
||||
"\n",
|
||||
" # Get camera ranges\n",
|
||||
" try:\n",
|
||||
" exp_min, exp_max, exp_step = mvsdk.CameraGetExposureTimeRange(hCamera)\n",
|
||||
" print(f\"Exposure time range: {exp_min:.1f} - {exp_max:.1f} μs\")\n",
|
||||
"\n",
|
||||
" gain_min, gain_max, gain_step = mvsdk.CameraGetAnalogGainXRange(hCamera)\n",
|
||||
" print(f\"Analog gain range: {gain_min:.2f} - {gain_max:.2f}x\")\n",
|
||||
"\n",
|
||||
" print(\"whatever this is: \", mvsdk.CameraGetAnalogGainXRange(hCamera))\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"Could not get camera ranges: {e}\")\n",
|
||||
" exp_min, exp_max = 100, 100000\n",
|
||||
" gain_min, gain_max = 1.0, 4.0\n",
|
||||
"\n",
|
||||
" # Set output format\n",
|
||||
" if monoCamera:\n",
|
||||
" mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)\n",
|
||||
" else:\n",
|
||||
" mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)\n",
|
||||
"\n",
|
||||
" # Set camera to continuous capture mode\n",
|
||||
" mvsdk.CameraSetTriggerMode(hCamera, 0)\n",
|
||||
" mvsdk.CameraSetAeState(hCamera, 0) # Disable auto exposure\n",
|
||||
"\n",
|
||||
" # Start camera\n",
|
||||
" mvsdk.CameraPlay(hCamera)\n",
|
||||
"\n",
|
||||
" # Allocate frame buffer\n",
|
||||
" FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)\n",
|
||||
" pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)\n",
|
||||
"\n",
|
||||
" # Create test directory\n",
|
||||
" if not os.path.exists(\"exposure_tests\"):\n",
|
||||
" os.makedirs(\"exposure_tests\")\n",
|
||||
"\n",
|
||||
" print(\"\\nTesting different exposure settings...\")\n",
|
||||
" print(\"=\" * 50)\n",
|
||||
"\n",
|
||||
" # Test different exposure times (in microseconds)\n",
|
||||
" exposure_times = [100, 200, 500, 1000, 2000, 5000, 10000, 20000] # 0.5ms to 20ms\n",
|
||||
" analog_gains = [2.5, 5.0, 10.0, 16.0] # Start with 1x gain\n",
|
||||
"\n",
|
||||
" test_count = 0\n",
|
||||
" for exp_time in exposure_times:\n",
|
||||
" for gain in analog_gains:\n",
|
||||
" # Clamp values to valid ranges\n",
|
||||
" exp_time = max(exp_min, min(exp_max, exp_time))\n",
|
||||
" gain = max(gain_min, min(gain_max, gain))\n",
|
||||
"\n",
|
||||
" print(f\"\\nTest {test_count + 1}: Exposure={exp_time/1000:.1f}ms, Gain={gain:.1f}x\")\n",
|
||||
"\n",
|
||||
" # Set camera parameters\n",
|
||||
" mvsdk.CameraSetExposureTime(hCamera, exp_time)\n",
|
||||
" try:\n",
|
||||
" mvsdk.CameraSetAnalogGainX(hCamera, gain)\n",
|
||||
" except:\n",
|
||||
" pass # Some cameras might not support this\n",
|
||||
"\n",
|
||||
" # Wait a moment for settings to take effect\n",
|
||||
" import time\n",
|
||||
"\n",
|
||||
" time.sleep(0.1)\n",
|
||||
"\n",
|
||||
" # Capture image\n",
|
||||
" try:\n",
|
||||
" pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 2000)\n",
|
||||
" mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)\n",
|
||||
" mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)\n",
|
||||
"\n",
|
||||
" # Handle Windows image flip\n",
|
||||
" if platform.system() == \"Windows\":\n",
|
||||
" mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)\n",
|
||||
"\n",
|
||||
" # Convert to numpy array\n",
|
||||
" frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)\n",
|
||||
" frame = np.frombuffer(frame_data, dtype=np.uint8)\n",
|
||||
"\n",
|
||||
" if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8:\n",
|
||||
" frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth))\n",
|
||||
" else:\n",
|
||||
" frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 3))\n",
|
||||
"\n",
|
||||
" # Calculate image statistics\n",
|
||||
" mean_brightness = np.mean(frame)\n",
|
||||
" max_brightness = np.max(frame)\n",
|
||||
"\n",
|
||||
" # Save image\n",
|
||||
" filename = f\"exposure_tests/test_{test_count+1:02d}_exp{exp_time/1000:.1f}ms_gain{gain:.1f}x.jpg\"\n",
|
||||
" cv2.imwrite(filename, frame)\n",
|
||||
"\n",
|
||||
" # Provide feedback\n",
|
||||
" status = \"\"\n",
|
||||
" if mean_brightness < 50:\n",
|
||||
" status = \"TOO DARK\"\n",
|
||||
" elif mean_brightness > 200:\n",
|
||||
" status = \"TOO BRIGHT\"\n",
|
||||
" elif max_brightness >= 255:\n",
|
||||
" status = \"OVEREXPOSED\"\n",
|
||||
" else:\n",
|
||||
" status = \"GOOD\"\n",
|
||||
"\n",
|
||||
" print(f\" → Saved: {filename}\")\n",
|
||||
" print(f\" → Brightness: mean={mean_brightness:.1f}, max={max_brightness:.1f} [{status}]\")\n",
|
||||
"\n",
|
||||
" test_count += 1\n",
|
||||
"\n",
|
||||
" except mvsdk.CameraException as e:\n",
|
||||
" print(f\" → Failed to capture: {e.message}\")\n",
|
||||
"\n",
|
||||
" print(f\"\\nCompleted {test_count} test captures!\")\n",
|
||||
" print(\"Check the 'exposure_tests' directory to see the results.\")\n",
|
||||
" print(\"\\nRecommendations:\")\n",
|
||||
" print(\"- Look for images marked as 'GOOD' - these have optimal exposure\")\n",
|
||||
" print(\"- If all images are 'TOO BRIGHT', try lower exposure times or gains\")\n",
|
||||
" print(\"- If all images are 'TOO DARK', try higher exposure times or gains\")\n",
|
||||
" print(\"- Avoid 'OVEREXPOSED' images as they have clipped highlights\")\n",
|
||||
"\n",
|
||||
" # Cleanup\n",
|
||||
" mvsdk.CameraAlignFree(pFrameBuffer)\n",
|
||||
"\n",
|
||||
" finally:\n",
|
||||
" # Close camera\n",
|
||||
" mvsdk.CameraUnInit(hCamera)\n",
|
||||
" print(\"\\nCamera closed\")\n",
|
||||
"\n",
|
||||
" return True"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 27,
|
||||
"id": "2891b5bf",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GigE Camera Exposure Test Script\n",
|
||||
"========================================\n",
|
||||
"This script will test different exposure settings and save sample images.\n",
|
||||
"Use this to find the optimal settings for your lighting conditions.\n",
|
||||
"\n",
|
||||
"SDK initialized successfully\n",
|
||||
"Found 2 camera(s):\n",
|
||||
" 0: Blower-Yield-Cam (NET-100M-192.168.1.204)\n",
|
||||
" 1: Cracker-Cam (NET-1000M-192.168.1.246)\n",
|
||||
"\n",
|
||||
"Selected camera: Blower-Yield-Cam\n",
|
||||
"Camera initialized successfully\n",
|
||||
"Camera type: Color\n",
|
||||
"Exposure time range: 8.0 - 1048568.0 μs\n",
|
||||
"Analog gain range: 2.50 - 16.50x\n",
|
||||
"whatever this is: (2.5, 16.5, 0.5)\n",
|
||||
"\n",
|
||||
"Testing different exposure settings...\n",
|
||||
"==================================================\n",
|
||||
"\n",
|
||||
"Test 1: Exposure=0.1ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_01_exp0.1ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=94.1, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 2: Exposure=0.1ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_02_exp0.1ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=13.7, max=173.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 3: Exposure=0.1ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_03_exp0.1ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=14.1, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 4: Exposure=0.1ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_04_exp0.1ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=18.2, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 5: Exposure=0.2ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_05_exp0.2ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=22.1, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 6: Exposure=0.2ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_06_exp0.2ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=19.5, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 7: Exposure=0.2ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_07_exp0.2ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=25.3, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 8: Exposure=0.2ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_08_exp0.2ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=36.6, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 9: Exposure=0.5ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_09_exp0.5ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=55.8, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 10: Exposure=0.5ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_10_exp0.5ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=38.5, max=255.0 [TOO DARK]\n",
|
||||
"\n",
|
||||
"Test 11: Exposure=0.5ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_11_exp0.5ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=60.2, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 12: Exposure=0.5ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_12_exp0.5ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=99.3, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 13: Exposure=1.0ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_13_exp1.0ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=121.1, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 14: Exposure=1.0ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_14_exp1.0ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=68.8, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 15: Exposure=1.0ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_15_exp1.0ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=109.6, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 16: Exposure=1.0ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_16_exp1.0ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=148.7, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 17: Exposure=2.0ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_17_exp2.0ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=171.9, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 18: Exposure=2.0ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_18_exp2.0ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=117.9, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 19: Exposure=2.0ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_19_exp2.0ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=159.0, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 20: Exposure=2.0ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_20_exp2.0ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=195.7, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 21: Exposure=5.0ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_21_exp5.0ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=214.6, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 22: Exposure=5.0ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_22_exp5.0ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=180.2, max=255.0 [OVEREXPOSED]\n",
|
||||
"\n",
|
||||
"Test 23: Exposure=5.0ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_23_exp5.0ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=214.6, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 24: Exposure=5.0ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_24_exp5.0ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=239.6, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 25: Exposure=10.0ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_25_exp10.0ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=247.5, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 26: Exposure=10.0ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_26_exp10.0ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=252.4, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 27: Exposure=10.0ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_27_exp10.0ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=218.9, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 28: Exposure=10.0ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_28_exp10.0ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=250.8, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 29: Exposure=20.0ms, Gain=2.5x\n",
|
||||
" → Saved: exposure_tests/test_29_exp20.0ms_gain2.5x.jpg\n",
|
||||
" → Brightness: mean=252.4, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 30: Exposure=20.0ms, Gain=5.0x\n",
|
||||
" → Saved: exposure_tests/test_30_exp20.0ms_gain5.0x.jpg\n",
|
||||
" → Brightness: mean=244.4, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 31: Exposure=20.0ms, Gain=10.0x\n",
|
||||
" → Saved: exposure_tests/test_31_exp20.0ms_gain10.0x.jpg\n",
|
||||
" → Brightness: mean=251.5, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Test 32: Exposure=20.0ms, Gain=16.0x\n",
|
||||
" → Saved: exposure_tests/test_32_exp20.0ms_gain16.0x.jpg\n",
|
||||
" → Brightness: mean=253.4, max=255.0 [TOO BRIGHT]\n",
|
||||
"\n",
|
||||
"Completed 32 test captures!\n",
|
||||
"Check the 'exposure_tests' directory to see the results.\n",
|
||||
"\n",
|
||||
"Recommendations:\n",
|
||||
"- Look for images marked as 'GOOD' - these have optimal exposure\n",
|
||||
"- If all images are 'TOO BRIGHT', try lower exposure times or gains\n",
|
||||
"- If all images are 'TOO DARK', try higher exposure times or gains\n",
|
||||
"- Avoid 'OVEREXPOSED' images as they have clipped highlights\n",
|
||||
"\n",
|
||||
"Camera closed\n",
|
||||
"\n",
|
||||
"Testing completed successfully!\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == \"__main__\":\n",
|
||||
" print(\"GigE Camera Exposure Test Script\")\n",
|
||||
" print(\"=\" * 40)\n",
|
||||
" print(\"This script will test different exposure settings and save sample images.\")\n",
|
||||
" print(\"Use this to find the optimal settings for your lighting conditions.\")\n",
|
||||
" print()\n",
|
||||
"\n",
|
||||
" success = test_exposure_settings()\n",
|
||||
"\n",
|
||||
" if success:\n",
|
||||
" print(\"\\nTesting completed successfully!\")\n",
|
||||
" else:\n",
|
||||
" print(\"\\nTesting failed!\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ead8d889",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "cc_pecan",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
BIN
python demo/__pycache__/mvsdk.cpython-313.pyc
Normal file
BIN
python demo/__pycache__/mvsdk.cpython-313.pyc
Normal file
Binary file not shown.
95
python demo/cv_grab.py
Normal file
95
python demo/cv_grab.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#coding=utf-8
|
||||
import cv2
|
||||
import numpy as np
|
||||
import mvsdk
|
||||
import platform
|
||||
|
||||
def main_loop():
|
||||
# 枚举相机
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
if nDev < 1:
|
||||
print("No camera was found!")
|
||||
return
|
||||
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
print("{}: {} {}".format(i, DevInfo.GetFriendlyName(), DevInfo.GetPortType()))
|
||||
i = 0 if nDev == 1 else int(input("Select camera: "))
|
||||
DevInfo = DevList[i]
|
||||
print(DevInfo)
|
||||
|
||||
# 打开相机
|
||||
hCamera = 0
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
|
||||
except mvsdk.CameraException as e:
|
||||
print("CameraInit Failed({}): {}".format(e.error_code, e.message) )
|
||||
return
|
||||
|
||||
# 获取相机特性描述
|
||||
cap = mvsdk.CameraGetCapability(hCamera)
|
||||
|
||||
# 判断是黑白相机还是彩色相机
|
||||
monoCamera = (cap.sIspCapacity.bMonoSensor != 0)
|
||||
|
||||
# 黑白相机让ISP直接输出MONO数据,而不是扩展成R=G=B的24位灰度
|
||||
if monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
|
||||
# 相机模式切换成连续采集
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
|
||||
# 手动曝光,曝光时间30ms
|
||||
mvsdk.CameraSetAeState(hCamera, 0)
|
||||
mvsdk.CameraSetExposureTime(hCamera, 30 * 1000)
|
||||
|
||||
# 让SDK内部取图线程开始工作
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
|
||||
# 计算RGB buffer所需的大小,这里直接按照相机的最大分辨率来分配
|
||||
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
|
||||
|
||||
# 分配RGB buffer,用来存放ISP输出的图像
|
||||
# 备注:从相机传输到PC端的是RAW数据,在PC端通过软件ISP转为RGB数据(如果是黑白相机就不需要转换格式,但是ISP还有其它处理,所以也需要分配这个buffer)
|
||||
pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
while (cv2.waitKey(1) & 0xFF) != ord('q'):
|
||||
# 从相机取一帧图片
|
||||
try:
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 200)
|
||||
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# windows下取到的图像数据是上下颠倒的,以BMP格式存放。转换成opencv则需要上下翻转成正的
|
||||
# linux下直接输出正的,不需要上下翻转
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# 此时图片已经存储在pFrameBuffer中,对于彩色相机pFrameBuffer=RGB数据,黑白相机pFrameBuffer=8位灰度数据
|
||||
# 把pFrameBuffer转换成opencv的图像格式以进行后续算法处理
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 1 if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8 else 3) )
|
||||
|
||||
frame = cv2.resize(frame, (640,480), interpolation = cv2.INTER_LINEAR)
|
||||
cv2.imshow("Press q to end", frame)
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
if e.error_code != mvsdk.CAMERA_STATUS_TIME_OUT:
|
||||
print("CameraGetImageBuffer failed({}): {}".format(e.error_code, e.message) )
|
||||
|
||||
# 关闭相机
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
|
||||
# 释放帧缓存
|
||||
mvsdk.CameraAlignFree(pFrameBuffer)
|
||||
|
||||
def main():
|
||||
try:
|
||||
main_loop()
|
||||
finally:
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
main()
|
||||
127
python demo/cv_grab2.py
Normal file
127
python demo/cv_grab2.py
Normal file
@@ -0,0 +1,127 @@
|
||||
#coding=utf-8
|
||||
import cv2
|
||||
import numpy as np
|
||||
import mvsdk
|
||||
import platform
|
||||
|
||||
class Camera(object):
|
||||
def __init__(self, DevInfo):
|
||||
super(Camera, self).__init__()
|
||||
self.DevInfo = DevInfo
|
||||
self.hCamera = 0
|
||||
self.cap = None
|
||||
self.pFrameBuffer = 0
|
||||
|
||||
def open(self):
|
||||
if self.hCamera > 0:
|
||||
return True
|
||||
|
||||
# 打开相机
|
||||
hCamera = 0
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(self.DevInfo, -1, -1)
|
||||
except mvsdk.CameraException as e:
|
||||
print("CameraInit Failed({}): {}".format(e.error_code, e.message) )
|
||||
return False
|
||||
|
||||
# 获取相机特性描述
|
||||
cap = mvsdk.CameraGetCapability(hCamera)
|
||||
|
||||
# 判断是黑白相机还是彩色相机
|
||||
monoCamera = (cap.sIspCapacity.bMonoSensor != 0)
|
||||
|
||||
# 黑白相机让ISP直接输出MONO数据,而不是扩展成R=G=B的24位灰度
|
||||
if monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
|
||||
# 计算RGB buffer所需的大小,这里直接按照相机的最大分辨率来分配
|
||||
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
|
||||
|
||||
# 分配RGB buffer,用来存放ISP输出的图像
|
||||
# 备注:从相机传输到PC端的是RAW数据,在PC端通过软件ISP转为RGB数据(如果是黑白相机就不需要转换格式,但是ISP还有其它处理,所以也需要分配这个buffer)
|
||||
pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
# 相机模式切换成连续采集
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
|
||||
# 手动曝光,曝光时间30ms
|
||||
mvsdk.CameraSetAeState(hCamera, 0)
|
||||
mvsdk.CameraSetExposureTime(hCamera, 30 * 1000)
|
||||
|
||||
# 让SDK内部取图线程开始工作
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
|
||||
self.hCamera = hCamera
|
||||
self.pFrameBuffer = pFrameBuffer
|
||||
self.cap = cap
|
||||
return True
|
||||
|
||||
def close(self):
|
||||
if self.hCamera > 0:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
self.hCamera = 0
|
||||
|
||||
mvsdk.CameraAlignFree(self.pFrameBuffer)
|
||||
self.pFrameBuffer = 0
|
||||
|
||||
def grab(self):
|
||||
# 从相机取一帧图片
|
||||
hCamera = self.hCamera
|
||||
pFrameBuffer = self.pFrameBuffer
|
||||
try:
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 200)
|
||||
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# windows下取到的图像数据是上下颠倒的,以BMP格式存放。转换成opencv则需要上下翻转成正的
|
||||
# linux下直接输出正的,不需要上下翻转
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# 此时图片已经存储在pFrameBuffer中,对于彩色相机pFrameBuffer=RGB数据,黑白相机pFrameBuffer=8位灰度数据
|
||||
# 把pFrameBuffer转换成opencv的图像格式以进行后续算法处理
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 1 if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8 else 3) )
|
||||
return frame
|
||||
except mvsdk.CameraException as e:
|
||||
if e.error_code != mvsdk.CAMERA_STATUS_TIME_OUT:
|
||||
print("CameraGetImageBuffer failed({}): {}".format(e.error_code, e.message) )
|
||||
return None
|
||||
|
||||
def main_loop():
|
||||
# 枚举相机
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
if nDev < 1:
|
||||
print("No camera was found!")
|
||||
return
|
||||
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
print("{}: {} {}".format(i, DevInfo.GetFriendlyName(), DevInfo.GetPortType()))
|
||||
|
||||
cams = []
|
||||
for i in map(lambda x: int(x), raw_input("Select cameras: ").split()):
|
||||
cam = Camera(DevList[i])
|
||||
if cam.open():
|
||||
cams.append(cam)
|
||||
|
||||
while (cv2.waitKey(1) & 0xFF) != ord('q'):
|
||||
for cam in cams:
|
||||
frame = cam.grab()
|
||||
if frame is not None:
|
||||
frame = cv2.resize(frame, (640,480), interpolation = cv2.INTER_LINEAR)
|
||||
cv2.imshow("{} Press q to end".format(cam.DevInfo.GetFriendlyName()), frame)
|
||||
|
||||
for cam in cams:
|
||||
cam.close()
|
||||
|
||||
def main():
|
||||
try:
|
||||
main_loop()
|
||||
finally:
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
main()
|
||||
110
python demo/cv_grab_callback.py
Normal file
110
python demo/cv_grab_callback.py
Normal file
@@ -0,0 +1,110 @@
|
||||
#coding=utf-8
|
||||
import cv2
|
||||
import numpy as np
|
||||
import mvsdk
|
||||
import time
|
||||
import platform
|
||||
|
||||
class App(object):
|
||||
def __init__(self):
|
||||
super(App, self).__init__()
|
||||
self.pFrameBuffer = 0
|
||||
self.quit = False
|
||||
|
||||
def main(self):
|
||||
# 枚举相机
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
if nDev < 1:
|
||||
print("No camera was found!")
|
||||
return
|
||||
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
print("{}: {} {}".format(i, DevInfo.GetFriendlyName(), DevInfo.GetPortType()))
|
||||
i = 0 if nDev == 1 else int(input("Select camera: "))
|
||||
DevInfo = DevList[i]
|
||||
print(DevInfo)
|
||||
|
||||
# 打开相机
|
||||
hCamera = 0
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
|
||||
except mvsdk.CameraException as e:
|
||||
print("CameraInit Failed({}): {}".format(e.error_code, e.message) )
|
||||
return
|
||||
|
||||
# 获取相机特性描述
|
||||
cap = mvsdk.CameraGetCapability(hCamera)
|
||||
|
||||
# 判断是黑白相机还是彩色相机
|
||||
monoCamera = (cap.sIspCapacity.bMonoSensor != 0)
|
||||
|
||||
# 黑白相机让ISP直接输出MONO数据,而不是扩展成R=G=B的24位灰度
|
||||
if monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
|
||||
# 相机模式切换成连续采集
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
|
||||
# 手动曝光,曝光时间30ms
|
||||
mvsdk.CameraSetAeState(hCamera, 0)
|
||||
mvsdk.CameraSetExposureTime(hCamera, 30 * 1000)
|
||||
|
||||
# 让SDK内部取图线程开始工作
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
|
||||
# 计算RGB buffer所需的大小,这里直接按照相机的最大分辨率来分配
|
||||
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
|
||||
|
||||
# 分配RGB buffer,用来存放ISP输出的图像
|
||||
# 备注:从相机传输到PC端的是RAW数据,在PC端通过软件ISP转为RGB数据(如果是黑白相机就不需要转换格式,但是ISP还有其它处理,所以也需要分配这个buffer)
|
||||
self.pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
# 设置采集回调函数
|
||||
self.quit = False
|
||||
mvsdk.CameraSetCallbackFunction(hCamera, self.GrabCallback, 0)
|
||||
|
||||
# 等待退出
|
||||
while not self.quit:
|
||||
time.sleep(0.1)
|
||||
|
||||
# 关闭相机
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
|
||||
# 释放帧缓存
|
||||
mvsdk.CameraAlignFree(self.pFrameBuffer)
|
||||
|
||||
@mvsdk.method(mvsdk.CAMERA_SNAP_PROC)
|
||||
def GrabCallback(self, hCamera, pRawData, pFrameHead, pContext):
|
||||
FrameHead = pFrameHead[0]
|
||||
pFrameBuffer = self.pFrameBuffer
|
||||
|
||||
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# windows下取到的图像数据是上下颠倒的,以BMP格式存放。转换成opencv则需要上下翻转成正的
|
||||
# linux下直接输出正的,不需要上下翻转
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# 此时图片已经存储在pFrameBuffer中,对于彩色相机pFrameBuffer=RGB数据,黑白相机pFrameBuffer=8位灰度数据
|
||||
# 把pFrameBuffer转换成opencv的图像格式以进行后续算法处理
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 1 if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8 else 3) )
|
||||
|
||||
frame = cv2.resize(frame, (640,480), interpolation = cv2.INTER_LINEAR)
|
||||
cv2.imshow("Press q to end", frame)
|
||||
if (cv2.waitKey(1) & 0xFF) == ord('q'):
|
||||
self.quit = True
|
||||
|
||||
def main():
|
||||
try:
|
||||
app = App()
|
||||
app.main()
|
||||
finally:
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
main()
|
||||
111
python demo/grab.py
Normal file
111
python demo/grab.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#coding=utf-8
|
||||
import mvsdk
|
||||
|
||||
def main():
|
||||
# 枚举相机
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
if nDev < 1:
|
||||
print("No camera was found!")
|
||||
return
|
||||
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
print("{}: {} {}".format(i, DevInfo.GetFriendlyName(), DevInfo.GetPortType()))
|
||||
i = 0 if nDev == 1 else int(input("Select camera: "))
|
||||
DevInfo = DevList[i]
|
||||
print(DevInfo)
|
||||
|
||||
# 打开相机
|
||||
hCamera = 0
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
|
||||
except mvsdk.CameraException as e:
|
||||
print("CameraInit Failed({}): {}".format(e.error_code, e.message) )
|
||||
return
|
||||
|
||||
# 获取相机特性描述
|
||||
cap = mvsdk.CameraGetCapability(hCamera)
|
||||
PrintCapbility(cap)
|
||||
|
||||
# 判断是黑白相机还是彩色相机
|
||||
monoCamera = (cap.sIspCapacity.bMonoSensor != 0)
|
||||
|
||||
# 黑白相机让ISP直接输出MONO数据,而不是扩展成R=G=B的24位灰度
|
||||
if monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
|
||||
# 相机模式切换成连续采集
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
|
||||
# 手动曝光,曝光时间30ms
|
||||
mvsdk.CameraSetAeState(hCamera, 0)
|
||||
mvsdk.CameraSetExposureTime(hCamera, 30 * 1000)
|
||||
|
||||
# 让SDK内部取图线程开始工作
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
|
||||
# 计算RGB buffer所需的大小,这里直接按照相机的最大分辨率来分配
|
||||
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
|
||||
|
||||
# 分配RGB buffer,用来存放ISP输出的图像
|
||||
# 备注:从相机传输到PC端的是RAW数据,在PC端通过软件ISP转为RGB数据(如果是黑白相机就不需要转换格式,但是ISP还有其它处理,所以也需要分配这个buffer)
|
||||
pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
# 从相机取一帧图片
|
||||
try:
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 2000)
|
||||
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# 此时图片已经存储在pFrameBuffer中,对于彩色相机pFrameBuffer=RGB数据,黑白相机pFrameBuffer=8位灰度数据
|
||||
# 该示例中我们只是把图片保存到硬盘文件中
|
||||
status = mvsdk.CameraSaveImage(hCamera, "./grab.bmp", pFrameBuffer, FrameHead, mvsdk.FILE_BMP, 100)
|
||||
if status == mvsdk.CAMERA_STATUS_SUCCESS:
|
||||
print("Save image successfully. image_size = {}X{}".format(FrameHead.iWidth, FrameHead.iHeight) )
|
||||
else:
|
||||
print("Save image failed. err={}".format(status) )
|
||||
except mvsdk.CameraException as e:
|
||||
print("CameraGetImageBuffer failed({}): {}".format(e.error_code, e.message) )
|
||||
|
||||
# 关闭相机
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
|
||||
# 释放帧缓存
|
||||
mvsdk.CameraAlignFree(pFrameBuffer)
|
||||
|
||||
def PrintCapbility(cap):
|
||||
for i in range(cap.iTriggerDesc):
|
||||
desc = cap.pTriggerDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iImageSizeDesc):
|
||||
desc = cap.pImageSizeDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iClrTempDesc):
|
||||
desc = cap.pClrTempDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iMediaTypeDesc):
|
||||
desc = cap.pMediaTypeDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iFrameSpeedDesc):
|
||||
desc = cap.pFrameSpeedDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iPackLenDesc):
|
||||
desc = cap.pPackLenDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iPresetLut):
|
||||
desc = cap.pPresetLutDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iAeAlmSwDesc):
|
||||
desc = cap.pAeAlmSwDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iAeAlmHdDesc):
|
||||
desc = cap.pAeAlmHdDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iBayerDecAlmSwDesc):
|
||||
desc = cap.pBayerDecAlmSwDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
for i in range(cap.iBayerDecAlmHdDesc):
|
||||
desc = cap.pBayerDecAlmHdDesc[i]
|
||||
print("{}: {}".format(desc.iIndex, desc.GetDescription()) )
|
||||
|
||||
main()
|
||||
2454
python demo/mvsdk.py
Normal file
2454
python demo/mvsdk.py
Normal file
File diff suppressed because it is too large
Load Diff
4
python demo/readme.txt
Normal file
4
python demo/readme.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
mvsdk.py: 相机SDK接口库(参考文档 WindowsSDK安装目录\Document\MVSDK_API_CHS.chm)
|
||||
|
||||
grab.py: 使用SDK采集图片,并保存到硬盘文件
|
||||
cv_grab.py: 使用SDK采集图片,转换为opencv的图像格式
|
||||
197
test_exposure.py
Normal file
197
test_exposure.py
Normal file
@@ -0,0 +1,197 @@
|
||||
#coding=utf-8
|
||||
"""
|
||||
Test script to help find optimal exposure settings for your GigE camera.
|
||||
This script captures a single test image with different exposure settings.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import mvsdk
|
||||
import numpy as np
|
||||
import cv2
|
||||
import platform
|
||||
from datetime import datetime
|
||||
|
||||
# Add the python demo directory to path
|
||||
sys.path.append('./python demo')
|
||||
|
||||
def test_exposure_settings():
|
||||
"""
|
||||
Test different exposure settings to find optimal values
|
||||
"""
|
||||
# Initialize SDK
|
||||
try:
|
||||
mvsdk.CameraSdkInit(1)
|
||||
print("SDK initialized successfully")
|
||||
except Exception as e:
|
||||
print(f"SDK initialization failed: {e}")
|
||||
return False
|
||||
|
||||
# Enumerate cameras
|
||||
DevList = mvsdk.CameraEnumerateDevice()
|
||||
nDev = len(DevList)
|
||||
|
||||
if nDev < 1:
|
||||
print("No camera was found!")
|
||||
return False
|
||||
|
||||
print(f"Found {nDev} camera(s):")
|
||||
for i, DevInfo in enumerate(DevList):
|
||||
print(f" {i}: {DevInfo.GetFriendlyName()} ({DevInfo.GetPortType()})")
|
||||
|
||||
# Use first camera
|
||||
DevInfo = DevList[0]
|
||||
print(f"\nSelected camera: {DevInfo.GetFriendlyName()}")
|
||||
|
||||
# Initialize camera
|
||||
try:
|
||||
hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
|
||||
print("Camera initialized successfully")
|
||||
except mvsdk.CameraException as e:
|
||||
print(f"CameraInit Failed({e.error_code}): {e.message}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Get camera capabilities
|
||||
cap = mvsdk.CameraGetCapability(hCamera)
|
||||
monoCamera = (cap.sIspCapacity.bMonoSensor != 0)
|
||||
print(f"Camera type: {'Monochrome' if monoCamera else 'Color'}")
|
||||
|
||||
# Get camera ranges
|
||||
try:
|
||||
exp_min, exp_max, exp_step = mvsdk.CameraGetExposureTimeRange(hCamera)
|
||||
print(f"Exposure time range: {exp_min:.1f} - {exp_max:.1f} μs")
|
||||
|
||||
gain_min, gain_max, gain_step = mvsdk.CameraGetAnalogGainXRange(hCamera)
|
||||
print(f"Analog gain range: {gain_min:.2f} - {gain_max:.2f}x")
|
||||
except Exception as e:
|
||||
print(f"Could not get camera ranges: {e}")
|
||||
exp_min, exp_max = 100, 100000
|
||||
gain_min, gain_max = 1.0, 4.0
|
||||
|
||||
# Set output format
|
||||
if monoCamera:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
|
||||
else:
|
||||
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
|
||||
|
||||
# Set camera to continuous capture mode
|
||||
mvsdk.CameraSetTriggerMode(hCamera, 0)
|
||||
mvsdk.CameraSetAeState(hCamera, 0) # Disable auto exposure
|
||||
|
||||
# Start camera
|
||||
mvsdk.CameraPlay(hCamera)
|
||||
|
||||
# Allocate frame buffer
|
||||
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
|
||||
pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
|
||||
|
||||
# Create test directory
|
||||
if not os.path.exists("exposure_tests"):
|
||||
os.makedirs("exposure_tests")
|
||||
|
||||
print("\nTesting different exposure settings...")
|
||||
print("=" * 50)
|
||||
|
||||
# Test different exposure times (in microseconds)
|
||||
exposure_times = [500, 1000, 2000, 5000, 10000, 20000] # 0.5ms to 20ms
|
||||
analog_gains = [1.0] # Start with 1x gain
|
||||
|
||||
test_count = 0
|
||||
for exp_time in exposure_times:
|
||||
for gain in analog_gains:
|
||||
# Clamp values to valid ranges
|
||||
exp_time = max(exp_min, min(exp_max, exp_time))
|
||||
gain = max(gain_min, min(gain_max, gain))
|
||||
|
||||
print(f"\nTest {test_count + 1}: Exposure={exp_time/1000:.1f}ms, Gain={gain:.1f}x")
|
||||
|
||||
# Set camera parameters
|
||||
mvsdk.CameraSetExposureTime(hCamera, exp_time)
|
||||
try:
|
||||
mvsdk.CameraSetAnalogGainX(hCamera, gain)
|
||||
except:
|
||||
pass # Some cameras might not support this
|
||||
|
||||
# Wait a moment for settings to take effect
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
|
||||
# Capture image
|
||||
try:
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 2000)
|
||||
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
|
||||
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
|
||||
|
||||
# Handle Windows image flip
|
||||
if platform.system() == "Windows":
|
||||
mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)
|
||||
|
||||
# Convert to numpy array
|
||||
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)
|
||||
frame = np.frombuffer(frame_data, dtype=np.uint8)
|
||||
|
||||
if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth))
|
||||
else:
|
||||
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth, 3))
|
||||
|
||||
# Calculate image statistics
|
||||
mean_brightness = np.mean(frame)
|
||||
max_brightness = np.max(frame)
|
||||
|
||||
# Save image
|
||||
filename = f"exposure_tests/test_{test_count+1:02d}_exp{exp_time/1000:.1f}ms_gain{gain:.1f}x.jpg"
|
||||
cv2.imwrite(filename, frame)
|
||||
|
||||
# Provide feedback
|
||||
status = ""
|
||||
if mean_brightness < 50:
|
||||
status = "TOO DARK"
|
||||
elif mean_brightness > 200:
|
||||
status = "TOO BRIGHT"
|
||||
elif max_brightness >= 255:
|
||||
status = "OVEREXPOSED"
|
||||
else:
|
||||
status = "GOOD"
|
||||
|
||||
print(f" → Saved: {filename}")
|
||||
print(f" → Brightness: mean={mean_brightness:.1f}, max={max_brightness:.1f} [{status}]")
|
||||
|
||||
test_count += 1
|
||||
|
||||
except mvsdk.CameraException as e:
|
||||
print(f" → Failed to capture: {e.message}")
|
||||
|
||||
print(f"\nCompleted {test_count} test captures!")
|
||||
print("Check the 'exposure_tests' directory to see the results.")
|
||||
print("\nRecommendations:")
|
||||
print("- Look for images marked as 'GOOD' - these have optimal exposure")
|
||||
print("- If all images are 'TOO BRIGHT', try lower exposure times or gains")
|
||||
print("- If all images are 'TOO DARK', try higher exposure times or gains")
|
||||
print("- Avoid 'OVEREXPOSED' images as they have clipped highlights")
|
||||
|
||||
# Cleanup
|
||||
mvsdk.CameraAlignFree(pFrameBuffer)
|
||||
|
||||
finally:
|
||||
# Close camera
|
||||
mvsdk.CameraUnInit(hCamera)
|
||||
print("\nCamera closed")
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("GigE Camera Exposure Test Script")
|
||||
print("=" * 40)
|
||||
print("This script will test different exposure settings and save sample images.")
|
||||
print("Use this to find the optimal settings for your lighting conditions.")
|
||||
print()
|
||||
|
||||
success = test_exposure_settings()
|
||||
|
||||
if success:
|
||||
print("\nTesting completed successfully!")
|
||||
else:
|
||||
print("\nTesting failed!")
|
||||
|
||||
input("Press Enter to exit...")
|
||||
Reference in New Issue
Block a user