Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feature/fisheye
Browse files Browse the repository at this point in the history
  • Loading branch information
aelmiger committed Jan 6, 2025
2 parents 50d6bc2 + 55b5111 commit 96fffb7
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 82 deletions.
83 changes: 57 additions & 26 deletions .github/workflows/deploy_to_pypi.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI

on: push
on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
auto-tag:
name: Create and push tag
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
outputs:
new_tag: ${{ steps.create_tag.outputs.new_tag }}
version: ${{ steps.get_version.outputs.VERSION }}

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version from pyproject.toml
id: get_version
run: |
VERSION=$(grep '^version =' pyproject.toml | awk -F'"' '{print $2}')
echo "VERSION=v$VERSION" >> $GITHUB_OUTPUT
- name: Create and push tag
id: create_tag
run: |
if ! git rev-parse ${{ steps.get_version.outputs.VERSION }} >/dev/null 2>&1; then
git config user.name github-actions
git config user.email github-actions@github.com
git tag ${{ steps.get_version.outputs.VERSION }}
git push origin ${{ steps.get_version.outputs.VERSION }}
echo "new_tag=true" >> $GITHUB_OUTPUT
else
echo "new_tag=false" >> $GITHUB_OUTPUT
fi
build:
name: Build distribution 📦
needs: [auto-tag]
runs-on: ubuntu-latest
if: >
github.event_name == 'pull_request' ||
(github.event_name == 'push' && needs.auto-tag.outputs.new_tag == 'true')
steps:
- uses: actions/checkout@v4
Expand All @@ -28,17 +66,15 @@ jobs:
path: dist/

publish-to-pypi:
name: >-
Publish Python 🐍 distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
needs:
- build
name: Publish Python 🐍 distribution 📦 to PyPI
needs: [auto-tag, build]
if: needs.auto-tag.outputs.new_tag == 'true'
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/syclops
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
id-token: write

steps:
- name: Download all the dists
Expand All @@ -50,16 +86,13 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1

github-release:
name: >-
Sign the Python 🐍 distribution 📦 with Sigstore
and upload them to GitHub Release
needs:
- publish-to-pypi
name: Sign and upload to GitHub Release
needs: [auto-tag, publish-to-pypi]
if: needs.auto-tag.outputs.new_tag == 'true'
runs-on: ubuntu-latest

permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
id-token: write # IMPORTANT: mandatory for sigstore
contents: write
id-token: write

