python3 glasswindow.py
玻璃窗检测系统启动
相机初始化失败: 'pyrealsense2.video_stream_profile' object has no attribute 'get_device'
程序执行完成
请根据上述问题修改程序代码,提供一份完整的可运行的程序代码
import cv2
import numpy as np
import matplotlib.pyplot as plt
import pyrealsense2 as rs
import os
import sys
from sklearn.cluster import DBSCAN
from sklearn.linear_model import RANSACRegressor
from collections import defaultdict
class RealSenseCamera:
"""RealSense D455相机控制类"""
def __init__(self, enable_ir_filter=True):
"""
初始化RealSense相机
参数:
enable_ir_filter: 是否启用红外滤光片功能
"""
self.pipeline = rs.pipeline()
self.config = rs.config()
self.align = rs.align(rs.stream.color)
self.enable_ir_filter = enable_ir_filter
# 配置深度和彩色流
self.config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
self.config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
def start(self):
"""启动相机流"""
profile = self.pipeline.start(self.config)
# 获取深度传感器并配置红外滤光片
if self.enable_ir_filter:
depth_sensor = profile.get_device().first_depth_sensor()
depth_sensor.set_option(rs.option.emitter_enabled, 0) # 关闭红外发射器
depth_sensor.set_option(rs.option.laser_power, 0) # 关闭激光器
# 设置自动曝光
color_sensor = profile.get_device().query_sensors()[1]
color_sensor.set_option(rs.option.enable_auto_exposure, True)
# 获取深度比例
depth_profile = rs.video_stream_profile(profile.get_stream(rs.stream.depth))
self.depth_scale = depth_profile.get_device().first_depth_sensor().get_depth_scale()
def capture_frame(self):
"""捕获一帧RGB和深度图像"""
frames = self.pipeline.wait_for_frames()
aligned_frames = self.align.process(frames)
depth_frame = aligned_frames.get_depth_frame()
color_frame = aligned_frames.get_color_frame()
if not depth_frame or not color_frame:
return None, None
# 转换为numpy数组
depth_image = np.asanyarray(depth_frame.get_data())
color_image = np.asanyarray(color_frame.get_data())
return color_image, depth_image
def stop(self):
"""停止相机流"""
self.pipeline.stop()
def cluster_line_segments(lines, eps=20, min_samples=2):
"""
对线段进行聚类处理
参数:
lines: 检测到的线段列表 [(x1,y1,x2,y2), ...]
eps: 聚类半径
min_samples: 最小聚类样本数
返回:
clusters: 聚类后的线段列表 [[line1, line2, ...], ...]
"""
if lines is None or len(lines) == 0:
return []
# 计算线段的中点和角度
segments = []
for line in lines:
x1, y1, x2, y2 = line
mid_x, mid_y = (x1+x2)/2, (y1+y2)/2
angle = np.arctan2(y2-y1, x2-x1) * 180 / np.pi
segments.append([mid_x, mid_y, angle])
segments = np.array(segments)
# 使用DBSCAN聚类算法
db = DBSCAN(eps=eps, min_samples=min_samples).fit(segments)
labels = db.labels_
# 按聚类分组
clusters = defaultdict(list)
for i, label in enumerate(labels):
if label >= 0: # 忽略噪声点
clusters[label].append(lines[i])
return list(clusters.values())
def extend_lines(lines, img_shape):
"""
延长线段以形成完整框架
参数:
lines: 同一簇的线段列表
img_shape: 图像尺寸 (h, w)
返回:
extended_lines: 延长后的线段列表
"""
if not lines:
return []
# 收集所有端点
all_points = []
for line in lines:
x1, y1, x2, y2 = line
all_points.extend([(x1, y1), (x2, y2)])
# 使用RANSAC拟合直线
points = np.array(all_points)
ransac = RANSACRegressor()
# 水平线处理
horizontal_lines = []
for line in lines:
x1, y1, x2, y2 = line
if abs(y1 - y2) < 10: # 水平线
horizontal_lines.append(line)
# 垂直线处理
vertical_lines = []
for line in lines:
x1, y1, x2, y2 = line
if abs(x1 - x2) < 10: # 垂直线
vertical_lines.append(line)
# 延长水平线
extended_lines = []
for cluster in [horizontal_lines, vertical_lines]:
if not cluster:
continue
# 收集端点
points = []
for line in cluster:
x1, y1, x2, y2 = line
points.extend([(x1, y1), (x2, y2)])
if len(points) < 2:
continue
points = np.array(points)
if cluster is horizontal_lines:
# 水平线:固定y值,延长x到图像边界
y_avg = np.mean(points[:, 1])
extended_lines.append((0, int(y_avg), img_shape[1], int(y_avg)))
else:
# 垂直线:固定x值,延长y到图像边界
x_avg = np.mean(points[:, 0])
extended_lines.append((int(x_avg), 0, int(x_avg), img_shape[0]))
return extended_lines
def detect_glass_and_frame(rgb_img, depth_map):
"""
改进的玻璃及窗框检测函数
参数:
rgb_img: RGB彩色图像
depth_map: 深度图
返回:
glass_mask: 玻璃区域掩膜
frame_lines: 检测到的窗框线段
result_img: 可视化结果图像
"""
# ===== 1. 深度图预处理 =====
# 创建玻璃候选区域掩膜(深度值为0的区域)
glass_mask = np.where(depth_map == 0, 255, 0).astype(np.uint8)
# 形态学操作优化掩膜
kernel = np.ones((5, 5), np.uint8)
glass_mask = cv2.morphologyEx(glass_mask, cv2.MORPH_CLOSE, kernel)
glass_mask = cv2.dilate(glass_mask, kernel, iterations=2)
glass_mask = cv2.medianBlur(glass_mask, 5)
# ===== 2. 玻璃区域分割 =====
contours, _ = cv2.findContours(glass_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
min_area = 1000
glass_roi = np.zeros_like(glass_mask)
for cnt in contours:
area = cv2.contourArea(cnt)
if area > min_area:
cv2.drawContours(glass_roi, [cnt], -1, 255, -1)
# ===== 3. 窗框检测 =====
# RGB图像预处理
gray = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
enhanced = clahe.apply(gray)
# 边缘检测
edges = cv2.Canny(enhanced, 50, 150)
# 霍夫变换检测直线
lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=50,
minLineLength=100, maxLineGap=10)
# 几何约束筛选窗框线
frame_lines = []
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
# 筛选水平/垂直线(角度容差±10度)
if abs(x1 - x2) < 10 or abs(y1 - y2) < 10:
frame_lines.append(line[0])
# ===== 4. 线段聚类和延长 =====
clustered_lines = cluster_line_segments(frame_lines)
extended_lines = []
for cluster in clustered_lines:
extended = extend_lines(cluster, rgb_img.shape[:2])
extended_lines.extend(extended)
# ===== 5. 结果可视化 =====
result_img = rgb_img.copy()
# 绘制玻璃区域(半透明红色)
glass_color = np.zeros_like(rgb_img)
glass_color[glass_roi == 255] = [0, 0, 255] # 红色
cv2.addWeighted(glass_color, 0.3, result_img, 1, 0, result_img)
# 绘制原始线段(黄色)
for line in frame_lines:
x1, y1, x2, y2 = line
cv2.line(result_img, (x1, y1), (x2, y2), (0, 255, 255), 2) # 黄色
# 绘制延长后的线段(绿色)
for line in extended_lines:
x1, y1, x2, y2 = line
cv2.line(result_img, (x1, y1), (x2, y2), (0, 255, 0), 3) # 绿色
return glass_roi, extended_lines, result_img
def main():
"""主函数"""
print("玻璃窗检测系统启动")
# 初始化RealSense相机
try:
camera = RealSenseCamera(enable_ir_filter=True)
camera.start()
print("RealSense D455相机已连接")
except Exception as e:
print(f"相机初始化失败: {str(e)}")
return
# 创建结果保存目录
output_dir = "detection_results"
os.makedirs(output_dir, exist_ok=True)
frame_count = 0
plt.ion() # 启用交互模式
try:
while True:
# 捕获帧
color_img, depth_img = camera.capture_frame()
if color_img is None or depth_img is None:
continue
# 执行检测
glass_mask, frame_lines, result_img = detect_glass_and_frame(color_img, depth_img)
# 显示结果
plt.figure(figsize=(15, 10))
plt.subplot(221)
plt.title("RGB Image")
plt.imshow(cv2.cvtColor(color_img, cv2.COLOR_BGR2RGB))
plt.subplot(222)
plt.title("Depth Map")
plt.imshow(depth_img, cmap='jet')
plt.colorbar()
plt.subplot(223)
plt.title("Glass Detection")
plt.imshow(glass_mask, cmap='gray')
plt.subplot(224)
plt.title("Detection Result")
plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB))
plt.tight_layout()
plt.draw()
plt.pause(0.001)
# 保存结果
if frame_count % 10 == 0:
cv2.imwrite(os.path.join(output_dir, f"frame_{frame_count:04d}_rgb.png"), color_img)
cv2.imwrite(os.path.join(output_dir, f"frame_{frame_count:04d}_depth.png"), depth_img)
cv2.imwrite(os.path.join(output_dir, f"frame_{frame_count:04d}_result.png"), result_img)
print(f"已保存帧 {frame_count}")
frame_count += 1
# 检测退出键
if cv2.waitKey(1) & 0xFF == ord('q'):
break
except KeyboardInterrupt:
print("用户中断")
finally:
camera.stop()
plt.ioff()
plt.close()
print("相机已关闭")
if __name__ == "__main__":
main()
print("程序执行完成")