Further optimisations and rustification of interpolation

Co-authored-by: Patrickfen <Patrickfen@users.noreply.github.com>
This commit is contained in:
CiscoTheWolf 2023-10-03 23:17:32 +02:00
parent 8447002de6
commit 9c008eb58d
10 changed files with 352 additions and 96 deletions

View file

@ -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 = []

View file

@ -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`
`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`

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,023 B

After

Width:  |  Height:  |  Size: 1,020 B

Binary file not shown.

View file

@ -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::<Vec<_>>();
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<Point>, points2: Vec<Point>) -> (Vec<usize>, Vec<usize
lsap::solve(points1.len(), points2.len(), &cost_matrix, false).unwrap()
}
pub fn flood_fill(point: Point, mut group: Vec<Point>, points: Vec<Point>) -> Vec<Point> {
pub fn flood_fill(point: Point, mut group: Vec<Point>, points: &[Point]) -> Vec<Point> {
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<Point>, points: Vec<Point>) -> 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<Point>) -> Vec<Vec<TuplePoint>> {
let mut groups = vec![];
let mut remaining = points.iter().filter(|p| p.x < 64).collect::<Vec<_>>();
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::<std::collections::VecDeque<_>>();
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<Vec<Point>>, set_b: Vec<Vec<Point>>) -> 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<Vec<Point>>, larger: Vec<Vec<Point>>) -> Vec<(Vec<TuplePoint>, Vec<TuplePoint>)> {
let smaller_center = smaller.iter().map(|v| centroid(v)).collect::<Vec<_>>();
let larger_center = larger.iter().map(|v| centroid(v)).collect::<Vec<_>>();
let mut map = std::collections::HashMap::<usize, Vec<usize>>::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<TuplePoint> {
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:?}");
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

View file

@ -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()

View file

@ -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

13
yaml parse test/util.py Normal file
View file

@ -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