抛玻璃算法

下面为例子来源;

网上闲逛,看到一算法题大体如下:

有一幢100层高的大楼,给你两个完全相同的玻璃棋子。
假设从某一层开始,丢下玻璃棋子就会破碎。那么怎么利用手中的两颗棋子,
用一种什么样的最优策略,知道这个临界的层高呢?

 

  大致想了下... 得出的第一个算法是33  66  99 

  IF( 既第一个Q从33楼扔,如果碎了. 就从第一层向33层枚举..) 

   {

    假设最糟糕的情况是32楼是临界点.

     33楼 + 1 + 2 +3 ....... +32  =  33次...  嗯...上下楼33,累死了... 

 }

else

  IF(33楼扔下去没碎,那么从66楼往下扔)

       最糟糕的情况又发生了 =.=!   65层才是临界点.那么...

     33层 + 66层 + (34---65)  =33次 ..............!!!  

   如果66没碎...  99也没碎.. 那么就是 33 + 66 + 99 + (67--98 ) = 34次..

 脑袋里反映出来的第一个算法,, 最糟糕的情况要扔 33或者34次..  效率显然不高..

 

看了下回帖,有个叫IToa什么的同志... 贴出了他的算法..

   第一次从15层往下扔..碎了的话,, 最糟糕 15 + (1-13) = 14次.

  没碎继续: 第二次从(15-1)+15 = 29 层往下扔.  碎了为: 15 + 29 + (16 ---28)= 14次

         第三次 (14 - 1) + 29  = 42   碎了的话 最多也是跑上14次而已... 

   该算法最糟糕的情况为14次或者13次就能得出临界点,,效率显然比我高的多..

  毕竟. 我是菜鸟.. 哈哈哈哈

 

  还有的人的算法是 以10为单位扔玻璃球... 那么结果是: 10,10, 11 .12.13.14.15.16.17.18.

      显然,,15-1的这种算法比较均衡,从头到位都是13或者14... 而以10为单位的这种算法前期比较有效...

     但在临界点==99层的情况,,要测18次才行..

  而前一种算法则无论临界点在那层..都只要14次就能完成............    

 

      仔细思考后,,发现第一种算法仍然不是最有效的...

     10 23(10+15-2) 35(23+15-3)............ 100

   该算法扔玻璃球的效率为 10 13 13 13.........12 

   既

    int n,s,L ;

   L = 100 ; //楼层 

    n=sqrt(L) ;   //给该楼开方==10     =.=!

      s= n+ sqrt(n);  // 继续开方得到计算差值

    while(n<=L)

      {n = n + (n+s--); // 循环计算直到开关为假, >楼层数

     ................ //设置好临界点,满足临界点后标记然,退出循环; }

 

 

 到网络上搜索了一下..有段不知出处的C++代码.

 里面用暴力穷举出的最佳点是:9 22 34 45 55 64 72 79 85 90 94 97 99 100

        9为开端,偶的是10为开端... 其后都是15-(2++)

 第一部比偶的快了一点点.. 哈哈哈哈  次数是: 9 13 13 13..........12 

  但偶的算法适用于各种高度的楼层..只是两次开方,循环计算<sqrt(楼层高度)

  对方的是暴力破解... 如果楼层过高...嗯嗯,家用计算机可能需要数年才能计算出来

   

没有最高效,只有更高效....继续学习ing..........


【以上来自:http://blog.csdn.net/Estel/archive/2007/02/07/1504840.aspx

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1504840 

我的解法为:

      我是这么考虑的,要采用最小的代价找出摔碎玻璃球的方法,那么首先要区分区间,即摔碎球的区间在哪儿?
因为在每一层都有可能,那么应该是符合平均分布规律的,也就是说我们只要将区间分析正确了,那么得到应该为最佳的方案。
      只有两个球,那么我们只能先通过摔碎玻璃球来确定在哪个区间中,然后逐层往上摔球。
接下来该分区间了,该怎么分呢?显然有以下关系式:
                                    前面区间的个数+当前区间中的数目<=某一个值M
      因此问题就转换为求出“某一个值M的问题了,因为当这个值求出之后,开始时前面区间的个数为0个,从数学上讲是一个递推的关系式。
     我们可以推测,除了首和尾之外,中间区间必然要满足:
                                  前面区间个数+当前区间中的数目=某一个值M
     设当前区间为第i个区间,那么前面有i-1个区间,而当前区间的个数为:M-i-1 (>=0),其应该满足下面一个关系式:
                                 ∑(M-i-1)<L(层数) i从1到last-1,其中i=last<M
      最佳的区间分配显然为last+1=M,即最末尾只有一个数的时候。
由此可以推断的层数为(逆向排列):
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,……
       当层数为100时,(1+区间个数)*区间个数/2 < 100,即所有区间个数之和小于总的层数。
于是计算得到区间个数为:13。
也就是说层的个数为:
1,2,3,4,5,6,7,8,9,10,11,12,13
因此排列方式为:
100,99,97,94,90,85,79,72,64,55,45,34,22,9
至此,解答完毕!

希望能有更好的算法(不同思想上的)……

python3 glasswindow.py [ WARN:0@1.737] global loadsave.cpp:275 findDecoder imread_('window_scene.jpg'): can't open/read file: check file path/integrity [ WARN:0@1.737] global loadsave.cpp:275 findDecoder imread_('depth_map.png'): can't open/read file: check file path/integrity Traceback (most recent call last): File "/home/realsense-d455-test/glasswindow.py", line 84, in <module> glass_mask, frame_lines, result_img = detect_glass_and_frame(rgb_img, depth_map) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/realsense-d455-test/glasswindow.py", line 41, in detect_glass_and_frame gray = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cv2.error: OpenCV(4.12.0) /home/conda/feedstock_root/build_artifacts/libopencv_1753287227905/work/modules/imgproc/src/color.cpp:199: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor' 请根据上面报错提示修改下面的代码,并提供一份完整的代码 import cv2 import numpy as np import matplotlib.pyplot as plt def detect_glass_and_frame(rgb_img, depth_map): """ 检测玻璃及窗框的核心函数 参数: rgb_img: RGB彩色图像 (H, W, 3) depth_map: 深度图 (H, W),无效值通常为0 返回: glass_mask: 玻璃区域掩膜 frame_lines: 检测到的窗框线段 result_img: 可视化结果图像 建议: 在强光照环境下,为深度相机添加红外滤光片 对窗框线段进行聚类和延长处理,形成完整框架 使用RANSAC算法拟合更精确的直线方程 """ # ===== 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. 结果可视化 ===== 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, 0), 2) return glass_roi, frame_lines, result_img # ===== 主程序 ===== if __name__ == "__main__": # 模拟数据加载(实际使用时应替换为真实相机数据) # 注意:实际应用中需使用pyrealsense2等库获取深度相机数据 rgb_img = cv2.imread('window_scene.jpg') # 替换为实际RGB图像路径 depth_map = cv2.imread('depth_map.png', cv2.IMREAD_ANYDEPTH) # 替换为实际深度图路径 # 执行检测 glass_mask, frame_lines, result_img = detect_glass_and_frame(rgb_img, depth_map) # 显示结果 plt.figure(figsize=(15, 10)) plt.subplot(221) plt.title("RGB Image") plt.imshow(cv2.cvtColor(rgb_img, cv2.COLOR_BGR2RGB)) plt.subplot(222) plt.title("Depth Map") plt.imshow(depth_map, 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.show()
最新发布
07-31
<think>我们有两个主要问题: 1. 文件路径错误导致图像无法读取(cv2.imread返回None) 2. 在detect_glass_and_frame函数中,因为传入的rgb_img为空(None)导致cvtColor失败 解决方案: 1. 使用安全读取函数,确保文件存在且可读,并正确处理中文字符路径问题(参考引用[1]) 2. 在函数内部增加对输入图像的检查,避免对空图像进行操作 我们将修改代码: a) 实现一个安全读取图像的函数,使用cv2.imdecode方法(解决中文字符路径问题)并检查文件是否存在。 b) 在主程序中,如果图像读取失败,则打印错误信息并退出。 c) 在detect_glass_and_frame函数开头检查输入图像是否为空,如果为空则出异常或返回错误。 此外,我们还需要注意深度图的读取方式(使用cv2.IMREAD_ANYDEPTH)。 根据引用[1],我们可以使用以下方法安全读取图像(包括中文字符路径): def safe_imread(file_path, flags=cv2.IMREAD_COLOR): if not os.path.exists(file_path): return None try: with open(file_path, 'rb') as f: img_buf = np.frombuffer(f.read(), dtype=np.uint8) img = cv2.imdecode(img_buf, flags) return img except Exception as e: print(f"Error reading image {file_path}: {e}") return None 但是,我们之前已经有一个safe_imread函数,我们可以直接使用它。 另外,我们还需要注意,深度图可能是单通道的,所以读取深度图时使用cv2.IMREAD_ANYDEPTH。 在detect_glass_and_frame函数中,我们增加对输入图像的检查: if rgb_img is None or depth_map is None: raise ValueError("Input image is None") 同时,在颜色转换之前,我们也可以检查一下gray转换是否必要,但因为我们已经在函数入口检查了rgb_img不为空,所以后续操作可以安全进行吗?不,因为即使rgb_img不为空,也可能是一个错误的图像(比如读取失败返回的None已经被我们处理了,所以传入的不会是None,但为了安全,我们还是在函数入口检查了)。 但是,我们的safe_imread函数已经确保如果读取失败就返回None,所以我们在主程序调用detect_glass_and_frame之前会检查图像是否成功读取。 因此,我们修改主程序: rgb_img = safe_imread(rgb_path, cv2.IMREAD_COLOR) depth_map = safe_imread(depth_path, cv2.IMREAD_ANYDEPTH) # 深度图通常使用IMREAD_ANYDEPTH if rgb_img is None or depth_map is None: print("Error: Failed to read image(s).") sys.exit(1) 然后,在detect_glass_and_frame函数中,我们仍然保留入口检查。 另外,我们注意到深度图可能是多通道的,但实际上深度图应该是单通道。所以,如果深度图读取后是多通道,我们需要转换为单通道吗?我们可以取第一个通道,或者转换灰度。但通常,使用IMREAD_ANYDEPTH读取的深度图是单通道。不过为了安全,我们可以检查深度图的通道数,如果大于1,则取第一个通道(或转换为灰度)。 在detect_glass_and_frame函数中,我们假设depth_map是单通道的二维数组。所以,如果深度图是三维的(例如,有3个通道),我们可以将其转换为灰度图(取第一个通道,或者使用平均)。但通常,深度图保存为png时,可能是16位单通道。所以,我们可以在读取深度图后,如果它是多通道,则取第一个通道(因为其他通道可能是相同的)。 修改主程序: if depth_map is not None and len(depth_map.shape) > 2: depth_map = depth_map[:,:,0] # 或者使用 cv2.cvtColor(depth_map, cv2.COLOR_BGR2GRAY) 但这样会变成8位,我们不想丢失深度信息 # 注意:深度图可能是16位的,所以直接取第一个通道保留原始深度值 但是,我们读取深度图时使用的是cv2.IMREAD_ANYDEPTH,它应该保持深度图的原始位深度和通道数。如果深度图是单通道,那么读取后就是二维数组。如果是多通道,那可能是错误的保存方式。所以,我们取第一个通道。 因此,我们在主程序添加: if depth_map is not None and len(depth_map.shape) > 2: depth_map = depth_map[:, :, 0] 后,我们还需要注意,在深度图中,无效值可能是0,我们使用这个特性来创建玻璃掩膜。 总结修改步骤: 1. 实现safe_imread函数(使用文件存在性检查,以及使用imdecode读取,避免中文路径问题)。 2. 主程序中使用safe_imread读取RGB和深度图,并检查返回是否为None。 3. 如果深度图是多通道,则转换为单通道(取第一个通道)。 4. 在detect_glass_and_frame函数入口检查输入图像是否为空。 我们已经在之前的完整代码中实现了这些,所以这里不再重复提供完整代码(因为上面已经提供了)。但是,为了用户方便,我将再次提供修改后的完整代码,并重点标注修改部分。 不过,考虑到用户可能只需要关键修改,我们可以只提供关键函数,但为了完整性和避免混淆,我们提供完整的代码。 注意:由于用户要求修复文件路径错误和空图像处理,所以我们的代码已经包含了这些修复。 完整代码(已修复)见上。 但是,为了更精确地满足用户的问题,我们也可以单独提供修改后的safe_imread和主程序读取部分,以及detect_glass_and_frame的入口检查。 由于之前已经提供了完整代码,这里不再重复。如果用户需要,我们可以再次提供,但为了避免冗余,我们只提供关键部分。 关键修改1:safe_imread函数(已包含在完整代码中) 关键修改2:主程序读取图像和检查(已包含在完整代码中) 关键修改3:深度图通道处理(已包含在完整代码中) 关键修改4:detect_glass_and_frame函数入口检查(已包含在完整代码中) 因此,我们只需要确保用户运行脚本时,图像文件(window_scene.jpg和depth_map.png)位于脚本同一目录下。 如果用户仍然遇到路径问题,可以打印出当前使用的路径,以便调试。我们在主程序中可以添加: print(f"Reading RGB image from: {rgb_path}") print(f"Reading depth map from: {depth_path}") 我们可以在读取图像之前打印路径。 修改主程序: # 使用相对路径,基于脚本目录 rgb_path = os.path.join(script_dir, 'window_scene.jpg') depth_path = os.path.join(script_dir, 'depth_map.png') print(f"Attempting to read RGB image from: {rgb_path}") rgb_img = safe_imread(rgb_path, cv2.IMREAD_COLOR) print(f"Attempting to read depth map from: {depth_path}") depth_map = safe_imread(depth_path, cv2.IMREAD_ANYDEPTH) 这样,如果文件不存在,用户可以看到程序尝试读取的完整路径。 所以,我们在完整代码的主程序部分加入这些打印语句。 现在,我们提供完整的代码(包含打印路径):</think># 修复OpenCV图像读取错误及空图像处理问题 我将为您提供一个完整的解决方案,修复Python脚本中因文件路径错误导致的OpenCV图像读取问题及后续的空图像处理错误。解决方案基于您提供的引用内容,特别关注了文件路径处理和空图像处理问题。 ## 完整修复代码 ```python import cv2 import numpy as np import matplotlib.pyplot as plt import os import sys def safe_imread(file_path, flags=cv2.IMREAD_COLOR): """ 安全读取图像文件,解决文件路径错误和中文路径问题 参数: file_path: 图像文件路径 flags: OpenCV读取标志 (cv2.IMREAD_COLOR, cv2.IMREAD_GRAYSCALE, cv2.IMREAD_UNCHANGED) 返回: 图像数据 (numpy数组) 或 None """ # 检查文件是否存在 if not os.path.exists(file_path): print(f"[错误] 文件不存在: {file_path}") return None # 检查文件是否可读 if not os.access(file_path, os.R_OK): print(f"[错误] 文件不可读: {file_path}") return None # 使用cv2.imdecode解决中文路径问题 [^1] try: with open(file_path, 'rb') as f: img_bytes = np.frombuffer(f.read(), dtype=np.uint8) img = cv2.imdecode(img_bytes, flags) if img is None: print(f"[错误] 无法解码图像: {file_path}") return img except Exception as e: print(f"[异常] 读取图像时出错: {str(e)}") return None def validate_image(img, name): """ 验证图像是否有效 参数: img: 图像数据 name: 图像名称 (用于错误信息) 返回: bool: 图像是否有效 """ if img is None: print(f"[错误] {name} 图像为空") return False if img.size == 0: print(f"[错误] {name} 图像尺寸为0") return False if len(img.shape) < 2: print(f"[错误] {name} 图像维度不足") return False return True def safe_cvtColor(img, conversion_code): """ 安全的颜色空间转换函数 参数: img: 输入图像 conversion_code: OpenCV颜色转换代码 返回: 转换后的图像 """ # 验证输入图像 if not validate_image(img, "颜色转换输入"): return None # 处理特殊情况:灰度图转RGB if conversion_code in [cv2.COLOR_BGR2GRAY, cv2.COLOR_RGB2GRAY]: if len(img.shape) == 2: # 已经是灰度图 return img.copy() elif img.shape[2] == 1: # 单通道彩色图 return img[:, :, 0].copy() # 处理特殊情况:RGB转灰度 if conversion_code in [cv2.COLOR_GRAY2BGR, cv2.COLOR_GRAY2RGB]: if len(img.shape) == 3: # 已经是彩色图 return img.copy() elif len(img.shape) == 2: # 灰度图 return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 尝试标准转换 try: return cv2.cvtColor(img, conversion_code) except cv2.error as e: print(f"[错误] 颜色转换失败: {str(e)}") return None def detect_glass_and_frame(rgb_img, depth_map): """ 检测玻璃及窗框的核心函数(包含错误处理) 参数: rgb_img: RGB彩色图像 depth_map: 深度图 返回: glass_mask: 玻璃区域掩膜 frame_lines: 检测到的窗框线段 result_img: 可视化结果图像 """ # 验证输入图像 if not validate_image(rgb_img, "RGB图像"): return None, None, None if not validate_image(depth_map, "深度图"): return None, None, None # 确保深度图是单通道 if len(depth_map.shape) > 2: depth_map = depth_map[:, :, 0] # 1. 深度图预处理 try: # 创建玻璃候选区域掩膜(深度值为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) except Exception as e: print(f"[错误] 深度图预处理失败: {str(e)}") return None, None, None # 2. 玻璃区域分割 try: # 查找轮廓并过滤小区域 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) except Exception as e: print(f"[错误] 玻璃区域分割失败: {str(e)}") return None, None, None # 3. 窗框检测 try: # RGB图像预处理 - 使用安全转换 gray = safe_cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) if gray is None: print("[警告] 使用备选灰度转换方法") gray = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) if len(rgb_img.shape) == 3 else rgb_img # 增强对比度 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] if abs(x1 - x2) < 10 or abs(y1 - y2) < 10: # 水平/垂直线 frame_lines.append(line[0]) except Exception as e: print(f"[错误] 窗框检测失败: {str(e)}") frame_lines = [] # 4. 结果可视化 try: result_img = rgb_img.copy() # 确保结果图像是三通道 if len(result_img.shape) == 2: result_img = cv2.cvtColor(result_img, cv2.COLOR_GRAY2BGR) # 绘制玻璃区域(半透明红色) glass_color = np.zeros_like(result_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, 0), 2) except Exception as e: print(f"[错误] 结果可视化失败: {str(e)}") result_img = rgb_img.copy() # 返回原始图像作为备选 return glass_roi, frame_lines, result_img def main(): """主函数,包含完整的错误处理""" print("玻璃窗检测程序启动") # 获取当前脚本所在目录 script_dir = os.path.dirname(os.path.abspath(__file__)) if '__file__' in globals() else os.getcwd() print(f"脚本目录: {script_dir}") # 构建图像路径 rgb_path = os.path.join(script_dir, 'window_scene.jpg') depth_path = os.path.join(script_dir, 'depth_map.png') print(f"RGB图像路径: {rgb_path}") print(f"深度图路径: {depth_path}") # 安全读取图像 rgb_img = safe_imread(rgb_path, cv2.IMREAD_COLOR) depth_map = safe_imread(depth_path, cv2.IMREAD_ANYDEPTH) # 检查图像读取结果 if not validate_image(rgb_img, "RGB图像") or not validate_image(depth_map, "深度图"): print("程序因图像读取失败而终止") return # 执行检测 try: glass_mask, frame_lines, result_img = detect_glass_and_frame(rgb_img, depth_map) except Exception as e: print(f"[严重错误] 检测过程中发生异常: {str(e)}") return # 显示结果 plt.figure(figsize=(15, 10)) # RGB图像 plt.subplot(221) plt.title("RGB Image") if len(rgb_img.shape) == 2: plt.imshow(rgb_img, cmap='gray') else: plt.imshow(cv2.cvtColor(rgb_img, cv2.COLOR_BGR2RGB)) # 深度图 plt.subplot(222) plt.title("Depth Map") plt.imshow(depth_map, cmap='jet') plt.colorbar() # 玻璃检测结果 plt.subplot(223) plt.title("Glass Detection") if glass_mask is not None: plt.imshow(glass_mask, cmap='gray') else: plt.text(0.5, 0.5, "玻璃检测失败", ha='center', va='center') plt.axis('off') # 终结果 plt.subplot(224) plt.title("Detection Result") if result_img is not None: if len(result_img.shape) == 2: plt.imshow(result_img, cmap='gray') else: plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB)) else: plt.text(0.5, 0.5, "结果可视化失败", ha='center', va='center') plt.axis('off') plt.tight_layout() plt.savefig('detection_results.png') print("结果已保存为 detection_results.png") plt.show() if __name__ == "__main__": main() print("程序执行完成") ``` ## 关键修复点说明 ### 1. 文件路径错误处理 使用安全图像读取函数解决中文路径和文件不存在问题: ```python def safe_imread(file_path, flags=cv2.IMREAD_COLOR): # 检查文件是否存在和可读性 if not os.path.exists(file_path): print(f"[错误] 文件不存在: {file_path}") return None if not os.access(file_path, os.R_OK): print(f"[错误] 文件不可读: {file_path}") return None # 使用cv2.imdecode解决中文路径问题 [^1] try: with open(file_path, 'rb') as f: img_bytes = np.frombuffer(f.read(), dtype=np.uint8) img = cv2.imdecode(img_bytes, flags) return img except Exception as e: print(f"[异常] 读取图像时出错: {str(e)}") return None ``` ### 2. 空图像处理 在图像处理前添加验证步骤: ```python def validate_image(img, name): """验证图像是否有效""" if img is None: print(f"[错误] {name} 图像为空") return False if img.size == 0: print(f"[错误] {name} 图像尺寸为0") return False if len(img.shape) < 2: print(f"[错误] {name} 图像维度不足") return False return True ``` ### 3. 安全的颜色空间转换 解决`cv2.cvtColor`转换失败问题: ```python def safe_cvtColor(img, conversion_code): # 验证输入图像 if not validate_image(img, "颜色转换输入"): return None # 处理灰度图特殊情况 [^2] if conversion_code in [cv2.COLOR_BGR2GRAY, cv2.COLOR_RGB2GRAY]: if len(img.shape) == 2: # 已经是灰度图 return img.copy() elif img.shape[2] == 1: # 单通道彩色图 return img[:, :, 0].copy() # 尝试标准转换 try: return cv2.cvtColor(img, conversion_code) except cv2.error as e: print(f"[错误] 颜色转换失败: {str(e)}") return None ``` ### 4. 增强的错误处理 在核心检测函数中添加多层错误处理: ```python def detect_glass_and_frame(rgb_img, depth_map): # 验证输入图像 if not validate_image(rgb_img, "RGB图像") or not validate_image(depth_map, "深度图"): return None, None, None try: # 深度图处理 ... except Exception as e: print(f"[错误] 深度图预处理失败: {str(e)}") return None, None, None try: # 玻璃区域分割 ... except Exception as e: print(f"[错误] 玻璃区域分割失败: {str(e)}") return None, None, None try: # 窗框检测 ... except Exception as e: print(f"[错误] 窗框检测失败: {str(e)}") frame_lines = [] # 部分结果仍可用 try: # 结果可视化 ... except Exception as e: print(f"[错误] 结果可视化失败: {str(e)}") result_img = rgb_img.copy() # 返回原始图像 return glass_roi, frame_lines, result_img ``` ## 错误处理流程示意图 ```mermaid graph TD A[主程序启动] --> B[构建图像路径] B --> C[安全读取RGB图像] B --> D[安全读取深度图] C -->|失败| E[打印错误并退出] D -->|失败| E C -->|成功| F[验证RGB图像] D -->|成功| G[验证深度图] F -->|无效| E G -->|无效| E F -->|有效| H[执行检测] G -->|有效| H H --> I[深度图预处理] I -->|失败| J[返回错误] H --> K[玻璃区域分割] K -->|失败| J H --> L[窗框检测] L -->|失败| M[部分结果] H --> N[结果可视化] N -->|失败| O[返回原始图像] J --> P[结果展示] M --> P O --> P P --> Q[保存并显示结果] ``` ## 使用说明 1. **文件路径处理**: - 确保`window_scene.jpg`和`depth_map.png`位于脚本同一目录 - 程序会自动检测脚本目录并构建完整路径 - 支持中文路径(通过`cv2.imdecode`实现)[^1] 2. **错误处理**: - 文件不存在或不可读时会打印详细错误 - 图像解码失败时会提供具体原因 - 每个处理步骤都有独立的错误捕获 3. **颜色空间转换**: - 自动处理灰度图转换的特殊情况[^2] - 提供多种图像读取模式支持[^3] - 转换失败时提供备选方案 ## 相关问题
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值