为了在图像A(宽度为W,高度为H)中找到一个固定宽度为X、高度为Y的ROI(Region of Interest),使得ROI内所有矩形框的高度之和最大,可以采用一种基于矩形框中心点的扫描线算法。该方法假设一个矩形框的中心点落在ROI内时,该矩形框即被视为在ROI中,并计入其高度。这种假设简化了问题,并允许高效计算。
算法步骤
-
预处理矩形框信息:
- 对于每个矩形框 (i)(其中 (i = 1, 2, \ldots, n)),计算其中心点坐标:
- ( \text{cx}_i = \text{left}_i + \frac{\text{width}_i}{2} )
- ( \text{cy}_i = \text{top}_i + \frac{\text{height}_i}{2} )
- 每个矩形框的高度记为 ( h_i = \text{height}_i ),作为权重。
- 对于每个矩形框 (i)(其中 (i = 1, 2, \ldots, n)),计算其中心点坐标:
-
生成x方向的事件点:
- 对于每个矩形框的中心点,生成两个事件:
- 添加事件:当ROI的左边界 ( L ) 达到 ( \text{cx}_i - X ) 时,矩形框进入ROI。
- 移除事件:当ROI的左边界 ( L ) 达到 ( \text{cx}_i ) 时,矩形框离开ROI。
- 将所有事件点(包括所有 ( \text{cx}_i - X ) 和 ( \text{cx}_i ))存储在一个列表中,并按x坐标排序。事件点总数不超过 ( 2n )。
- 对于每个矩形框的中心点,生成两个事件:
-
扫描x方向事件点:
- 初始化一个空的数据结构(如平衡二叉搜索树或排序列表)来维护当前在x方向窗口 ([L, L+X]) 内的矩形框点集(按y坐标排序)。
- 初始化最大高度和 ( \text{max_sum} = 0 ) 和对应的ROI位置 ( (L_{\text{best}}, T_{\text{best}}) )。
- 遍历排序后的事件点序列:
- 对于每个事件点:
- 如果是添加事件(对应某个矩形框i),将该点 ( (\text{cx}_i, \text{cy}_i, h_i) ) 插入到y排序的数据结构中。
- 如果是移除事件(对应某个矩形框i),将该点从y排序的数据结构中移除。
- 在每次添加或移除操作后,当前点集代表在x窗口 ([L, L+X]) 内的矩形框(其中 ( L ) 为当前事件点的x值)。
- 对于每个事件点:
-
在y方向计算滑动窗口最大和:
- 对于当前点集(大小为 ( p ),计算在y方向高度为Y的滑动窗口 ([T, T+Y]) 中的最大高度和:
- 从y排序的数据结构中提取所有点,按 ( \text{cy} ) 排序。
- 生成y方向的事件点:对于每个点,事件点为 ( \text{cy}_i )(点进入y窗口)和 ( \text{cy}_i - Y )(点离开y窗口)。
- 排序所有y事件点(事件点总数不超过 ( 2p ))。
- 扫描排序后的y事件点,维护当前高度和 ( \text{current_sum} ):
- 当遇到 ( \text{cy}_i ) 事件时,添加 ( h_i ) 到 ( \text{current_sum} )。
- 当遇到 ( \text{cy}_i - Y ) 事件时,从 ( \text{current_sum} ) 中减去 ( h_i )。
- 记录扫描过程中的最大 ( \text{current_sum} ) 及其对应的 ( T ) 值(即事件点的y值)。
- 记录该点集在y方向的最大和及对应的 ( T )。
- 对于当前点集(大小为 ( p ),计算在y方向高度为Y的滑动窗口 ([T, T+Y]) 中的最大高度和:
-
更新全局最大值:
- 比较当前x事件点计算出的y方向最大和与全局 ( \text{max_sum} )。
- 如果更大,则更新 ( \text{max_sum} )、( L_{\text{best}} )(取当前事件点的x值)和 ( T_{\text{best}} ).
-
输出结果:
- 扫描完成后,最优ROI位置为 ( (L_{\text{best}}, T_{\text{best}}) ),其中 ( L_{\text{best}} ) 和 ( T_{\text{best}} ) 满足 ( 0 \leq L_{\text{best}} \leq W - X ) 和 ( 0 \leq T_{\text{best}} \leq H - Y ).
时间复杂度
- 生成和排序x事件点:( O(n \log n) )。
- 每个x事件点处理:添加/移除点到y数据结构(( O(\log n) ) 时间),以及计算y方向最大和(排序y点 ( O(p \log p) ),扫描事件点 ( O§ ),其中 ( p ) 是当前点集大小)。
- 由于x事件点数为 ( O(n) ),且每个点最多被添加和移除一次,总时间复杂度为 ( O(n^2 \log n) )(最坏情况下, ( p ) 可达 ( n ),每个事件点处理需 ( O(n \log n) ) 时间)。
- 空间复杂度:( O(n) ) 用于存储事件点和数据结构。
注意事项
- 坐标处理:如果矩形框坐标是浮点数,算法仍适用(事件点排序时需处理浮点比较)。如果坐标是整数,可以进一步优化(例如使用整数排序)。
- 边界处理:在事件点处理时,确保边界包含(例如,当中心点正好在ROI边界时视为内部)。
- 部分覆盖:本算法基于中心点定义“在ROI中”。如果需考虑矩形框完全包含在ROI内(而非仅中心点),算法会更复杂(需处理矩形边界事件),时间复杂度可能优化到 ( O(n \log n) )(使用区间树或Fenwick树),但实现更复杂。
- 优化:对于大规模问题,可通过离散化坐标或使用更高效的数据结构(如线段树)优化y方向计算,但上述方法在n中等规模(如数千)时已足够。
伪代码
import bisect
def find_optimal_roi(W, H, rectangles, X, Y):
n = len(rectangles)
events = [] # x方向事件点: (x, type, index), type=0添加, type=1移除
# 预处理中心点和事件
points = []
for i, rect in enumerate(rectangles):
left, top, width, height = rect
cx = left + width / 2.0
cy = top + height / 2.0
h = height
points.append((cx, cy, h))
events.append((cx - X, 0, i)) # 添加事件
events.append((cx, 1, i)) # 移除事件
# 按x排序事件点
events.sort(key=lambda e: e[0])
# 当前点集 (按cy排序)
current_points = [] # 列表维护(cy, h)
max_sum = 0
best_L = 0
best_T = 0
# 扫描x事件
for event in events:
x, etype, idx = event
cx, cy, h = points[idx]
if etype == 0: # 添加点
# 插入到current_points并保持按cy排序
pos = bisect.bisect(current_points, (cy, h))
current_points.insert(pos, (cy, h))
else: # 移除点
# 从current_points中移除
pos = bisect.bisect_left(current_points, (cy, h))
if pos < len(current_points) and current_points[pos] == (cy, h):
del current_points[pos]
# 计算当前点集在y方向的最大和
if not current_points:
continue
y_events = []
for cy_val, h_val in current_points:
y_events.append((cy_val, 1, h_val)) # 进入事件
y_events.append((cy_val - Y, -1, h_val)) # 离开事件
y_events.sort(key=lambda e: e[0])
current_sum = 0
max_y_sum = 0
best_T_local = 0
for y_event in y_events:
y_pos, etype_y, h_val = y_event
current_sum += etype_y * h_val
if current_sum > max_y_sum:
max_y_sum = current_sum
best_T_local = y_pos # T位置
# 更新全局最大和
if max_y_sum > max_sum:
max_sum = max_y_sum
best_L = x # L为当前事件点x值
best_T = best_T_local
# 确保ROI在图像范围内
best_L = max(0, min(best_L, W - X))
best_T = max(0, min(best_T, H - Y))
return (best_L, best_T, max_sum)
此算法在矩形框位置随机时表现良好,并能高效找到最优ROI。如果实际应用中矩形框数量巨大,可考虑近似算法或进一步优化(如使用KD树加速范围查询)。

503

被折叠的 条评论
为什么被折叠?



