import cv2
import numpy as np
import os
# from scipy.cluster.hierarchy import fcluster, linkage
# from scipy.spatial.distance import pdist
# image = cv2.imread('/home/incam/Desktop/mycode/template/CAD/orig_img/111.png')
# cv2.imshow('Origin', image)
# # 定义ROI的矩形框 #8 167 1907 968
# x, y, width, height = 206, 4, 1236, 951#8, 167, 1907, 968#22,232,1876,730# # #21,250,1882,671 #22 353 1881 509 #black2:22,232,1876,730
# roi = (x, y, width, height)
# # 利用ROI截取区域
# cropped_image = image[roi[1]:roi[1]+roi[3], roi[0]:roi[0]+roi[2]]
# cv2.imshow('Result - Me', cropped_image)
img_path = '/home/incam/Desktop/mycode/template/CAD/cad/Snipaste_2025-09-09_16-38-23.png'
# Read image
img = cv2.imread(img_path)
# 创建一个窗口
#cv2.namedWindow("image", flags= cv2.WINDOW_NORMAL | cv2.WINDOW_FREERATIO)
#cv2.namedWindow("image_roi", flags= cv2.WINDOW_NORMAL | cv2.WINDOW_FREERATIO)
cv2.imshow("image", img)
# 是否显示网格
showCrosshair = False
# 如果为Ture的话 , 则鼠标的起始位置就作为了roi的中心
# False: 从左上角到右下角选中区域
fromCenter = False
# 选择 ROI(感兴趣的部分)图像 选择后按回车确认,按ESC取消
roi = cv2.selectROI("image", img, showCrosshair, fromCenter)
(x, y, w, h) = roi
# 截取的图像
imCrop = img[y : y+h, x:x+w]
print(x,y,w,h)
# 显示截取图像
cv2.imshow("image_roi", imCrop)
# 1. 预处理:灰度化 + 高斯去模糊降噪 + 二值化 + 形态学闭操作
gray = cv2.cvtColor(imCrop, cv2.COLOR_BGR2GRAY)
# gray = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
'''
原始二值图像中,某些本应属于同一逻辑区域的内容(如一个矩形主体 + 旁边的标注文字/引线)被 OpenCV 分割成了多个独立轮廓;
# 方法1的第二步: 查找所有轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
所以cv2.findContours 是通过找到多个小轮廓 → 每个轮廓都生成一个矩形 → 无法生成一个包含整体的大矩形;
'''
# 形态学闭操作连接微小间隙(使用形态学操作才能分割出完整轮廓)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) #MORPH_CLOSE是先膨胀后腐蚀的操作,能够填充小的孔洞或缝隙,连接邻近的前景区域,平滑轮廓边界
# 2. 查找所有外部轮廓
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
# 外扩**个像素,确保外接矩形包含所有点
expansion = 2
rect = (rect[0], (rect[1][0] + expansion*2, rect[1][1] + expansion*2), rect[2])
# 获取矩形角点并排序
box = cv2.boxPoints(rect)
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])}")
# 高斯双边滤波
'''
* 双边滤波参数:
* 15--->计算半径,半径之内的都会被纳入计算,如果提供-1则根据sigma space参数进行计算
* 100--->sigma color 决定多少差值之内的像素会被计算
* 5----->sigma space 如果d的值大于0则申明无效,否则根据他来计算d的值
'''
# bilateralMat = cv2.bilateralFilter(image, 15, 50, 5)
# cv2.imshow("bilateralMat", bilateralMat)
# # 锐化操作
# kernel = np.array([[0, -1, 0],
# [-1, 5, -1],
# [0, -1, 0]], dtype=np.int32)
# resultImage = cv2.filter2D(bilateralMat, -1, kernel)
# # 显示结果
# cv2.imshow('Result - Merged Bounding Boxes', resultImage)
# # cv2.imwrite('CAD/result_merged_boxes.jpg', image)
# cv2.imwrite('CAD/result_merged_boxes.jpg', resultImage)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 4. 显示结果
cv2.imshow('Multi-Object Detection', img)
# cv2.imwrite('multi_result.png', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
这段代码检测土坯indows()
这段代码检测土坯ianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
'''
原始二值图像中,某些本应属于同一逻辑区域的内容(如一个矩形主体 + 旁边的标注文字/引线)被 OpenCV 分割成了多个独立轮廓;
# 方法1的第二步: 查找所有轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
所以cv2.findContours 是通过找到多个小轮廓 → 每个轮廓都生成一个矩形 → 无法生成一个包含整体的大矩形;
'''
# 形态学闭操作连接微小间隙(使用形态学操作才能分割出完整轮廓)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) #MORPH_CLOSE是先膨胀后腐蚀的操作,能够填充小的孔洞或缝隙,连接邻近的前景区域,平滑轮廓边界
# 2. 查找所有外部轮廓
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
# 外扩**个像素,确保外接矩形包含所有点
expansion = 2
rect = (rect[0], (rect[1][0] + expansion*2, rect[1][1] + expansion*2), rect[2])
# 获取矩形角点并排序
box = cv2.boxPoints(rect)
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])}")
# 高斯双边滤波
'''
* 双边滤波参数:
* 15--->计算半径,半径之内的都会被纳入计算,如果提供-1则根据sigma space参数进行计算
* 100--->sigma color 决定多少差值之内的像素会被计算
* 5----->sigma space 如果d的值大于0则申明无效,否则根据他来计算d的值
'''
# bilateralMat = cv2.bilateralFilter(image, 15, 50, 5)
# cv2.imshow("bilateralMat", bilateralMat)
# # 锐化操作
# kernel = np.array([[0, -1, 0],
# [-1, 5, -1],
# [0, -1, 0]], dtype=np.int32)
# resultImage = cv2.filter2D(bilateralMat, -1, kernel)
# # 显示结果
# cv2.imshow('Result - Merged Bounding Boxes', resultImage)
# # cv2.imwrite('CAD/result_merged_boxes.jpg', image)
# cv2.imwrite('CAD/result_merged_boxes.jpg', resultImage)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 4. 显示结果
cv2.imshow('Multi-Object Detection', img)
# cv2.imwrite('multi_result.png', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
这段代码检测土坯indows()
这段代码检测图片绘制内容的最小外接矩形框,然而还是有些内容的矩形框巍峨ult.png', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
这段代码检测图片绘制内容的最小外接矩形框,然而还是有些内容的矩形框无法识别出来,也就没办法绘制了,问题出在哪里?二值化结果不够好吗?还是什么?如果我加入一个边缘检测算子识别会好一点吗?