250 lines
8.6 KiB
Python
250 lines
8.6 KiB
Python
|
||
import json
|
||
|
||
import os
|
||
import numpy as np
|
||
import cv2
|
||
import time
|
||
|
||
def set_camera_resolution(cap, width, height):
|
||
"""
|
||
设置摄像头的分辨率。
|
||
|
||
参数:
|
||
- cap: cv2.VideoCapture 对象
|
||
- width: 目标宽度
|
||
- height: 目标高度
|
||
"""
|
||
# 设置摄像头的宽度和高度
|
||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
||
|
||
# 获取实际设置的宽度和高度
|
||
actual_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
|
||
actual_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
|
||
|
||
print(f"设置的分辨率: 宽度={width}, 高度={height}")
|
||
print(f"实际的分辨率: 宽度={actual_width}, 高度={actual_height}")
|
||
|
||
def show_mask(mask, ax, random_color=False):
|
||
if random_color:
|
||
color = np.concatenate([np.random.random(3), np.array([0.6])], axis=0)
|
||
else:
|
||
color = np.array([30/255, 144/255, 255/255, 0.6])
|
||
h, w = mask.shape[-2:]
|
||
mask_image = mask.reshape(h, w, 1) * color.reshape(1, 1, -1)
|
||
ax.imshow(mask_image)
|
||
|
||
def findchesslen(image):
|
||
# 转换为灰度图像
|
||
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||
|
||
# 棋盘格规格,例如8x8内部角点(根据你的实际棋盘规格修改)
|
||
board_size = (3, 4) # 对于8x8的棋盘,内部角点数为7x7
|
||
ret, corners = cv2.findChessboardCorners(gray, board_size, None)
|
||
|
||
frameshow = image.copy()
|
||
cv2.drawChessboardCorners(frameshow, board_size, corners, ret)
|
||
cv2.imshow('Chessboard Corners', frameshow)
|
||
|
||
if ret: # 如果成功找到角点
|
||
distances = []
|
||
|
||
for row in range(board_size[1]): # 遍历每一行
|
||
for col in range(board_size[0] - 1): # 对于每行中的每个角点,计算到下一个角点的距离
|
||
idx = row * board_size[0] + col
|
||
p1 = corners[idx][0]
|
||
p2 = corners[idx + 1][0]
|
||
distance = np.linalg.norm(p1 - p2)
|
||
distances.append(distance)
|
||
print(f"角点 {idx} 到 {idx+1} 的距离: {distance:.2f} 像素")
|
||
|
||
for col in range(board_size[0]): # 遍历每一列
|
||
for row in range(board_size[1] - 1): # 对于每列中的每个角点,计算到下一个角点的距离
|
||
idx = row * board_size[0] + col
|
||
p1 = corners[idx][0]
|
||
p2 = corners[idx + board_size[0]][0]
|
||
distance = np.linalg.norm(p1 - p2)
|
||
distances.append(distance)
|
||
print(f"角点 {idx} 到 {idx+board_size[0]} 的距离: {distance:.2f} 像素")
|
||
|
||
# 计算平均边长
|
||
avg_distance = np.mean(distances)
|
||
return avg_distance
|
||
else:
|
||
return -1
|
||
|
||
|
||
def getseeds(image,dislen=89.01):
|
||
frame = image
|
||
# 将图像从BGR转换为HSV
|
||
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
||
|
||
# 定义橘红色在HSV颜色空间中的范围
|
||
# 色调(H):橘红色大致在0-20之间
|
||
# 饱和度(S):通常较高的值表示更纯的颜色
|
||
# 亮度(V):根据具体需求调整,这里我们选择较低的阈值以包含较暗的部分
|
||
lower_orange_red = np.array([0, 180, 80])
|
||
upper_orange_red = np.array([30, 255, 195])
|
||
|
||
# 创建掩码
|
||
mask = cv2.inRange(hsv, lower_orange_red, upper_orange_red)
|
||
|
||
# 找到符合条件的像素坐标
|
||
orange_red_points = cv2.findNonZero(mask)
|
||
|
||
frameshow = frame.copy()
|
||
# 创建一个与原图大小相同的空白掩码
|
||
mask = np.zeros_like(frame[:, :, 0]) # 单通道掩码
|
||
|
||
if orange_red_points is not None:
|
||
for point in orange_red_points:
|
||
x, y = point[0]
|
||
# 在原图上画圆标记这些点
|
||
cv2.circle(frameshow, (x, y), 1, (0, 255, 0), -1) # 使用绿色标记点
|
||
cv2.circle(mask, (x, y), 1, 255, -1) # 使用白色标记点
|
||
|
||
# 查找轮廓
|
||
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||
|
||
if contours:
|
||
for max_contour in contours:
|
||
# 找到面积最大的轮廓
|
||
# max_contour = max(contours, key=cv2.contourArea)
|
||
|
||
# 计算最小边界矩形(旋转)
|
||
rect = cv2.minAreaRect(max_contour)
|
||
box = cv2.boxPoints(rect)
|
||
box = np.int32(box)
|
||
|
||
# 计算边界框的宽度和高度
|
||
width = int(rect[1][0])
|
||
height = int(rect[1][1])
|
||
|
||
# 输出边界框的信息
|
||
# print(f"Bounding Box Center: ({rect[0][0]:.2f}, {rect[0][1]:.2f})")
|
||
# print(f"Bounding Box Width: {width}")
|
||
# print(f"Bounding Box Height: {height}")
|
||
|
||
if dislen >20 and rect[1][0] > 25 and rect[1][1] > 25 :
|
||
ww = rect[1][0]*3.0/dislen
|
||
hh = rect[1][1]*3.0/dislen
|
||
# 格式化输出保留两位有效数字
|
||
ww_text = f"w=: {ww:.2f}"
|
||
hh_text = f"h=: {hh:.2f}"
|
||
# 获取边界框左上角的坐标
|
||
# x, y = np.min(box, axis=0)
|
||
|
||
# 计算中心点
|
||
x = int(np.mean(box[:, 0]))
|
||
y = int(np.mean(box[:, 1]))
|
||
print(x,y)
|
||
print(rect[1][0])
|
||
print(ww_text)
|
||
|
||
# center_point = (center_x, center_y)
|
||
|
||
# 设置字体、缩放比例、颜色和厚度
|
||
font = cv2.FONT_HERSHEY_SIMPLEX
|
||
font_scale = 2
|
||
color = (0, 0, 255) # BGR颜色格式,这里是蓝色
|
||
thickness = 2
|
||
|
||
# 显示宽度信息
|
||
cv2.putText(frameshow, ww_text, (x, y-10), font, font_scale, color, thickness)
|
||
|
||
# 显示高度信息
|
||
cv2.putText(frameshow, hh_text, (x, y - 40), font, font_scale, color, thickness)
|
||
|
||
# 在原图上绘制边界框
|
||
cv2.drawContours(frameshow, [box], 0, (0, 0, 255), 2)
|
||
|
||
# 显示结果帧
|
||
# cv2.imshow('Orange Red Points and Bounding Box', frameshow)
|
||
return frameshow
|
||
|
||
# 显示结果帧
|
||
#cv2.imshow('Orange Red Points', frameshow)
|
||
|
||
|
||
|
||
# 打开USB摄像头
|
||
cap = cv2.VideoCapture(0) # 0是默认的摄像头ID,如果有多个摄像头可能需要调整
|
||
# 设置目标分辨率
|
||
target_width = 1920
|
||
target_height = 1080
|
||
set_camera_resolution(cap, target_width, target_height)
|
||
|
||
if not cap.isOpened():
|
||
print("无法打开摄像头")
|
||
else:
|
||
|
||
last_save_time = time.time()
|
||
interval = 10*20 # 10分钟间隔
|
||
save_dir="data"
|
||
save_path_format="frame_%m-%d_%H-%M.png"
|
||
save_path_format_det="frame_%m-%d_%H-%M_det.png"
|
||
if not os.path.exists(save_dir):
|
||
os.makedirs(save_dir)
|
||
|
||
|
||
# 设置显示窗口的目标尺寸
|
||
display_width = 640
|
||
display_height = 360
|
||
|
||
while True:
|
||
ret, frame = cap.read()
|
||
## height, width, channels = frame.shape[:3] # 获取帧的高度、宽度和通道数
|
||
#print(f"Frame 尺寸: 宽度={width}, 高度={height}, 通道数={channels if len(frame.shape) == 3 else 1}")
|
||
if not ret:
|
||
print("无法获取帧")
|
||
break
|
||
if 0:
|
||
#print(frame)
|
||
dislen = findchesslen(frame)
|
||
#dislen = 148.50
|
||
print(f"cell={dislen}")
|
||
cv2.waitKey(20)
|
||
continue
|
||
#continue
|
||
#print(frame)
|
||
#dislen = findchesslen(frame)
|
||
|
||
dislen = 147.50
|
||
#print(f"cell={dislen}")
|
||
# frame_det = frame
|
||
frame_det = getseeds(frame,dislen)
|
||
|
||
rzframe = cv2.resize(frame, (display_width, display_height))
|
||
cv2.imshow('orgimage', rzframe)
|
||
|
||
rzframe_det = cv2.resize(frame_det, (display_width, display_height))
|
||
cv2.imshow('detimage', rzframe_det)
|
||
|
||
|
||
current_time = time.time()
|
||
if current_time - last_save_time > interval:
|
||
# 根据当前时间生成文件名
|
||
file_name = time.strftime(save_path_format, time.localtime(current_time))
|
||
file_name_det = time.strftime(save_path_format_det, time.localtime(current_time))
|
||
|
||
save_path = os.path.join(save_dir, file_name)
|
||
save_path_det = os.path.join(save_dir, file_name_det)
|
||
|
||
# 保存原始帧
|
||
cv2.imwrite(save_path, frame)
|
||
print(f"已保存帧到 {save_path}")
|
||
|
||
# 获取并保存检测结果帧
|
||
cv2.imwrite(save_path_det, frame_det)
|
||
print(f"已保存检测结果帧到 {save_path_det}")
|
||
|
||
last_save_time = current_time # 更新最后保存时间为当前时间
|
||
|
||
# 显示结果帧
|
||
# cv2.imshow('Chessboard Corners', frame)
|
||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||
break
|
||
|
||
cap.release()
|
||
cv2.destroyAllWindows() |