如何用OpenCV Python检测图像中血液目标?背景与目标区分遇阻
解决方案:区分血液目标与背景
针对你遇到的背景与目标无法区分的问题,结合你提供的背景图和原始图像,推荐两种高效的OpenCV Python解决方案:
方案一:基于背景差分的目标提取
既然你有单独的背景图像,直接计算原始图与背景图的差异是最精准的方式,核心思路是利用固定背景与含目标图像的像素差值,快速定位目标区域:
- 提前加载并预处理背景图(灰度化+模糊)
- 对输入图像做同样预处理,计算与背景图的绝对差值
- 阈值提取差异区域,再通过形态学操作优化掩码
- 用掩码提取目标区域并筛选有效轮廓
代码实现
import cv2 import numpy as np import os # 提前加载背景图,替换为你的背景图路径 bg_img = cv2.imread("./BG.png") bg_gray = cv2.cvtColor(bg_img, cv2.COLOR_BGR2GRAY) bg_gray = cv2.GaussianBlur(bg_gray, (5,5), 0) def detect_blood(input_path): img = cv2.imread(input_path) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_gray = cv2.GaussianBlur(img_gray, (5,5), 0) # 计算背景与原图的灰度差值 diff = cv2.absdiff(img_gray, bg_gray) # 阈值过滤,提取差异区域 _, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY) # 形态学操作:闭运算填充孔洞,开运算去除噪点 kernel = np.ones((3,3), np.uint8) mask = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1) # 提取目标前景 foreground = cv2.bitwise_and(img, img, mask=mask) # 筛选大轮廓,过滤微小噪点 min_area = 800 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) large_contours = [c for c in contours if cv2.contourArea(c) > min_area] cv2.drawContours(foreground, large_contours, -1, (0,255,0), 3) # 显示结果 resized_mask = cv2.resize(mask, (480,640)) resized_foreground = cv2.resize(foreground, (480,640)) cv2.imshow("mask", resized_mask) cv2.imshow("output", resized_foreground) cv2.waitKey(0) cv2.destroyAllWindows() return foreground def process_images(input_folder, output_folder): if not os.path.exists(output_folder): os.makedirs(output_folder) for filename in os.listdir(input_folder): if filename.endswith(('.jpg', '.jpeg', '.png')): input_path = os.path.join(input_folder, filename) output_path = os.path.join(output_folder, 'result_{}'.format(filename)) result = detect_blood(input_path) cv2.imwrite(output_path, result) if __name__ == "__main__": input_folder = "./BloodV2" output_folder = "./img_detect" process_images(input_folder, output_folder)
方案二:基于HSV颜色空间提取红色目标
如果没有背景图可用,可利用血液的红色特征在HSV空间中精准提取:
- 将图像转换为HSV空间(分离颜色、饱和度、亮度,更适合颜色筛选)
- 设定红色的HSV范围(红色在HSV中跨0度,需分两个区间)
- 生成颜色掩码并优化,提取目标区域
代码实现
import cv2 import numpy as np import os def detect_blood(input_path): img = cv2.imread(input_path) # 转换为HSV颜色空间 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 红色的HSV范围(两个区间覆盖完整红色谱) lower_red1 = np.array([0, 70, 50]) upper_red1 = np.array([10, 255, 255]) lower_red2 = np.array([170, 70, 50]) upper_red2 = np.array([180, 255, 255]) # 生成两个掩码并合并 mask1 = cv2.inRange(hsv, lower_red1, upper_red1) mask2 = cv2.inRange(hsv, lower_red2, upper_red2) mask = cv2.bitwise_or(mask1, mask2) # 形态学操作优化掩码 kernel = np.ones((3,3), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1) # 提取目标前景 foreground = cv2.bitwise_and(img, img, mask=mask) # 筛选大轮廓 min_area = 800 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) large_contours = [c for c in contours if cv2.contourArea(c) > min_area] cv2.drawContours(foreground, large_contours, -1, (0,255,0), 3) # 显示结果 resized_mask = cv2.resize(mask, (480,640)) resized_foreground = cv2.resize(foreground, (480,640)) cv2.imshow("mask", resized_mask) cv2.imshow("output", resized_foreground) cv2.waitKey(0) cv2.destroyAllWindows() return foreground # process_images函数和主函数与方案一一致,此处省略
关键优化说明
- 背景差分:利用固定背景直接过滤无关区域,彻底解决背景与目标灰度重叠的问题
- HSV颜色提取:相比RGB,HSV更适合颜色类目标检测,红色范围更易界定
- 形态学操作:闭运算填充目标内部孔洞,开运算去除微小噪点,让掩码更干净
- 轮廓筛选:通过最小面积过滤无效噪点区域,只保留真正的目标
内容的提问来源于stack exchange,提问作者iKnowss
相关产品推荐
相关产品推荐

