///|
pub(all) struct FrameGroup {
frame_id : String
mut count : Int
first : Stamp
mut last : Stamp
paths : Array[String]
} derive(Debug, ToJson)
///|
pub fn group_images_by_frame(
frames : ArrayView[ImageFrameRef],
) -> Array[FrameGroup] {
let groups : Array[FrameGroup] = []
for frame in frames {
let mut index : Int? = None
for i in 0.. {
groups[i].count += 1
groups[i].last = frame.stamp
groups[i].paths.push(frame.path)
}
None =>
groups.push({
frame_id: frame.frame_id,
count: 1,
first: frame.stamp,
last: frame.stamp,
paths: [frame.path],
})
}
}
groups
}
///|
pub fn image_paths_for_frame(
frames : ArrayView[ImageFrameRef],
frame_id : String,
) -> Array[String] {
frames.filter_map(fn(frame) {
if frame.frame_id == frame_id {
Some(frame.path)
} else {
None
}
})
}
///|
pub fn image_frame_ids(frames : ArrayView[ImageFrameRef]) -> Array[String] {
let result = Array::new()
for frame in frames {
if !result.contains(frame.frame_id) {
result.push(frame.frame_id)
}
}
result
}
///|
pub fn filter_images_by_extension(
frames : ArrayView[ImageFrameRef],
extension : String,
) -> Array[ImageFrameRef] {
frames.filter(fn(frame) {
frame.path.to_lower().has_suffix(extension.to_lower())
})
}
///|
pub fn image_index_duration_ns(frames : ArrayView[ImageFrameRef]) -> Int64 {
timestamp_span_ns(frames, fn(frame) { frame.stamp })
}
///|
pub fn image_rate_hz(frames : ArrayView[ImageFrameRef]) -> Double {
let duration = image_index_duration_ns(frames)
if duration <= 0L {
0.0
} else {
(frames.length() - 1).to_double() * 1000000000.0 / duration.to_double()
}
}
///|
pub fn image_index_is_complete(
frames : ArrayView[ImageFrameRef],
expected_period : Int64,
tolerance : Int64,
) -> Bool {
if frames.is_empty() || expected_period <= 0L {
false
} else {
image_periods_ns(frames).all(fn(period) {
abs_i64(period - expected_period) <= tolerance
})
}
}