slider-solver-cv


Nameslider-solver-cv JSON
Version 0.1.1 PyPI version JSON
download
home_pagehttps://github.com/SkyAerope/SliderSolver
Summary识别滑块验证码缺口位置
upload_time2025-10-30 07:44:50
maintainerNone
docs_urlNone
authorYour Name
requires_python>=3.7
licenseApache-2.0
keywords slider captcha opencv computer-vision
VCS
bugtrack_url
requirements opencv-python numpy pillow pytest
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # SliderSolver

![Tests](https://github.com/SkyAerope/SliderSolver/workflows/Run%20Tests/badge.svg)
![PyPI](https://img.shields.io/pypi/v/slider-solver-cv)
![Python](https://img.shields.io/pypi/pyversions/slider-solver-cv)
![License](https://img.shields.io/github/license/SkyAerope/SliderSolver)

一个用于识别滑块验证码缺口位置的 Python 包。通过图像处理技术,自动识别缺口在背景图中的位置,并返回缺口左边缘到背景图左边缘的距离。

## 功能特点

- 🎯 精准定位:使用 OpenCV 模板匹配算法精确识别缺口位置
- 🖼️ 边缘检测:基于 Canny 边缘检测提高匹配准确率
- 📊 可视化结果:自动在背景图上标记识别位置
- 🚀 简单易用:仅需两行代码即可完成识别

## 安装

### 从源码安装

```bash
git clone https://github.com/SkyAerope/SliderSolver.git
cd SliderSolver
pip install -e .
```

### 使用 pip 安装

```bash
pip install slider-solver-cv
```

## 依赖

- Python >= 3.9
- opencv-python >= 4.5.0
- numpy >= 1.19.0
- pillow >= 8.0.0

## 使用方法

### 基本用法

```python
from slider_solver import SliderSolver

# 创建求解器实例
solver = SliderSolver(
    bg_img_path='path/to/background.png',    # 背景图路径
    front_img_path='path/to/slider.png'      # 缺口图路径
)

# 计算缺口位置
distance = solver.detect_distance()
print(f'缺口位置: {distance}px')
```

### 带可视化的完整示例

```python
from slider_solver import SliderSolver
import os

def solve_slider_captcha():
    # 图片路径
    bg_img = 'images/background.png'
    slider_img = 'images/slider.png'
  
    # 检查文件是否存在
    if not os.path.exists(bg_img) or not os.path.exists(slider_img):
        print("错误:图片文件不存在")
        return
  
    # 创建求解器
    solver = SliderSolver(bg_img, slider_img)
  
    # 计算位置
    distance = solver.detect_distance()
    print(f'✅ 识别成功!缺口位置在 x = {distance}px')
  
    # 可选:绘制标记线并保存结果图片
    result_path = solver.draw_line(distance, bg_img)
    print(f'📁 结果图片已保存到: {result_path}')
  
    return distance

if __name__ == '__main__':
    solve_slider_captcha()
```

### 自定义保存路径

```python
from slider_solver import SliderSolver

solver = SliderSolver('background.png', 'slider.png')
distance = solver.detect_distance()

# 指定自定义的保存路径
result_path = solver.draw_line(
    x=distance,
    bg_img_path='background.png',
    target_path='output/marked_result.png'  # 可选,不指定则自动生成
)
print(f'结果保存到: {result_path}')
```

## API 说明

### SliderSolver 类

#### `__init__(bg_img_path, front_img_path)`

初始化求解器。

**参数:**

- `bg_img_path` (str): 背景图片的文件路径
- `front_img_path` (str): 缺口图片的文件路径

#### `detect_distance()`

检测缺口在背景图中的 x 坐标位置。

**返回值:**

- `int`: 缺口距离左边界的像素距离

**示例:**

```python
solver = SliderSolver('bg.png', 'slider.png')
distance = solver.detect_distance()  # 返回如: 120
```

#### `draw_line(x, bg_img_path, target_path=None)`

在背景图上绘制红色竖线标记位置。

**参数:**

- `x` (int): 竖线的 x 坐标
- `bg_img_path` (str): 背景图片路径
- `target_path` (str, 可选): 结果图片保存路径,不指定则自动生成(添加 `_result` 后缀)

**返回值:**

- `str`: 保存的结果图片路径

**示例:**

```python
result_path = solver.draw_line(120, 'bg.png')  # 自动保存为 bg_result.png
# 或指定路径
result_path = solver.draw_line(120, 'bg.png', 'output/marked.png')
```

## 工作原理

1. **读取图片**:加载背景图和缺口图
2. **预处理**:去除缺口图的透明边界
3. **灰度转换**:将图片转换为灰度图
4. **边缘检测**:使用 Canny 算法检测边缘
5. **模板匹配**:使用 TM_CCOEFF_NORMED 方法进行匹配
6. **返回结果**:返回匹配到的 x 坐标
7. **可选可视化**:调用 `draw_line()` 方法绘制标记线

## 项目结构

```
SliderSolver/
├── src/
│   └── slider_solver/
│       ├── __init__.py      # 包初始化文件
│       └── solver.py        # 核心实现
├── tests/                   # 测试目录
│   ├── __init__.py         # 测试包初始化
│   ├── test_solver.py      # 单元测试
│   └── test_images/        # 测试图片
│       ├── bg1.png         # 测试背景图1
│       ├── bg2.png         # 测试背景图2
│       ├── t1.png          # 测试滑块图1
│       └── t2.png          # 测试滑块图2
├── setup.py                # 安装配置(传统方式)
├── pyproject.toml         # 现代 Python 包配置
├── requirements.txt       # 依赖列表
├── README.md             # 使用文档
├── LICENSE               # 许可证
└── .gitignore           # Git 忽略规则
```

## 开发与测试

### 安装开发依赖

```bash
# 安装所有依赖(包括测试工具)
pip install -r requirements.txt
```

### 运行测试

`tests/test_images`中含有示例图片,可以用于测试目的

```bash
# 运行所有测试
pytest tests/ -v

# 运行特定测试
pytest tests/test_solver.py::TestSliderSolver::test_detect_distance_case1 -v

# 显示详细输出
pytest tests/ -v -s
```

### 测试覆盖的功能

- ✅ 基本的距离检测功能
- ✅ 多组图片组合测试
- ✅ 默认路径的标记线绘制
- ✅ 自定义路径的标记线绘制
- ✅ 无效路径的错误处理
- ✅ 初始化参数验证

## 许可证

本项目采用 Apache-2.0 许可证。详见 [LICENSE](LICENSE) 文件。

## 贡献

欢迎提交 Issue 和 Pull Request!

## 作者

- GitHub: [@SkyAerope](https://github.com/SkyAerope)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/SkyAerope/SliderSolver",
    "name": "slider-solver-cv",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "slider, captcha, opencv, computer-vision",
    "author": "Your Name",
    "author_email": "SkyAerope <skyaerope@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/62/18/2ebae7d979bd164570bb2b22656ca8fc7e354c7369bc4198919383769474/slider_solver_cv-0.1.1.tar.gz",
    "platform": null,
    "description": "# SliderSolver\n\n![Tests](https://github.com/SkyAerope/SliderSolver/workflows/Run%20Tests/badge.svg)\n![PyPI](https://img.shields.io/pypi/v/slider-solver-cv)\n![Python](https://img.shields.io/pypi/pyversions/slider-solver-cv)\n![License](https://img.shields.io/github/license/SkyAerope/SliderSolver)\n\n\u4e00\u4e2a\u7528\u4e8e\u8bc6\u522b\u6ed1\u5757\u9a8c\u8bc1\u7801\u7f3a\u53e3\u4f4d\u7f6e\u7684 Python \u5305\u3002\u901a\u8fc7\u56fe\u50cf\u5904\u7406\u6280\u672f\uff0c\u81ea\u52a8\u8bc6\u522b\u7f3a\u53e3\u5728\u80cc\u666f\u56fe\u4e2d\u7684\u4f4d\u7f6e\uff0c\u5e76\u8fd4\u56de\u7f3a\u53e3\u5de6\u8fb9\u7f18\u5230\u80cc\u666f\u56fe\u5de6\u8fb9\u7f18\u7684\u8ddd\u79bb\u3002\n\n## \u529f\u80fd\u7279\u70b9\n\n- \ud83c\udfaf \u7cbe\u51c6\u5b9a\u4f4d\uff1a\u4f7f\u7528 OpenCV \u6a21\u677f\u5339\u914d\u7b97\u6cd5\u7cbe\u786e\u8bc6\u522b\u7f3a\u53e3\u4f4d\u7f6e\n- \ud83d\uddbc\ufe0f \u8fb9\u7f18\u68c0\u6d4b\uff1a\u57fa\u4e8e Canny \u8fb9\u7f18\u68c0\u6d4b\u63d0\u9ad8\u5339\u914d\u51c6\u786e\u7387\n- \ud83d\udcca \u53ef\u89c6\u5316\u7ed3\u679c\uff1a\u81ea\u52a8\u5728\u80cc\u666f\u56fe\u4e0a\u6807\u8bb0\u8bc6\u522b\u4f4d\u7f6e\n- \ud83d\ude80 \u7b80\u5355\u6613\u7528\uff1a\u4ec5\u9700\u4e24\u884c\u4ee3\u7801\u5373\u53ef\u5b8c\u6210\u8bc6\u522b\n\n## \u5b89\u88c5\n\n### \u4ece\u6e90\u7801\u5b89\u88c5\n\n```bash\ngit clone https://github.com/SkyAerope/SliderSolver.git\ncd SliderSolver\npip install -e .\n```\n\n### \u4f7f\u7528 pip \u5b89\u88c5\n\n```bash\npip install slider-solver-cv\n```\n\n## \u4f9d\u8d56\n\n- Python >= 3.9\n- opencv-python >= 4.5.0\n- numpy >= 1.19.0\n- pillow >= 8.0.0\n\n## \u4f7f\u7528\u65b9\u6cd5\n\n### \u57fa\u672c\u7528\u6cd5\n\n```python\nfrom slider_solver import SliderSolver\n\n# \u521b\u5efa\u6c42\u89e3\u5668\u5b9e\u4f8b\nsolver = SliderSolver(\n    bg_img_path='path/to/background.png',    # \u80cc\u666f\u56fe\u8def\u5f84\n    front_img_path='path/to/slider.png'      # \u7f3a\u53e3\u56fe\u8def\u5f84\n)\n\n# \u8ba1\u7b97\u7f3a\u53e3\u4f4d\u7f6e\ndistance = solver.detect_distance()\nprint(f'\u7f3a\u53e3\u4f4d\u7f6e: {distance}px')\n```\n\n### \u5e26\u53ef\u89c6\u5316\u7684\u5b8c\u6574\u793a\u4f8b\n\n```python\nfrom slider_solver import SliderSolver\nimport os\n\ndef solve_slider_captcha():\n    # \u56fe\u7247\u8def\u5f84\n    bg_img = 'images/background.png'\n    slider_img = 'images/slider.png'\n  \n    # \u68c0\u67e5\u6587\u4ef6\u662f\u5426\u5b58\u5728\n    if not os.path.exists(bg_img) or not os.path.exists(slider_img):\n        print(\"\u9519\u8bef\uff1a\u56fe\u7247\u6587\u4ef6\u4e0d\u5b58\u5728\")\n        return\n  \n    # \u521b\u5efa\u6c42\u89e3\u5668\n    solver = SliderSolver(bg_img, slider_img)\n  \n    # \u8ba1\u7b97\u4f4d\u7f6e\n    distance = solver.detect_distance()\n    print(f'\u2705 \u8bc6\u522b\u6210\u529f\uff01\u7f3a\u53e3\u4f4d\u7f6e\u5728 x = {distance}px')\n  \n    # \u53ef\u9009\uff1a\u7ed8\u5236\u6807\u8bb0\u7ebf\u5e76\u4fdd\u5b58\u7ed3\u679c\u56fe\u7247\n    result_path = solver.draw_line(distance, bg_img)\n    print(f'\ud83d\udcc1 \u7ed3\u679c\u56fe\u7247\u5df2\u4fdd\u5b58\u5230: {result_path}')\n  \n    return distance\n\nif __name__ == '__main__':\n    solve_slider_captcha()\n```\n\n### \u81ea\u5b9a\u4e49\u4fdd\u5b58\u8def\u5f84\n\n```python\nfrom slider_solver import SliderSolver\n\nsolver = SliderSolver('background.png', 'slider.png')\ndistance = solver.detect_distance()\n\n# \u6307\u5b9a\u81ea\u5b9a\u4e49\u7684\u4fdd\u5b58\u8def\u5f84\nresult_path = solver.draw_line(\n    x=distance,\n    bg_img_path='background.png',\n    target_path='output/marked_result.png'  # \u53ef\u9009\uff0c\u4e0d\u6307\u5b9a\u5219\u81ea\u52a8\u751f\u6210\n)\nprint(f'\u7ed3\u679c\u4fdd\u5b58\u5230: {result_path}')\n```\n\n## API \u8bf4\u660e\n\n### SliderSolver \u7c7b\n\n#### `__init__(bg_img_path, front_img_path)`\n\n\u521d\u59cb\u5316\u6c42\u89e3\u5668\u3002\n\n**\u53c2\u6570\uff1a**\n\n- `bg_img_path` (str): \u80cc\u666f\u56fe\u7247\u7684\u6587\u4ef6\u8def\u5f84\n- `front_img_path` (str): \u7f3a\u53e3\u56fe\u7247\u7684\u6587\u4ef6\u8def\u5f84\n\n#### `detect_distance()`\n\n\u68c0\u6d4b\u7f3a\u53e3\u5728\u80cc\u666f\u56fe\u4e2d\u7684 x \u5750\u6807\u4f4d\u7f6e\u3002\n\n**\u8fd4\u56de\u503c\uff1a**\n\n- `int`: \u7f3a\u53e3\u8ddd\u79bb\u5de6\u8fb9\u754c\u7684\u50cf\u7d20\u8ddd\u79bb\n\n**\u793a\u4f8b\uff1a**\n\n```python\nsolver = SliderSolver('bg.png', 'slider.png')\ndistance = solver.detect_distance()  # \u8fd4\u56de\u5982: 120\n```\n\n#### `draw_line(x, bg_img_path, target_path=None)`\n\n\u5728\u80cc\u666f\u56fe\u4e0a\u7ed8\u5236\u7ea2\u8272\u7ad6\u7ebf\u6807\u8bb0\u4f4d\u7f6e\u3002\n\n**\u53c2\u6570\uff1a**\n\n- `x` (int): \u7ad6\u7ebf\u7684 x \u5750\u6807\n- `bg_img_path` (str): \u80cc\u666f\u56fe\u7247\u8def\u5f84\n- `target_path` (str, \u53ef\u9009): \u7ed3\u679c\u56fe\u7247\u4fdd\u5b58\u8def\u5f84\uff0c\u4e0d\u6307\u5b9a\u5219\u81ea\u52a8\u751f\u6210\uff08\u6dfb\u52a0 `_result` \u540e\u7f00\uff09\n\n**\u8fd4\u56de\u503c\uff1a**\n\n- `str`: \u4fdd\u5b58\u7684\u7ed3\u679c\u56fe\u7247\u8def\u5f84\n\n**\u793a\u4f8b\uff1a**\n\n```python\nresult_path = solver.draw_line(120, 'bg.png')  # \u81ea\u52a8\u4fdd\u5b58\u4e3a bg_result.png\n# \u6216\u6307\u5b9a\u8def\u5f84\nresult_path = solver.draw_line(120, 'bg.png', 'output/marked.png')\n```\n\n## \u5de5\u4f5c\u539f\u7406\n\n1. **\u8bfb\u53d6\u56fe\u7247**\uff1a\u52a0\u8f7d\u80cc\u666f\u56fe\u548c\u7f3a\u53e3\u56fe\n2. **\u9884\u5904\u7406**\uff1a\u53bb\u9664\u7f3a\u53e3\u56fe\u7684\u900f\u660e\u8fb9\u754c\n3. **\u7070\u5ea6\u8f6c\u6362**\uff1a\u5c06\u56fe\u7247\u8f6c\u6362\u4e3a\u7070\u5ea6\u56fe\n4. **\u8fb9\u7f18\u68c0\u6d4b**\uff1a\u4f7f\u7528 Canny \u7b97\u6cd5\u68c0\u6d4b\u8fb9\u7f18\n5. **\u6a21\u677f\u5339\u914d**\uff1a\u4f7f\u7528 TM_CCOEFF_NORMED \u65b9\u6cd5\u8fdb\u884c\u5339\u914d\n6. **\u8fd4\u56de\u7ed3\u679c**\uff1a\u8fd4\u56de\u5339\u914d\u5230\u7684 x \u5750\u6807\n7. **\u53ef\u9009\u53ef\u89c6\u5316**\uff1a\u8c03\u7528 `draw_line()` \u65b9\u6cd5\u7ed8\u5236\u6807\u8bb0\u7ebf\n\n## \u9879\u76ee\u7ed3\u6784\n\n```\nSliderSolver/\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 slider_solver/\n\u2502       \u251c\u2500\u2500 __init__.py      # \u5305\u521d\u59cb\u5316\u6587\u4ef6\n\u2502       \u2514\u2500\u2500 solver.py        # \u6838\u5fc3\u5b9e\u73b0\n\u251c\u2500\u2500 tests/                   # \u6d4b\u8bd5\u76ee\u5f55\n\u2502   \u251c\u2500\u2500 __init__.py         # \u6d4b\u8bd5\u5305\u521d\u59cb\u5316\n\u2502   \u251c\u2500\u2500 test_solver.py      # \u5355\u5143\u6d4b\u8bd5\n\u2502   \u2514\u2500\u2500 test_images/        # \u6d4b\u8bd5\u56fe\u7247\n\u2502       \u251c\u2500\u2500 bg1.png         # \u6d4b\u8bd5\u80cc\u666f\u56fe1\n\u2502       \u251c\u2500\u2500 bg2.png         # \u6d4b\u8bd5\u80cc\u666f\u56fe2\n\u2502       \u251c\u2500\u2500 t1.png          # \u6d4b\u8bd5\u6ed1\u5757\u56fe1\n\u2502       \u2514\u2500\u2500 t2.png          # \u6d4b\u8bd5\u6ed1\u5757\u56fe2\n\u251c\u2500\u2500 setup.py                # \u5b89\u88c5\u914d\u7f6e\uff08\u4f20\u7edf\u65b9\u5f0f\uff09\n\u251c\u2500\u2500 pyproject.toml         # \u73b0\u4ee3 Python \u5305\u914d\u7f6e\n\u251c\u2500\u2500 requirements.txt       # \u4f9d\u8d56\u5217\u8868\n\u251c\u2500\u2500 README.md             # \u4f7f\u7528\u6587\u6863\n\u251c\u2500\u2500 LICENSE               # \u8bb8\u53ef\u8bc1\n\u2514\u2500\u2500 .gitignore           # Git \u5ffd\u7565\u89c4\u5219\n```\n\n## \u5f00\u53d1\u4e0e\u6d4b\u8bd5\n\n### \u5b89\u88c5\u5f00\u53d1\u4f9d\u8d56\n\n```bash\n# \u5b89\u88c5\u6240\u6709\u4f9d\u8d56\uff08\u5305\u62ec\u6d4b\u8bd5\u5de5\u5177\uff09\npip install -r requirements.txt\n```\n\n### \u8fd0\u884c\u6d4b\u8bd5\n\n`tests/test_images`\u4e2d\u542b\u6709\u793a\u4f8b\u56fe\u7247\uff0c\u53ef\u4ee5\u7528\u4e8e\u6d4b\u8bd5\u76ee\u7684\n\n```bash\n# \u8fd0\u884c\u6240\u6709\u6d4b\u8bd5\npytest tests/ -v\n\n# \u8fd0\u884c\u7279\u5b9a\u6d4b\u8bd5\npytest tests/test_solver.py::TestSliderSolver::test_detect_distance_case1 -v\n\n# \u663e\u793a\u8be6\u7ec6\u8f93\u51fa\npytest tests/ -v -s\n```\n\n### \u6d4b\u8bd5\u8986\u76d6\u7684\u529f\u80fd\n\n- \u2705 \u57fa\u672c\u7684\u8ddd\u79bb\u68c0\u6d4b\u529f\u80fd\n- \u2705 \u591a\u7ec4\u56fe\u7247\u7ec4\u5408\u6d4b\u8bd5\n- \u2705 \u9ed8\u8ba4\u8def\u5f84\u7684\u6807\u8bb0\u7ebf\u7ed8\u5236\n- \u2705 \u81ea\u5b9a\u4e49\u8def\u5f84\u7684\u6807\u8bb0\u7ebf\u7ed8\u5236\n- \u2705 \u65e0\u6548\u8def\u5f84\u7684\u9519\u8bef\u5904\u7406\n- \u2705 \u521d\u59cb\u5316\u53c2\u6570\u9a8c\u8bc1\n\n## \u8bb8\u53ef\u8bc1\n\n\u672c\u9879\u76ee\u91c7\u7528 Apache-2.0 \u8bb8\u53ef\u8bc1\u3002\u8be6\u89c1 [LICENSE](LICENSE) \u6587\u4ef6\u3002\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4 Issue \u548c Pull Request\uff01\n\n## \u4f5c\u8005\n\n- GitHub: [@SkyAerope](https://github.com/SkyAerope)\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "\u8bc6\u522b\u6ed1\u5757\u9a8c\u8bc1\u7801\u7f3a\u53e3\u4f4d\u7f6e",
    "version": "0.1.1",
    "project_urls": {
        "Bug Reports": "https://github.com/SkyAerope/SliderSolver/issues",
        "Homepage": "https://github.com/SkyAerope/SliderSolver",
        "Source": "https://github.com/SkyAerope/SliderSolver"
    },
    "split_keywords": [
        "slider",
        " captcha",
        " opencv",
        " computer-vision"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c9ff00a1fc50cef833c9041a3a49be441ed6018816afee965eb0f2c3145f9df8",
                "md5": "56735c8d64f484602ca51a38121a88c0",
                "sha256": "72383b3ce7afe1b22b7a5672ac03af8ee218fe415e7212e5557864c9e24ec3d3"
            },
            "downloads": -1,
            "filename": "slider_solver_cv-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "56735c8d64f484602ca51a38121a88c0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 9628,
            "upload_time": "2025-10-30T07:44:49",
            "upload_time_iso_8601": "2025-10-30T07:44:49.584550Z",
            "url": "https://files.pythonhosted.org/packages/c9/ff/00a1fc50cef833c9041a3a49be441ed6018816afee965eb0f2c3145f9df8/slider_solver_cv-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "62182ebae7d979bd164570bb2b22656ca8fc7e354c7369bc4198919383769474",
                "md5": "b572aee99676cdeefd00a15f09383817",
                "sha256": "01f93da851614e02d66079d8e013e8f3f76a62ba1cb417009318bb08425c4b8c"
            },
            "downloads": -1,
            "filename": "slider_solver_cv-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "b572aee99676cdeefd00a15f09383817",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 10141,
            "upload_time": "2025-10-30T07:44:50",
            "upload_time_iso_8601": "2025-10-30T07:44:50.344145Z",
            "url": "https://files.pythonhosted.org/packages/62/18/2ebae7d979bd164570bb2b22656ca8fc7e354c7369bc4198919383769474/slider_solver_cv-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-30 07:44:50",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "SkyAerope",
    "github_project": "SliderSolver",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "opencv-python",
            "specs": [
                [
                    ">=",
                    "4.5.0"
                ]
            ]
        },
        {
            "name": "numpy",
            "specs": [
                [
                    ">=",
                    "1.19.0"
                ]
            ]
        },
        {
            "name": "pillow",
            "specs": [
                [
                    ">=",
                    "8.0.0"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        }
    ],
    "lcname": "slider-solver-cv"
}
        
Elapsed time: 2.88143s