根据你的线和矩阵的算法,还是没法识别出线或者矩形,你看我给你附的图中,是黑色的底,然后有排列整齐的白色的圆圈和白色的线段,这些线段都有一定的长度和宽度,所以我才和你说识别矩形,但不是那种真正完美的矩形,你先自己识别看看,就是一列白色圆点,然后下一列就是一列白色线段(或者说宽度很短的矩形),然后紧接着一列圆圈,然后根据你自己识别的情况来看的话,能不能把这些线段给标记出来,标记的话呢,只需要标记这个线段的左右两个端点(如果是晓矩形,就是两条最短边的中点的像素坐标),所以我在想,是不是可以根据灰度值来计算和判断这些线段或小矩形?因为我后面还要判断重影的算法,意思是呢这个hud投影以后可能会因为玻璃厚度或者贴膜的原因导致出现一个重影叠加在原图上,这就是我上面说灰度值的原因,这个重影的灰度值肯定和这个投影原矩形的值是不一样的,所以能根据这个检测出来重影,这个判断重影算法只能根据这些小线段或矩形来了,因为圆形的不好判断,当然这是后话,第一步是要把这些白色的线段(或者小矩形)识别出来了,所以请你在你上面搭建的项目基础上,再修改下识别(线段或小矩形的识别)算法,根据我的要求标记出来,并输出坐标。
# line_detection.py
import cv2
import numpy as np
# 下面两个量你可以根据样本图亮度自行调节:
BIN_THRESH = 200 # 灰度二值化阈值(0–255)
MIN_RECT_AREA = 500 # 最小连通域(矩形)面积
MIN_ASPECT = 4.0 # 宽高比(长/短)下限
def detect_line_segments(gray_img):
"""
基于灰度阈值 + 连通域,提取所有“线段”或“小矩形”区域。
返回列表 [(x, y, w, h), ...],坐标基于原图。
"""
# 1. 二值化,提取白色区域
_, bw = cv2.threshold(gray_img, BIN_THRESH, 255, cv2.THRESH_BINARY)
# 2. 形态学闭运算,连接可能的断点
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
bw = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel, iterations=2)
# 3. 找外部轮廓
contours, _ = cv2.findContours(bw,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
rects = []
for cnt in contours:
# 4. 最小面积过滤
x, y, w, h = cv2.boundingRect(cnt)
if w*h < MIN_RECT_AREA:
continue
# 5. 长宽比过滤(保证是“线”状)
ratio = max(w/h, h/w)
if ratio < MIN_ASPECT:
continue
# 6. 扩一点 margin(防止裁得太紧)
xm = max(x - 5, 0)
ym = max(y - 5, 0)
rects.append((xm, ym, w + 10, h + 10))
return rects
import os
import cv2
from config import LINES_IMG, LOG_DIR, FONT, FONT_SCALE, FONT_THICKNESS, FONT_COLOR_LINE
from utils import prepare_log_dir, read_gray, save_image, save_log
from line_detection import detect_line_segments
def segment_and_label_lines():
"""
1. 灰度图阈值提取白色线段/小矩形
2. 计算最小外接框裁剪
3. 在裁剪图中标注每个线段的左右端点
4. 保存图和 log2.txt
"""
# 1. 读取原图
orig = read_gray(LINES_IMG)
H, W = orig.shape
# 2. 检测线段小矩形
rects = detect_line_segments(orig)
# 3. 如果没检测到,直接输出原图 & 空日志
if not rects:
vis_full = cv2.cvtColor(orig, cv2.COLOR_GRAY2BGR)
save_image(vis_full, os.path.join(LOG_DIR, "lines_segmented.png"))
log = [
f"Original image size: {W}x{H}",
f"Cropped image size: {W}x{H}",
"Number of lines: 0"
]
save_log("\n".join(log), os.path.join(LOG_DIR, "log2.txt"))
return
# 4. 计算所有 rect 的外接裁剪框
xs = [x for x,y,w,h in rects] + [x+w for x,y,w,h in rects]
ys = [y for x,y,w,h in rects] + [y+h for x,y,w,h in rects]
x_min, x_max = max(int(min(xs)), 0), min(int(max(xs)), W)
y_min, y_max = max(int(min(ys)), 0), min(int(max(ys)), H)
cropped = orig[y_min:y_max, x_min:x_max]
ch, cw = cropped.shape
# 5. 转到局部坐标并排序(从左上往右下阅读顺序)
rects_local = [(x-x_min, y-y_min, w, h) for x,y,w,h in rects]
rects_sorted = sorted(rects_local, key=lambda r: (r[1], r[0]))
# 6. 绘制 & 标记端点
vis = cv2.cvtColor(cropped, cv2.COLOR_GRAY2BGR)
log_lines = [
f"Original image size: {W}x{H}",
f"Cropped image size: {cw}x{ch}",
f"Number of lines: {len(rects_sorted)}",
"Index, x1, y1, x2, y2"
]
for idx, (x, y, w, h) in enumerate(rects_sorted, start=1):
# 画锐化的矩形框
cv2.rectangle(vis, (x, y), (x+w, y+h), FONT_COLOR_LINE, 2)
# 左右端点:矩形中心水平线上的点
mid_y = y + h//2
x1e, y1e = x, mid_y
x2e, y2e = x + w, mid_y
# 标号放在右端点偏移一点的位置
cv2.putText(vis, str(idx), (x2e + 3, y2e + 3),
FONT, FONT_SCALE, FONT_COLOR_LINE, FONT_THICKNESS)
log_lines.append(f"{idx}, {x1e}, {y1e}, {x2e}, {y2e}")
# 7. 保存结果
save_image(vis, os.path.join(LOG_DIR, "lines_segmented.png"))
save_log("\n".join(log_lines), os.path.join(LOG_DIR, "log2.txt"))