{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# GigE Camera Test Setup\n", "\n", "This notebook helps you test and configure your GigE cameras for the USDA vision project.\n", "\n", "## Key Features:\n", "- Test camera connectivity\n", "- Display images inline (no GUI needed)\n", "- Save test images/videos to `/storage`\n", "- Configure camera parameters\n", "- Test recording functionality" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ All imports successful!\n", "OpenCV version: 4.11.0\n", "NumPy version: 2.3.2\n" ] } ], "source": [ "import cv2\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import os\n", "from datetime import datetime\n", "import time\n", "from pathlib import Path\n", "import imageio\n", "from tqdm import tqdm\n", "\n", "# Configure matplotlib for inline display\n", "plt.rcParams['figure.figsize'] = (12, 8)\n", "plt.rcParams['image.cmap'] = 'gray'\n", "\n", "print(\"✅ All imports successful!\")\n", "print(f\"OpenCV version: {cv2.__version__}\")\n", "print(f\"NumPy version: {np.__version__}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Utility Functions" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ Utility functions loaded!\n" ] } ], "source": [ "def display_image(image, title=\"Image\", figsize=(10, 8)):\n", " \"\"\"Display image inline in Jupyter notebook\"\"\"\n", " plt.figure(figsize=figsize)\n", " if len(image.shape) == 3:\n", " # Convert BGR to RGB for matplotlib\n", " image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n", " plt.imshow(image_rgb)\n", " else:\n", " plt.imshow(image, cmap='gray')\n", " plt.title(title)\n", " plt.axis('off')\n", " plt.tight_layout()\n", " plt.show()\n", "\n", "def save_image_to_storage(image, filename_prefix=\"test_image\"):\n", " \"\"\"Save image to /storage with timestamp\"\"\"\n", " timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n", " filename = f\"{filename_prefix}_{timestamp}.jpg\"\n", " filepath = f\"/storage/{filename}\"\n", " \n", " success = cv2.imwrite(filepath, image)\n", " if success:\n", " print(f\"✅ Image saved: {filepath}\")\n", " return filepath\n", " else:\n", " print(f\"❌ Failed to save image: {filepath}\")\n", " return None\n", "\n", "def create_storage_subdir(subdir_name):\n", " \"\"\"Create subdirectory in /storage\"\"\"\n", " path = Path(f\"/storage/{subdir_name}\")\n", " path.mkdir(exist_ok=True)\n", " print(f\"📁 Directory ready: {path}\")\n", " return str(path)\n", "\n", "def list_available_cameras():\n", " \"\"\"List all available camera devices\"\"\"\n", " print(\"🔍 Scanning for available cameras...\")\n", " available_cameras = []\n", " \n", " # Test camera indices 0-10\n", " for i in range(11):\n", " cap = cv2.VideoCapture(i)\n", " if cap.isOpened():\n", " ret, frame = cap.read()\n", " if ret:\n", " available_cameras.append(i)\n", " print(f\"📷 Camera {i}: Available (Resolution: {frame.shape[1]}x{frame.shape[0]})\")\n", " cap.release()\n", " else:\n", " # Try with different backends for GigE cameras\n", " cap = cv2.VideoCapture(i, cv2.CAP_GSTREAMER)\n", " if cap.isOpened():\n", " ret, frame = cap.read()\n", " if ret:\n", " available_cameras.append(i)\n", " print(f\"📷 Camera {i}: Available via GStreamer (Resolution: {frame.shape[1]}x{frame.shape[0]})\")\n", " cap.release()\n", " \n", " if not available_cameras:\n", " print(\"❌ No cameras found\")\n", " \n", " return available_cameras\n", "\n", "print(\"✅ Utility functions loaded!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 1: Check Storage Directory" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Storage directory exists: True\n", "Storage directory writable: True\n", "📁 Directory ready: /storage/test_images\n", "📁 Directory ready: /storage/test_videos\n", "📁 Directory ready: /storage/camera1\n", "📁 Directory ready: /storage/camera2\n" ] } ], "source": [ "# Check storage directory\n", "storage_path = Path(\"/storage\")\n", "print(f\"Storage directory exists: {storage_path.exists()}\")\n", "print(f\"Storage directory writable: {os.access('/storage', os.W_OK)}\")\n", "\n", "# Create test subdirectories\n", "test_images_dir = create_storage_subdir(\"test_images\")\n", "test_videos_dir = create_storage_subdir(\"test_videos\")\n", "camera1_dir = create_storage_subdir(\"camera1\")\n", "camera2_dir = create_storage_subdir(\"camera2\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 2: Scan for Available Cameras" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "🔍 Scanning for available cameras...\n", "❌ No cameras found\n", "\n", "📊 Summary: Found 0 camera(s): []\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "[ WARN:0@9.977] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video0): can't open camera by index\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.977] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.977] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video1): can't open camera by index\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.977] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.977] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video2): can't open camera by index\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.977] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.977] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video3): can't open camera by index\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.977] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.977] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.977] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video4): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.978] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.978] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video5): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.978] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.978] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video6): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.978] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.978] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video7): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.978] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.978] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video8): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.978] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.978] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video9): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.978] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@9.978] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video10): can't open camera by index\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.978] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@9.979] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@9.979] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@9.979] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n" ] } ], "source": [ "# Scan for cameras\n", "cameras = list_available_cameras()\n", "print(f\"\\n📊 Summary: Found {len(cameras)} camera(s): {cameras}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 3: Test Individual Camera" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "🔧 Testing camera 0...\n", " Trying Default backend...\n", " ❌ Default backend failed to open\n", " Trying GStreamer backend...\n", " ❌ GStreamer backend failed to open\n", " Trying V4L2 backend...\n", " ❌ V4L2 backend failed to open\n", " Trying FFmpeg backend...\n", " ❌ FFmpeg backend failed to open\n", "❌ Camera 0 not accessible with any backend\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "[ WARN:0@27.995] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video0): can't open camera by index\n", "[ WARN:0@27.995] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@27.995] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ WARN:0@27.995] global obsensor_stream_channel_v4l2.cpp:82 xioctl ioctl: fd=-1, req=-2140645888\n", "[ WARN:0@27.995] global obsensor_stream_channel_v4l2.cpp:138 queryUvcDeviceInfoList ioctl error return: 9\n", "[ERROR:0@27.995] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range\n", "[ WARN:0@27.996] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video0): can't open camera by index\n", "[ WARN:0@27.996] global cap.cpp:478 open VIDEOIO(V4L2): backend is generally available but can't be used to capture by index\n", "[ WARN:0@27.996] global cap.cpp:478 open VIDEOIO(FFMPEG): backend is generally available but can't be used to capture by index\n" ] } ], "source": [ "# Test a specific camera (change camera_id as needed)\n", "camera_id = 0 # Change this to test different cameras\n", "\n", "print(f\"🔧 Testing camera {camera_id}...\")\n", "\n", "# Try different backends for GigE cameras\n", "backends_to_try = [\n", " (cv2.CAP_ANY, \"Default\"),\n", " (cv2.CAP_GSTREAMER, \"GStreamer\"),\n", " (cv2.CAP_V4L2, \"V4L2\"),\n", " (cv2.CAP_FFMPEG, \"FFmpeg\")\n", "]\n", "\n", "successful_backend = None\n", "cap = None\n", "\n", "for backend, name in backends_to_try:\n", " print(f\" Trying {name} backend...\")\n", " cap = cv2.VideoCapture(camera_id, backend)\n", " if cap.isOpened():\n", " ret, frame = cap.read()\n", " if ret:\n", " print(f\" ✅ {name} backend works!\")\n", " successful_backend = (backend, name)\n", " break\n", " else:\n", " print(f\" ❌ {name} backend opened but can't read frames\")\n", " else:\n", " print(f\" ❌ {name} backend failed to open\")\n", " cap.release()\n", "\n", "if successful_backend:\n", " backend, backend_name = successful_backend\n", " cap = cv2.VideoCapture(camera_id, backend)\n", " \n", " # Get camera properties\n", " width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n", " height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n", " fps = cap.get(cv2.CAP_PROP_FPS)\n", " \n", " print(f\"\\n📷 Camera {camera_id} Properties ({backend_name}):\")\n", " print(f\" Resolution: {width}x{height}\")\n", " print(f\" FPS: {fps}\")\n", " \n", " # Capture a test frame\n", " ret, frame = cap.read()\n", " if ret:\n", " print(f\" Frame shape: {frame.shape}\")\n", " print(f\" Frame dtype: {frame.dtype}\")\n", " \n", " # Display the frame\n", " display_image(frame, f\"Camera {camera_id} Test Frame\")\n", " \n", " # Save test image\n", " save_image_to_storage(frame, f\"camera_{camera_id}_test\")\n", " else:\n", " print(\" ❌ Failed to capture frame\")\n", " \n", " cap.release()\n", "else:\n", " print(f\"❌ Camera {camera_id} not accessible with any backend\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 4: Test Video Recording" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Test video recording\n", "def test_video_recording(camera_id, duration_seconds=5, fps=30):\n", " \"\"\"Test video recording from camera\"\"\"\n", " print(f\"🎥 Testing video recording from camera {camera_id} for {duration_seconds} seconds...\")\n", " \n", " # Open camera\n", " cap = cv2.VideoCapture(camera_id)\n", " if not cap.isOpened():\n", " print(f\"❌ Cannot open camera {camera_id}\")\n", " return None\n", " \n", " # Get camera properties\n", " width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n", " height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n", " \n", " # Create video writer\n", " timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n", " video_filename = f\"/storage/test_videos/camera_{camera_id}_test_{timestamp}.mp4\"\n", " \n", " fourcc = cv2.VideoWriter_fourcc(*'mp4v')\n", " out = cv2.VideoWriter(video_filename, fourcc, fps, (width, height))\n", " \n", " if not out.isOpened():\n", " print(\"❌ Cannot create video writer\")\n", " cap.release()\n", " return None\n", " \n", " # Record video\n", " frames_to_capture = duration_seconds * fps\n", " frames_captured = 0\n", " \n", " print(f\"Recording {frames_to_capture} frames...\")\n", " \n", " with tqdm(total=frames_to_capture, desc=\"Recording\") as pbar:\n", " start_time = time.time()\n", " \n", " while frames_captured < frames_to_capture:\n", " ret, frame = cap.read()\n", " if ret:\n", " out.write(frame)\n", " frames_captured += 1\n", " pbar.update(1)\n", " \n", " # Display first frame\n", " if frames_captured == 1:\n", " display_image(frame, f\"First frame from camera {camera_id}\")\n", " else:\n", " print(f\"❌ Failed to read frame {frames_captured}\")\n", " break\n", " \n", " # Cleanup\n", " cap.release()\n", " out.release()\n", " \n", " elapsed_time = time.time() - start_time\n", " actual_fps = frames_captured / elapsed_time\n", " \n", " print(f\"✅ Video saved: {video_filename}\")\n", " print(f\"📊 Captured {frames_captured} frames in {elapsed_time:.2f}s\")\n", " print(f\"📊 Actual FPS: {actual_fps:.2f}\")\n", " \n", " return video_filename\n", "\n", "# Test recording (change camera_id as needed)\n", "if cameras: # Only test if cameras were found\n", " test_camera = cameras[0] # Use first available camera\n", " video_file = test_video_recording(test_camera, duration_seconds=3)\n", "else:\n", " print(\"⚠️ No cameras available for video test\")" ] } ], "metadata": { "kernelspec": { "display_name": "USDA-vision-cameras", "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.11.2" } }, "nbformat": 4, "nbformat_minor": 4 }