From 172f46d44d0231c930814f873dbbc5e38e52def8 Mon Sep 17 00:00:00 2001 From: Alireza Vaezi Date: Fri, 25 Jul 2025 12:07:30 -0400 Subject: [PATCH] init commit --- .gitignore | 2 + .vscode/settings.json | 5 + 01README.md | 146 + VIDEO_RECORDER_README.md | 191 ++ camera_capture.py | 291 ++ camera_status_test.ipynb | 607 ++++ camera_video_recorder.py | 439 +++ exposure test.ipynb | 426 +++ python demo/__pycache__/mvsdk.cpython-313.pyc | Bin 0 -> 126551 bytes python demo/cv_grab.py | 95 + python demo/cv_grab2.py | 127 + python demo/cv_grab_callback.py | 110 + python demo/grab.py | 111 + python demo/mvsdk.py | 2454 +++++++++++++++++ python demo/readme.txt | 4 + test_exposure.py | 197 ++ 16 files changed, 5205 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 01README.md create mode 100644 VIDEO_RECORDER_README.md create mode 100644 camera_capture.py create mode 100644 camera_status_test.ipynb create mode 100644 camera_video_recorder.py create mode 100644 exposure test.ipynb create mode 100644 python demo/__pycache__/mvsdk.cpython-313.pyc create mode 100644 python demo/cv_grab.py create mode 100644 python demo/cv_grab2.py create mode 100644 python demo/cv_grab_callback.py create mode 100644 python demo/grab.py create mode 100644 python demo/mvsdk.py create mode 100644 python demo/readme.txt create mode 100644 test_exposure.py diff --git a/.gitignore b/.gitignore index 9a5aced..fcc266f 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,5 @@ dist # Vite logs files vite.config.js.timestamp-* vite.config.ts.timestamp-* + +/videos/* \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7fa27ff --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.analysis.extraPaths": [ + "./python demo" + ] +} \ No newline at end of file diff --git a/01README.md b/01README.md new file mode 100644 index 0000000..8a3059d --- /dev/null +++ b/01README.md @@ -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. diff --git a/VIDEO_RECORDER_README.md b/VIDEO_RECORDER_README.md new file mode 100644 index 0000000..d1daba3 --- /dev/null +++ b/VIDEO_RECORDER_README.md @@ -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 diff --git a/camera_capture.py b/camera_capture.py new file mode 100644 index 0000000..a585883 --- /dev/null +++ b/camera_capture.py @@ -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...") diff --git a/camera_status_test.ipynb b/camera_status_test.ipynb new file mode 100644 index 0000000..ffd0f85 --- /dev/null +++ b/camera_status_test.ipynb @@ -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 +} diff --git a/camera_video_recorder.py b/camera_video_recorder.py new file mode 100644 index 0000000..7efd72b --- /dev/null +++ b/camera_video_recorder.py @@ -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() diff --git a/exposure test.ipynb b/exposure test.ipynb new file mode 100644 index 0000000..467802d --- /dev/null +++ b/exposure test.ipynb @@ -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 +} diff --git a/python demo/__pycache__/mvsdk.cpython-313.pyc b/python demo/__pycache__/mvsdk.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1b88dbc3c516383df65e7fa38f70cc574c2221e GIT binary patch literal 126551 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 Qv7P;m-Mxo*7{}cGKRj7g00000 literal 0 HcmV?d00001 diff --git a/python demo/cv_grab.py b/python demo/cv_grab.py new file mode 100644 index 0000000..e49ab8b --- /dev/null +++ b/python demo/cv_grab.py @@ -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() diff --git a/python demo/cv_grab2.py b/python demo/cv_grab2.py new file mode 100644 index 0000000..1d257cb --- /dev/null +++ b/python demo/cv_grab2.py @@ -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() diff --git a/python demo/cv_grab_callback.py b/python demo/cv_grab_callback.py new file mode 100644 index 0000000..137868d --- /dev/null +++ b/python demo/cv_grab_callback.py @@ -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() diff --git a/python demo/grab.py b/python demo/grab.py new file mode 100644 index 0000000..59bfe2c --- /dev/null +++ b/python demo/grab.py @@ -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() diff --git a/python demo/mvsdk.py b/python demo/mvsdk.py new file mode 100644 index 0000000..6a3af90 --- /dev/null +++ b/python demo/mvsdk.py @@ -0,0 +1,2454 @@ +#coding=utf-8 +import platform +from ctypes import * +from threading import local + +# 回调函数类型 +CALLBACK_FUNC_TYPE = None + +# SDK动态库 +_sdk = None + +def _Init(): + global _sdk + global CALLBACK_FUNC_TYPE + + is_win = (platform.system() == "Windows") + is_x86 = (platform.architecture()[0] == '32bit') + + if is_win: + _sdk = windll.MVCAMSDK if is_x86 else windll.MVCAMSDK_X64 + CALLBACK_FUNC_TYPE = WINFUNCTYPE + else: + _sdk = cdll.LoadLibrary("libMVSDK.so") + CALLBACK_FUNC_TYPE = CFUNCTYPE + +_Init() + +#-------------------------------------------类型定义-------------------------------------------------- + +# 状态码定义 +CAMERA_STATUS_SUCCESS = 0 # 操作成功 +CAMERA_STATUS_FAILED = -1 # 操作失败 +CAMERA_STATUS_INTERNAL_ERROR = -2 # 内部错误 +CAMERA_STATUS_UNKNOW = -3 # 未知错误 +CAMERA_STATUS_NOT_SUPPORTED = -4 # 不支持该功能 +CAMERA_STATUS_NOT_INITIALIZED = -5 # 初始化未完成 +CAMERA_STATUS_PARAMETER_INVALID = -6 # 参数无效 +CAMERA_STATUS_PARAMETER_OUT_OF_BOUND = -7 # 参数越界 +CAMERA_STATUS_UNENABLED = -8 # 未使能 +CAMERA_STATUS_USER_CANCEL = -9 # 用户手动取消了,比如roi面板点击取消,返回 +CAMERA_STATUS_PATH_NOT_FOUND = -10 # 注册表中没有找到对应的路径 +CAMERA_STATUS_SIZE_DISMATCH = -11 # 获得图像数据长度和定义的尺寸不匹配 +CAMERA_STATUS_TIME_OUT = -12 # 超时错误 +CAMERA_STATUS_IO_ERROR = -13 # 硬件IO错误 +CAMERA_STATUS_COMM_ERROR = -14 # 通讯错误 +CAMERA_STATUS_BUS_ERROR = -15 # 总线错误 +CAMERA_STATUS_NO_DEVICE_FOUND = -16 # 没有发现设备 +CAMERA_STATUS_NO_LOGIC_DEVICE_FOUND = -17 # 未找到逻辑设备 +CAMERA_STATUS_DEVICE_IS_OPENED = -18 # 设备已经打开 +CAMERA_STATUS_DEVICE_IS_CLOSED = -19 # 设备已经关闭 +CAMERA_STATUS_DEVICE_VEDIO_CLOSED = -20 # 没有打开设备视频,调用录像相关的函数时,如果相机视频没有打开,则回返回该错误。 +CAMERA_STATUS_NO_MEMORY = -21 # 没有足够系统内存 +CAMERA_STATUS_FILE_CREATE_FAILED = -22 # 创建文件失败 +CAMERA_STATUS_FILE_INVALID = -23 # 文件格式无效 +CAMERA_STATUS_WRITE_PROTECTED = -24 # 写保护,不可写 +CAMERA_STATUS_GRAB_FAILED = -25 # 数据采集失败 +CAMERA_STATUS_LOST_DATA = -26 # 数据丢失,不完整 +CAMERA_STATUS_EOF_ERROR = -27 # 未接收到帧结束符 +CAMERA_STATUS_BUSY = -28 # 正忙(上一次操作还在进行中),此次操作不能进行 +CAMERA_STATUS_WAIT = -29 # 需要等待(进行操作的条件不成立),可以再次尝试 +CAMERA_STATUS_IN_PROCESS = -30 # 正在进行,已经被操作过 +CAMERA_STATUS_IIC_ERROR = -31 # IIC传输错误 +CAMERA_STATUS_SPI_ERROR = -32 # SPI传输错误 +CAMERA_STATUS_USB_CONTROL_ERROR = -33 # USB控制传输错误 +CAMERA_STATUS_USB_BULK_ERROR = -34 # USB BULK传输错误 +CAMERA_STATUS_SOCKET_INIT_ERROR = -35 # 网络传输套件初始化失败 +CAMERA_STATUS_GIGE_FILTER_INIT_ERROR = -36 # 网络相机内核过滤驱动初始化失败,请检查是否正确安装了驱动,或者重新安装。 +CAMERA_STATUS_NET_SEND_ERROR = -37 # 网络数据发送错误 +CAMERA_STATUS_DEVICE_LOST = -38 # 与网络相机失去连接,心跳检测超时 +CAMERA_STATUS_DATA_RECV_LESS = -39 # 接收到的字节数比请求的少 +CAMERA_STATUS_FUNCTION_LOAD_FAILED = -40 # 从文件中加载程序失败 +CAMERA_STATUS_CRITICAL_FILE_LOST = -41 # 程序运行所必须的文件丢失。 +CAMERA_STATUS_SENSOR_ID_DISMATCH = -42 # 固件和程序不匹配,原因是下载了错误的固件。 +CAMERA_STATUS_OUT_OF_RANGE = -43 # 参数超出有效范围。 +CAMERA_STATUS_REGISTRY_ERROR = -44 # 安装程序注册错误。请重新安装程序,或者运行安装目录Setup/Installer.exe +CAMERA_STATUS_ACCESS_DENY = -45 # 禁止访问。指定相机已经被其他程序占用时,再申请访问该相机,会返回该状态。(一个相机不能被多个程序同时访问) +#AIA的标准兼容的错误码 +CAMERA_AIA_PACKET_RESEND = 0x0100 #该帧需要重传 +CAMERA_AIA_NOT_IMPLEMENTED = 0x8001 #设备不支持的命令 +CAMERA_AIA_INVALID_PARAMETER = 0x8002 #命令参数非法 +CAMERA_AIA_INVALID_ADDRESS = 0x8003 #不可访问的地址 +CAMERA_AIA_WRITE_PROTECT = 0x8004 #访问的对象不可写 +CAMERA_AIA_BAD_ALIGNMENT = 0x8005 #访问的地址没有按照要求对齐 +CAMERA_AIA_ACCESS_DENIED = 0x8006 #没有访问权限 +CAMERA_AIA_BUSY = 0x8007 #命令正在处理中 +CAMERA_AIA_DEPRECATED = 0x8008 #0x8008-0x0800B 0x800F 该指令已经废弃 +CAMERA_AIA_PACKET_UNAVAILABLE = 0x800C #包无效 +CAMERA_AIA_DATA_OVERRUN = 0x800D #数据溢出,通常是收到的数据比需要的多 +CAMERA_AIA_INVALID_HEADER = 0x800E #数据包头部中某些区域与协议不匹配 +CAMERA_AIA_PACKET_NOT_YET_AVAILABLE = 0x8010 #图像分包数据还未准备好,多用于触发模式,应用程序访问超时 +CAMERA_AIA_PACKET_AND_PREV_REMOVED_FROM_MEMORY = 0x8011 #需要访问的分包已经不存在。多用于重传时数据已经不在缓冲区中 +CAMERA_AIA_PACKET_REMOVED_FROM_MEMORY = 0x8012 #CAMERA_AIA_PACKET_AND_PREV_REMOVED_FROM_MEMORY +CAMERA_AIA_NO_REF_TIME = 0x0813 #没有参考时钟源。多用于时间同步的命令执行时 +CAMERA_AIA_PACKET_TEMPORARILY_UNAVAILABLE = 0x0814 #由于信道带宽问题,当前分包暂时不可用,需稍后进行访问 +CAMERA_AIA_OVERFLOW = 0x0815 #设备端数据溢出,通常是队列已满 +CAMERA_AIA_ACTION_LATE = 0x0816 #命令执行已经超过有效的指定时间 +CAMERA_AIA_ERROR = 0x8FFF #错误 + +# 图像格式定义 +CAMERA_MEDIA_TYPE_MONO = 0x01000000 +CAMERA_MEDIA_TYPE_RGB = 0x02000000 +CAMERA_MEDIA_TYPE_COLOR = 0x02000000 +CAMERA_MEDIA_TYPE_OCCUPY1BIT = 0x00010000 +CAMERA_MEDIA_TYPE_OCCUPY2BIT = 0x00020000 +CAMERA_MEDIA_TYPE_OCCUPY4BIT = 0x00040000 +CAMERA_MEDIA_TYPE_OCCUPY8BIT = 0x00080000 +CAMERA_MEDIA_TYPE_OCCUPY10BIT = 0x000A0000 +CAMERA_MEDIA_TYPE_OCCUPY12BIT = 0x000C0000 +CAMERA_MEDIA_TYPE_OCCUPY16BIT = 0x00100000 +CAMERA_MEDIA_TYPE_OCCUPY24BIT = 0x00180000 +CAMERA_MEDIA_TYPE_OCCUPY32BIT = 0x00200000 +CAMERA_MEDIA_TYPE_OCCUPY36BIT = 0x00240000 +CAMERA_MEDIA_TYPE_OCCUPY48BIT = 0x00300000 +CAMERA_MEDIA_TYPE_EFFECTIVE_PIXEL_SIZE_MASK = 0x00FF0000 +CAMERA_MEDIA_TYPE_EFFECTIVE_PIXEL_SIZE_SHIFT = 16 +CAMERA_MEDIA_TYPE_ID_MASK = 0x0000FFFF +CAMERA_MEDIA_TYPE_COUNT = 0x46 + +#mono +CAMERA_MEDIA_TYPE_MONO1P = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY1BIT | 0x0037) +CAMERA_MEDIA_TYPE_MONO2P = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY2BIT | 0x0038) +CAMERA_MEDIA_TYPE_MONO4P = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY4BIT | 0x0039) +CAMERA_MEDIA_TYPE_MONO8 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0001) +CAMERA_MEDIA_TYPE_MONO8S = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0002) +CAMERA_MEDIA_TYPE_MONO10 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0003) +CAMERA_MEDIA_TYPE_MONO10_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0004) +CAMERA_MEDIA_TYPE_MONO12 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0005) +CAMERA_MEDIA_TYPE_MONO12_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0006) +CAMERA_MEDIA_TYPE_MONO14 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0025) +CAMERA_MEDIA_TYPE_MONO16 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0007) + +# Bayer +CAMERA_MEDIA_TYPE_BAYGR8 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0008) +CAMERA_MEDIA_TYPE_BAYRG8 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0009) +CAMERA_MEDIA_TYPE_BAYGB8 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x000A) +CAMERA_MEDIA_TYPE_BAYBG8 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x000B) + +CAMERA_MEDIA_TYPE_BAYGR10_MIPI = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0026) +CAMERA_MEDIA_TYPE_BAYRG10_MIPI = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0027) +CAMERA_MEDIA_TYPE_BAYGB10_MIPI = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0028) +CAMERA_MEDIA_TYPE_BAYBG10_MIPI = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0029) + +CAMERA_MEDIA_TYPE_BAYGR10 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000C) +CAMERA_MEDIA_TYPE_BAYRG10 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000D) +CAMERA_MEDIA_TYPE_BAYGB10 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000E) +CAMERA_MEDIA_TYPE_BAYBG10 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000F) + +CAMERA_MEDIA_TYPE_BAYGR12 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0010) +CAMERA_MEDIA_TYPE_BAYRG12 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0011) +CAMERA_MEDIA_TYPE_BAYGB12 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0012) +CAMERA_MEDIA_TYPE_BAYBG12 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0013) + +CAMERA_MEDIA_TYPE_BAYGR10_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0026) +CAMERA_MEDIA_TYPE_BAYRG10_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0027) +CAMERA_MEDIA_TYPE_BAYGB10_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0028) +CAMERA_MEDIA_TYPE_BAYBG10_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0029) + +CAMERA_MEDIA_TYPE_BAYGR12_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002A) +CAMERA_MEDIA_TYPE_BAYRG12_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002B) +CAMERA_MEDIA_TYPE_BAYGB12_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002C) +CAMERA_MEDIA_TYPE_BAYBG12_PACKED = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002D) + +CAMERA_MEDIA_TYPE_BAYGR16 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x002E) +CAMERA_MEDIA_TYPE_BAYRG16 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x002F) +CAMERA_MEDIA_TYPE_BAYGB16 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0030) +CAMERA_MEDIA_TYPE_BAYBG16 = (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0031) + +# RGB +CAMERA_MEDIA_TYPE_RGB8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0014) +CAMERA_MEDIA_TYPE_BGR8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0015) +CAMERA_MEDIA_TYPE_RGBA8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x0016) +CAMERA_MEDIA_TYPE_BGRA8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x0017) +CAMERA_MEDIA_TYPE_RGB10 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0018) +CAMERA_MEDIA_TYPE_BGR10 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0019) +CAMERA_MEDIA_TYPE_RGB12 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x001A) +CAMERA_MEDIA_TYPE_BGR12 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x001B) +CAMERA_MEDIA_TYPE_RGB16 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0033) +CAMERA_MEDIA_TYPE_RGB10V1_PACKED = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x001C) +CAMERA_MEDIA_TYPE_RGB10P32 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x001D) +CAMERA_MEDIA_TYPE_RGB12V1_PACKED = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY36BIT | 0X0034) +CAMERA_MEDIA_TYPE_RGB565P = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0035) +CAMERA_MEDIA_TYPE_BGR565P = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0X0036) + +# YUV and YCbCr +CAMERA_MEDIA_TYPE_YUV411_8_UYYVYY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x001E) +CAMERA_MEDIA_TYPE_YUV422_8_UYVY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x001F) +CAMERA_MEDIA_TYPE_YUV422_8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0032) +CAMERA_MEDIA_TYPE_YUV8_UYV = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0020) +CAMERA_MEDIA_TYPE_YCBCR8_CBYCR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x003A) +#CAMERA_MEDIA_TYPE_YCBCR422_8 : YYYYCbCrCbCr +CAMERA_MEDIA_TYPE_YCBCR422_8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x003B) +CAMERA_MEDIA_TYPE_YCBCR422_8_CBYCRY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0043) +CAMERA_MEDIA_TYPE_YCBCR411_8_CBYYCRYY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x003C) +CAMERA_MEDIA_TYPE_YCBCR601_8_CBYCR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x003D) +CAMERA_MEDIA_TYPE_YCBCR601_422_8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x003E) +CAMERA_MEDIA_TYPE_YCBCR601_422_8_CBYCRY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0044) +CAMERA_MEDIA_TYPE_YCBCR601_411_8_CBYYCRYY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x003F) +CAMERA_MEDIA_TYPE_YCBCR709_8_CBYCR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0040) +CAMERA_MEDIA_TYPE_YCBCR709_422_8 = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0041) +CAMERA_MEDIA_TYPE_YCBCR709_422_8_CBYCRY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0045) +CAMERA_MEDIA_TYPE_YCBCR709_411_8_CBYYCRYY = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0042) + +# RGB Planar +CAMERA_MEDIA_TYPE_RGB8_PLANAR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0021) +CAMERA_MEDIA_TYPE_RGB10_PLANAR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0022) +CAMERA_MEDIA_TYPE_RGB12_PLANAR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0023) +CAMERA_MEDIA_TYPE_RGB16_PLANAR = (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0024) + +# 保存格式 +FILE_JPG = 1 +FILE_BMP = 2 +FILE_RAW = 4 +FILE_PNG = 8 +FILE_BMP_8BIT = 16 +FILE_PNG_8BIT = 32 +FILE_RAW_16BIT = 64 + +# 触发信号 +EXT_TRIG_LEADING_EDGE = 0 +EXT_TRIG_TRAILING_EDGE = 1 +EXT_TRIG_HIGH_LEVEL = 2 +EXT_TRIG_LOW_LEVEL = 3 +EXT_TRIG_DOUBLE_EDGE = 4 + +# IO模式 +IOMODE_TRIG_INPUT = 0 +IOMODE_STROBE_OUTPUT = 1 +IOMODE_GP_INPUT = 2 +IOMODE_GP_OUTPUT = 3 +IOMODE_PWM_OUTPUT = 4 + + +# 相机操作异常信息 +class CameraException(Exception): + """docstring for CameraException""" + def __init__(self, error_code): + super(CameraException, self).__init__() + self.error_code = error_code + self.message = CameraGetErrorString(error_code) + + def __str__(self): + return 'error_code:{} message:{}'.format(self.error_code, self.message) + +class MvStructure(Structure): + def __str__(self): + strs = [] + for field in self._fields_: + name = field[0] + value = getattr(self, name) + if isinstance(value, type(b'')): + value = _string_buffer_to_str(value) + strs.append("{}:{}".format(name, value)) + return '\n'.join(strs) + + def __repr__(self): + return self.__str__() + + def clone(self): + obj = type(self)() + memmove(byref(obj), byref(self), sizeof(self)) + return obj + +# 相机的设备信息,只读信息,请勿修改 +class tSdkCameraDevInfo(MvStructure): + _fields_ = [("acProductSeries", c_char * 32), #产品系列 + ("acProductName", c_char * 32), #产品名称 + ("acFriendlyName", c_char * 32), #产品昵称 + ("acLinkName", c_char * 32), #内核符号连接名,内部使用 + ("acDriverVersion", c_char * 32), #驱动版本 + ("acSensorType", c_char * 32), #sensor类型 + ("acPortType", c_char * 32), #接口类型 + ("acSn", c_char * 32), #产品唯一序列号 + ("uInstance", c_uint)] #该型号相机在该电脑上的实例索引号,用于区分同型号多相机 + + def GetProductSeries(self): + return _string_buffer_to_str(self.acProductSeries) + def GetProductName(self): + return _string_buffer_to_str(self.acProductName) + def GetFriendlyName(self): + return _string_buffer_to_str(self.acFriendlyName) + def GetLinkName(self): + return _string_buffer_to_str(self.acLinkName) + def GetDriverVersion(self): + return _string_buffer_to_str(self.acDriverVersion) + def GetSensorType(self): + return _string_buffer_to_str(self.acSensorType) + def GetPortType(self): + return _string_buffer_to_str(self.acPortType) + def GetSn(self): + return _string_buffer_to_str(self.acSn) + +# 相机的分辨率设定范围 +class tSdkResolutionRange(MvStructure): + _fields_ = [("iHeightMax", c_int), #图像最大高度 + ("iHeightMin", c_int), #图像最小高度 + ("iWidthMax", c_int), #图像最大宽度 + ("iWidthMin", c_int), #图像最小宽度 + ("uSkipModeMask", c_uint), #SKIP模式掩码,为0,表示不支持SKIP 。bit0为1,表示支持SKIP 2x2 bit1为1,表示支持SKIP 3x3.... + ("uBinSumModeMask", c_uint), #BIN(求和)模式掩码,为0,表示不支持BIN 。bit0为1,表示支持BIN 2x2 bit1为1,表示支持BIN 3x3.... + ("uBinAverageModeMask", c_uint),#BIN(求均值)模式掩码,为0,表示不支持BIN 。bit0为1,表示支持BIN 2x2 bit1为1,表示支持BIN 3x3.... + ("uResampleMask", c_uint)] #硬件重采样的掩码 + +#相机的分辨率描述 +class tSdkImageResolution(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 索引号,[0,N]表示预设的分辨率(N 为预设分辨率的最大个数,一般不超过20),OXFF 表示自定义分辨率(ROI) + ("acDescription", c_char * 32), # 该分辨率的描述信息。仅预设分辨率时该信息有效。自定义分辨率可忽略该信息 + ("uBinSumMode", c_uint), # BIN(求和)的模式,范围不能超过tSdkResolutionRange中uBinSumModeMask + ("uBinAverageMode", c_uint), # BIN(求均值)的模式,范围不能超过tSdkResolutionRange中uBinAverageModeMask + ("uSkipMode", c_uint), # 是否SKIP的尺寸,为0表示禁止SKIP模式,范围不能超过tSdkResolutionRange中uSkipModeMask + ("uResampleMask", c_uint), # 硬件重采样的掩码 + ("iHOffsetFOV", c_int), # 采集视场相对于Sensor最大视场左上角的垂直偏移 + ("iVOffsetFOV", c_int), # 采集视场相对于Sensor最大视场左上角的水平偏移 + ("iWidthFOV", c_int), # 采集视场的宽度 + ("iHeightFOV", c_int), # 采集视场的高度 + ("iWidth", c_int), # 相机最终输出的图像的宽度 + ("iHeight", c_int), # 相机最终输出的图像的高度 + ("iWidthZoomHd", c_int), # 硬件缩放的宽度,不需要进行此操作的分辨率,此变量设置为0. + ("iHeightZoomHd", c_int), # 硬件缩放的高度,不需要进行此操作的分辨率,此变量设置为0. + ("iWidthZoomSw", c_int), # 软件缩放的宽度,不需要进行此操作的分辨率,此变量设置为0. + ("iHeightZoomSw", c_int), # 软件缩放的高度,不需要进行此操作的分辨率,此变量设置为0. + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#相机白平衡模式描述信息 +class tSdkColorTemperatureDes(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 模式索引号 + ("acDescription", c_char * 32), # 描述信息 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#相机帧率描述信息 +class tSdkFrameSpeed(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 帧率索引号,一般0对应于低速模式,1对应于普通模式,2对应于高速模式 + ("acDescription", c_char * 32), # 描述信息 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#相机曝光功能范围定义 +class tSdkExpose(MvStructure): + _fields_ = [ + ("uiTargetMin", c_uint), #自动曝光亮度目标最小值 + ("uiTargetMax", c_uint), #自动曝光亮度目标最大值 + ("uiAnalogGainMin", c_uint), #模拟增益的最小值,单位为fAnalogGainStep中定义 + ("uiAnalogGainMax", c_uint), #模拟增益的最大值,单位为fAnalogGainStep中定义 + ("fAnalogGainStep", c_float), #模拟增益每增加1,对应的增加的放大倍数。例如,uiAnalogGainMin一般为16,fAnalogGainStep一般为0.125,那么最小放大倍数就是16*0.125 = 2倍 + ("uiExposeTimeMin", c_uint), #手动模式下,曝光时间的最小值,单位:行。根据CameraGetExposureLineTime可以获得一行对应的时间(微秒),从而得到整帧的曝光时间 + ("uiExposeTimeMax", c_uint), #手动模式下,曝光时间的最大值,单位:行 + ] + +#触发模式描述 +class tSdkTrigger(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 模式索引号 + ("acDescription", c_char * 32), # 描述信息 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#传输分包大小描述(主要是针对网络相机有效) +class tSdkPackLength(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 模式索引号 + ("acDescription", c_char * 32), # 描述信息 + ("iPackSize", c_uint), + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#预设的LUT表描述 +class tSdkPresetLut(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 编号 + ("acDescription", c_char * 32), # 描述信息 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#AE算法描述 +class tSdkAeAlgorithm(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 编号 + ("acDescription", c_char * 32), # 描述信息 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#RAW转RGB算法描述 +class tSdkBayerDecodeAlgorithm(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 编号 + ("acDescription", c_char * 32), # 描述信息 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#帧率统计信息 +class tSdkFrameStatistic(MvStructure): + _fields_ = [ + ("iTotal", c_int), #当前采集的总帧数(包括错误帧) + ("iCapture", c_int), #当前采集的有效帧的数量 + ("iLost", c_int), #当前丢帧的数量 + ] + +#相机输出的图像数据格式 +class tSdkMediaType(MvStructure): + _fields_ = [ + ("iIndex", c_int), # 格式种类编号 + ("acDescription", c_char * 32), # 描述信息 + ("iMediaType", c_uint), # 对应的图像格式编码,如CAMERA_MEDIA_TYPE_BAYGR8。 + ] + + def GetDescription(self): + return _string_buffer_to_str(self.acDescription) + +#伽马的设定范围 +class tGammaRange(MvStructure): + _fields_ = [ + ("iMin", c_int), #最小值 + ("iMax", c_int), #最大值 + ] + +#对比度的设定范围 +class tContrastRange(MvStructure): + _fields_ = [ + ("iMin", c_int), #最小值 + ("iMax", c_int), #最大值 + ] + +#RGB三通道数字增益的设定范围 +class tRgbGainRange(MvStructure): + _fields_ = [ + ("iRGainMin", c_int), #红色增益的最小值 + ("iRGainMax", c_int), #红色增益的最大值 + ("iGGainMin", c_int), #绿色增益的最小值 + ("iGGainMax", c_int), #绿色增益的最大值 + ("iBGainMin", c_int), #蓝色增益的最小值 + ("iBGainMax", c_int), #蓝色增益的最大值 + ] + +#饱和度设定的范围 +class tSaturationRange(MvStructure): + _fields_ = [ + ("iMin", c_int), #最小值 + ("iMax", c_int), #最大值 + ] + +#锐化的设定范围 +class tSharpnessRange(MvStructure): + _fields_ = [ + ("iMin", c_int), #最小值 + ("iMax", c_int), #最大值 + ] + +#ISP模块的使能信息 +class tSdkIspCapacity(MvStructure): + _fields_ = [ + ("bMonoSensor", c_int), #表示该型号相机是否为黑白相机,如果是黑白相机,则颜色相关的功能都无法调节 + ("bWbOnce", c_int), #表示该型号相机是否支持手动白平衡功能 + ("bAutoWb", c_int), #表示该型号相机是否支持自动白平衡功能 + ("bAutoExposure", c_int), #表示该型号相机是否支持自动曝光功能 + ("bManualExposure", c_int), #表示该型号相机是否支持手动曝光功能 + ("bAntiFlick", c_int), #表示该型号相机是否支持抗频闪功能 + ("bDeviceIsp", c_int), #表示该型号相机是否支持硬件ISP功能 + ("bForceUseDeviceIsp", c_int), #bDeviceIsp和bForceUseDeviceIsp同时为TRUE时,表示强制只用硬件ISP,不可取消。 + ("bZoomHD", c_int), #相机硬件是否支持图像缩放输出(只能是缩小)。 + ] + +# 定义整合的设备描述信息,这些信息可以用于动态构建UI +class tSdkCameraCapbility(MvStructure): + _fields_ = [ + ("pTriggerDesc", POINTER(tSdkTrigger)), + ("iTriggerDesc", c_int), #触发模式的个数,即pTriggerDesc数组的大小 + ("pImageSizeDesc", POINTER(tSdkImageResolution)), + ("iImageSizeDesc", c_int), #预设分辨率的个数,即pImageSizeDesc数组的大小 + ("pClrTempDesc", POINTER(tSdkColorTemperatureDes)), + ("iClrTempDesc", c_int), #预设色温个数 + ("pMediaTypeDesc", POINTER(tSdkMediaType)), + ("iMediaTypeDesc", c_int), #相机输出图像格式的种类个数,即pMediaTypeDesc数组的大小。 + ("pFrameSpeedDesc", POINTER(tSdkFrameSpeed)), #可调节帧速类型,对应界面上普通 高速 和超级三种速度设置 + ("iFrameSpeedDesc", c_int), #可调节帧速类型的个数,即pFrameSpeedDesc数组的大小。 + ("pPackLenDesc", POINTER(tSdkPackLength)), #传输包长度,一般用于网络设备 + ("iPackLenDesc", c_int), #可供选择的传输分包长度的个数,即pPackLenDesc数组的大小。 + ("iOutputIoCounts", c_int), #可编程输出IO的个数 + ("iInputIoCounts", c_int), #可编程输入IO的个数 + ("pPresetLutDesc", POINTER(tSdkPresetLut)), #相机预设的LUT表 + ("iPresetLut", c_int), #相机预设的LUT表的个数,即pPresetLutDesc数组的大小 + ("iUserDataMaxLen", c_int), #指示该相机中用于保存用户数据区的最大长度。为0表示无。 + ("bParamInDevice", c_int), #指示该设备是否支持从设备中读写参数组。1为支持,0不支持。 + ("pAeAlmSwDesc", POINTER(tSdkAeAlgorithm)),#软件自动曝光算法描述 + ("iAeAlmSwDesc", c_int), #软件自动曝光算法个数 + ("pAeAlmHdDesc", POINTER(tSdkAeAlgorithm)),#硬件自动曝光算法描述,为NULL表示不支持硬件自动曝光 + ("iAeAlmHdDesc", c_int), #硬件自动曝光算法个数,为0表示不支持硬件自动曝光 + ("pBayerDecAlmSwDesc", POINTER(tSdkBayerDecodeAlgorithm)),#软件Bayer转换为RGB数据的算法描述 + ("iBayerDecAlmSwDesc", c_int), #软件Bayer转换为RGB数据的算法个数 + ("pBayerDecAlmHdDesc", POINTER(tSdkBayerDecodeAlgorithm)),#硬件Bayer转换为RGB数据的算法描述,为NULL表示不支持 + ("iBayerDecAlmHdDesc", c_int), #硬件Bayer转换为RGB数据的算法个数,为0表示不支持 + + # 图像参数的调节范围定义,用于动态构建UI + ("sExposeDesc", tSdkExpose), #曝光的范围值 + ("sResolutionRange", tSdkResolutionRange), #分辨率范围描述 + ("sRgbGainRange", tRgbGainRange), #图像数字增益范围描述 + ("sSaturationRange", tSaturationRange), #饱和度范围描述 + ("sGammaRange", tGammaRange), #伽马范围描述 + ("sContrastRange", tContrastRange), #对比度范围描述 + ("sSharpnessRange", tSharpnessRange), #锐化范围描述 + ("sIspCapacity", tSdkIspCapacity), #ISP能力描述 + ] + +#图像帧头信息 +class tSdkFrameHead(MvStructure): + _fields_ = [ + ("uiMediaType", c_uint), # 图像格式,Image Format + ("uBytes", c_uint), # 图像数据字节数,Total bytes + ("iWidth", c_int), # 宽度 Image height + ("iHeight", c_int), # 高度 Image width + ("iWidthZoomSw", c_int), # 软件缩放的宽度,不需要进行软件裁剪的图像,此变量设置为0. + ("iHeightZoomSw", c_int), # 软件缩放的高度,不需要进行软件裁剪的图像,此变量设置为0. + ("bIsTrigger", c_int), # 指示是否为触发帧 is trigger + ("uiTimeStamp", c_uint), # 该帧的采集时间,单位0.1毫秒 + ("uiExpTime", c_uint), # 当前图像的曝光值,单位为微秒us + ("fAnalogGain", c_float), # 当前图像的模拟增益倍数 + ("iGamma", c_int), # 该帧图像的伽马设定值,仅当LUT模式为动态参数生成时有效,其余模式下为-1 + ("iContrast", c_int), # 该帧图像的对比度设定值,仅当LUT模式为动态参数生成时有效,其余模式下为-1 + ("iSaturation", c_int), # 该帧图像的饱和度设定值,对于黑白相机无意义,为0 + ("fRgain", c_float), # 该帧图像处理的红色数字增益倍数,对于黑白相机无意义,为1 + ("fGgain", c_float), # 该帧图像处理的绿色数字增益倍数,对于黑白相机无意义,为1 + ("fBgain", c_float), # 该帧图像处理的蓝色数字增益倍数,对于黑白相机无意义,为1 + ] + +# Grabber统计信息 +class tSdkGrabberStat(MvStructure): + _fields_ = [ + ("Width", c_int), # 帧图像大小 + ("Height", c_int), # 帧图像大小 + ("Disp", c_int), # 显示帧数量 + ("Capture", c_int), # 采集的有效帧的数量 + ("Lost", c_int), # 丢帧的数量 + ("Error", c_int), # 错帧的数量 + ("DispFps", c_float), # 显示帧率 + ("CapFps", c_float), # 捕获帧率 + ] + +# 方法回调辅助类 +class method(object): + def __init__(self, FuncType): + super(method, self).__init__() + self.FuncType = FuncType + self.cache = {} + + def __call__(self, cb): + self.cb = cb + return self + + def __get__(self, obj, objtype): + try: + return self.cache[obj] + except KeyError as e: + def cl(*args): + return self.cb(obj, *args) + r = self.cache[obj] = self.FuncType(cl) + return r + +# 图像捕获的回调函数定义 +CAMERA_SNAP_PROC = CALLBACK_FUNC_TYPE(None, c_int, c_void_p, POINTER(tSdkFrameHead), c_void_p) + +# 相机连接状态回调 +CAMERA_CONNECTION_STATUS_CALLBACK = CALLBACK_FUNC_TYPE(None, c_int, c_uint, c_uint, c_void_p) + +# 异步抓图完成回调 +pfnCameraGrabberSaveImageComplete = CALLBACK_FUNC_TYPE(None, c_void_p, c_void_p, c_int, c_void_p) + +# 帧监听回调 +pfnCameraGrabberFrameListener = CALLBACK_FUNC_TYPE(c_int, c_void_p, c_int, c_void_p, POINTER(tSdkFrameHead), c_void_p) + +# 采集器图像捕获的回调 +pfnCameraGrabberFrameCallback = CALLBACK_FUNC_TYPE(None, c_void_p, c_void_p, POINTER(tSdkFrameHead), c_void_p) + +#-----------------------------------函数接口------------------------------------------ + +# 线程局部存储 +_tls = local() + +# 存储最后一次SDK调用返回的错误码 +def GetLastError(): + try: + return _tls.last_error + except AttributeError as e: + _tls.last_error = 0 + return 0 + +def SetLastError(err_code): + _tls.last_error = err_code + +def _string_buffer_to_str(buf): + s = buf if isinstance(buf, type(b'')) else buf.value + + for codec in ('gbk', 'utf-8'): + try: + s = s.decode(codec) + break + except UnicodeDecodeError as e: + continue + + if isinstance(s, str): + return s + else: + return s.encode('utf-8') + +def _str_to_string_buffer(str): + if type(str) is type(u''): + s = str.encode('gbk') + else: + s = str.decode('utf-8').encode('gbk') + return create_string_buffer(s) + +def CameraSdkInit(iLanguageSel): + err_code = _sdk.CameraSdkInit(iLanguageSel) + SetLastError(err_code) + return err_code + +def CameraSetSysOption(optionName, value): + err_code = _sdk.CameraSetSysOption(_str_to_string_buffer(optionName), _str_to_string_buffer(str(value))) + SetLastError(err_code) + return err_code + +def CameraEnumerateDevice(MaxCount = 32): + Nums = c_int(MaxCount) + pCameraList = (tSdkCameraDevInfo * Nums.value)() + err_code = _sdk.CameraEnumerateDevice(pCameraList, byref(Nums)) + SetLastError(err_code) + return pCameraList[0:Nums.value] + +def CameraEnumerateDeviceEx(): + return _sdk.CameraEnumerateDeviceEx() + +def CameraIsOpened(pCameraInfo): + pOpened = c_int() + err_code = _sdk.CameraIsOpened(byref(pCameraInfo), byref(pOpened) ) + SetLastError(err_code) + return pOpened.value != 0 + +def CameraInit(pCameraInfo, emParamLoadMode = -1, emTeam = -1): + pCameraHandle = c_int() + err_code = _sdk.CameraInit(byref(pCameraInfo), emParamLoadMode, emTeam, byref(pCameraHandle)) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return pCameraHandle.value + +def CameraInitEx(iDeviceIndex, emParamLoadMode = -1, emTeam = -1): + pCameraHandle = c_int() + err_code = _sdk.CameraInitEx(iDeviceIndex, emParamLoadMode, emTeam, byref(pCameraHandle)) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return pCameraHandle.value + +def CameraInitEx2(CameraName): + pCameraHandle = c_int() + err_code = _sdk.CameraInitEx2(_str_to_string_buffer(CameraName), byref(pCameraHandle)) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return pCameraHandle.value + +def CameraSetCallbackFunction(hCamera, pCallBack, pContext = 0): + err_code = _sdk.CameraSetCallbackFunction(hCamera, pCallBack, c_void_p(pContext), None) + SetLastError(err_code) + return err_code + +def CameraUnInit(hCamera): + err_code = _sdk.CameraUnInit(hCamera) + SetLastError(err_code) + return err_code + +def CameraGetInformation(hCamera): + pbuffer = c_char_p() + err_code = _sdk.CameraGetInformation(hCamera, byref(pbuffer) ) + SetLastError(err_code) + if err_code == 0 and pbuffer.value is not None: + return _string_buffer_to_str(pbuffer) + return '' + +def CameraImageProcess(hCamera, pbyIn, pbyOut, pFrInfo): + err_code = _sdk.CameraImageProcess(hCamera, c_void_p(pbyIn), c_void_p(pbyOut), byref(pFrInfo)) + SetLastError(err_code) + return err_code + +def CameraImageProcessEx(hCamera, pbyIn, pbyOut, pFrInfo, uOutFormat, uReserved): + err_code = _sdk.CameraImageProcessEx(hCamera, c_void_p(pbyIn), c_void_p(pbyOut), byref(pFrInfo), uOutFormat, uReserved) + SetLastError(err_code) + return err_code + +def CameraDisplayInit(hCamera, hWndDisplay): + err_code = _sdk.CameraDisplayInit(hCamera, hWndDisplay) + SetLastError(err_code) + return err_code + +def CameraDisplayRGB24(hCamera, pFrameBuffer, pFrInfo): + err_code = _sdk.CameraDisplayRGB24(hCamera, c_void_p(pFrameBuffer), byref(pFrInfo) ) + SetLastError(err_code) + return err_code + +def CameraSetDisplayMode(hCamera, iMode): + err_code = _sdk.CameraSetDisplayMode(hCamera, iMode) + SetLastError(err_code) + return err_code + +def CameraSetDisplayOffset(hCamera, iOffsetX, iOffsetY): + err_code = _sdk.CameraSetDisplayOffset(hCamera, iOffsetX, iOffsetY) + SetLastError(err_code) + return err_code + +def CameraSetDisplaySize(hCamera, iWidth, iHeight): + err_code = _sdk.CameraSetDisplaySize(hCamera, iWidth, iHeight) + SetLastError(err_code) + return err_code + +def CameraGetImageBuffer(hCamera, wTimes): + pbyBuffer = c_void_p() + pFrameInfo = tSdkFrameHead() + err_code = _sdk.CameraGetImageBuffer(hCamera, byref(pFrameInfo), byref(pbyBuffer), wTimes) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (pbyBuffer.value, pFrameInfo) + +def CameraGetImageBufferEx(hCamera, wTimes): + _sdk.CameraGetImageBufferEx.restype = c_void_p + piWidth = c_int() + piHeight = c_int() + pFrameBuffer = _sdk.CameraGetImageBufferEx(hCamera, byref(piWidth), byref(piHeight), wTimes) + err_code = CAMERA_STATUS_SUCCESS if pFrameBuffer else CAMERA_STATUS_TIME_OUT + SetLastError(err_code) + if pFrameBuffer: + return (pFrameBuffer, piWidth.value, piHeight.value) + else: + raise CameraException(err_code) + +def CameraSnapToBuffer(hCamera, wTimes): + pbyBuffer = c_void_p() + pFrameInfo = tSdkFrameHead() + err_code = _sdk.CameraSnapToBuffer(hCamera, byref(pFrameInfo), byref(pbyBuffer), wTimes) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (pbyBuffer.value, pFrameInfo) + +def CameraReleaseImageBuffer(hCamera, pbyBuffer): + err_code = _sdk.CameraReleaseImageBuffer(hCamera, c_void_p(pbyBuffer) ) + SetLastError(err_code) + return err_code + +def CameraPlay(hCamera): + err_code = _sdk.CameraPlay(hCamera) + SetLastError(err_code) + return err_code + +def CameraPause(hCamera): + err_code = _sdk.CameraPause(hCamera) + SetLastError(err_code) + return err_code + +def CameraStop(hCamera): + err_code = _sdk.CameraStop(hCamera) + SetLastError(err_code) + return err_code + +def CameraInitRecord(hCamera, iFormat, pcSavePath, b2GLimit, dwQuality, iFrameRate): + err_code = _sdk.CameraInitRecord(hCamera, iFormat, _str_to_string_buffer(pcSavePath), b2GLimit, dwQuality, iFrameRate) + SetLastError(err_code) + return err_code + +def CameraStopRecord(hCamera): + err_code = _sdk.CameraStopRecord(hCamera) + SetLastError(err_code) + return err_code + +def CameraPushFrame(hCamera, pbyImageBuffer, pFrInfo): + err_code = _sdk.CameraPushFrame(hCamera, c_void_p(pbyImageBuffer), byref(pFrInfo) ) + SetLastError(err_code) + return err_code + +def CameraSaveImage(hCamera, lpszFileName, pbyImageBuffer, pFrInfo, byFileType, byQuality): + err_code = _sdk.CameraSaveImage(hCamera, _str_to_string_buffer(lpszFileName), c_void_p(pbyImageBuffer), byref(pFrInfo), byFileType, byQuality) + SetLastError(err_code) + return err_code + +def CameraSaveImageEx(hCamera, lpszFileName, pbyImageBuffer, uImageFormat, iWidth, iHeight, byFileType, byQuality): + err_code = _sdk.CameraSaveImageEx(hCamera, _str_to_string_buffer(lpszFileName), c_void_p(pbyImageBuffer), uImageFormat, iWidth, iHeight, byFileType, byQuality) + SetLastError(err_code) + return err_code + +def CameraGetImageResolution(hCamera): + psCurVideoSize = tSdkImageResolution() + err_code = _sdk.CameraGetImageResolution(hCamera, byref(psCurVideoSize) ) + SetLastError(err_code) + return psCurVideoSize + +def CameraSetImageResolution(hCamera, pImageResolution): + err_code = _sdk.CameraSetImageResolution(hCamera, byref(pImageResolution) ) + SetLastError(err_code) + return err_code + +def CameraSetImageResolutionEx(hCamera, iIndex, Mode, ModeSize, x, y, width, height, ZoomWidth, ZoomHeight): + err_code = _sdk.CameraSetImageResolutionEx(hCamera, iIndex, Mode, ModeSize, x, y, width, height, ZoomWidth, ZoomHeight) + SetLastError(err_code) + return err_code + +def CameraGetMediaType(hCamera): + piMediaType = c_int() + err_code = _sdk.CameraGetMediaType(hCamera, byref(piMediaType) ) + SetLastError(err_code) + return piMediaType.value + +def CameraSetMediaType(hCamera, iMediaType): + err_code = _sdk.CameraSetMediaType(hCamera, iMediaType) + SetLastError(err_code) + return err_code + +def CameraSetAeState(hCamera, bAeState): + err_code = _sdk.CameraSetAeState(hCamera, bAeState) + SetLastError(err_code) + return err_code + +def CameraGetAeState(hCamera): + pAeState = c_int() + err_code = _sdk.CameraGetAeState(hCamera, byref(pAeState) ) + SetLastError(err_code) + return pAeState.value + +def CameraSetSharpness(hCamera, iSharpness): + err_code = _sdk.CameraSetSharpness(hCamera, iSharpness) + SetLastError(err_code) + return err_code + +def CameraGetSharpness(hCamera): + piSharpness = c_int() + err_code = _sdk.CameraGetSharpness(hCamera, byref(piSharpness) ) + SetLastError(err_code) + return piSharpness.value + +def CameraSetLutMode(hCamera, emLutMode): + err_code = _sdk.CameraSetLutMode(hCamera, emLutMode) + SetLastError(err_code) + return err_code + +def CameraGetLutMode(hCamera): + pemLutMode = c_int() + err_code = _sdk.CameraGetLutMode(hCamera, byref(pemLutMode) ) + SetLastError(err_code) + return pemLutMode.value + +def CameraSelectLutPreset(hCamera, iSel): + err_code = _sdk.CameraSelectLutPreset(hCamera, iSel) + SetLastError(err_code) + return err_code + +def CameraGetLutPresetSel(hCamera): + piSel = c_int() + err_code = _sdk.CameraGetLutPresetSel(hCamera, byref(piSel) ) + SetLastError(err_code) + return piSel.value + +def CameraSetCustomLut(hCamera, iChannel, pLut): + pLutNative = (c_ushort * 4096)(*pLut) + err_code = _sdk.CameraSetCustomLut(hCamera, iChannel, pLutNative) + SetLastError(err_code) + return err_code + +def CameraGetCustomLut(hCamera, iChannel): + pLutNative = (c_ushort * 4096)() + err_code = _sdk.CameraGetCustomLut(hCamera, iChannel, pLutNative) + SetLastError(err_code) + return pLutNative[:] + +def CameraGetCurrentLut(hCamera, iChannel): + pLutNative = (c_ushort * 4096)() + err_code = _sdk.CameraGetCurrentLut(hCamera, iChannel, pLutNative) + SetLastError(err_code) + return pLutNative[:] + +def CameraSetWbMode(hCamera, bAuto): + err_code = _sdk.CameraSetWbMode(hCamera, bAuto) + SetLastError(err_code) + return err_code + +def CameraGetWbMode(hCamera): + pbAuto = c_int() + err_code = _sdk.CameraGetWbMode(hCamera, byref(pbAuto) ) + SetLastError(err_code) + return pbAuto.value + +def CameraSetPresetClrTemp(hCamera, iSel): + err_code = _sdk.CameraSetPresetClrTemp(hCamera, iSel) + SetLastError(err_code) + return err_code + +def CameraGetPresetClrTemp(hCamera): + piSel = c_int() + err_code = _sdk.CameraGetPresetClrTemp(hCamera, byref(piSel) ) + SetLastError(err_code) + return piSel.value + +def CameraSetUserClrTempGain(hCamera, iRgain, iGgain, iBgain): + err_code = _sdk.CameraSetUserClrTempGain(hCamera, iRgain, iGgain, iBgain) + SetLastError(err_code) + return err_code + +def CameraGetUserClrTempGain(hCamera): + piRgain = c_int() + piGgain = c_int() + piBgain = c_int() + err_code = _sdk.CameraGetUserClrTempGain(hCamera, byref(piRgain), byref(piGgain), byref(piBgain) ) + SetLastError(err_code) + return (piRgain.value, piGgain.value, piBgain.value) + +def CameraSetUserClrTempMatrix(hCamera, pMatrix): + pMatrixNative = (c_float * 9)(*pMatrix) + err_code = _sdk.CameraSetUserClrTempMatrix(hCamera, pMatrixNative) + SetLastError(err_code) + return err_code + +def CameraGetUserClrTempMatrix(hCamera): + pMatrixNative = (c_float * 9)() + err_code = _sdk.CameraGetUserClrTempMatrix(hCamera, pMatrixNative) + SetLastError(err_code) + return pMatrixNative[:] + +def CameraSetClrTempMode(hCamera, iMode): + err_code = _sdk.CameraSetClrTempMode(hCamera, iMode) + SetLastError(err_code) + return err_code + +def CameraGetClrTempMode(hCamera): + piMode = c_int() + err_code = _sdk.CameraGetClrTempMode(hCamera, byref(piMode) ) + SetLastError(err_code) + return piMode.value + +def CameraSetOnceWB(hCamera): + err_code = _sdk.CameraSetOnceWB(hCamera) + SetLastError(err_code) + return err_code + +def CameraSetOnceBB(hCamera): + err_code = _sdk.CameraSetOnceBB(hCamera) + SetLastError(err_code) + return err_code + +def CameraSetAeTarget(hCamera, iAeTarget): + err_code = _sdk.CameraSetAeTarget(hCamera, iAeTarget) + SetLastError(err_code) + return err_code + +def CameraGetAeTarget(hCamera): + piAeTarget = c_int() + err_code = _sdk.CameraGetAeTarget(hCamera, byref(piAeTarget) ) + SetLastError(err_code) + return piAeTarget.value + +def CameraSetAeExposureRange(hCamera, fMinExposureTime, fMaxExposureTime): + err_code = _sdk.CameraSetAeExposureRange(hCamera, c_double(fMinExposureTime), c_double(fMaxExposureTime) ) + SetLastError(err_code) + return err_code + +def CameraGetAeExposureRange(hCamera): + fMinExposureTime = c_double() + fMaxExposureTime = c_double() + err_code = _sdk.CameraGetAeExposureRange(hCamera, byref(fMinExposureTime), byref(fMaxExposureTime) ) + SetLastError(err_code) + return (fMinExposureTime.value, fMaxExposureTime.value) + +def CameraSetAeAnalogGainRange(hCamera, iMinAnalogGain, iMaxAnalogGain): + err_code = _sdk.CameraSetAeAnalogGainRange(hCamera, iMinAnalogGain, iMaxAnalogGain) + SetLastError(err_code) + return err_code + +def CameraGetAeAnalogGainRange(hCamera): + iMinAnalogGain = c_int() + iMaxAnalogGain = c_int() + err_code = _sdk.CameraGetAeAnalogGainRange(hCamera, byref(iMinAnalogGain), byref(iMaxAnalogGain) ) + SetLastError(err_code) + return (iMinAnalogGain.value, iMaxAnalogGain.value) + +def CameraSetAeThreshold(hCamera, iThreshold): + err_code = _sdk.CameraSetAeThreshold(hCamera, iThreshold) + SetLastError(err_code) + return err_code + +def CameraGetAeThreshold(hCamera): + iThreshold = c_int() + err_code = _sdk.CameraGetAeThreshold(hCamera, byref(iThreshold)) + SetLastError(err_code) + return iThreshold.value + +def CameraSetExposureTime(hCamera, fExposureTime): + err_code = _sdk.CameraSetExposureTime(hCamera, c_double(fExposureTime) ) + SetLastError(err_code) + return err_code + +def CameraGetExposureLineTime(hCamera): + pfLineTime = c_double() + err_code = _sdk.CameraGetExposureLineTime(hCamera, byref(pfLineTime)) + SetLastError(err_code) + return pfLineTime.value + +def CameraGetExposureTime(hCamera): + pfExposureTime = c_double() + err_code = _sdk.CameraGetExposureTime(hCamera, byref(pfExposureTime)) + SetLastError(err_code) + return pfExposureTime.value + +def CameraGetExposureTimeRange(hCamera): + pfMin = c_double() + pfMax = c_double() + pfStep = c_double() + err_code = _sdk.CameraGetExposureTimeRange(hCamera, byref(pfMin), byref(pfMax), byref(pfStep)) + SetLastError(err_code) + return (pfMin.value, pfMax.value, pfStep.value) + +def CameraSetAnalogGain(hCamera, iAnalogGain): + err_code = _sdk.CameraSetAnalogGain(hCamera, iAnalogGain) + SetLastError(err_code) + return err_code + +def CameraGetAnalogGain(hCamera): + piAnalogGain = c_int() + err_code = _sdk.CameraGetAnalogGain(hCamera, byref(piAnalogGain)) + SetLastError(err_code) + return piAnalogGain.value + +def CameraSetAnalogGainX(hCamera, fGain): + err_code = _sdk.CameraSetAnalogGainX(hCamera, c_float(fGain) ) + SetLastError(err_code) + return err_code + +def CameraGetAnalogGainX(hCamera): + fGain = c_float() + err_code = _sdk.CameraGetAnalogGainX(hCamera, byref(fGain)) + SetLastError(err_code) + return fGain.value + +def CameraGetAnalogGainXRange(hCamera): + pfMin = c_float() + pfMax = c_float() + pfStep = c_float() + err_code = _sdk.CameraGetAnalogGainXRange(hCamera, byref(pfMin), byref(pfMax), byref(pfStep)) + SetLastError(err_code) + return (pfMin.value, pfMax.value, pfStep.value) + +def CameraSetGain(hCamera, iRGain, iGGain, iBGain): + err_code = _sdk.CameraSetGain(hCamera, iRGain, iGGain, iBGain) + SetLastError(err_code) + return err_code + +def CameraGetGain(hCamera): + piRGain = c_int() + piGGain = c_int() + piBGain = c_int() + err_code = _sdk.CameraGetGain(hCamera, byref(piRGain), byref(piGGain), byref(piBGain)) + SetLastError(err_code) + return (piRGain.value, piGGain.value, piBGain.value) + +def CameraSetGamma(hCamera, iGamma): + err_code = _sdk.CameraSetGamma(hCamera, iGamma) + SetLastError(err_code) + return err_code + +def CameraGetGamma(hCamera): + piGamma = c_int() + err_code = _sdk.CameraGetGamma(hCamera, byref(piGamma)) + SetLastError(err_code) + return piGamma.value + +def CameraSetContrast(hCamera, iContrast): + err_code = _sdk.CameraSetContrast(hCamera, iContrast) + SetLastError(err_code) + return err_code + +def CameraGetContrast(hCamera): + piContrast = c_int() + err_code = _sdk.CameraGetContrast(hCamera, byref(piContrast)) + SetLastError(err_code) + return piContrast.value + +def CameraSetSaturation(hCamera, iSaturation): + err_code = _sdk.CameraSetSaturation(hCamera, iSaturation) + SetLastError(err_code) + return err_code + +def CameraGetSaturation(hCamera): + piSaturation = c_int() + err_code = _sdk.CameraGetSaturation(hCamera, byref(piSaturation)) + SetLastError(err_code) + return piSaturation.value + +def CameraSetMonochrome(hCamera, bEnable): + err_code = _sdk.CameraSetMonochrome(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetMonochrome(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraGetMonochrome(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraSetInverse(hCamera, bEnable): + err_code = _sdk.CameraSetInverse(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetInverse(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraGetInverse(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraSetAntiFlick(hCamera, bEnable): + err_code = _sdk.CameraSetAntiFlick(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetAntiFlick(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraGetAntiFlick(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraGetLightFrequency(hCamera): + piFrequencySel = c_int() + err_code = _sdk.CameraGetLightFrequency(hCamera, byref(piFrequencySel)) + SetLastError(err_code) + return piFrequencySel.value + +def CameraSetLightFrequency(hCamera, iFrequencySel): + err_code = _sdk.CameraSetLightFrequency(hCamera, iFrequencySel) + SetLastError(err_code) + return err_code + +def CameraSetFrameSpeed(hCamera, iFrameSpeed): + err_code = _sdk.CameraSetFrameSpeed(hCamera, iFrameSpeed) + SetLastError(err_code) + return err_code + +def CameraGetFrameSpeed(hCamera): + piFrameSpeed = c_int() + err_code = _sdk.CameraGetFrameSpeed(hCamera, byref(piFrameSpeed)) + SetLastError(err_code) + return piFrameSpeed.value + +def CameraSetParameterMode(hCamera, iMode): + err_code = _sdk.CameraSetParameterMode(hCamera, iMode) + SetLastError(err_code) + return err_code + +def CameraGetParameterMode(hCamera): + piTarget = c_int() + err_code = _sdk.CameraGetParameterMode(hCamera, byref(piTarget)) + SetLastError(err_code) + return piTarget.value + +def CameraSetParameterMask(hCamera, uMask): + err_code = _sdk.CameraSetParameterMask(hCamera, uMask) + SetLastError(err_code) + return err_code + +def CameraSaveParameter(hCamera, iTeam): + err_code = _sdk.CameraSaveParameter(hCamera, iTeam) + SetLastError(err_code) + return err_code + +def CameraSaveParameterToFile(hCamera, sFileName): + err_code = _sdk.CameraSaveParameterToFile(hCamera, _str_to_string_buffer(sFileName)) + SetLastError(err_code) + return err_code + +def CameraReadParameterFromFile(hCamera, sFileName): + err_code = _sdk.CameraReadParameterFromFile(hCamera, _str_to_string_buffer(sFileName)) + SetLastError(err_code) + return err_code + +def CameraLoadParameter(hCamera, iTeam): + err_code = _sdk.CameraLoadParameter(hCamera, iTeam) + SetLastError(err_code) + return err_code + +def CameraGetCurrentParameterGroup(hCamera): + piTeam = c_int() + err_code = _sdk.CameraGetCurrentParameterGroup(hCamera, byref(piTeam)) + SetLastError(err_code) + return piTeam.value + +def CameraSetTransPackLen(hCamera, iPackSel): + err_code = _sdk.CameraSetTransPackLen(hCamera, iPackSel) + SetLastError(err_code) + return err_code + +def CameraGetTransPackLen(hCamera): + piPackSel = c_int() + err_code = _sdk.CameraGetTransPackLen(hCamera, byref(piPackSel)) + SetLastError(err_code) + return piPackSel.value + +def CameraIsAeWinVisible(hCamera): + pbIsVisible = c_int() + err_code = _sdk.CameraIsAeWinVisible(hCamera, byref(pbIsVisible)) + SetLastError(err_code) + return pbIsVisible.value + +def CameraSetAeWinVisible(hCamera, bIsVisible): + err_code = _sdk.CameraSetAeWinVisible(hCamera, bIsVisible) + SetLastError(err_code) + return err_code + +def CameraGetAeWindow(hCamera): + piHOff = c_int() + piVOff = c_int() + piWidth = c_int() + piHeight = c_int() + err_code = _sdk.CameraGetAeWindow(hCamera, byref(piHOff), byref(piVOff), byref(piWidth), byref(piHeight)) + SetLastError(err_code) + return (piHOff.value, piVOff.value, piWidth.value, piHeight.value) + +def CameraSetAeWindow(hCamera, iHOff, iVOff, iWidth, iHeight): + err_code = _sdk.CameraSetAeWindow(hCamera, iHOff, iVOff, iWidth, iHeight) + SetLastError(err_code) + return err_code + +def CameraSetMirror(hCamera, iDir, bEnable): + err_code = _sdk.CameraSetMirror(hCamera, iDir, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetMirror(hCamera, iDir): + pbEnable = c_int() + err_code = _sdk.CameraGetMirror(hCamera, iDir, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraSetRotate(hCamera, iRot): + err_code = _sdk.CameraSetRotate(hCamera, iRot) + SetLastError(err_code) + return err_code + +def CameraGetRotate(hCamera): + iRot = c_int() + err_code = _sdk.CameraGetRotate(hCamera, byref(iRot)) + SetLastError(err_code) + return iRot.value + +def CameraGetWbWindow(hCamera): + PiHOff = c_int() + PiVOff = c_int() + PiWidth = c_int() + PiHeight = c_int() + err_code = _sdk.CameraGetWbWindow(hCamera, byref(PiHOff), byref(PiVOff), byref(PiWidth), byref(PiHeight)) + SetLastError(err_code) + return (PiHOff.value, PiVOff.value, PiWidth.value, PiHeight.value) + +def CameraSetWbWindow(hCamera, iHOff, iVOff, iWidth, iHeight): + err_code = _sdk.CameraSetWbWindow(hCamera, iHOff, iVOff, iWidth, iHeight) + SetLastError(err_code) + return err_code + +def CameraIsWbWinVisible(hCamera): + pbShow = c_int() + err_code = _sdk.CameraIsWbWinVisible(hCamera, byref(pbShow)) + SetLastError(err_code) + return pbShow.value + +def CameraSetWbWinVisible(hCamera, bShow): + err_code = _sdk.CameraSetWbWinVisible(hCamera, bShow) + SetLastError(err_code) + return err_code + +def CameraImageOverlay(hCamera, pRgbBuffer, pFrInfo): + err_code = _sdk.CameraImageOverlay(hCamera, c_void_p(pRgbBuffer), byref(pFrInfo)) + SetLastError(err_code) + return err_code + +def CameraSetCrossLine(hCamera, iLine, x, y, uColor, bVisible): + err_code = _sdk.CameraSetCrossLine(hCamera, iLine, x, y, uColor, bVisible) + SetLastError(err_code) + return err_code + +def CameraGetCrossLine(hCamera, iLine): + px = c_int() + py = c_int() + pcolor = c_uint() + pbVisible = c_int() + err_code = _sdk.CameraGetCrossLine(hCamera, iLine, byref(px), byref(py), byref(pcolor), byref(pbVisible)) + SetLastError(err_code) + return (px.value, py.value, pcolor.value, pbVisible.value) + +def CameraGetCapability(hCamera): + pCameraInfo = tSdkCameraCapbility() + err_code = _sdk.CameraGetCapability(hCamera, byref(pCameraInfo)) + SetLastError(err_code) + return pCameraInfo + +def CameraWriteSN(hCamera, pbySN, iLevel): + err_code = _sdk.CameraWriteSN(hCamera, _str_to_string_buffer(pbySN), iLevel) + SetLastError(err_code) + return err_code + +def CameraReadSN(hCamera, iLevel): + pbySN = create_string_buffer(64) + err_code = _sdk.CameraReadSN(hCamera, pbySN, iLevel) + SetLastError(err_code) + return _string_buffer_to_str(pbySN) + +def CameraSetTriggerDelayTime(hCamera, uDelayTimeUs): + err_code = _sdk.CameraSetTriggerDelayTime(hCamera, uDelayTimeUs) + SetLastError(err_code) + return err_code + +def CameraGetTriggerDelayTime(hCamera): + puDelayTimeUs = c_uint() + err_code = _sdk.CameraGetTriggerDelayTime(hCamera, byref(puDelayTimeUs)) + SetLastError(err_code) + return puDelayTimeUs.value + +def CameraSetTriggerCount(hCamera, iCount): + err_code = _sdk.CameraSetTriggerCount(hCamera, iCount) + SetLastError(err_code) + return err_code + +def CameraGetTriggerCount(hCamera): + piCount = c_int() + err_code = _sdk.CameraGetTriggerCount(hCamera, byref(piCount)) + SetLastError(err_code) + return piCount.value + +def CameraSoftTrigger(hCamera): + err_code = _sdk.CameraSoftTrigger(hCamera) + SetLastError(err_code) + return err_code + +def CameraSetTriggerMode(hCamera, iModeSel): + err_code = _sdk.CameraSetTriggerMode(hCamera, iModeSel) + SetLastError(err_code) + return err_code + +def CameraGetTriggerMode(hCamera): + piModeSel = c_int() + err_code = _sdk.CameraGetTriggerMode(hCamera, byref(piModeSel)) + SetLastError(err_code) + return piModeSel.value + +def CameraSetStrobeMode(hCamera, iMode): + err_code = _sdk.CameraSetStrobeMode(hCamera, iMode) + SetLastError(err_code) + return err_code + +def CameraGetStrobeMode(hCamera): + piMode = c_int() + err_code = _sdk.CameraGetStrobeMode(hCamera, byref(piMode)) + SetLastError(err_code) + return piMode.value + +def CameraSetStrobeDelayTime(hCamera, uDelayTimeUs): + err_code = _sdk.CameraSetStrobeDelayTime(hCamera, uDelayTimeUs) + SetLastError(err_code) + return err_code + +def CameraGetStrobeDelayTime(hCamera): + upDelayTimeUs = c_uint() + err_code = _sdk.CameraGetStrobeDelayTime(hCamera, byref(upDelayTimeUs)) + SetLastError(err_code) + return upDelayTimeUs.value + +def CameraSetStrobePulseWidth(hCamera, uTimeUs): + err_code = _sdk.CameraSetStrobePulseWidth(hCamera, uTimeUs) + SetLastError(err_code) + return err_code + +def CameraGetStrobePulseWidth(hCamera): + upTimeUs = c_uint() + err_code = _sdk.CameraGetStrobePulseWidth(hCamera, byref(upTimeUs)) + SetLastError(err_code) + return upTimeUs.value + +def CameraSetStrobePolarity(hCamera, uPolarity): + err_code = _sdk.CameraSetStrobePolarity(hCamera, uPolarity) + SetLastError(err_code) + return err_code + +def CameraGetStrobePolarity(hCamera): + upPolarity = c_uint() + err_code = _sdk.CameraGetStrobePolarity(hCamera, byref(upPolarity)) + SetLastError(err_code) + return upPolarity.value + +def CameraSetExtTrigSignalType(hCamera, iType): + err_code = _sdk.CameraSetExtTrigSignalType(hCamera, iType) + SetLastError(err_code) + return err_code + +def CameraGetExtTrigSignalType(hCamera): + ipType = c_int() + err_code = _sdk.CameraGetExtTrigSignalType(hCamera, byref(ipType)) + SetLastError(err_code) + return ipType.value + +def CameraSetExtTrigShutterType(hCamera, iType): + err_code = _sdk.CameraSetExtTrigShutterType(hCamera, iType) + SetLastError(err_code) + return err_code + +def CameraGetExtTrigShutterType(hCamera): + ipType = c_int() + err_code = _sdk.CameraGetExtTrigShutterType(hCamera, byref(ipType)) + SetLastError(err_code) + return ipType.value + +def CameraSetExtTrigDelayTime(hCamera, uDelayTimeUs): + err_code = _sdk.CameraSetExtTrigDelayTime(hCamera, uDelayTimeUs) + SetLastError(err_code) + return err_code + +def CameraGetExtTrigDelayTime(hCamera): + upDelayTimeUs = c_uint() + err_code = _sdk.CameraGetExtTrigDelayTime(hCamera, byref(upDelayTimeUs)) + SetLastError(err_code) + return upDelayTimeUs.value + +def CameraSetExtTrigJitterTime(hCamera, uTimeUs): + err_code = _sdk.CameraSetExtTrigJitterTime(hCamera, uTimeUs) + SetLastError(err_code) + return err_code + +def CameraGetExtTrigJitterTime(hCamera): + upTimeUs = c_uint() + err_code = _sdk.CameraGetExtTrigJitterTime(hCamera, byref(upTimeUs)) + SetLastError(err_code) + return upTimeUs.value + +def CameraGetExtTrigCapability(hCamera): + puCapabilityMask = c_uint() + err_code = _sdk.CameraGetExtTrigCapability(hCamera, byref(puCapabilityMask)) + SetLastError(err_code) + return puCapabilityMask.value + +def CameraPauseLevelTrigger(hCamera): + err_code = _sdk.CameraPauseLevelTrigger(hCamera) + SetLastError(err_code) + return err_code + +def CameraGetResolutionForSnap(hCamera): + pImageResolution = tSdkImageResolution() + err_code = _sdk.CameraGetResolutionForSnap(hCamera, byref(pImageResolution)) + SetLastError(err_code) + return pImageResolution + +def CameraSetResolutionForSnap(hCamera, pImageResolution): + err_code = _sdk.CameraSetResolutionForSnap(hCamera, byref(pImageResolution)) + SetLastError(err_code) + return err_code + +def CameraCustomizeResolution(hCamera): + pImageCustom = tSdkImageResolution() + err_code = _sdk.CameraCustomizeResolution(hCamera, byref(pImageCustom)) + SetLastError(err_code) + return pImageCustom + +def CameraCustomizeReferWin(hCamera, iWinType, hParent): + piHOff = c_int() + piVOff = c_int() + piWidth = c_int() + piHeight = c_int() + err_code = _sdk.CameraCustomizeReferWin(hCamera, iWinType, hParent, byref(piHOff), byref(piVOff), byref(piWidth), byref(piHeight)) + SetLastError(err_code) + return (piHOff.value, piVOff.value, piWidth.value, piHeight.value) + +def CameraShowSettingPage(hCamera, bShow): + err_code = _sdk.CameraShowSettingPage(hCamera, bShow) + SetLastError(err_code) + return err_code + +def CameraCreateSettingPage(hCamera, hParent, pWinText, pCallbackFunc = None, pCallbackCtx = 0, uReserved = 0): + err_code = _sdk.CameraCreateSettingPage(hCamera, hParent, _str_to_string_buffer(pWinText), pCallbackFunc, c_void_p(pCallbackCtx), uReserved) + SetLastError(err_code) + return err_code + +def CameraCreateSettingPageEx(hCamera): + err_code = _sdk.CameraCreateSettingPageEx(hCamera) + SetLastError(err_code) + return err_code + +def CameraSetActiveSettingSubPage(hCamera, index): + err_code = _sdk.CameraSetActiveSettingSubPage(hCamera, index) + SetLastError(err_code) + return err_code + +def CameraSetSettingPageParent(hCamera, hParentWnd, Flags): + err_code = _sdk.CameraSetSettingPageParent(hCamera, hParentWnd, Flags) + SetLastError(err_code) + return err_code + +def CameraGetSettingPageHWnd(hCamera): + hWnd = c_void_p() + err_code = _sdk.CameraGetSettingPageHWnd(hCamera, byref(hWnd)) + SetLastError(err_code) + return hWnd.value + +def CameraSpecialControl(hCamera, dwCtrlCode, dwParam, lpData): + err_code = _sdk.CameraSpecialControl(hCamera, dwCtrlCode, dwParam, c_void_p(lpData) ) + SetLastError(err_code) + return err_code + +def CameraGetFrameStatistic(hCamera): + psFrameStatistic = tSdkFrameStatistic() + err_code = _sdk.CameraGetFrameStatistic(hCamera, byref(psFrameStatistic)) + SetLastError(err_code) + return psFrameStatistic + +def CameraSetNoiseFilter(hCamera, bEnable): + err_code = _sdk.CameraSetNoiseFilter(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetNoiseFilterState(hCamera): + pEnable = c_int() + err_code = _sdk.CameraGetNoiseFilterState(hCamera, byref(pEnable)) + SetLastError(err_code) + return pEnable.value + +def CameraRstTimeStamp(hCamera): + err_code = _sdk.CameraRstTimeStamp(hCamera) + SetLastError(err_code) + return err_code + +def CameraSaveUserData(hCamera, uStartAddr, pbData): + err_code = _sdk.CameraSaveUserData(hCamera, uStartAddr, pbData, len(pbData)) + SetLastError(err_code) + return err_code + +def CameraLoadUserData(hCamera, uStartAddr, ilen): + pbData = create_string_buffer(ilen) + err_code = _sdk.CameraLoadUserData(hCamera, uStartAddr, pbData, ilen) + SetLastError(err_code) + return pbData[:] + +def CameraGetFriendlyName(hCamera): + pName = create_string_buffer(64) + err_code = _sdk.CameraGetFriendlyName(hCamera, pName) + SetLastError(err_code) + return _string_buffer_to_str(pName) + +def CameraSetFriendlyName(hCamera, pName): + pNameBuf = _str_to_string_buffer(pName) + resize(pNameBuf, 64) + err_code = _sdk.CameraSetFriendlyName(hCamera, pNameBuf) + SetLastError(err_code) + return err_code + +def CameraSdkGetVersionString(): + pVersionString = create_string_buffer(64) + err_code = _sdk.CameraSdkGetVersionString(pVersionString) + SetLastError(err_code) + return _string_buffer_to_str(pVersionString) + +def CameraCheckFwUpdate(hCamera): + pNeedUpdate = c_int() + err_code = _sdk.CameraCheckFwUpdate(hCamera, byref(pNeedUpdate)) + SetLastError(err_code) + return pNeedUpdate.value + +def CameraGetFirmwareVersion(hCamera): + pVersion = create_string_buffer(64) + err_code = _sdk.CameraGetFirmwareVersion(hCamera, pVersion) + SetLastError(err_code) + return _string_buffer_to_str(pVersion) + +def CameraGetEnumInfo(hCamera): + pCameraInfo = tSdkCameraDevInfo() + err_code = _sdk.CameraGetEnumInfo(hCamera, byref(pCameraInfo)) + SetLastError(err_code) + return pCameraInfo + +def CameraGetInerfaceVersion(hCamera): + pVersion = create_string_buffer(64) + err_code = _sdk.CameraGetInerfaceVersion(hCamera, pVersion) + SetLastError(err_code) + return _string_buffer_to_str(pVersion) + +def CameraSetIOState(hCamera, iOutputIOIndex, uState): + err_code = _sdk.CameraSetIOState(hCamera, iOutputIOIndex, uState) + SetLastError(err_code) + return err_code + +def CameraSetIOStateEx(hCamera, iOutputIOIndex, uState): + err_code = _sdk.CameraSetIOStateEx(hCamera, iOutputIOIndex, uState) + SetLastError(err_code) + return err_code + +def CameraGetOutPutIOState(hCamera, iOutputIOIndex): + puState = c_int() + err_code = _sdk.CameraGetOutPutIOState(hCamera, iOutputIOIndex, byref(puState)) + SetLastError(err_code) + return puState.value + +def CameraGetOutPutIOStateEx(hCamera, iOutputIOIndex): + puState = c_int() + err_code = _sdk.CameraGetOutPutIOStateEx(hCamera, iOutputIOIndex, byref(puState)) + SetLastError(err_code) + return puState.value + +def CameraGetIOState(hCamera, iInputIOIndex): + puState = c_int() + err_code = _sdk.CameraGetIOState(hCamera, iInputIOIndex, byref(puState)) + SetLastError(err_code) + return puState.value + +def CameraGetIOStateEx(hCamera, iInputIOIndex): + puState = c_int() + err_code = _sdk.CameraGetIOStateEx(hCamera, iInputIOIndex, byref(puState)) + SetLastError(err_code) + return puState.value + +def CameraSetInPutIOMode(hCamera, iInputIOIndex, iMode): + err_code = _sdk.CameraSetInPutIOMode(hCamera, iInputIOIndex, iMode) + SetLastError(err_code) + return err_code + +def CameraSetOutPutIOMode(hCamera, iOutputIOIndex, iMode): + err_code = _sdk.CameraSetOutPutIOMode(hCamera, iOutputIOIndex, iMode) + SetLastError(err_code) + return err_code + +def CameraSetOutPutPWM(hCamera, iOutputIOIndex, iCycle, uDuty): + err_code = _sdk.CameraSetOutPutPWM(hCamera, iOutputIOIndex, iCycle, uDuty) + SetLastError(err_code) + return err_code + +def CameraSetAeAlgorithm(hCamera, iIspProcessor, iAeAlgorithmSel): + err_code = _sdk.CameraSetAeAlgorithm(hCamera, iIspProcessor, iAeAlgorithmSel) + SetLastError(err_code) + return err_code + +def CameraGetAeAlgorithm(hCamera, iIspProcessor): + piAlgorithmSel = c_int() + err_code = _sdk.CameraGetAeAlgorithm(hCamera, iIspProcessor, byref(piAlgorithmSel)) + SetLastError(err_code) + return piAlgorithmSel.value + +def CameraSetBayerDecAlgorithm(hCamera, iIspProcessor, iAlgorithmSel): + err_code = _sdk.CameraSetBayerDecAlgorithm(hCamera, iIspProcessor, iAlgorithmSel) + SetLastError(err_code) + return err_code + +def CameraGetBayerDecAlgorithm(hCamera, iIspProcessor): + piAlgorithmSel = c_int() + err_code = _sdk.CameraGetBayerDecAlgorithm(hCamera, iIspProcessor, byref(piAlgorithmSel)) + SetLastError(err_code) + return piAlgorithmSel.value + +def CameraSetIspProcessor(hCamera, iIspProcessor): + err_code = _sdk.CameraSetIspProcessor(hCamera, iIspProcessor) + SetLastError(err_code) + return err_code + +def CameraGetIspProcessor(hCamera): + piIspProcessor = c_int() + err_code = _sdk.CameraGetIspProcessor(hCamera, byref(piIspProcessor)) + SetLastError(err_code) + return piIspProcessor.value + +def CameraSetBlackLevel(hCamera, iBlackLevel): + err_code = _sdk.CameraSetBlackLevel(hCamera, iBlackLevel) + SetLastError(err_code) + return err_code + +def CameraGetBlackLevel(hCamera): + piBlackLevel = c_int() + err_code = _sdk.CameraGetBlackLevel(hCamera, byref(piBlackLevel)) + SetLastError(err_code) + return piBlackLevel.value + +def CameraSetWhiteLevel(hCamera, iWhiteLevel): + err_code = _sdk.CameraSetWhiteLevel(hCamera, iWhiteLevel) + SetLastError(err_code) + return err_code + +def CameraGetWhiteLevel(hCamera): + piWhiteLevel = c_int() + err_code = _sdk.CameraGetWhiteLevel(hCamera, byref(piWhiteLevel)) + SetLastError(err_code) + return piWhiteLevel.value + +def CameraSetIspOutFormat(hCamera, uFormat): + err_code = _sdk.CameraSetIspOutFormat(hCamera, uFormat) + SetLastError(err_code) + return err_code + +def CameraGetIspOutFormat(hCamera): + puFormat = c_int() + err_code = _sdk.CameraGetIspOutFormat(hCamera, byref(puFormat)) + SetLastError(err_code) + return puFormat.value + +def CameraGetErrorString(iStatusCode): + _sdk.CameraGetErrorString.restype = c_char_p + msg = _sdk.CameraGetErrorString(iStatusCode) + if msg: + return _string_buffer_to_str(msg) + else: + return '' + +def CameraGetImageBufferEx2(hCamera, pImageData, uOutFormat, wTimes): + piWidth = c_int() + piHeight = c_int() + err_code = _sdk.CameraGetImageBufferEx2(hCamera, c_void_p(pImageData), uOutFormat, byref(piWidth), byref(piHeight), wTimes) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (piWidth.value, piHeight.value) + +def CameraGetImageBufferEx3(hCamera, pImageData, uOutFormat, wTimes): + piWidth = c_int() + piHeight = c_int() + puTimeStamp = c_int() + err_code = _sdk.CameraGetImageBufferEx3(hCamera, c_void_p(pImageData), uOutFormat, byref(piWidth), byref(piHeight), byref(puTimeStamp), wTimes) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (piWidth.value, piHeight.value, puTimeStamp.value) + +def CameraGetCapabilityEx2(hCamera): + pMaxWidth = c_int() + pMaxHeight = c_int() + pbColorCamera = c_int() + err_code = _sdk.CameraGetCapabilityEx2(hCamera, byref(pMaxWidth), byref(pMaxHeight), byref(pbColorCamera)) + SetLastError(err_code) + return (pMaxWidth.value, pMaxHeight.value, pbColorCamera.value) + +def CameraReConnect(hCamera): + err_code = _sdk.CameraReConnect(hCamera) + SetLastError(err_code) + return err_code + +def CameraConnectTest(hCamera): + err_code = _sdk.CameraConnectTest(hCamera) + SetLastError(err_code) + return err_code + +def CameraSetLedEnable(hCamera, index, enable): + err_code = _sdk.CameraSetLedEnable(hCamera, index, enable) + SetLastError(err_code) + return err_code + +def CameraGetLedEnable(hCamera, index): + enable = c_int() + err_code = _sdk.CameraGetLedEnable(hCamera, index, byref(enable)) + SetLastError(err_code) + return enable.value + +def CameraSetLedOnOff(hCamera, index, onoff): + err_code = _sdk.CameraSetLedOnOff(hCamera, index, onoff) + SetLastError(err_code) + return err_code + +def CameraGetLedOnOff(hCamera, index): + onoff = c_int() + err_code = _sdk.CameraGetLedOnOff(hCamera, index, byref(onoff)) + SetLastError(err_code) + return onoff.value + +def CameraSetLedDuration(hCamera, index, duration): + err_code = _sdk.CameraSetLedDuration(hCamera, index, duration) + SetLastError(err_code) + return err_code + +def CameraGetLedDuration(hCamera, index): + duration = c_uint() + err_code = _sdk.CameraGetLedDuration(hCamera, index, byref(duration)) + SetLastError(err_code) + return duration.value + +def CameraSetLedBrightness(hCamera, index, uBrightness): + err_code = _sdk.CameraSetLedBrightness(hCamera, index, uBrightness) + SetLastError(err_code) + return err_code + +def CameraGetLedBrightness(hCamera, index): + uBrightness = c_uint() + err_code = _sdk.CameraGetLedBrightness(hCamera, index, byref(uBrightness)) + SetLastError(err_code) + return uBrightness.value + +def CameraEnableTransferRoi(hCamera, uEnableMask): + err_code = _sdk.CameraEnableTransferRoi(hCamera, uEnableMask) + SetLastError(err_code) + return err_code + +def CameraSetTransferRoi(hCamera, index, X1, Y1, X2, Y2): + err_code = _sdk.CameraSetTransferRoi(hCamera, index, X1, Y1, X2, Y2) + SetLastError(err_code) + return err_code + +def CameraGetTransferRoi(hCamera, index): + pX1 = c_uint() + pY1 = c_uint() + pX2 = c_uint() + pY2 = c_uint() + err_code = _sdk.CameraGetTransferRoi(hCamera, index, byref(pX1), byref(pY1), byref(pX2), byref(pY2)) + SetLastError(err_code) + return (pX1.value, pY1.value, pX2.value, pY2.value) + +def CameraAlignMalloc(size, align = 16): + _sdk.CameraAlignMalloc.restype = c_void_p + r = _sdk.CameraAlignMalloc(size, align) + return r + +def CameraAlignFree(membuffer): + _sdk.CameraAlignFree(c_void_p(membuffer)) + +def CameraSetAutoConnect(hCamera, bEnable): + err_code = _sdk.CameraSetAutoConnect(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetAutoConnect(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraGetAutoConnect(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraGetReConnectCounts(hCamera): + puCounts = c_int() + err_code = _sdk.CameraGetReConnectCounts(hCamera, byref(puCounts)) + SetLastError(err_code) + return puCounts.value + +def CameraSetSingleGrabMode(hCamera, bEnable): + err_code = _sdk.CameraSetSingleGrabMode(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetSingleGrabMode(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraGetSingleGrabMode(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraRestartGrab(hCamera): + err_code = _sdk.CameraRestartGrab(hCamera) + SetLastError(err_code) + return err_code + +def CameraEvaluateImageDefinition(hCamera, iAlgorithSel, pbyIn, pFrInfo): + DefinitionValue = c_double() + err_code = _sdk.CameraEvaluateImageDefinition(hCamera, iAlgorithSel, c_void_p(pbyIn), byref(pFrInfo), byref(DefinitionValue)) + SetLastError(err_code) + return DefinitionValue.value + +def CameraDrawText(pRgbBuffer, pFrInfo, pFontFileName, FontWidth, FontHeight, pText, Left, Top, Width, Height, TextColor, uFlags): + err_code = _sdk.CameraDrawText(c_void_p(pRgbBuffer), byref(pFrInfo), _str_to_string_buffer(pFontFileName), FontWidth, FontHeight, _str_to_string_buffer(pText), Left, Top, Width, Height, TextColor, uFlags) + SetLastError(err_code) + return err_code + +def CameraGigeEnumerateDevice(ipList, MaxCount = 32): + if type(ipList) in (list, tuple): + ipList = map(lambda x: _str_to_string_buffer(x), ipList) + else: + ipList = (_str_to_string_buffer(ipList),) + numIP = len(ipList) + ppIpList = (c_void_p * numIP)(*map(lambda x: addressof(x), ipList)) + Nums = c_int(MaxCount) + pCameraList = (tSdkCameraDevInfo * Nums.value)() + err_code = _sdk.CameraGigeEnumerateDevice(ppIpList, numIP, pCameraList, byref(Nums)) + SetLastError(err_code) + return pCameraList[0:Nums.value] + +def CameraGigeGetIp(pCameraInfo): + CamIp = create_string_buffer(32) + CamMask = create_string_buffer(32) + CamGateWay = create_string_buffer(32) + EtIp = create_string_buffer(32) + EtMask = create_string_buffer(32) + EtGateWay = create_string_buffer(32) + err_code = _sdk.CameraGigeGetIp(byref(pCameraInfo), CamIp, CamMask, CamGateWay, EtIp, EtMask, EtGateWay) + SetLastError(err_code) + return (_string_buffer_to_str(CamIp), _string_buffer_to_str(CamMask), _string_buffer_to_str(CamGateWay), + _string_buffer_to_str(EtIp), _string_buffer_to_str(EtMask), _string_buffer_to_str(EtGateWay) ) + +def CameraGigeSetIp(pCameraInfo, Ip, SubMask, GateWay, bPersistent): + err_code = _sdk.CameraGigeSetIp(byref(pCameraInfo), + _str_to_string_buffer(Ip), _str_to_string_buffer(SubMask), _str_to_string_buffer(GateWay), bPersistent) + SetLastError(err_code) + return err_code + +def CameraGigeGetMac(pCameraInfo): + CamMac = create_string_buffer(32) + EtMac = create_string_buffer(32) + err_code = _sdk.CameraGigeGetMac(byref(pCameraInfo), CamMac, EtMac) + SetLastError(err_code) + return (_string_buffer_to_str(CamMac), _string_buffer_to_str(EtMac) ) + +def CameraEnableFastResponse(hCamera): + err_code = _sdk.CameraEnableFastResponse(hCamera) + SetLastError(err_code) + return err_code + +def CameraSetCorrectDeadPixel(hCamera, bEnable): + err_code = _sdk.CameraSetCorrectDeadPixel(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetCorrectDeadPixel(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraGetCorrectDeadPixel(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraFlatFieldingCorrectSetEnable(hCamera, bEnable): + err_code = _sdk.CameraFlatFieldingCorrectSetEnable(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraFlatFieldingCorrectGetEnable(hCamera): + pbEnable = c_int() + err_code = _sdk.CameraFlatFieldingCorrectGetEnable(hCamera, byref(pbEnable)) + SetLastError(err_code) + return pbEnable.value + +def CameraFlatFieldingCorrectSetParameter(hCamera, pDarkFieldingImage, pDarkFieldingFrInfo, pLightFieldingImage, pLightFieldingFrInfo): + err_code = _sdk.CameraFlatFieldingCorrectSetParameter(hCamera, c_void_p(pDarkFieldingImage), byref(pDarkFieldingFrInfo), c_void_p(pLightFieldingImage), byref(pLightFieldingFrInfo)) + SetLastError(err_code) + return err_code + +def CameraFlatFieldingCorrectGetParameterState(hCamera): + pbValid = c_int() + pFilePath = create_string_buffer(1024) + err_code = _sdk.CameraFlatFieldingCorrectGetParameterState(hCamera, byref(pbValid), pFilePath) + SetLastError(err_code) + return (pbValid.value, _string_buffer_to_str(pFilePath) ) + +def CameraFlatFieldingCorrectSaveParameterToFile(hCamera, pszFileName): + err_code = _sdk.CameraFlatFieldingCorrectSaveParameterToFile(hCamera, _str_to_string_buffer(pszFileName)) + SetLastError(err_code) + return err_code + +def CameraFlatFieldingCorrectLoadParameterFromFile(hCamera, pszFileName): + err_code = _sdk.CameraFlatFieldingCorrectLoadParameterFromFile(hCamera, _str_to_string_buffer(pszFileName)) + SetLastError(err_code) + return err_code + +def CameraCommonCall(hCamera, pszCall, uResultBufSize): + pszResult = create_string_buffer(uResultBufSize) if uResultBufSize > 0 else None + err_code = _sdk.CameraCommonCall(hCamera, _str_to_string_buffer(pszCall), pszResult, uResultBufSize) + SetLastError(err_code) + return _string_buffer_to_str(pszResult) if pszResult else '' + +def CameraSetDenoise3DParams(hCamera, bEnable, nCount, Weights): + assert(nCount >= 2 and nCount <= 8) + if Weights: + assert(len(Weights) == nCount) + WeightsNative = (c_float * nCount)(*Weights) + else: + WeightsNative = None + err_code = _sdk.CameraSetDenoise3DParams(hCamera, bEnable, nCount, WeightsNative) + SetLastError(err_code) + return err_code + +def CameraGetDenoise3DParams(hCamera): + bEnable = c_int() + nCount = c_int() + bUseWeight = c_int() + Weights = (c_float * 8)() + err_code = _sdk.CameraGetDenoise3DParams(hCamera, byref(bEnable), byref(nCount), byref(bUseWeight), Weights) + SetLastError(err_code) + bEnable, nCount, bUseWeight = bEnable.value, nCount.value, bUseWeight.value + if bUseWeight: + Weights = Weights[:nCount] + else: + Weights = None + return (bEnable, nCount, bUseWeight, Weights) + +def CameraManualDenoise3D(InFramesHead, InFramesData, nCount, Weights, OutFrameHead, OutFrameData): + assert(nCount > 0) + assert(len(InFramesData) == nCount) + assert(Weights is None or len(Weights) == nCount) + InFramesDataNative = (c_void_p * nCount)(*InFramesData) + WeightsNative = (c_float * nCount)(*Weights) if Weights else None + err_code = _sdk.CameraManualDenoise3D(byref(InFramesHead), InFramesDataNative, nCount, WeightsNative, byref(OutFrameHead), c_void_p(OutFrameData)) + SetLastError(err_code) + return err_code + +def CameraCustomizeDeadPixels(hCamera, hParent): + err_code = _sdk.CameraCustomizeDeadPixels(hCamera, hParent) + SetLastError(err_code) + return err_code + +def CameraReadDeadPixels(hCamera): + pNumPixel = c_int() + err_code = _sdk.CameraReadDeadPixels(hCamera, None, None, byref(pNumPixel)) + SetLastError(err_code) + if pNumPixel.value < 1: + return None + UShortArray = c_ushort * pNumPixel.value + pRows = UShortArray() + pCols = UShortArray() + err_code = _sdk.CameraReadDeadPixels(hCamera, pRows, pCols, byref(pNumPixel)) + SetLastError(err_code) + if err_code == 0: + pNumPixel = pNumPixel.value + else: + pNumPixel = 0 + return (pRows[:pNumPixel], pCols[:pNumPixel]) + +def CameraAddDeadPixels(hCamera, pRows, pCols, NumPixel): + UShortArray = c_ushort * NumPixel + pRowsNative = UShortArray(*pRows) + pColsNative = UShortArray(*pCols) + err_code = _sdk.CameraAddDeadPixels(hCamera, pRowsNative, pColsNative, NumPixel) + SetLastError(err_code) + return err_code + +def CameraRemoveDeadPixels(hCamera, pRows, pCols, NumPixel): + UShortArray = c_ushort * NumPixel + pRowsNative = UShortArray(*pRows) + pColsNative = UShortArray(*pCols) + err_code = _sdk.CameraRemoveDeadPixels(hCamera, pRowsNative, pColsNative, NumPixel) + SetLastError(err_code) + return err_code + +def CameraRemoveAllDeadPixels(hCamera): + err_code = _sdk.CameraRemoveAllDeadPixels(hCamera) + SetLastError(err_code) + return err_code + +def CameraSaveDeadPixels(hCamera): + err_code = _sdk.CameraSaveDeadPixels(hCamera) + SetLastError(err_code) + return err_code + +def CameraSaveDeadPixelsToFile(hCamera, sFileName): + err_code = _sdk.CameraSaveDeadPixelsToFile(hCamera, _str_to_string_buffer(sFileName)) + SetLastError(err_code) + return err_code + +def CameraLoadDeadPixelsFromFile(hCamera, sFileName): + err_code = _sdk.CameraLoadDeadPixelsFromFile(hCamera, _str_to_string_buffer(sFileName)) + SetLastError(err_code) + return err_code + +def CameraGetImageBufferPriority(hCamera, wTimes, Priority): + pFrameInfo = tSdkFrameHead() + pbyBuffer = c_void_p() + err_code = _sdk.CameraGetImageBufferPriority(hCamera, byref(pFrameInfo), byref(pbyBuffer), wTimes, Priority) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (pbyBuffer.value, pFrameInfo) + +def CameraGetImageBufferPriorityEx(hCamera, wTimes, Priority): + _sdk.CameraGetImageBufferPriorityEx.restype = c_void_p + piWidth = c_int() + piHeight = c_int() + pFrameBuffer = _sdk.CameraGetImageBufferPriorityEx(hCamera, byref(piWidth), byref(piHeight), wTimes, Priority) + err_code = CAMERA_STATUS_SUCCESS if pFrameBuffer else CAMERA_STATUS_TIME_OUT + SetLastError(err_code) + if pFrameBuffer: + return (pFrameBuffer, piWidth.value, piHeight.value) + else: + raise CameraException(err_code) + +def CameraGetImageBufferPriorityEx2(hCamera, pImageData, uOutFormat, wTimes, Priority): + piWidth = c_int() + piHeight = c_int() + err_code = _sdk.CameraGetImageBufferPriorityEx2(hCamera, c_void_p(pImageData), uOutFormat, byref(piWidth), byref(piHeight), wTimes, Priority) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (piWidth.value, piHeight.value) + +def CameraGetImageBufferPriorityEx3(hCamera, pImageData, uOutFormat, wTimes, Priority): + piWidth = c_int() + piHeight = c_int() + puTimeStamp = c_uint() + err_code = _sdk.CameraGetImageBufferPriorityEx3(hCamera, c_void_p(pImageData), uOutFormat, byref(piWidth), byref(piHeight), byref(puTimeStamp), wTimes, Priority) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return (piWidth.value, piHeight.value, puTimeStamp.value) + +def CameraClearBuffer(hCamera): + err_code = _sdk.CameraClearBuffer(hCamera) + SetLastError(err_code) + return err_code + +def CameraSoftTriggerEx(hCamera, uFlags): + err_code = _sdk.CameraSoftTriggerEx(hCamera, uFlags) + SetLastError(err_code) + return err_code + +def CameraSetHDR(hCamera, value): + err_code = _sdk.CameraSetHDR(hCamera, value) + SetLastError(err_code) + return err_code + +def CameraGetHDR(hCamera): + value = c_int() + err_code = _sdk.CameraGetHDR(hCamera, byref(value)) + SetLastError(err_code) + return value.value + +def CameraGetFrameID(hCamera): + FrameID = c_uint() + err_code = _sdk.CameraGetFrameID(hCamera, byref(FrameID)) + SetLastError(err_code) + return FrameID.value + +def CameraGetFrameTimeStamp(hCamera): + TimeStamp = c_uint64() + TimeStampL = c_uint32.from_buffer(TimeStamp) + TimeStampH = c_uint32.from_buffer(TimeStamp, 4) + err_code = _sdk.CameraGetFrameTimeStamp(hCamera, byref(TimeStampL), byref(TimeStampH)) + SetLastError(err_code) + return TimeStamp.value + +def CameraSetHDRGainMode(hCamera, value): + err_code = _sdk.CameraSetHDRGainMode(hCamera, value) + SetLastError(err_code) + return err_code + +def CameraGetHDRGainMode(hCamera): + value = c_int() + err_code = _sdk.CameraGetHDRGainMode(hCamera, byref(value)) + SetLastError(err_code) + return value.value + +def CameraCreateDIBitmap(hDC, pFrameBuffer, pFrameHead): + outBitmap = c_void_p() + err_code = _sdk.CameraCreateDIBitmap(hDC, c_void_p(pFrameBuffer), byref(pFrameHead), byref(outBitmap)) + SetLastError(err_code) + return outBitmap.value + +def CameraDrawFrameBuffer(pFrameBuffer, pFrameHead, hWnd, Algorithm, Mode): + err_code = _sdk.CameraDrawFrameBuffer(c_void_p(pFrameBuffer), byref(pFrameHead), c_void_p(hWnd), Algorithm, Mode) + SetLastError(err_code) + return err_code + +def CameraFlipFrameBuffer(pFrameBuffer, pFrameHead, Flags): + err_code = _sdk.CameraFlipFrameBuffer(c_void_p(pFrameBuffer), byref(pFrameHead), Flags) + SetLastError(err_code) + return err_code + +def CameraConvertFrameBufferFormat(hCamera, pInFrameBuffer, pOutFrameBuffer, outWidth, outHeight, outMediaType, pFrameHead): + err_code = _sdk.CameraConvertFrameBufferFormat(hCamera, c_void_p(pInFrameBuffer), c_void_p(pOutFrameBuffer), outWidth, outHeight, outMediaType, byref(pFrameHead)) + SetLastError(err_code) + return err_code + +def CameraSetConnectionStatusCallback(hCamera, pCallBack, pContext = 0): + err_code = _sdk.CameraSetConnectionStatusCallback(hCamera, pCallBack, c_void_p(pContext) ) + SetLastError(err_code) + return err_code + +def CameraSetLightingControllerMode(hCamera, index, mode): + err_code = _sdk.CameraSetLightingControllerMode(hCamera, index, mode) + SetLastError(err_code) + return err_code + +def CameraSetLightingControllerState(hCamera, index, state): + err_code = _sdk.CameraSetLightingControllerState(hCamera, index, state) + SetLastError(err_code) + return err_code + +def CameraSetFrameResendCount(hCamera, count): + err_code = _sdk.CameraSetFrameResendCount(hCamera, count) + SetLastError(err_code) + return err_code + +def CameraSetUndistortParams(hCamera, width, height, cameraMatrix, distCoeffs): + assert(len(cameraMatrix) == 4) + assert(len(distCoeffs) == 5) + cameraMatrixNative = (c_double * len(cameraMatrix))(*cameraMatrix) + distCoeffsNative = (c_double * len(distCoeffs))(*distCoeffs) + err_code = _sdk.CameraSetUndistortParams(hCamera, width, height, cameraMatrixNative, distCoeffsNative) + SetLastError(err_code) + return err_code + +def CameraGetUndistortParams(hCamera): + width = c_int() + height = c_int() + cameraMatrix = (c_double * 4)() + distCoeffs = (c_double * 5)() + err_code = _sdk.CameraGetUndistortParams(hCamera, byref(width), byref(height), cameraMatrix, distCoeffs) + SetLastError(err_code) + width, height = width.value, height.value + cameraMatrix = cameraMatrix[:] + distCoeffs = distCoeffs[:] + return (width, height, cameraMatrix, distCoeffs) + +def CameraSetUndistortEnable(hCamera, bEnable): + err_code = _sdk.CameraSetUndistortEnable(hCamera, bEnable) + SetLastError(err_code) + return err_code + +def CameraGetUndistortEnable(hCamera): + value = c_int() + err_code = _sdk.CameraGetUndistortEnable(hCamera, byref(value)) + SetLastError(err_code) + return value.value + +def CameraCustomizeUndistort(hCamera, hParent): + err_code = _sdk.CameraCustomizeUndistort(hCamera, hParent) + SetLastError(err_code) + return err_code + +def CameraGetEyeCount(hCamera): + EyeCount = c_int() + err_code = _sdk.CameraGetEyeCount(hCamera, byref(EyeCount)) + SetLastError(err_code) + return EyeCount.value + +def CameraMultiEyeImageProcess(hCamera, iEyeIndex, pbyIn, pInFrInfo, pbyOut, pOutFrInfo, uOutFormat, uReserved): + err_code = _sdk.CameraMultiEyeImageProcess(hCamera, iEyeIndex, c_void_p(pbyIn), byref(pInFrInfo), c_void_p(pbyOut), byref(pOutFrInfo), uOutFormat, uReserved) + SetLastError(err_code) + return err_code + +# CameraGrabber + +def CameraGrabber_CreateFromDevicePage(): + Grabber = c_void_p() + err_code = _sdk.CameraGrabber_CreateFromDevicePage(byref(Grabber)) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return Grabber.value + +def CameraGrabber_CreateByIndex(Index): + Grabber = c_void_p() + err_code = _sdk.CameraGrabber_CreateByIndex(byref(Grabber), Index) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return Grabber.value + +def CameraGrabber_CreateByName(Name): + Grabber = c_void_p() + err_code = _sdk.CameraGrabber_CreateByName(byref(Grabber), _str_to_string_buffer(Name)) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return Grabber.value + +def CameraGrabber_Create(pDevInfo): + Grabber = c_void_p() + err_code = _sdk.CameraGrabber_Create(byref(Grabber), byref(pDevInfo)) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return Grabber.value + +def CameraGrabber_Destroy(Grabber): + err_code = _sdk.CameraGrabber_Destroy(c_void_p(Grabber)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SetHWnd(Grabber, hWnd): + err_code = _sdk.CameraGrabber_SetHWnd(c_void_p(Grabber), c_void_p(hWnd) ) + SetLastError(err_code) + return err_code + +def CameraGrabber_SetPriority(Grabber, Priority): + err_code = _sdk.CameraGrabber_SetPriority(c_void_p(Grabber), Priority) + SetLastError(err_code) + return err_code + +def CameraGrabber_StartLive(Grabber): + err_code = _sdk.CameraGrabber_StartLive(c_void_p(Grabber)) + SetLastError(err_code) + return err_code + +def CameraGrabber_StopLive(Grabber): + err_code = _sdk.CameraGrabber_StopLive(c_void_p(Grabber)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SaveImage(Grabber, TimeOut): + Image = c_void_p() + err_code = _sdk.CameraGrabber_SaveImage(c_void_p(Grabber), byref(Image), TimeOut) + SetLastError(err_code) + if err_code != 0: + raise CameraException(err_code) + return Image.value + +def CameraGrabber_SaveImageAsync(Grabber): + err_code = _sdk.CameraGrabber_SaveImageAsync(c_void_p(Grabber)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SaveImageAsyncEx(Grabber, UserData): + err_code = _sdk.CameraGrabber_SaveImageAsyncEx(c_void_p(Grabber), c_void_p(UserData)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SetSaveImageCompleteCallback(Grabber, Callback, Context = 0): + err_code = _sdk.CameraGrabber_SetSaveImageCompleteCallback(c_void_p(Grabber), Callback, c_void_p(Context)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SetFrameListener(Grabber, Listener, Context = 0): + err_code = _sdk.CameraGrabber_SetFrameListener(c_void_p(Grabber), Listener, c_void_p(Context)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SetRawCallback(Grabber, Callback, Context = 0): + err_code = _sdk.CameraGrabber_SetRawCallback(c_void_p(Grabber), Callback, c_void_p(Context)) + SetLastError(err_code) + return err_code + +def CameraGrabber_SetRGBCallback(Grabber, Callback, Context = 0): + err_code = _sdk.CameraGrabber_SetRGBCallback(c_void_p(Grabber), Callback, c_void_p(Context)) + SetLastError(err_code) + return err_code + +def CameraGrabber_GetCameraHandle(Grabber): + hCamera = c_int() + err_code = _sdk.CameraGrabber_GetCameraHandle(c_void_p(Grabber), byref(hCamera)) + SetLastError(err_code) + return hCamera.value + +def CameraGrabber_GetStat(Grabber): + stat = tSdkGrabberStat() + err_code = _sdk.CameraGrabber_GetStat(c_void_p(Grabber), byref(stat)) + SetLastError(err_code) + return stat + +def CameraGrabber_GetCameraDevInfo(Grabber): + DevInfo = tSdkCameraDevInfo() + err_code = _sdk.CameraGrabber_GetCameraDevInfo(c_void_p(Grabber), byref(DevInfo)) + SetLastError(err_code) + return DevInfo + +# CameraImage + +def CameraImage_Create(pFrameBuffer, pFrameHead, bCopy): + Image = c_void_p() + err_code = _sdk.CameraImage_Create(byref(Image), c_void_p(pFrameBuffer), byref(pFrameHead), bCopy) + SetLastError(err_code) + return Image.value + +def CameraImage_CreateEmpty(): + Image = c_void_p() + err_code = _sdk.CameraImage_CreateEmpty(byref(Image)) + SetLastError(err_code) + return Image.value + +def CameraImage_Destroy(Image): + err_code = _sdk.CameraImage_Destroy(c_void_p(Image)) + SetLastError(err_code) + return err_code + +def CameraImage_GetData(Image): + DataBuffer = c_void_p() + HeadPtr = c_void_p() + err_code = _sdk.CameraImage_GetData(c_void_p(Image), byref(DataBuffer), byref(HeadPtr)) + SetLastError(err_code) + if err_code == 0: + return (DataBuffer.value, tSdkFrameHead.from_address(HeadPtr.value) ) + else: + return (0, None) + +def CameraImage_GetUserData(Image): + UserData = c_void_p() + err_code = _sdk.CameraImage_GetUserData(c_void_p(Image), byref(UserData)) + SetLastError(err_code) + return UserData.value + +def CameraImage_SetUserData(Image, UserData): + err_code = _sdk.CameraImage_SetUserData(c_void_p(Image), c_void_p(UserData)) + SetLastError(err_code) + return err_code + +def CameraImage_IsEmpty(Image): + IsEmpty = c_int() + err_code = _sdk.CameraImage_IsEmpty(c_void_p(Image), byref(IsEmpty)) + SetLastError(err_code) + return IsEmpty.value + +def CameraImage_Draw(Image, hWnd, Algorithm): + err_code = _sdk.CameraImage_Draw(c_void_p(Image), c_void_p(hWnd), Algorithm) + SetLastError(err_code) + return err_code + +def CameraImage_DrawFit(Image, hWnd, Algorithm): + err_code = _sdk.CameraImage_DrawFit(c_void_p(Image), c_void_p(hWnd), Algorithm) + SetLastError(err_code) + return err_code + +def CameraImage_DrawToDC(Image, hDC, Algorithm, xDst, yDst, cxDst, cyDst): + err_code = _sdk.CameraImage_DrawToDC(c_void_p(Image), c_void_p(hDC), Algorithm, xDst, yDst, cxDst, cyDst) + SetLastError(err_code) + return err_code + +def CameraImage_DrawToDCFit(Image, hDC, Algorithm, xDst, yDst, cxDst, cyDst): + err_code = _sdk.CameraImage_DrawToDCFit(c_void_p(Image), c_void_p(hDC), Algorithm, xDst, yDst, cxDst, cyDst) + SetLastError(err_code) + return err_code + +def CameraImage_BitBlt(Image, hWnd, xDst, yDst, cxDst, cyDst, xSrc, ySrc): + err_code = _sdk.CameraImage_BitBlt(c_void_p(Image), c_void_p(hWnd), xDst, yDst, cxDst, cyDst, xSrc, ySrc) + SetLastError(err_code) + return err_code + +def CameraImage_BitBltToDC(Image, hDC, xDst, yDst, cxDst, cyDst, xSrc, ySrc): + err_code = _sdk.CameraImage_BitBltToDC(c_void_p(Image), c_void_p(hDC), xDst, yDst, cxDst, cyDst, xSrc, ySrc) + SetLastError(err_code) + return err_code + +def CameraImage_SaveAsBmp(Image, FileName): + err_code = _sdk.CameraImage_SaveAsBmp(c_void_p(Image), _str_to_string_buffer(FileName)) + SetLastError(err_code) + return err_code + +def CameraImage_SaveAsJpeg(Image, FileName, Quality): + err_code = _sdk.CameraImage_SaveAsJpeg(c_void_p(Image), _str_to_string_buffer(FileName), Quality) + SetLastError(err_code) + return err_code + +def CameraImage_SaveAsPng(Image, FileName): + err_code = _sdk.CameraImage_SaveAsPng(c_void_p(Image), _str_to_string_buffer(FileName)) + SetLastError(err_code) + return err_code + +def CameraImage_SaveAsRaw(Image, FileName, Format): + err_code = _sdk.CameraImage_SaveAsRaw(c_void_p(Image), _str_to_string_buffer(FileName), Format) + SetLastError(err_code) + return err_code + +def CameraImage_IPicture(Image): + NewPic = c_void_p() + err_code = _sdk.CameraImage_IPicture(c_void_p(Image), byref(NewPic)) + SetLastError(err_code) + return NewPic.value diff --git a/python demo/readme.txt b/python demo/readme.txt new file mode 100644 index 0000000..749c79e --- /dev/null +++ b/python demo/readme.txt @@ -0,0 +1,4 @@ +mvsdk.py: 相机SDK接口库(参考文档 WindowsSDK安装目录\Document\MVSDK_API_CHS.chm) + +grab.py: 使用SDK采集图片,并保存到硬盘文件 +cv_grab.py: 使用SDK采集图片,转换为opencv的图像格式 diff --git a/test_exposure.py b/test_exposure.py new file mode 100644 index 0000000..bcfb0fd --- /dev/null +++ b/test_exposure.py @@ -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...")