steps:
- name: Download all the dists
Expand All @@ -68,7 +101,7 @@ jobs:
name: python-package-distributions
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@v1.2.3
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: >-
./dist/*.tar.gz
Expand All @@ -78,32 +111,29 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
run: >-
gh release create
'${{ github.ref_name }}'
'${{ needs.auto-tag.outputs.version }}'
--repo '${{ github.repository }}'
--notes ""
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
'${{ github.ref_name }}' dist/**
'${{ needs.auto-tag.outputs.version }}' dist/**
--repo '${{ github.repository }}'
publish-to-testpypi:
name: Publish Python 🐍 distribution 📦 to TestPyPI
needs:
- build
needs: [auto-tag, build]
if: >
github.event_name == 'pull_request' ||
(github.event_name == 'push' && needs.auto-tag.outputs.new_tag == 'true')
runs-on: ubuntu-latest

environment:
name: testpypi
url: https://test.pypi.org/p/syclops

permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
id-token: write

steps:
- name: Download all the dists
Expand All @@ -115,3 +145,4 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip_existing: true
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ readme = "README.md"
requires-python = ">=3.8"
license = {text = "GPLv3"}

version = "1.3.3"
version = "1.3.10"

dynamic = ["dependencies"]

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ filelock==3.9.0
GitPython==3.1.29
jsonschema==4.17.3
opencv-python==4.6.0.66
numpy==1.23.5
Pillow==9.4.0
PyYAML==6.0.1
requests==2.27.1
Expand Down
11 changes: 8 additions & 3 deletions syclops/blender/plugins/ground.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _setup_modifiers(self, ground):
bpy.context.object.modifiers["Subdivision"].subdivision_type = "SIMPLE"
bpy.context.object.modifiers["Subdivision"].levels = 2
bpy.context.object.cycles.use_adaptive_subdivision = True
bpy.context.object.cycles.dicing_rate = 2.0
bpy.context.object.cycles.dicing_rate = 1.0

def _setup_ground_material(self):
"""Configure the ground material."""
Expand All @@ -69,7 +69,7 @@ def _setup_ground_material(self):
self._configure_node_mappings(nodes, texture["texture_size"])
self._import_and_set_images(nodes, root_path, texture)
self._set_voronoi_scale(nodes)
self._set_displacement_scale(nodes, texture)
self._set_displacement_params(nodes, texture)

def _configure_node_mappings(self, nodes, texture_size):
scale = self.config["size"] / texture_size
Expand Down Expand Up @@ -101,11 +101,16 @@ def _set_voronoi_scale(self, nodes):
for node_name in ["Voronoi Texture", "Voronoi Texture.001"]:
nodes.get(node_name).inputs["Scale"].default_value = scale_value

def _set_displacement_scale(self, nodes, texture):
def _set_displacement_params(self, nodes, texture):
if "texture_displacement_scale" in texture:
nodes.get("Displacement").inputs["Scale"].default_value = float(
texture["texture_displacement_scale"]
)
if "texture_displacement_midlevel" in texture:
nodes.get("Displacement").inputs["Midlevel"].default_value = float(
texture["texture_displacement_midlevel"]
)


def _setup_ground_geometry(self):
"""Create a plane, scale and subdivide according to the ground size."""
Expand Down
2 changes: 1 addition & 1 deletion syclops/blender/sensor_outputs/keypoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def generate_output(self, parent_class: object):
if class_id is not None:
if "keypoints" in object_instance.object:
location = object_instance.matrix_world.translation
location = [round(x, 4) for x in location]
location = [round(x, 6) for x in location]
instance_id = self._calculate_instance_id(location)
for keypoint, pos in object_instance.object["keypoints"].items():
vec = mathutils.Vector((pos['x'], pos['y'], pos['z']))
Expand Down
6 changes: 4 additions & 2 deletions syclops/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"-o",
"--output-path",
help="Output path of generated files. Defaults to <install_folder>/output",
default="./output",
default=None,
)
parser.add_argument(
"-d",
Expand Down Expand Up @@ -225,7 +225,9 @@ def _wait_for_debugger():


def _run_syclops_job(args, install_folder: Path, job_description: Path):
output_path = _configure_output_path(install_folder / "output")
output_path = (_configure_output_path(Path(args.output_path).absolute())
if args.output_path
else _configure_output_path(install_folder / "output"))

job_filepath = job_description
asset_catalog_filepath = install_folder / "asset_catalog.yaml"
Expand Down
2 changes: 1 addition & 1 deletion syclops/schema/base_schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ definitions:
velocities:
type: object
properties:
translation:
location:
description: Translation velocity in meters per second
$ref: "#/definitions/vector_evaluation"
rotation:
Expand Down
12 changes: 11 additions & 1 deletion syclops/utility/blender_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,14 +398,15 @@ def convex_decomposition(
obj_pointer: ObjPointer,
conv_hull_collection_pointer: ObjPointer,
quality: float = 90,
max_hull_vertices: int = 100,
) -> List[bpy.types.Object]:
"""Decompose an object into convex hulls for physics simulation.
Args:
obj_pointer (ObjPointer): Pointer to object to decompose.
conv_hull_collection_pointer (ObjPointer): Pointer to collection to store convex hulls in.
quality (float, optional): Quality of the convex decomposition. Defaults to 90.
max_hull_vertices (int, optional): Maximum number of vertices in a convex hull. Defaults to 256.
Returns:
list[bpy.types.Object]: List of convex hulls.
"""
Expand Down Expand Up @@ -436,6 +437,15 @@ def convex_decomposition(
# Create the mesh data
mesh.from_pydata(convex_hull[0], [], convex_hull[1])

# Num vertices of mesh
num_vertices = len(mesh.vertices)
if num_vertices > max_hull_vertices:
decimate_factor = max_hull_vertices / num_vertices

# Decimate the mesh if it has too many vertices
decimate_mesh(convex_obj, decimate_factor)


# Update the mesh and object
mesh.update()
convex_obj.select_set(True)
Expand Down
71 changes: 25 additions & 46 deletions syclops/utility/keypoint_script.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,45 @@
"""
Script to be used inside of Blender to add keypoint information to 3d objects
"""

import bpy
import mathutils


# Function to get relative position
def get_relative_position(obj, target):
return target.matrix_world.inverted() @ obj.matrix_world.translation


# Function to create empties at keypoint positions relative to the mesh object
def create_empties_from_keypoints(mesh_object):
keypoints = mesh_object["keypoints"]
for key, pos in keypoints.items():
# Calculate the world position from the relative position
world_position = mesh_object.matrix_world @ mathutils.Vector(
(pos["x"], pos["y"], pos["z"])
)
# Create an empty and set its world position
world_position = mesh_object.matrix_world @ mathutils.Vector((pos["x"], pos["y"], pos["z"]))
bpy.ops.object.empty_add(location=world_position)
empty = bpy.context.active_object
empty.name = f"Keypoint_{key}"

empty.name = f"Keypoint_{mesh_object.name}_{key}"

def add_keypoints_to_mesh(mesh_object, empty_objects):
mesh_object["keypoints"] = {}
for index, empty in enumerate(empty_objects):
relative_pos = get_relative_position(empty, mesh_object)
mesh_object["keypoints"][str(index)] = {
"x": relative_pos.x,
"y": relative_pos.y,
"z": relative_pos.z,
}

# Main script
selected_objects = bpy.context.selected_objects
active_object = bpy.context.active_object

# Case 1: Multiple objects selected, last is a mesh
if len(selected_objects) > 1 and active_object.type == "MESH":
selected_objects.remove(active_object)
selected_objects.sort(key=lambda x: x.name)

keypoints = {}

for index, obj in enumerate(selected_objects):
if obj.type == "EMPTY":
relative_pos = get_relative_position(obj, active_object)
keypoints[str(index)] = {
"x": relative_pos.x,
"y": relative_pos.y,
"z": relative_pos.z,
}

if "keypoints" in active_object:
del active_object["keypoints"]

active_object["keypoints"] = keypoints
print("Key points added to", active_object.name)

# Case 2: Single mesh object with keypoints attribute
mesh_objects = [obj for obj in selected_objects if obj.type == "MESH"]
empty_objects = [obj for obj in selected_objects if obj.type == "EMPTY"]

if mesh_objects and empty_objects:
# Sort empty objects by name
empty_objects.sort(key=lambda x: x.name)

for mesh in mesh_objects:
add_keypoints_to_mesh(mesh, empty_objects)
print(f"Key points added to {mesh.name}")
elif len(selected_objects) == 1 and selected_objects[0].type == "MESH":
active_object = selected_objects[0]
if "keypoints" in active_object:
create_empties_from_keypoints(active_object)
print("Empties created from key points in", active_object.name)
print(f"Empties created from key points in {active_object.name}")
else:
print("No keypoints attribute found in", active_object.name)

print(f"No keypoints attribute found in {active_object.name}")
else:
print(
"Please select either multiple objects with a mesh as the active object, or a single mesh with a keypoints attribute."
)
print("Please select either multiple mesh objects and at least one empty, or a single mesh with a keypoints attribute.")
3 changes: 2 additions & 1 deletion syclops/utility/viewer_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def read_and_draw_bounding_boxes(img, bb_path):

bb_img = img.copy()
for line in lines:
_, x_center, y_center, width, height = map(float, line.split())
_, x_center, y_center, width, height, *_ = map(float, line.split())
x = int(x_center * img.shape[1] - width * img.shape[1] / 2)
y = int(y_center * img.shape[0] - height * img.shape[0] / 2)
w = int(width * img.shape[1])
Expand Down Expand Up @@ -127,6 +127,7 @@ def dataset_viewer(args):
object_positions_dict = json.load(f)
for _, poses in object_positions_dict.items():
location_list = [element["loc"] for element in poses]
rotation_list = [element["rot"] for element in poses]
positions_array = np.array(location_list, dtype=np.float32).reshape(
(-1, 3)
)
Expand Down

0 comments on commit 96fffb7

Please sign in to comment.