[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7C8BCFHWYVF3M2SYAD86MP0":3,"skill-same:01M7C8BCFHWYVF3M2SYAD86MP0":45},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":6,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":30,"install":31,"resources":44},"01M7C8BCFHWYVF3M2SYAD86MP0","video-frame-extraction",null,"Extract frames from video files and save them as images using OpenCV","linyouxue\u002Fskill-repair-benchmark","linyouxue","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F216151464?v=4","01M7BJEVCXKD74KH6FG9CBVSQB","林宥学","01M7BJEVE02NP217V93BKZFC0J",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fwml-claude4.7\u002Fevidence\u002Ffinal_runs\u002Frun_02\u002Finputs\u002Fskills\u002Fvideo-frame-extraction\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\r\nname: video-frame-extraction\r\ndescription: Extract frames from video files and save them as images using OpenCV\r\n---\r\n\r\n# Video Frame Extraction Skill\r\n\r\n## Purpose\r\nThis skill enables extraction of individual frames from video files (MP4, AVI, MOV, etc.) using OpenCV. Extracted frames are saved as image files in a specified output directory. It is suitable for video analysis, creating training datasets, thumbnail generation, and preprocessing video content for further processing.\r\n\r\n## When to Use\r\n- Extracting frames for machine learning training data\r\n- Creating image sequences from video content\r\n- Generating video thumbnails or preview images\r\n- Preprocessing videos for object detection or tracking\r\n- Converting video segments to image collections for analysis\r\n- Sampling frames at specific intervals for time-lapse effects\r\n\r\n## Required Libraries\r\n\r\nThe following Python libraries are required:\r\n\r\n```python\r\nimport cv2\r\nimport os\r\nimport json\r\nfrom pathlib import Path\r\n```\r\n\r\n## Input Requirements\r\n- **File formats**: MP4, AVI, MOV, MKV, WMV, FLV, WEBM\r\n- **Video codec**: Must be readable by OpenCV (most common codecs supported)\r\n- **File access**: Read permissions on source video\r\n- **Output directory**: Write permissions on destination folder\r\n- **Disk space**: Ensure sufficient space for extracted frames (uncompressed images)\r\n\r\n## Output Schema\r\nAll extraction results must be returned as valid JSON conforming to this schema:\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"source_video\": \"sample.mp4\",\r\n  \"output_directory\": \"\u002Fpath\u002Fto\u002Fframes\",\r\n  \"frames_extracted\": 150,\r\n  \"extraction_params\": {\r\n    \"interval\": 1,\r\n    \"start_frame\": 0,\r\n    \"end_frame\": null,\r\n    \"output_format\": \"jpg\"\r\n  },\r\n  \"video_metadata\": {\r\n    \"total_frames\": 300,\r\n    \"fps\": 30.0,\r\n    \"duration_seconds\": 10.0,\r\n    \"resolution\": [1920, 1080]\r\n  },\r\n  \"output_files\": [\r\n    \"frame_000001.jpg\",\r\n    \"frame_000002.jpg\"\r\n  ],\r\n  \"warnings\": []\r\n}\r\n```\r\n\r\n\r\n### Field Descriptions\r\n\r\n- `success`: Boolean indicating whether frame extraction completed\r\n- `source_video`: Original video filename\r\n- `output_directory`: Path where frames were saved\r\n- `frames_extracted`: Total number of frames successfully saved\r\n- `extraction_params.interval`: Frame sampling interval (1 = every frame, 2 = every other frame, etc.)\r\n- `extraction_params.start_frame`: First frame index extracted\r\n- `extraction_params.end_frame`: Last frame index extracted (null if extracted to end)\r\n- `extraction_params.output_format`: Image format used for saving frames\r\n- `video_metadata.total_frames`: Total frame count in source video\r\n- `video_metadata.fps`: Frames per second of source video\r\n- `video_metadata.duration_seconds`: Video duration in seconds\r\n- `video_metadata.resolution`: Video dimensions as [width, height]\r\n- `output_files`: List of generated frame filenames\r\n- `warnings`: Array of issues encountered during extraction\r\n\r\n\r\n## Code Examples\r\n\r\n### Basic Frame Extraction\r\n\r\n```python\r\nimport cv2\r\nimport os\r\n\r\ndef extract_all_frames(video_path, output_dir):\r\n    \"\"\"Extract all frames from a video file.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    frame_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        filename = os.path.join(output_dir, f\"frame_{frame_count:06d}.jpg\")\r\n        cv2.imwrite(filename, frame)\r\n        frame_count += 1\r\n    \r\n    cap.release()\r\n    return frame_count\r\n```\r\n\r\n### Interval-Based Frame Extraction\r\n\r\n```python\r\nimport cv2\r\nimport os\r\n\r\ndef extract_frames_at_interval(video_path, output_dir, interval=1):\r\n    \"\"\"Extract frames at specified intervals.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    frame_index = 0\r\n    saved_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        if frame_index % interval == 0:\r\n            filename = os.path.join(output_dir, f\"frame_{saved_count:06d}.jpg\")\r\n            cv2.imwrite(filename, frame)\r\n            saved_count += 1\r\n        \r\n        frame_index += 1\r\n    \r\n    cap.release()\r\n    return saved_count\r\n```\r\n\r\n### Full Extraction with JSON Output\r\n\r\n```python\r\nimport cv2\r\nimport os\r\nimport json\r\nfrom pathlib import Path\r\n\r\ndef extract_frames_to_json(video_path, output_dir, interval=1, \r\n                           start_frame=0, end_frame=None, output_format=\"jpg\"):\r\n    \"\"\"Extract frames and return results as JSON.\"\"\"\r\n    video_name = os.path.basename(video_path)\r\n    warnings = []\r\n    output_files = []\r\n    \r\n    try:\r\n        os.makedirs(output_dir, exist_ok=True)\r\n        cap = cv2.VideoCapture(video_path)\r\n        \r\n        if not cap.isOpened():\r\n            raise ValueError(f\"Cannot open video: {video_path}\")\r\n        \r\n        # Get video metadata\r\n        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\r\n        fps = cap.get(cv2.CAP_PROP_FPS)\r\n        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\r\n        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\r\n        duration = total_frames \u002F fps if fps > 0 else 0\r\n        \r\n        # Set end frame if not specified\r\n        if end_frame is None:\r\n            end_frame = total_frames\r\n        \r\n        # Seek to start frame\r\n        if start_frame > 0:\r\n            cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)\r\n        \r\n        frame_index = start_frame\r\n        saved_count = 0\r\n        \r\n        while frame_index \u003C end_frame:\r\n            ret, frame = cap.read()\r\n            if not ret:\r\n                if frame_index \u003C end_frame:\r\n                    warnings.append(f\"Video ended early at frame {frame_index}\")\r\n                break\r\n            \r\n            if (frame_index - start_frame) % interval == 0:\r\n                filename = f\"frame_{saved_count:06d}.{output_format}\"\r\n                filepath = os.path.join(output_dir, filename)\r\n                cv2.imwrite(filepath, frame)\r\n                output_files.append(filename)\r\n                saved_count += 1\r\n            \r\n            frame_index += 1\r\n        \r\n        cap.release()\r\n        \r\n        result = {\r\n            \"success\": True,\r\n            \"source_video\": video_name,\r\n            \"output_directory\": str(output_dir),\r\n            \"frames_extracted\": saved_count,\r\n            \"extraction_params\": {\r\n                \"interval\": interval,\r\n                \"start_frame\": start_frame,\r\n                \"end_frame\": end_frame,\r\n                \"output_format\": output_format\r\n            },\r\n            \"video_metadata\": {\r\n                \"total_frames\": total_frames,\r\n                \"fps\": fps,\r\n                \"duration_seconds\": round(duration, 2),\r\n                \"resolution\": [width, height]\r\n            },\r\n            \"output_files\": output_files,\r\n            \"warnings\": warnings\r\n        }\r\n        \r\n    except Exception as e:\r\n        result = {\r\n            \"success\": False,\r\n            \"source_video\": video_name,\r\n            \"output_directory\": str(output_dir),\r\n            \"frames_extracted\": 0,\r\n            \"extraction_params\": {\r\n                \"interval\": interval,\r\n                \"start_frame\": start_frame,\r\n                \"end_frame\": end_frame,\r\n                \"output_format\": output_format\r\n            },\r\n            \"video_metadata\": {\r\n                \"total_frames\": 0,\r\n                \"fps\": 0,\r\n                \"duration_seconds\": 0,\r\n                \"resolution\": [0, 0]\r\n            },\r\n            \"output_files\": [],\r\n            \"warnings\": [f\"Extraction failed: {str(e)}\"]\r\n        }\r\n    \r\n    return result\r\n\r\n# Usage\r\nresult = extract_frames_to_json(\"video.mp4\", \".\u002Fframes\", interval=10)\r\nprint(json.dumps(result, indent=2))\r\n```\r\n\r\n### Time-Based Frame Extraction\r\n\r\n```python\r\nimport cv2\r\nimport os\r\n\r\ndef extract_frames_by_seconds(video_path, output_dir, seconds_interval=1.0):\r\n    \"\"\"Extract frames at specific time intervals (in seconds).\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    fps = cap.get(cv2.CAP_PROP_FPS)\r\n    frame_interval = int(fps * seconds_interval)\r\n    \r\n    if frame_interval \u003C 1:\r\n        frame_interval = 1\r\n    \r\n    frame_index = 0\r\n    saved_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        if frame_index % frame_interval == 0:\r\n            filename = os.path.join(output_dir, f\"frame_{saved_count:06d}.jpg\")\r\n            cv2.imwrite(filename, frame)\r\n            saved_count += 1\r\n        \r\n        frame_index += 1\r\n    \r\n    cap.release()\r\n    return saved_count\r\n```\r\n\r\n### Batch Processing Multiple Videos\r\n\r\n```python\r\nimport cv2\r\nimport os\r\nimport json\r\nfrom pathlib import Path\r\n\r\ndef process_video_directory(video_dir, output_base_dir, interval=1):\r\n    \"\"\"Process all videos in a directory and extract frames.\"\"\"\r\n    video_extensions = {'.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm'}\r\n    results = []\r\n    \r\n    for video_file in sorted(Path(video_dir).iterdir()):\r\n        if video_file.suffix.lower() in video_extensions:\r\n            video_output_dir = os.path.join(\r\n                output_base_dir, \r\n                video_file.stem\r\n            )\r\n            result = extract_frames_to_json(\r\n                str(video_file), \r\n                video_output_dir, \r\n                interval=interval\r\n            )\r\n            results.append(result)\r\n            print(f\"Processed: {video_file.name} -> {result['frames_extracted']} frames\")\r\n    \r\n    return results\r\n```\r\n\r\n\r\n## Extraction Configuration Options\r\n\r\n### Output Image Formats\r\n\r\n```python\r\n# JPEG format (default, good balance of quality and size)\r\ncv2.imwrite(\"frame.jpg\", frame)\r\n\r\n# PNG format (lossless, larger files)\r\ncv2.imwrite(\"frame.png\", frame)\r\n\r\n# JPEG with custom quality (0-100)\r\ncv2.imwrite(\"frame.jpg\", frame, [cv2.IMWRITE_JPEG_QUALITY, 95])\r\n\r\n# PNG with compression level (0-9)\r\ncv2.imwrite(\"frame.png\", frame, [cv2.IMWRITE_PNG_COMPRESSION, 3])\r\n```\r\n\r\n### Frame Seeking Methods\r\n\r\n```python\r\n# Seek by frame number\r\ncap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)\r\n\r\n# Seek by milliseconds\r\ncap.set(cv2.CAP_PROP_POS_MSEC, milliseconds)\r\n\r\n# Seek by ratio (0.0 to 1.0)\r\ncap.set(cv2.CAP_PROP_POS_AVI_RATIO, 0.5)  # Middle of video\r\n```\r\n\r\n### Frame Resizing\r\n\r\n```python\r\ndef extract_resized_frames(video_path, output_dir, target_size=(640, 480)):\r\n    \"\"\"Extract and resize frames to specified dimensions.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    frame_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        resized = cv2.resize(frame, target_size)\r\n        filename = os.path.join(output_dir, f\"frame_{frame_count:06d}.jpg\")\r\n        cv2.imwrite(filename, resized)\r\n        frame_count += 1\r\n    \r\n    cap.release()\r\n    return frame_count\r\n```\r\n\r\n\r\n## Video Metadata Retrieval\r\n\r\nExtract video properties before processing:\r\n\r\n```python\r\ndef get_video_info(video_path):\r\n    \"\"\"Retrieve video metadata.\"\"\"\r\n    cap = cv2.VideoCapture(video_path)\r\n    \r\n    if not cap.isOpened():\r\n        return None\r\n    \r\n    info = {\r\n        \"total_frames\": int(cap.get(cv2.CAP_PROP_FRAME_COUNT)),\r\n        \"fps\": cap.get(cv2.CAP_PROP_FPS),\r\n        \"width\": int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),\r\n        \"height\": int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),\r\n        \"codec\": int(cap.get(cv2.CAP_PROP_FOURCC)),\r\n        \"duration_seconds\": cap.get(cv2.CAP_PROP_FRAME_COUNT) \u002F cap.get(cv2.CAP_PROP_FPS)\r\n    }\r\n    \r\n    cap.release()\r\n    return info\r\n```\r\n\r\n\r\n## Specific Frame Extraction\r\n\r\nFor extracting frames at exact positions:\r\n\r\n```python\r\ndef extract_specific_frames(video_path, output_dir, frame_numbers):\r\n    \"\"\"Extract specific frames by their indices.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    extracted = []\r\n    \r\n    for frame_num in sorted(frame_numbers):\r\n        cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)\r\n        ret, frame = cap.read()\r\n        \r\n        if ret:\r\n            filename = os.path.join(output_dir, f\"frame_{frame_num:06d}.jpg\")\r\n            cv2.imwrite(filename, frame)\r\n            extracted.append(frame_num)\r\n    \r\n    cap.release()\r\n    return extracted\r\n```\r\n\r\n\r\n## Error Handling\r\n\r\n### Common Issues and Solutions\r\n\r\n**Issue**: Video file cannot be opened\r\n\r\n```python\r\ncap = cv2.VideoCapture(video_path)\r\nif not cap.isOpened():\r\n    print(f\"Error: Cannot open video file: {video_path}\")\r\n    print(\"Check file path, permissions, and codec support\")\r\n```\r\n\r\n**Issue**: Frames read as None\r\n\r\n```python\r\nret, frame = cap.read()\r\nif not ret or frame is None:\r\n    print(\"Failed to read frame - video may be corrupted or ended\")\r\n```\r\n\r\n**Issue**: Codec not supported\r\n\r\n```python\r\n# Check if video has valid properties\r\nfps = cap.get(cv2.CAP_PROP_FPS)\r\nif fps == 0:\r\n    print(\"Warning: Could not detect FPS - codec may be unsupported\")\r\n```\r\n\r\n**Issue**: Disk space exhausted\r\n\r\n```python\r\nimport shutil\r\n\r\ndef check_disk_space(output_dir, required_mb=100):\r\n    \"\"\"Check available disk space before extraction.\"\"\"\r\n    stat = shutil.disk_usage(output_dir)\r\n    available_mb = stat.free \u002F (1024 * 1024)\r\n    return available_mb >= required_mb\r\n```\r\n\r\n\r\n## Quality Self-Check\r\n\r\nBefore returning results, verify:\r\n\r\n- [ ] Output is valid JSON (use `json.loads()` to validate)\r\n- [ ] All required fields are present (`success`, `source_video`, `frames_extracted`, `video_metadata`)\r\n- [ ] Output directory was created successfully\r\n- [ ] Extracted frame count matches expected value based on interval\r\n- [ ] Warnings array includes all detected issues\r\n- [ ] Video was properly released with `cap.release()`\r\n- [ ] Frame filenames follow consistent zero-padded numbering\r\n\r\n\r\n## Limitations\r\n\r\n- OpenCV may not support all video codecs; install additional codecs if needed\r\n- Seeking in variable frame rate videos may be inaccurate\r\n- Large videos with high frame counts require significant disk space\r\n- Memory usage increases with video resolution\r\n- Some container formats (MKV with certain codecs) may have seeking issues\r\n- Encrypted or DRM-protected videos cannot be processed\r\n- Damaged or partially corrupted videos may extract partial results\r\n\r\n\r\n## Version History\r\n\r\n- **1.0.0** (2026-01-21): Initial release with OpenCV video frame extraction\r\n","# Video Frame Extraction Skill\r\n\r\n## Purpose\r\nThis skill enables extraction of individual frames from video files (MP4, AVI, MOV, etc.) using OpenCV. Extracted frames are saved as image files in a specified output directory. It is suitable for video analysis, creating training datasets, thumbnail generation, and preprocessing video content for further processing.\r\n\r\n## When to Use\r\n- Extracting frames for machine learning training data\r\n- Creating image sequences from video content\r\n- Generating video thumbnails or preview images\r\n- Preprocessing videos for object detection or tracking\r\n- Converting video segments to image collections for analysis\r\n- Sampling frames at specific intervals for time-lapse effects\r\n\r\n## Required Libraries\r\n\r\nThe following Python libraries are required:\r\n\r\n```python\r\nimport cv2\r\nimport os\r\nimport json\r\nfrom pathlib import Path\r\n```\r\n\r\n## Input Requirements\r\n- **File formats**: MP4, AVI, MOV, MKV, WMV, FLV, WEBM\r\n- **Video codec**: Must be readable by OpenCV (most common codecs supported)\r\n- **File access**: Read permissions on source video\r\n- **Output directory**: Write permissions on destination folder\r\n- **Disk space**: Ensure sufficient space for extracted frames (uncompressed images)\r\n\r\n## Output Schema\r\nAll extraction results must be returned as valid JSON conforming to this schema:\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"source_video\": \"sample.mp4\",\r\n  \"output_directory\": \"\u002Fpath\u002Fto\u002Fframes\",\r\n  \"frames_extracted\": 150,\r\n  \"extraction_params\": {\r\n    \"interval\": 1,\r\n    \"start_frame\": 0,\r\n    \"end_frame\": null,\r\n    \"output_format\": \"jpg\"\r\n  },\r\n  \"video_metadata\": {\r\n    \"total_frames\": 300,\r\n    \"fps\": 30.0,\r\n    \"duration_seconds\": 10.0,\r\n    \"resolution\": [1920, 1080]\r\n  },\r\n  \"output_files\": [\r\n    \"frame_000001.jpg\",\r\n    \"frame_000002.jpg\"\r\n  ],\r\n  \"warnings\": []\r\n}\r\n```\r\n\r\n\r\n### Field Descriptions\r\n\r\n- `success`: Boolean indicating whether frame extraction completed\r\n- `source_video`: Original video filename\r\n- `output_directory`: Path where frames were saved\r\n- `frames_extracted`: Total number of frames successfully saved\r\n- `extraction_params.interval`: Frame sampling interval (1 = every frame, 2 = every other frame, etc.)\r\n- `extraction_params.start_frame`: First frame index extracted\r\n- `extraction_params.end_frame`: Last frame index extracted (null if extracted to end)\r\n- `extraction_params.output_format`: Image format used for saving frames\r\n- `video_metadata.total_frames`: Total frame count in source video\r\n- `video_metadata.fps`: Frames per second of source video\r\n- `video_metadata.duration_seconds`: Video duration in seconds\r\n- `video_metadata.resolution`: Video dimensions as [width, height]\r\n- `output_files`: List of generated frame filenames\r\n- `warnings`: Array of issues encountered during extraction\r\n\r\n\r\n## Code Examples\r\n\r\n### Basic Frame Extraction\r\n\r\n```python\r\nimport cv2\r\nimport os\r\n\r\ndef extract_all_frames(video_path, output_dir):\r\n    \"\"\"Extract all frames from a video file.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    frame_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        filename = os.path.join(output_dir, f\"frame_{frame_count:06d}.jpg\")\r\n        cv2.imwrite(filename, frame)\r\n        frame_count += 1\r\n    \r\n    cap.release()\r\n    return frame_count\r\n```\r\n\r\n### Interval-Based Frame Extraction\r\n\r\n```python\r\nimport cv2\r\nimport os\r\n\r\ndef extract_frames_at_interval(video_path, output_dir, interval=1):\r\n    \"\"\"Extract frames at specified intervals.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    frame_index = 0\r\n    saved_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        if frame_index % interval == 0:\r\n            filename = os.path.join(output_dir, f\"frame_{saved_count:06d}.jpg\")\r\n            cv2.imwrite(filename, frame)\r\n            saved_count += 1\r\n        \r\n        frame_index += 1\r\n    \r\n    cap.release()\r\n    return saved_count\r\n```\r\n\r\n### Full Extraction with JSON Output\r\n\r\n```python\r\nimport cv2\r\nimport os\r\nimport json\r\nfrom pathlib import Path\r\n\r\ndef extract_frames_to_json(video_path, output_dir, interval=1, \r\n                           start_frame=0, end_frame=None, output_format=\"jpg\"):\r\n    \"\"\"Extract frames and return results as JSON.\"\"\"\r\n    video_name = os.path.basename(video_path)\r\n    warnings = []\r\n    output_files = []\r\n    \r\n    try:\r\n        os.makedirs(output_dir, exist_ok=True)\r\n        cap = cv2.VideoCapture(video_path)\r\n        \r\n        if not cap.isOpened():\r\n            raise ValueError(f\"Cannot open video: {video_path}\")\r\n        \r\n        # Get video metadata\r\n        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\r\n        fps = cap.get(cv2.CAP_PROP_FPS)\r\n        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\r\n        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\r\n        duration = total_frames \u002F fps if fps > 0 else 0\r\n        \r\n        # Set end frame if not specified\r\n        if end_frame is None:\r\n            end_frame = total_frames\r\n        \r\n        # Seek to start frame\r\n        if start_frame > 0:\r\n            cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)\r\n        \r\n        frame_index = start_frame\r\n        saved_count = 0\r\n        \r\n        while frame_index \u003C end_frame:\r\n            ret, frame = cap.read()\r\n            if not ret:\r\n                if frame_index \u003C end_frame:\r\n                    warnings.append(f\"Video ended early at frame {frame_index}\")\r\n                break\r\n            \r\n            if (frame_index - start_frame) % interval == 0:\r\n                filename = f\"frame_{saved_count:06d}.{output_format}\"\r\n                filepath = os.path.join(output_dir, filename)\r\n                cv2.imwrite(filepath, frame)\r\n                output_files.append(filename)\r\n                saved_count += 1\r\n            \r\n            frame_index += 1\r\n        \r\n        cap.release()\r\n        \r\n        result = {\r\n            \"success\": True,\r\n            \"source_video\": video_name,\r\n            \"output_directory\": str(output_dir),\r\n            \"frames_extracted\": saved_count,\r\n            \"extraction_params\": {\r\n                \"interval\": interval,\r\n                \"start_frame\": start_frame,\r\n                \"end_frame\": end_frame,\r\n                \"output_format\": output_format\r\n            },\r\n            \"video_metadata\": {\r\n                \"total_frames\": total_frames,\r\n                \"fps\": fps,\r\n                \"duration_seconds\": round(duration, 2),\r\n                \"resolution\": [width, height]\r\n            },\r\n            \"output_files\": output_files,\r\n            \"warnings\": warnings\r\n        }\r\n        \r\n    except Exception as e:\r\n        result = {\r\n            \"success\": False,\r\n            \"source_video\": video_name,\r\n            \"output_directory\": str(output_dir),\r\n            \"frames_extracted\": 0,\r\n            \"extraction_params\": {\r\n                \"interval\": interval,\r\n                \"start_frame\": start_frame,\r\n                \"end_frame\": end_frame,\r\n                \"output_format\": output_format\r\n            },\r\n            \"video_metadata\": {\r\n                \"total_frames\": 0,\r\n                \"fps\": 0,\r\n                \"duration_seconds\": 0,\r\n                \"resolution\": [0, 0]\r\n            },\r\n            \"output_files\": [],\r\n            \"warnings\": [f\"Extraction failed: {str(e)}\"]\r\n        }\r\n    \r\n    return result\r\n\r\n# Usage\r\nresult = extract_frames_to_json(\"video.mp4\", \".\u002Fframes\", interval=10)\r\nprint(json.dumps(result, indent=2))\r\n```\r\n\r\n### Time-Based Frame Extraction\r\n\r\n```python\r\nimport cv2\r\nimport os\r\n\r\ndef extract_frames_by_seconds(video_path, output_dir, seconds_interval=1.0):\r\n    \"\"\"Extract frames at specific time intervals (in seconds).\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    fps = cap.get(cv2.CAP_PROP_FPS)\r\n    frame_interval = int(fps * seconds_interval)\r\n    \r\n    if frame_interval \u003C 1:\r\n        frame_interval = 1\r\n    \r\n    frame_index = 0\r\n    saved_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        if frame_index % frame_interval == 0:\r\n            filename = os.path.join(output_dir, f\"frame_{saved_count:06d}.jpg\")\r\n            cv2.imwrite(filename, frame)\r\n            saved_count += 1\r\n        \r\n        frame_index += 1\r\n    \r\n    cap.release()\r\n    return saved_count\r\n```\r\n\r\n### Batch Processing Multiple Videos\r\n\r\n```python\r\nimport cv2\r\nimport os\r\nimport json\r\nfrom pathlib import Path\r\n\r\ndef process_video_directory(video_dir, output_base_dir, interval=1):\r\n    \"\"\"Process all videos in a directory and extract frames.\"\"\"\r\n    video_extensions = {'.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm'}\r\n    results = []\r\n    \r\n    for video_file in sorted(Path(video_dir).iterdir()):\r\n        if video_file.suffix.lower() in video_extensions:\r\n            video_output_dir = os.path.join(\r\n                output_base_dir, \r\n                video_file.stem\r\n            )\r\n            result = extract_frames_to_json(\r\n                str(video_file), \r\n                video_output_dir, \r\n                interval=interval\r\n            )\r\n            results.append(result)\r\n            print(f\"Processed: {video_file.name} -> {result['frames_extracted']} frames\")\r\n    \r\n    return results\r\n```\r\n\r\n\r\n## Extraction Configuration Options\r\n\r\n### Output Image Formats\r\n\r\n```python\r\n# JPEG format (default, good balance of quality and size)\r\ncv2.imwrite(\"frame.jpg\", frame)\r\n\r\n# PNG format (lossless, larger files)\r\ncv2.imwrite(\"frame.png\", frame)\r\n\r\n# JPEG with custom quality (0-100)\r\ncv2.imwrite(\"frame.jpg\", frame, [cv2.IMWRITE_JPEG_QUALITY, 95])\r\n\r\n# PNG with compression level (0-9)\r\ncv2.imwrite(\"frame.png\", frame, [cv2.IMWRITE_PNG_COMPRESSION, 3])\r\n```\r\n\r\n### Frame Seeking Methods\r\n\r\n```python\r\n# Seek by frame number\r\ncap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)\r\n\r\n# Seek by milliseconds\r\ncap.set(cv2.CAP_PROP_POS_MSEC, milliseconds)\r\n\r\n# Seek by ratio (0.0 to 1.0)\r\ncap.set(cv2.CAP_PROP_POS_AVI_RATIO, 0.5)  # Middle of video\r\n```\r\n\r\n### Frame Resizing\r\n\r\n```python\r\ndef extract_resized_frames(video_path, output_dir, target_size=(640, 480)):\r\n    \"\"\"Extract and resize frames to specified dimensions.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    frame_count = 0\r\n    \r\n    while True:\r\n        ret, frame = cap.read()\r\n        if not ret:\r\n            break\r\n        \r\n        resized = cv2.resize(frame, target_size)\r\n        filename = os.path.join(output_dir, f\"frame_{frame_count:06d}.jpg\")\r\n        cv2.imwrite(filename, resized)\r\n        frame_count += 1\r\n    \r\n    cap.release()\r\n    return frame_count\r\n```\r\n\r\n\r\n## Video Metadata Retrieval\r\n\r\nExtract video properties before processing:\r\n\r\n```python\r\ndef get_video_info(video_path):\r\n    \"\"\"Retrieve video metadata.\"\"\"\r\n    cap = cv2.VideoCapture(video_path)\r\n    \r\n    if not cap.isOpened():\r\n        return None\r\n    \r\n    info = {\r\n        \"total_frames\": int(cap.get(cv2.CAP_PROP_FRAME_COUNT)),\r\n        \"fps\": cap.get(cv2.CAP_PROP_FPS),\r\n        \"width\": int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),\r\n        \"height\": int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),\r\n        \"codec\": int(cap.get(cv2.CAP_PROP_FOURCC)),\r\n        \"duration_seconds\": cap.get(cv2.CAP_PROP_FRAME_COUNT) \u002F cap.get(cv2.CAP_PROP_FPS)\r\n    }\r\n    \r\n    cap.release()\r\n    return info\r\n```\r\n\r\n\r\n## Specific Frame Extraction\r\n\r\nFor extracting frames at exact positions:\r\n\r\n```python\r\ndef extract_specific_frames(video_path, output_dir, frame_numbers):\r\n    \"\"\"Extract specific frames by their indices.\"\"\"\r\n    os.makedirs(output_dir, exist_ok=True)\r\n    \r\n    cap = cv2.VideoCapture(video_path)\r\n    extracted = []\r\n    \r\n    for frame_num in sorted(frame_numbers):\r\n        cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)\r\n        ret, frame = cap.read()\r\n        \r\n        if ret:\r\n            filename = os.path.join(output_dir, f\"frame_{frame_num:06d}.jpg\")\r\n            cv2.imwrite(filename, frame)\r\n            extracted.append(frame_num)\r\n    \r\n    cap.release()\r\n    return extracted\r\n```\r\n\r\n\r\n## Error Handling\r\n\r\n### Common Issues and Solutions\r\n\r\n**Issue**: Video file cannot be opened\r\n\r\n```python\r\ncap = cv2.VideoCapture(video_path)\r\nif not cap.isOpened():\r\n    print(f\"Error: Cannot open video file: {video_path}\")\r\n    print(\"Check file path, permissions, and codec support\")\r\n```\r\n\r\n**Issue**: Frames read as None\r\n\r\n```python\r\nret, frame = cap.read()\r\nif not ret or frame is None:\r\n    print(\"Failed to read frame - video may be corrupted or ended\")\r\n```\r\n\r\n**Issue**: Codec not supported\r\n\r\n```python\r\n# Check if video has valid properties\r\nfps = cap.get(cv2.CAP_PROP_FPS)\r\nif fps == 0:\r\n    print(\"Warning: Could not detect FPS - codec may be unsupported\")\r\n```\r\n\r\n**Issue**: Disk space exhausted\r\n\r\n```python\r\nimport shutil\r\n\r\ndef check_disk_space(output_dir, required_mb=100):\r\n    \"\"\"Check available disk space before extraction.\"\"\"\r\n    stat = shutil.disk_usage(output_dir)\r\n    available_mb = stat.free \u002F (1024 * 1024)\r\n    return available_mb >= required_mb\r\n```\r\n\r\n\r\n## Quality Self-Check\r\n\r\nBefore returning results, verify:\r\n\r\n- [ ] Output is valid JSON (use `json.loads()` to validate)\r\n- [ ] All required fields are present (`success`, `source_video`, `frames_extracted`, `video_metadata`)\r\n- [ ] Output directory was created successfully\r\n- [ ] Extracted frame count matches expected value based on interval\r\n- [ ] Warnings array includes all detected issues\r\n- [ ] Video was properly released with `cap.release()`\r\n- [ ] Frame filenames follow consistent zero-padded numbering\r\n\r\n\r\n## Limitations\r\n\r\n- OpenCV may not support all video codecs; install additional codecs if needed\r\n- Seeking in variable frame rate videos may be inaccurate\r\n- Large videos with high frame counts require significant disk space\r\n- Memory usage increases with video resolution\r\n- Some container formats (MKV with certain codecs) may have seeking issues\r\n- Encrypted or DRM-protected videos cannot be processed\r\n- Damaged or partially corrupted videos may extract partial results\r\n\r\n\r\n## Version History\r\n\r\n- **1.0.0** (2026-01-21): Initial release with OpenCV video frame extraction\r\n",{"name":5,"description":7},"main","cdcb6d230f3b15c3c33f8a2bdd16439f43602cbe","jpg-ocr-stat\u002Fresult\u002Fwml-claude4.7\u002Fevidence\u002Ffinal_runs\u002Frun_02\u002Finputs\u002Fskills\u002Fvideo-frame-extraction",1,"https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark","https:\u002F\u002Fgithub.com\u002Flinyouxue","2026-11-14 20:28:35",{"source":8,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add linyouxue\u002Fskill-repair-benchmark --skill video-frame-extraction",{"tool":37,"command":38},"bunx","bunx skills add linyouxue\u002Fskill-repair-benchmark --skill video-frame-extraction",{"tool":40,"command":41},"pnpm","pnpm dlx skills add linyouxue\u002Fskill-repair-benchmark --skill video-frame-extraction","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fwml-claude4.7\u002Fevidence\u002Ffinal_runs\u002Frun_02\u002Finputs\u002Fskills\u002Fvideo-frame-extraction\u002FSKILL.md",true,[],[46,51,58,65,70,75],{"skillNo":47,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":48,"categories":49,"keywords":50,"publishedAt":19},"01M7E1HGVRY73NBJ022CJG13X6","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fskilltta-claude4.7\u002Fgroup_03\u002Frun_03\u002Finputs\u002Fskills\u002Fvideo-frame-extraction\u002FSKILL.md",[],[],{"skillNo":52,"name":53,"nameZh":6,"description":54,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":55,"categories":56,"keywords":57,"publishedAt":19},"01M7E1HAG5R7CJ9C8NYJS771MB","openai-vision","Analyze images and multi-frame sequences using OpenAI GPT vision models","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fskilltta-claude4.7\u002Fgroup_03\u002Frun_03\u002Finputs\u002Fskills\u002Fopenai-vision\u002FSKILL.md",[],[],{"skillNo":59,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M7E1H7DADKB6QBWKC2KQ63SZ","image-ocr","Extract text content from images using Tesseract OCR via Python, including structured field extraction from receipts and forms","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fskilltta-claude4.7\u002Fgroup_03\u002Frun_03\u002Finputs\u002Fskills\u002Fimage-ocr\u002FSKILL.md",[],[],{"skillNo":66,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":69,"publishedAt":19},"01M7E1H0WBNT43TENGQY7AVZHD","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fskilltta-claude4.7\u002Fgroup_03\u002Frun_02\u002Finputs\u002Fskills\u002Fvideo-frame-extraction\u002FSKILL.md",[],[],{"skillNo":71,"name":53,"nameZh":6,"description":54,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":74,"publishedAt":19},"01M7E1GTC7D4N4Q2EF03875J9E","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fskilltta-claude4.7\u002Fgroup_03\u002Frun_02\u002Finputs\u002Fskills\u002Fopenai-vision\u002FSKILL.md",[],[],{"skillNo":76,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":77,"categories":78,"keywords":79,"publishedAt":19},"01M7E1GQ92CWFMGH53KSSE4WER","https:\u002F\u002Fgithub.com\u002Flinyouxue\u002Fskill-repair-benchmark\u002Fblob\u002Fmain\u002Fjpg-ocr-stat\u002Fresult\u002Fskilltta-claude4.7\u002Fgroup_03\u002Frun_02\u002Finputs\u002Fskills\u002Fimage-ocr\u002FSKILL.md",[],[]]