125 lines
3.8 KiB
Python
125 lines
3.8 KiB
Python
"""
|
|
摄像头拍照模块 - Windows 兼容
|
|
"""
|
|
import cv2
|
|
import datetime
|
|
from pathlib import Path
|
|
from config import config_mgr
|
|
|
|
|
|
class CameraCapture:
|
|
"""摄像头拍照管理"""
|
|
|
|
def __init__(self):
|
|
self.camera_index = config_mgr.get('camera_index', 0)
|
|
self.cap = None
|
|
|
|
def open(self):
|
|
"""打开摄像头"""
|
|
if self.cap is None or not self.cap.isOpened():
|
|
self.camera_index = config_mgr.get('camera_index', 0)
|
|
self.cap = cv2.VideoCapture(self.camera_index, cv2.CAP_DSHOW) # Windows DirectShow
|
|
if not self.cap.isOpened():
|
|
raise Exception(f"无法打开摄像头 {self.camera_index}")
|
|
# 设置分辨率
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
|
|
return self.cap.isOpened()
|
|
|
|
def close(self):
|
|
"""关闭摄像头"""
|
|
if self.cap is not None:
|
|
self.cap.release()
|
|
self.cap = None
|
|
|
|
def capture(self, save_path=None):
|
|
"""拍照并保存(按日期文件夹组织)
|
|
|
|
Returns:
|
|
dict: {'success': bool, 'path': str, 'timestamp': str, 'date_folder': str, 'error': str}
|
|
"""
|
|
try:
|
|
self.open()
|
|
|
|
# 等待摄像头稳定(Windows 上需要预热)
|
|
for _ in range(5):
|
|
self.cap.read()
|
|
|
|
ret, frame = self.cap.read()
|
|
if not ret:
|
|
return {'success': False, 'error': '无法捕获图像'}
|
|
|
|
# 获取当前日期
|
|
now = datetime.datetime.now()
|
|
date_str = now.strftime('%Y-%m-%d')
|
|
timestamp = now.strftime('%Y%m%d_%H%M%S')
|
|
|
|
# 获取按日期的保存目录
|
|
date_folder = config_mgr.get_images_dir(date_str)
|
|
|
|
if save_path is None:
|
|
filename = f"capture_{timestamp}.jpg"
|
|
save_path = date_folder / filename
|
|
|
|
# 保存图片
|
|
cv2.imwrite(str(save_path), frame, [cv2.IMWRITE_JPEG_QUALITY, 90])
|
|
|
|
return {
|
|
'success': True,
|
|
'path': str(save_path),
|
|
'timestamp': timestamp,
|
|
'date_folder': date_str,
|
|
'filename': save_path.name
|
|
}
|
|
|
|
except Exception as e:
|
|
return {'success': False, 'error': str(e)}
|
|
|
|
def get_camera_info(self):
|
|
"""获取摄像头信息"""
|
|
try:
|
|
self.open()
|
|
width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
|
height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
|
fps = int(self.cap.get(cv2.CAP_PROP_FPS))
|
|
return {
|
|
'index': self.camera_index,
|
|
'width': width,
|
|
'height': height,
|
|
'fps': fps,
|
|
'status': 'opened'
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
'index': self.camera_index,
|
|
'status': 'error',
|
|
'error': str(e)
|
|
}
|
|
|
|
def __del__(self):
|
|
self.close()
|
|
|
|
|
|
def list_available_cameras(max_test=5):
|
|
"""列出可用的摄像头"""
|
|
available = []
|
|
for i in range(max_test):
|
|
cap = cv2.VideoCapture(i, cv2.CAP_DSHOW)
|
|
if cap.isOpened():
|
|
available.append(i)
|
|
cap.release()
|
|
return available
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# 测试摄像头
|
|
print("检测可用摄像头...")
|
|
cams = list_available_cameras()
|
|
print(f"可用摄像头: {cams}")
|
|
|
|
if cams:
|
|
print("\n测试拍照...")
|
|
camera = CameraCapture()
|
|
result = camera.capture()
|
|
print(f"结果: {result}")
|
|
camera.close() |