基于面积筛选OpenCV边界框监控样品头位置变化的问题
问题描述
我希望通过对比运动指令下达前后的静态相机图像,使用OpenCV与边界框来监控旋转且移动的样品头的位置变化。由于存在位置变化及潜在光照变动,无法仅通过调整图像阈值来单独提取样品;而样品尺寸固定,因此计划通过面积筛选边界框数组,仅保留覆盖样品的边界框。但在尝试使用cv2.contourArea()函数计算轮廓面积数组时,持续报错:
OpenCV(4.7.0) :-1: error: (-5:Bad argument) in function 'contourArea' - contour is not a numerical tuple
附上相关代码寻求帮助:
import numpy as np import matplotlib.pyplot as plt import cv2 # read the image img = cv2.imread("Test_IMG_Rev1\IMG_3_ROT100.jpg") # Convert to Grayscale and RGB img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Apply Thresholding on the grayscale image ret,thresh = cv2.threshold(img_gray,127,255,0) # Plot Images fig = plt.figure(figsize=(20,20)) ax = plt.subplot(1, 2, 1) plt.imshow(img_rgb) ax.set_title("Original Image") ax = plt.subplot(1, 2, 2) plt.imshow(thresh) ax.set_title("Threshold Image") # plt.show() # Get contours (Rotated) result1 = img.copy() contours1 = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours1 = contours1[0] if len(contours1) == 2 else contours1[1] for cntr1 in contours1: rect = cv2.minAreaRect(cntr1) box = cv2.boxPoints(rect) box = np.int0(box) G = cv2.drawContours(result1,[box],0,(0,0,255),2) # plt.figure(figsize=(10,10)) img_result1 = cv2.cvtColor(result1, cv2.COLOR_BGR2RGB) plt.imshow(img_result1)
解决方案
报错原因
你大概率是把拟合后的矩形框(box)传给了cv2.contourArea(),但这个函数要求的输入是原始轮廓(cntr1),不是拟合后的矩形点集;另外如果轮廓本身不是合法的数值数组,也会触发该错误。
修改后的代码
import numpy as np import matplotlib.pyplot as plt import cv2 # 读取图像 img = cv2.imread("Test_IMG_Rev1\IMG_3_ROT100.jpg") # 转换为灰度图和RGB图 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 灰度图阈值处理 ret, thresh = cv2.threshold(img_gray, 127, 255, 0) # 绘制图像 fig = plt.figure(figsize=(20,20)) ax = plt.subplot(1, 2, 1) plt.imshow(img_rgb) ax.set_title("原始图像") ax = plt.subplot(1, 2, 2) plt.imshow(thresh, cmap='gray') ax.set_title("阈值处理后图像") plt.show() # 获取轮廓并基于面积筛选 result1 = img.copy() contours1 = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours1 = contours1[0] if len(contours1) == 2 else contours1[1] # 根据实际样品尺寸设置面积范围(单位:像素),替换成你的实际值 sample_min_area = 1000 sample_max_area = 5000 for cntr1 in contours1: # 计算原始轮廓的面积,传入正确的参数 area = cv2.contourArea(cntr1) # 筛选符合样品面积范围的轮廓 if sample_min_area < area < sample_max_area: rect = cv2.minAreaRect(cntr1) box = cv2.boxPoints(rect) box = np.int0(box) cv2.drawContours(result1, [box], 0, (0,0,255), 2) plt.figure(figsize=(10,10)) img_result1 = cv2.cvtColor(result1, cv2.COLOR_BGR2RGB) plt.imshow(img_result1) plt.title("筛选后的样品边界框") plt.show()
关键说明
cv2.contourArea()必须传入**cv2.findContours()返回的原始轮廓对象**,不能用拟合后的矩形点集- 提前测量样品对应的像素面积范围,设置合理的
sample_min_area和sample_max_area,过滤掉背景噪声或其他无关轮廓 - 确保图像读取正常:如果
img为None,后续轮廓提取会得到无效数据,也可能触发类似错误,可添加assert img is not None, "图像读取失败"验证
内容的提问来源于stack exchange,提问作者Zach K
相关产品推荐
相关产品推荐

