如何拆分VNCoreMLRequest的识别结果,实现多物体辐条数的分别统计
如何拆分VNCoreMLRequest的识别结果,实现多物体辐条数的分别统计
嗨,我看了你的问题和代码,问题出在你现在只是把所有检测到的辐条结果直接汇总统计,没有把辐条和它所属的齿轮物体绑定在一起,所以才会出现把所有辐条总数加起来的情况。咱们需要把每个辐条对应到它所在的齿轮框里,再按齿轮分组统计。
问题根源分析
你当前的代码中,coreResults是所有辐条的检测结果,gearDetectorResults是所有齿轮的检测结果,但两者之间没有建立关联。你之前的统计逻辑只是把所有在交叉线区域内的辐条计数求和,完全没考虑这些辐条属于哪个齿轮,自然就会把所有物体的辐条数加总在一起。
解决方案:建立辐条与齿轮的关联,按齿轮分组统计
我们需要先把每个齿轮的检测框转换成视图坐标系,然后遍历每个辐条结果,判断它属于哪个齿轮的范围,最后按齿轮分组统计数量。下面是修改后的核心统计代码,替换你原来的counts计算部分:
////// 替换原来的counts计算代码 // 1. 先处理齿轮检测结果:转成视图坐标系的框,给每个齿轮分配唯一ID和颜色 let gearBoxes = gearDetectorResults.enumerated().map { index, gearObservation in let gearRect = self.rect(for: gearObservation) // 可以按齿轮序号分配颜色,比如从你的colors字典里取,或者生成不同颜色 let gearColor = colors["gear_\(index)"] ?? [.red, .blue, .green, .orange][index % 4] return (id: index, rect: gearRect, color: gearColor) } // 2. 把每个辐条匹配到对应的齿轮 let spokeToGearMatches = coreResults.compactMap { spokeObservation -> (gearId: Int, spoke: VNRecognizedObjectObservation)? in let spokeRect = self.rect(for: spokeObservation) // 判断辐条是否属于某个齿轮:这里用交集面积来判断,比单纯contains更灵活 guard let matchedGear = gearBoxes.first(where: { gearBox in let intersectionRect = spokeRect.intersection(gearBox.rect) // 交集面积超过辐条面积的50%,就认为属于这个齿轮,可根据实际调整阈值 return intersectionRect.area / spokeRect.area > 0.5 }) else { return nil // 忽略不属于任何齿轮的辐条 } return (gearId: matchedGear.id, spoke: spokeObservation) } // 3. 按齿轮分组统计辐条数量 let counts = gearBoxes.map { gearBox in // 统计当前齿轮下的辐条总数 let totalSpokes = spokeToGearMatches.filter { $0.gearId == gearBox.id }.count // 生成对应的结果对象 return CountingResult( key: "Object \(gearBox.id + 1)", count: totalSpokes, color: gearBox.color ) } //////
代码逻辑说明
- 齿轮预处理:给每个检测到的齿轮分配一个序号(
index),把它的bounding box转换成和辐条结果一致的视图坐标系,同时分配对应的颜色。 - 辐条-齿轮匹配:遍历每个辐条,计算它的框和每个齿轮框的交集面积,当交集占辐条面积的50%以上时,就认为这个辐条属于该齿轮(你可以根据实际情况调整这个阈值)。
- 分组统计:针对每个齿轮,统计匹配到它的辐条数量,最后生成每个物体单独的统计结果,也就是你想要的
Object 1 : 20 spokes | Color1这种格式。
额外优化建议
- 确保
rect(for:)方法能正确把VN的坐标转换成视图坐标(VN的坐标原点在左下角,而UIKit的原点在左上角,这个转换是关键)。 - 如果存在齿轮重叠的情况,可以考虑用更精确的匹配逻辑,比如判断辐条框的中心点是否在齿轮框内,避免重叠时的误匹配。
- 可以去掉原来的
crosshairSize相关判断,因为现在我们是基于齿轮的范围来统计辐条,不需要再依赖交叉线区域了。
这样修改后,你就能得到每个物体单独的辐条数量统计结果啦!
备注:内容来源于stack exchange,提问作者Jobins John
相关产品推荐
相关产品推荐

