OpenCV中[WARN:0]终止异步回调错误排查求助
解决OpenCV [WARN:0] terminating async callback 警告问题
我之前在Windows上做OpenCV摄像头项目时也踩过这个坑,这个警告本质是摄像头资源释放不彻底,异步回调线程还在后台运行就被强制终止导致的。你已经尝试了camera.release()和cv2.destroyAllWindows(),但问题出在这些操作的位置和覆盖范围不对,结合你的代码,给你几个具体的修复方案:
核心问题分析
你的代码里存在两个关键疏漏:
- 正常退出循环后(按ESC),只关闭了socket,完全没处理摄像头资源释放和窗口销毁
- 异常捕获块里也没清理摄像头资源,一旦程序抛出异常,摄像头资源会残留,触发异步回调警告
修复方案
1. 用finally块统一管理资源释放
把所有资源清理逻辑放在finally块里,不管程序是正常退出还是抛出异常,都会执行资源清理,避免残留。
2. 给Windows摄像头指定CAP_DSHOW后端
Windows上默认的摄像头后端存在异步回调兼容性问题,显式指定CAP_DSHOW可以直接规避很多这类警告。
修改后的完整代码
import cv2 import socket import numpy as np import math import time # 提前初始化全局变量,避免finally块报错 state1 = "off" state2 = "off" state3 = "off" mode = "on" host = "192.168.0.106" port = 9345 mySocket = None cap = None try: start_time = time.time() mySocket = socket.socket() mySocket.connect((host,port)) # 显式指定Windows摄像头后端,解决异步回调问题 cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) while(cap.isOpened()): ret, img = cap.read() if not ret: # 增加判断,防止摄像头读取失败导致后续报错 break cv2.rectangle(img, (300,300), (100,100), (0,255,0),0) crop_img = img[100:300, 100:300] grey = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY) value = (35, 35) blurred = cv2.GaussianBlur(grey, value, 0) _, thresh1 = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) cv2.imshow('Thresholded', thresh1) (version, _, _) = cv2.__version__.split('.') if version == '3': image, contours, hierarchy = cv2.findContours(thresh1.copy(), \ cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) elif version == '2': contours, hierarchy = cv2.findContours(thresh1.copy(),cv2.RETR_TREE, \ cv2.CHAIN_APPROX_NONE) cnt = max(contours, key = lambda x: cv2.contourArea(x)) x, y, w, h = cv2.boundingRect(cnt) cv2.rectangle(crop_img, (x, y), (x+w, y+h), (0, 0, 255), 0) hull = cv2.convexHull(cnt) drawing = np.zeros(crop_img.shape,np.uint8) cv2.drawContours(drawing, [cnt], 0, (0, 255, 0), 0) cv2.drawContours(drawing, [hull], 0,(0, 0, 255), 0) hull = cv2.convexHull(cnt, returnPoints=False) defects = cv2.convexityDefects(cnt, hull) count_defects = 0 cv2.drawContours(thresh1, contours, -1, (0, 255, 0), 3) # 增加判断,避免没有检测到手势缺陷时报错 if defects is not None: for i in range(defects.shape[0]): s,e,f,d = defects[i,0] start = tuple(cnt[s][0]) end = tuple(cnt[e][0]) far = tuple(cnt[f][0]) a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2) c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57 if angle <= 90: count_defects += 1 cv2.circle(crop_img, far, 1, [0,0,255], -1) cv2.line(crop_img,start, end, [0,255,0], 2) # 手势控制逻辑保持不变 if count_defects == 1: if (time.time()>start_time+2): if mode == "on": mySocket.send("on_led1".encode()) state1 = "on" print("led 1 is on") else: mySocket.send("off_led1".encode()) state1 = "off" print("led 1 is off") start_time = time.time() cv2.putText(img, "led 1 is "+state1, (5, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, 2) elif count_defects == 2: if (time.time()>start_time+2): if mode == "on": mySocket.send("on_led2".encode()) state2 = "on" print("led 2 is on") else: mySocket.send("off_led2".encode()) state2 = "off" print("led 2 is off") start_time = time.time() cv2.putText(img, "led 2 is "+state2, (5, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, 2) elif count_defects == 3: if (time.time()>start_time+2): if mode == "on": mySocket.send("on_led3".encode()) state3 = "on" print("led 3 is on") else: mySocket.send("off_led3".encode()) state3 = "off" print("led 3 is off") start_time = time.time() cv2.putText(img, "led 3 is "+state3, (5, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, 2) elif count_defects == 4: cv2.putText(img,"mode is "+mode, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 2, 2) if(time.time() > start_time+2): mode = "off" if mode == "on" else "on" start_time = time.time() print(mode) else: cv2.putText(img, "use your fingure for turn On/Off lights current mode is "+mode, (5, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, 2) cv2.imshow('Gesture', img) all_img = np.hstack((drawing, crop_img)) cv2.imshow('Contours', all_img) k = cv2.waitKey(10) if k == 27: break except Exception as e: print(f"程序运行出错: {e}") if mySocket: try: mySocket.send("close_all".encode()) except: pass finally: # 统一释放所有资源,不管正常退出还是异常 if mySocket: mySocket.close() if cap: cap.release() cv2.destroyAllWindows() cv2.waitKey(1) # Windows上额外加这句,确保窗口彻底销毁
关键修改点说明
finally块统一清理:确保所有路径下都会释放摄像头、关闭socket和销毁窗口,彻底避免资源残留CAP_DSHOW后端:Windows平台专属的摄像头后端,从根源减少异步回调的兼容性问题- 增加异常安全判断:防止摄像头读取失败、未检测到手势缺陷时出现崩溃
- 最后加
cv2.waitKey(1):解决Windows上destroyAllWindows()有时不生效的问题,确保窗口彻底关闭
这样修改后,那个异步回调的警告应该就会消失,同时你的程序鲁棒性也会提升不少。
内容的提问来源于stack exchange,提问作者manan5439
相关产品推荐
相关产品推荐

