import cv2
import numpy as np
# 读取图像
img_path = '/home/incam/Desktop/mycode/template/CAD/cad/Snipaste_2025-09-09_16-38-23.png'
image = cv2.imread(img_path)
if image is None:
print("图像加载失败,请检查路径")
exit()
#图像中有多个区域,各自有边框,此外还有一个大的框将这三个区域都包含在内,友好的是,大框内的三个小框之间各有一条分割线隔开,也就是说在大框上存在与分割线的交点,现在只能检测出整个的大框,可需要的是三个小框的坐标,针对这种情况应该怎么处理
roi = cv2.selectROI("Select ROI", image, showCrosshair=True, fromCenter=False)
cv2.destroyWindow("Select ROI")
(x, y, w, h) = roi
if w == 0 or h == 0:
imCrop = image
else:
imCrop = image[y:y+h, x:x+w]
# 转换为 HSV 颜色空间
hsv = cv2.cvtColor(imCrop, cv2.COLOR_BGR2HSV)
#白色部分内容转换为灰度图
gray = cv2.cvtColor(imCrop, cv2.COLOR_BGR2GRAY)
########################检测彩色区域#############
# 检测红色
# 红色在 HSV 中有两个范围:低 H 和高 H(因为色环是环形)
lower_red1 = np.array([0, 100, 100]) # 红色下界1
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 100, 100]) # 红色下界2
upper_red2 = np.array([180, 255, 255])
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
red_mask = cv2.bitwise_or(mask1, mask2)
# 检测蓝色
lower_blue = np.array([100, 100, 100])
upper_blue = np.array([130, 255, 255])
blue_mask = cv2.inRange(hsv, lower_blue, upper_blue)
# 检测绿色
lower_green = np.array([40, 100, 100])
upper_green = np.array([80, 255, 255])
green_mask = cv2.inRange(hsv, lower_green, upper_green)
# 可视化各个颜色掩码
cv2.imshow("Red Mask", red_mask)
cv2.imshow("Blue Mask", blue_mask)
cv2.imshow("Green Mask", green_mask)
# 合并所有颜色区域
color_mask = cv2.bitwise_or(cv2.bitwise_or(red_mask, blue_mask), green_mask)
##############检测白色区域##########
# 白色:高亮度 + 低饱和度
lower_white = np.array([0, 0, 200]) # V > 200,接近白色
upper_white = np.array([180, 30, 255]) # S < 30,避免彩色干扰
mask_white = cv2.inRange(hsv, lower_white, upper_white)
#结合灰度图增强白色检测效果
_, mask_white_gray = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
mask_white = cv2.bitwise_or(mask_white, mask_white_gray)
# 合并所有掩码(彩色 + 白色)
combined_mask = cv2.bitwise_or(color_mask, mask_white)
# 形态学操作去噪
# kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
# combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_CLOSE, kernel) #连接断裂
# combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_OPEN, kernel) #去除噪点
# _, binary = cv2.threshold(combined_mask, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
_, binary = cv2.threshold(combined_mask, 127, 255, cv2.THRESH_BINARY) # 固定阈值二值化
#形态学操作,去除噪点,连接断裂区域
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
# 查找轮廓
# contours, _ = cv2.findContours(combined_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
print("未检测到任何轮廓")
else:
min_side_threshold = 150
# 3. 处理每个轮廓
for i, contour in enumerate(contours):
# 获取当前轮廓点
contour_points = contour.reshape(-1, 2)
if len(contour_points) >= 3:
# 计算最小外接矩形
rect = cv2.minAreaRect(contour_points)
width, height = rect[1] # 获取宽高
# 跳过过小的矩形(任一方向边长不足阈值)
if min(width, height) < min_side_threshold:
continue
# 绘制最小外接矩形
# min_side_threshold = 400
# for i, cnt in enumerate(contours):
# if cv2.contourArea(cnt) < min_side_threshold:
# continue
# 获取最小外接矩形
# rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int32(box)
# 扩展一点避免裁剪
expansion = 2
center, (w, h), angle = rect
rect_expanded = (center, (w + 2*expansion, h + 2*expansion), angle)
# 获取矩形角点并排序
# box = cv2.boxPoints(rect)
box = cv2.boxPoints(rect_expanded)
box = np.int32(box)
box = sorted(box, key=lambda x: (x[0], x[1]))
box = np.array([box[0], box[2], box[3], box[1]]) # 左上开始顺时针
# # 绘制矩形和编号
# color = (0, 255 - i*50, 100 + i*50) # 自动生成不同颜色
# # cv2.drawContours(image, [box], 0, color, 2)
# cv2.drawContours(imCrop, [box], 0, color, 2)
cv2.drawContours(imCrop, [box], 0, (0, 255, 0), 2)
# cv2.putText(image, str(i+1), tuple(box[0]), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,255), 2)
# # 将框的坐标转换回原图坐标系
box[:, 0] += roi[0] # x坐标加上ROI的x偏移
box[:, 1] += roi[1] # y坐标加上ROI的y偏移
# 输出坐标信息,先输出i最大的那个,也就是从右下角开始输出
# print(f"\n区域 {i+1} 坐标:")
print(f"Top-Left: {tuple(box[0])}, Top-Right: {tuple(box[1])}, Bottom-Right: {tuple(box[2])}, Bottom-Left: {tuple(box[3])}")
# box = cv2.boxPoints(rect_expanded)
# box = np.int32(box)
# # 坐标偏移回全局图像
# box_global = box.copy()
# box_global[:, 0] += x
# box_global[:, 1] += y
# cv2.drawContours(image, [box_global], 0, (0, 255, 0), 2)
# cv2.putText(image, str(i+1), tuple(box_global[0]), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# 显示结果
cv2.imshow("Original Image", image)
cv2.imshow("Combined Mask", combined_mask)
cv2.imshow("Segmented Result", imCrop)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这段代码的基础上,实现:图像中有多个区域,各自有边框(称为小框),此外还有一个大的框将这三个区域都包含在内,友好的是,大框内的三个小框之间各有一条分割线隔开,也就是说在大框上存在与分割线的交点,现在只能检测出整个的大框,可我需要的是三个小框的坐标,这个功能
最新发布