diff --git a/yaml parse test/Point2D.py b/yaml parse test/Point2D.py index 980eb95..2b0400d 100644 --- a/yaml parse test/Point2D.py +++ b/yaml parse test/Point2D.py @@ -1,4 +1,5 @@ import hashlib +from itertools import permutations import json import os.path import math @@ -46,6 +47,7 @@ class Point2D: def divide_points_into_groups(points): + print("divide_points_into_groups: ", len(points)) result = fastproot.divide_into_groups(points) res = [[Point2D(p[0], p[1], p[2]) for p in arr] for arr in result] return res @@ -90,7 +92,27 @@ def calculate_distance(points1: list[Point2D], points2: list[Point2D]) -> float: center2_y = (points2[0].y + points2[-1].y) / 2 return ((center1_x - center2_x) ** 2 + (center1_y - center2_y) ** 2) ** 0.5 + def pair_groups(set_a: list[list[Point2D]], set_b: list[list[Point2D]]) -> list[tuple[list[Point2D], list[Point2D]]]: + # print("set_a", [[(b.x, b.y) for b in i] for i in set_a]) + # print("set_b", [[(b.x, b.y) for b in i] for i in set_b]) + result = [] + if len(set_a) <= len(set_b): + result = fastproot.pair_groups(set_a, set_b) + else: + for (b, a) in fastproot.pair_groups(set_b, set_a): + result.append((a,b)) + res = [ + ( + [Point2D(a1[0], a1[1], a1[2]) for a1 in a], + [Point2D(b1[0], b1[1], b1[2]) for b1 in b] + ) for (a, b) in result + ] + #res = [[Point2D(p[0], p[1], p[2]) for p in arr] for arr in result] + return res + + +def _pair_groups(set_a: list[list[Point2D]], set_b: list[list[Point2D]]) -> list[tuple[list[Point2D], list[Point2D]]]: pairs = [] # Create dictionaries to store bounding boxes for each group @@ -131,7 +153,7 @@ def pair_groups(set_a: list[list[Point2D]], set_b: list[list[Point2D]]) -> list[ def mirror_points(points: list[Point2D]) -> list[Point2D]: mirrored_points = [] for point in points: - mirrored_x = 128 - point.x # Calculate the mirrored x-coordinate + mirrored_x = 127 - point.x # Calculate the mirrored x-coordinate mirrored_point = Point2D(mirrored_x, point.y, point.color) mirrored_points.append(mirrored_point) return mirrored_points @@ -174,7 +196,7 @@ def generate_point_array_from_image(image): width, height = image.size pixel_array = [] - image.save(LOADED_IMAGE_PATH) + #image.save(LOADED_IMAGE_PATH) for y in range(height): for x in range(width): @@ -204,13 +226,18 @@ def generate_image_from_point_array(points: list[Point2D], width: int, height: i return image - def interpolate_point_pairs(pairs: list[tuple[Point2D, Point2D]], percentage: float) -> list[Point2D]: + result = fastproot.interpolate_point_pairs(pairs, percentage) + res = [Point2D(p[0], p[1], p[2]) for p in result] + return res + +def _interpolate_point_pairs(pairs: list[tuple[Point2D, Point2D]], percentage: float) -> list[Point2D]: interpolated_points:list[Point2D] = [] for pair in pairs: point1, point2 = pair interpolated_point = point1.interpolate(point2, percentage) - interpolated_points.append(interpolated_point) + if not interpolated_point in interpolated_points: + interpolated_points.append(interpolated_point) return interpolated_points @@ -229,7 +256,7 @@ def pair_points(points1: list[Point2D], points2: list[Point2D]) -> list[tuple[Po duplicated_points = np.random.choice(points1, size=num_duplicates).tolist() points1 += duplicated_points - row_ind, col_ind = fastproot.solve(points1, points2) + row_ind, col_ind = (fastproot.solve(points1, points2)) # Create pairs of points based on the optimal assignment pairs = [] diff --git a/yaml parse test/README.md b/yaml parse test/README.md index 6c70535..6fd73ac 100644 --- a/yaml parse test/README.md +++ b/yaml parse test/README.md @@ -2,4 +2,8 @@ Crosscompile instructions: * Build docker image with python armv7 installed: `docker build -t my-image .` * Use cross to crosscompile: - `cross.exe build --target=armv7-unknown-linux-gnueabihf --release` \ No newline at end of file + `cross.exe build --target=armv7-unknown-linux-gnueabihf --release` +* Move built library to the correct folder: + `cp fastproot/target/armv7-unknown-linux-gnueabihf/release/libfastproot.so ./` +* Move windows binary + `cp fastproot/target/release/fastproot.dll ./fastproot.pyd` \ No newline at end of file diff --git a/yaml parse test/angryFace.png b/yaml parse test/angryFace.png new file mode 100644 index 0000000..bb0ed7d Binary files /dev/null and b/yaml parse test/angryFace.png differ diff --git a/yaml parse test/dizzyFace.png b/yaml parse test/dizzyFace.png index a4006ee..2299388 100644 Binary files a/yaml parse test/dizzyFace.png and b/yaml parse test/dizzyFace.png differ diff --git a/yaml parse test/fastproot.so b/yaml parse test/fastproot.so new file mode 100644 index 0000000..f66b1e4 Binary files /dev/null and b/yaml parse test/fastproot.so differ diff --git a/yaml parse test/fastproot/src/lib.rs b/yaml parse test/fastproot/src/lib.rs index 61ba7b6..5b5920d 100644 --- a/yaml parse test/fastproot/src/lib.rs +++ b/yaml parse test/fastproot/src/lib.rs @@ -1,16 +1,35 @@ use pyo3::prelude::*; -#[derive(Copy, Clone, PartialEq, FromPyObject)] +#[derive(Copy, Clone, FromPyObject, Default, Debug)] pub struct Point { x: u8, y: u8, - color: (u8, u8, u8), + color: [u8; 3], +} + +impl PartialEq for Point { + fn eq(&self, other: &Self) -> bool { + self.x == other.x && self.y == other.y + } +} + +impl std::fmt::Display for Point { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "({}, {})", self.x, self.y) + } } type TuplePoint = (u8,u8, (u8,u8,u8)); impl Point { + pub fn new(x: u8, y: u8) -> Self { + Self { + x, y, + ..Default::default() + } + } + fn distance(self, other: Point) -> f64 { let dx = self.x as f64 - other.x as f64; let dy = self.y as f64 - other.y as f64; @@ -18,7 +37,20 @@ impl Point { } fn into_tuple(&self) -> TuplePoint { - (self.x, self.y, self.color) + (self.x, self.y, (self.color[0], self.color[1], self.color[2])) + } + + fn interpolate(self, other: Point, percent: f32) -> Point{ + let x = self.x as f32 + ((other.x as f32 - self.x as f32) as f32 * percent); + let y = self.y as f32 + ((other.y as f32 - self.y as f32) as f32 * percent); + + let color = (0..3).map(|i| ((1.0 - percent) * self.color[i] as f32 + percent * other.color[i] as f32) as u8).collect::>(); + let color = [ + color[0], + color[1], + color[2], + ]; + Point { x: x as u8, y: y as u8, color } } } @@ -35,17 +67,26 @@ pub fn solve(points1: Vec, points2: Vec) -> (Vec, Vec, points: Vec) -> Vec { +pub fn flood_fill(point: Point, mut group: Vec, points: &[Point]) -> Vec { if !group.contains(&point) { group.push(point); - let neighbors = [(point.x + 1, point.y), (point.x - 1, point.y), (point.x, point.y + 1), (point.x, point.y - 1)]; + let neighbors = [ + (point.x + 1, point.y), + (point.x - 1, point.y), + (point.x, point.y + 1), + (point.x, point.y - 1), + (point.x + 1, point.y + 1), + (point.x + 1, point.y - 1), + (point.x - 1, point.y + 1), + (point.x - 1, point.y - 1), + ]; for neighbor_coords in neighbors { let neighbor = points.iter().find(|p| p.x == neighbor_coords.0 && p.y == neighbor_coords.1); if let Some(neighbor) = neighbor { if !group.contains(&neighbor) { - group = flood_fill(*neighbor, group, points.clone()) + group = flood_fill(*neighbor, group, points) } } } @@ -54,78 +95,181 @@ pub fn flood_fill(point: Point, mut group: Vec, points: Vec) -> Ve group } +// def divide_points_into_groups(points): +// def flood_fill(point, group): +// if point not in group: +// group.append(point) +// neighbors = [(point.x + 1, point.y), (point.x - 1, point.y), (point.x, point.y + 1), (point.x, point.y - 1)] +// for neighbor_coords in neighbors: +// neighbor = next((p for p in points if p.x == neighbor_coords[0] and p.y == neighbor_coords[1]), None) +// if neighbor and neighbor not in group: +// flood_fill(neighbor, group) +// +// groups = [] +// remaining_points = [point for point in points if point.x < 64] # Filter points with x < 64 +// while remaining_points: +// group = [] +// flood_fill(remaining_points[0], group) +// groups.append(group) +// # Remove points in the group from the remaining points +// remaining_points = [point for point in remaining_points if point not in group] +// return groups + + #[pyfunction] pub fn divide_into_groups(points: Vec) -> Vec> { let mut groups = vec![]; - let mut remaining = points.iter().filter(|p| p.x < 64).collect::>(); - while let Some(&point) = remaining.get(0) { - let group = flood_fill(*point, vec![], points.clone()); - groups.push(group.iter().map(|v| v.into_tuple()).collect()); + let mut remaining = points.clone().into_iter().filter(|p| p.x < 64).collect::>(); + while let Some(point) = remaining.pop_front() { + let group = flood_fill(point, vec![], &points); + groups.push(group.clone()); remaining = remaining.into_iter().filter(|p| !group.contains(p)).collect(); } - groups + groups.into_iter().map(|r| r.into_iter().map(|c| c.into_tuple()).collect()).collect() } -// #[pyfunction] -// fn pair_groups(set_a: Vec>, set_b: Vec>) -> Vec<(TuplePoint, TuplePoint)> { -// let mut pairs = vec![]; - -// // Create dictionaries to store bounding boxes for each group -// let mut bounding_boxes_a: std::collections::HashMap::new(); // dict[int, tuple[float, float, float, float]] = {} -// let mut bounding_boxes_a: std::collections::HashMap::new(); +pub fn distance(this: (u8, u8), other: (u8, u8)) -> f64 { + let dx = this.0 as f64 - other.0 as f64; + let dy = this.1 as f64 - other.1 as f64; + (dx.powf(2.0) + dy.powf(2.0)).sqrt() +} -// // Calculate bounding boxes for all groups in both sets -// for (i, group) in set_a.iter().chain(set_b).iter().enumerate() { -// let bounding_box = compute_bounding_box(group); -// if i < set_a.len() { -// bounding_boxes_a[i] = bounding_box; -// } else { -// bounding_boxes_b[i - set_a.len()] = bounding_box; -// } -// } +pub fn centroid(points: &[Point]) -> (u8, u8) { + let x = points.iter().fold(0usize, |acc, p| acc + p.x as usize) / points.len(); + let y = points.iter().fold(0usize, |acc, p| acc + p.y as usize) / points.len(); + (x as u8, y as u8) +} -// // Check for overlaps and determine pairs -// for (i, group_a) in set_a.iter().enumerate() { -// let overlap_detected = false; -// for (j, group_b) in set_b.iter().enenumerate() { -// let bounding_box_a = bounding_boxes_a[i]; -// let bounding_box_b = bounding_boxes_b[j]; -// if ( -// bounding_box_a[0] <= bounding_box_b[1] && -// bounding_box_a[1] >= bounding_box_b[0] && -// bounding_box_a[2] <= bounding_box_b[3] && -// bounding_box_a[3] >= bounding_box_b[2] -// ) { -// pairs.push((group_a, group_b)); -// overlap_detected = true; -// break -// } -// } - -// if !overlap_detected { -// // Find the nearest neighbor in set B -// let mut nearest_group = set_b[0]; -// let mut nearest_value = 0.0f64; -// for val in set_b.iter() { -// if calculate_distance(group_a, val) < nearest_value { -// nearest_group = val; -// } -// } -// pairs.append((group_a, nearest_group)); -// } -// } +#[pyfunction] +pub fn pair_groups(smaller: Vec>, larger: Vec>) -> Vec<(Vec, Vec)> { + let smaller_center = smaller.iter().map(|v| centroid(v)).collect::>(); + let larger_center = larger.iter().map(|v| centroid(v)).collect::>(); + + let mut map = std::collections::HashMap::>::new(); + + // Map each item from centroids2 to an item in centroids1. + for (idx2, coords2) in larger_center.iter().enumerate() { + // Get nearest item in centroids1 + let mut nearest_idx = 0; + let mut nearest_dist = f64::MAX; + for (idx1, coords1) in smaller_center.iter().enumerate() { + if distance(*coords1, *coords2) < nearest_dist { + nearest_dist = distance(*coords1, *coords2); + nearest_idx = idx1; + } + } + // now, nearest_idx is the index in centroid1 of the nearest point. + map.entry(nearest_idx).and_modify(|v| v.push(idx2)).or_insert_with(||vec![idx2]); + } + + let mut result = vec![]; + for (k, indexes) in map { + let mut combined = vec![]; + for i in indexes { + combined.extend(larger[i].iter()) + } + + let key = smaller[k].iter().map(|v| v.into_tuple()).collect(); + let combined = combined.into_iter().map(|v: Point| v.into_tuple()).collect(); + result.push((key, combined)) + } + + result +} + +#[pyfunction] +pub fn interpolate_point_pairs(pairs: Vec<(Point, Point)>, percent: f32) -> Vec { + let mut interpolated_points = vec![]; + for (point1, point2) in pairs { + let interpolated_point = point1.interpolate(point2, percent); + if !interpolated_points.contains(&interpolated_point){ + interpolated_points.push(interpolated_point); + } + } + interpolated_points.into_iter().map(|v| v.into_tuple()).collect() +} -// pairs -// } #[pymodule] fn fastproot(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(solve, m)?)?; m.add_function(wrap_pyfunction!(divide_into_groups, m)?)?; - // m.add_function(wrap_pyfunction!(pair_groups, m)?)?; + m.add_function(wrap_pyfunction!(pair_groups, m)?)?; + m.add_function(wrap_pyfunction!(interpolate_point_pairs, m)?)?; Ok(()) +} + +#[cfg(test)] +pub mod tests { + use super::{Point, flood_fill, divide_into_groups, centroid, pair_groups, interpolate_point_pairs}; + #[test] + fn should_do_flood_fill() { + let groups = flood_fill(Point::new(1,1), vec![], &vec![ + Point::new(1,1), + Point::new(1,2), + Point::new(2,1), + + Point::new(3,3), + ]); + println!("{groups:?}"); + } + + #[test] + fn should_divide_into_groups() { + let groups = divide_into_groups(vec![ + Point::new(1,1), + Point::new(1,2), + Point::new(2,1), + + Point::new(3,3), + Point::new(3,4), + Point::new(4,4) + ]); + for (i, g) in groups.iter().enumerate() { + println!("{i}: {g:?}"); + } + } + + #[test] + fn should_create_centroid() { + let centroid = centroid(&vec![ + Point::new(1,1), + Point::new(1,2), + Point::new(2,1), + Point::new(20,10), + ]); + + println!("{centroid:?}"); + } + + + #[test] + fn should_pair_groups() { + + let a = vec![vec![(59, 2), (60, 2), (61, 2), (62, 2), (62, 3)], vec![(15, 8), (16, 8), (17, 8), (18, 8), (19, 8), (20, 8), (21, 8), (22, 8), (23, 8), (24, 8), (25, 8), (26, 8), (27, 8), (27, 9), (28, 9), (29, 9), (30, 9), (30, 10), (31, 10), (31, 11), (29, 10), (26, 9), (25, 9), (24, 9), (23, 9), (22, 9), (21, 9), (20, 9), (19, 9), (18, 9), (17, 9), (16, 9), (15, 9)], vec![(26, 22), (27, 22), (28, 22), (28, 23), (29, 23), (30, 23), (31, 23), (31, 24), (32, 24), (33, 24), (33, 25), (34, 25), (35, 25), (36, 25), (36, 26), (37, 26), (38, 26), (39, 26), (40, 26), (41, 26), (42, 26), (42, 27), (43, 27), (44, 27), (45, 27), (46, 27), (47, 27), (47, 26), (48, 26), (49, 26), (50, 26), (50, 25), (51, 25), (52, 25), (52, 26), (53, 26), (53, 27), (53, 28), (54, 28), (54, 29), (55, 29), (55, 30), (56, 30), (57, 30), (57, 29), (58, 29), (58, 28), (59, 28), (59, 27), (60, 27), (60, 26), (61, 26), (61, 25), (62, 25), (62, 24), (51, 24)]]; + let b = vec![vec![(21, 1), (22, 1), (23, 1), (24, 1), (25, 1), (26, 1), (27, 1), (28, 1), (28, 2), (29, 2), (30, 2), (31, 2), (31, 3), (32, 3), (32, 4), (33, 4), (33, 5), (34, 5), (34, 6), (34, 7), (35, 7), (35, 8), (35, 9), (35, 10), (35, 11), (34, 11), (34, 12), (33, 12), (33, 13), (32, 13), (32, 14), (31, 14), (30, 14), (29, 14), (29, 15), (28, 15), (27, 15), (26, 15), (25, 15), (24, 15), (23, 15), (22, 15), (21, 15), (20, 15), (19, 15), (19, 14), (18, 14), (17, 14), (16, 14), (16, 13), (15, 13), (15, 12), (14, 12), (13, 12), (13, 11), (12, 11), (12, 10), (12, 9), (12, 8), (21, 2), (20, 2), (19, 2), (18, 2), (18, 3), (17, 3), (17, 4), (17, 5), (17, 6), (16, 6), (16, 7), (16, 8), (16, 9), (17, 9), (17, 10), (18, 10), (18, 11), (19, 11), (19, 12), (20, 12), (21, 12), (21, 13), (22, 13), (23, 13), (24, 13), (25, 13), (26, 13), (27, 13), (27, 12), (28, 12), (29, 12), (29, 11), (30, 11), (30, 10), (31, 10), (31, 9), (31, 8), (31, 7), (30, 7), (30, 6), (30, 5), (29, 5), (28, 5), (28, 4), (27, 4), (26, 4), (25, 4), (24, 4), (23, 4), (22, 4), (22, 5), (21, 5), (21, 6), (20, 6), (20, 7), (20, 8), (20, 9), (21, 9), (21, 10), (22, 10), (23, 10), (24, 10), (25, 10), (26, 10), (27, 10), (27, 9), (27, 8), (28, 8), (27, 7), (26, 7), (25, 7), (24, 7)], vec![(59, 2), (60, 2), (61, 2), (62, 2), (62, 3)], vec![(26, 22), (27, 22), (28, 22), (28, 23), (29, 23), (30, 23), (31, 23), (31, 24), (32, 24), (33, 24), (33, 25), (34, 25), (35, 25), (36, 25), (36, 26), (37, 26), (38, 26), (39, 26), (40, 26), (41, 26), (42, 26), (42, 27), (43, 27), (44, 27), (45, 27), (46, 27), (47, 27), (47, 26), (48, 26), (49, 26), (50, 26), (50, 25), (51, 25), (52, 25), (52, 26), (53, 26), (53, 27), (53, 28), (54, 28), (54, 29), (55, 29), (55, 30), (56, 30), (57, 30), (57, 29), (58, 29), (58, 28), (59, 28), (59, 27), (60, 27), (60, 26), (61, 26), (61, 25), (62, 25), (62, 24), (51, 24)]]; + + let a = a.into_iter().map(|r| r.into_iter().map(|(x,y)| Point::new(x,y)).collect()).collect(); + let b = b.into_iter().map(|r| r.into_iter().map(|(x,y)| Point::new(x,y)).collect()).collect(); + + let res = pair_groups(a, b + // vec![ + // vec![Point::new(1,1)], + // vec![Point::new(3,3),Point::new(3,4)], + // vec![Point::new(10,10), Point::new(11,11)] + // ], + // vec![ + // vec![Point::new(2,2)], + // vec![Point::new(2,5)], + // vec![Point::new(12,12)], + // ] + ); + for (i, s) in res { + println!("====> {i:?} => {s:?}"); + } + } } \ No newline at end of file diff --git a/yaml parse test/loveFace.png b/yaml parse test/loveFace.png new file mode 100644 index 0000000..7a4e29e Binary files /dev/null and b/yaml parse test/loveFace.png differ diff --git a/yaml parse test/prootOS.py b/yaml parse test/prootOS.py index 2d55faa..15d3a34 100644 --- a/yaml parse test/prootOS.py +++ b/yaml parse test/prootOS.py @@ -179,6 +179,9 @@ class RenderingLayer: self.frame_rate = frame_rate # Set the desired frame rate self.frame_duration = 1.0 / frame_rate # Calculate the frame duration self.animation_queue = [] # Initialize the animation queue + + self.previous_to = [] + self.previous_point_pairs_groups = [] def play_animation_by_name(self, animation_name): for animation in self.animations: @@ -209,15 +212,16 @@ class RenderingLayer: animation_queue.append({'type': graphic.get('type'), 'point_array': point_array}) if graphic.get('type') == 'transition': + to_file_name = graphic.get('to_file') to_point_array = graphic.get('to_point_array') duration = graphic.get('duration', 1) # Default duration is 1 frame if not specified # Add frames to the queue based on the specified duration for i in range(int(duration)): - animation_queue.append({'type': graphic.get('type'), 'to_point_array': to_point_array, 'stepPercentage' : (1/(int(duration)-i))}) + animation_queue.append({'type': graphic.get('type'), 'to_point_array': to_point_array, 'to_file_name': to_file_name, 'additionalStepPercentage' : (1/(int(duration)-i)), 'stepPercentage' : ((i+1)/duration)}) return animation_queue - + def start_rendering(self): frameCount = 0 new_image = Image.new("RGB", (128, 32), "black") @@ -226,8 +230,10 @@ class RenderingLayer: pairgrouptime = 0 pairpointtime = 0 imagingtime = 0 + interpolatetime = 0 transitionFrameCount = 1 + while True: start_time = time.time() # Get the current time before rendering @@ -245,38 +251,87 @@ class RenderingLayer: print("image generated") elif current_animation_action.get('type') == "transition": - transitionFrameCount += 1 - divtime_start = time.time() - groupsa = divide_points_into_groups(self.current_point_array) - groupsb = divide_points_into_groups(current_animation_action.get('to_point_array')) - devisiontime += time.time() - divtime_start - pairgrouptime_start = time.time() - paired_groups = pair_groups(groupsa, groupsb) - pairgrouptime += time.time() - pairgrouptime_start - new_point_array = [] - for pair in paired_groups: - pairpointtime_start = time.time() - point_pairs = pair_points(pair[0], pair[1]) - pairpointtime += time.time() - pairpointtime_start - print(str(current_animation_action.get('stepPercentage'))) - new_point_array += interpolate_point_pairs(point_pairs, current_animation_action.get('stepPercentage')) + frame_time_start = time.time() + + + if self.previous_to == str(current_animation_action.get('to_file_name')): + + + point_pairs_groups = self.previous_point_pairs_groups + + new_point_array = [] + for point_pairs in point_pairs_groups: + interpolatetime_start = time.time() + new_point_array += interpolate_point_pairs(point_pairs, current_animation_action.get('stepPercentage')) + print("interpolationg took: " + str(time.time() - interpolatetime_start) + " sec. (cached)") + print("step percentate for this transition step is: " + str(current_animation_action.get('stepPercentage'))) + + else: + print("starting transition generation") + transitionFrameCount += 1 + divtime_start = time.time() + + groupsa = divide_points_into_groups(self.current_point_array) + groupsb = divide_points_into_groups(current_animation_action.get('to_point_array')) + devisiontime += time.time() - divtime_start + + print("groups divided, len(groupsa), len(groups(b)=", len(groupsa), len(groupsb)) + + pairgrouptime_start = time.time() + paired_groups = pair_groups(groupsa, groupsb) + pairgrouptime += time.time() - pairgrouptime_start + + + print("paired_groups generated, len(paired_groups)=", len(paired_groups)) + + self.previous_point_pairs_groups = [] + new_point_array = [] + for pair in paired_groups: + pairpointtime_start = time.time() + point_pairs = pair_points(pair[0], pair[1]) + self.previous_point_pairs_groups.append(point_pairs) + pairpointtime += time.time() - pairpointtime_start + print("step percentate for this transition stepp is: " + str(current_animation_action.get('additionalStepPercentage'))) + + interpolatetime_start = time.time() + new_point_array += interpolate_point_pairs(point_pairs, current_animation_action.get('additionalStepPercentage')) + print("interpolationg took: " + str(time.time() - interpolatetime_start) + " sec.") + + print("face feature interpolated len(new_point_array) =", len(new_point_array)) + + # set previous "to" screen. This is used + self.previous_to = str(current_animation_action.get('to_file_name')) + imagingtime_start = time.time() + new_image = generate_image_from_point_array(new_point_array + mirror_points(new_point_array), 128, 32) + #new_image.save("output/frameNumber"+str(frameCount)+".png") imagingtime += time.time() - imagingtime_start self.current_point_array = new_point_array + print("transition generated, len(new_point_array) =", len(new_point_array)) + + print("creating transition frame took: " + str(time.time() - frame_time_start) + " sec.") + print("================== end frame ==================") + else: + print("unknown action: ", current_animation_action) + + print("setting image to canvas") offscreen_canvas = matrix.CreateFrameCanvas() offscreen_canvas.SetImage(new_image, unsafe=False) + print("pushing image to matrix") matrix.SwapOnVSync(offscreen_canvas) + print("pushing image done") # Save the image to a file with the desired format and file name # new_image.save("output/frameNumber"+str(frameCount)+".png") - frameCount += 1 + frameCount += 1 + # new_image.save("output/frameNumber"+str(frameCount)+".png") elapsed_time = time.time() - start_time # Calculate time elapsed during rendering @@ -285,11 +340,12 @@ class RenderingLayer: print("remaining time in frame: " + str(sleep_time)) if sleep_time > 0: time.sleep(sleep_time) - print("average time cost per part for transition frames:") - print("devisiontime :" + str(devisiontime /transitionFrameCount )) - print("pairgrouptime :" + str(pairgrouptime /transitionFrameCount)) - print("pairpointtime :" + str(pairpointtime /transitionFrameCount)) - print("imagingtime :" + str(imagingtime /transitionFrameCount)) + # print("average time cost per part for transition frames:") + # print("devisiontime :" + str(devisiontime /transitionFrameCount )) + # print("pairgrouptime :" + str(pairgrouptime /transitionFrameCount)) + # print("pairpointtime :" + str(pairpointtime /transitionFrameCount)) + # print("interpolatetime :" + str(interpolatetime /transitionFrameCount)) + # print("imagingtime :" + str(imagingtime /transitionFrameCount)) devisiontime = 0 @@ -345,7 +401,7 @@ def main(): mqtt_client.loop_start() # Initialize the rendering layer - rendering_layer = RenderingLayer(animations, frame_rate=10) + rendering_layer = RenderingLayer(animations, frame_rate=40) rendering_thread = threading.Thread(target=rendering_layer.start_rendering) rendering_thread.start() diff --git a/yaml parse test/testAnimationYaml.yaml b/yaml parse test/testAnimationYaml.yaml index b639bdc..b4165a9 100644 --- a/yaml parse test/testAnimationYaml.yaml +++ b/yaml parse test/testAnimationYaml.yaml @@ -41,16 +41,16 @@ animations: graphics: - type: transition # close the eye from whatever the current state - to_file: dizzyFace.png - duration: 5 + to_file: eyesClosed_neutral.png + duration: 6 - type: image # hold eye closed - source_file: dizzyFace.png + source_file: eyesClosed_neutral.png duration: 10 - type: transition # open the eye again from being closed to_file: neutral.png - duration: 5 + duration: 6 - name: openEye description: Animation for blinking @@ -65,9 +65,21 @@ animations: source_file: eyesClosed_neutral.png duration: 1 - - type: transition # open the eye again from being closed + - type: transition to_file: dizzyFace.png - duration: 5 + duration: 10 + + - type: transition + to_file: angryFace.png + duration: 10 + + - type: transition + to_file: loveFace.png + duration: 10 + + - type: transition + to_file: neutral.png + duration: 10 - name: make dizzy description: Animation for making dizzy diff --git a/yaml parse test/util.py b/yaml parse test/util.py new file mode 100644 index 0000000..025545c --- /dev/null +++ b/yaml parse test/util.py @@ -0,0 +1,13 @@ +from time import time + +def timer(func): + # This function shows the execution time of + # the function object passed + def wrap_func(*args, **kwargs): + t1 = time() + result = func(*args, **kwargs) + t2 = time() + print(f'Function {func.__name__!r} execution: {(t2-t1):.4f}s') + return result + return wrap_func + \ No newline at end of file