Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_PCL.PointCloud with 3D transform apply, and testing #876

Merged
merged 5 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
Major change news in Caesar.jl
# NEWS Caesar.jl

# Changes in v0.13
Major changes and news in Caesar.jl.

## Changes in v0.13

- Finally adding a NEWS.md to Caesar.jl.
- Standardize all Manifolds.jl representations to use `SciML/ArrayPartition` instead of `Manifold/ProductRepr`.
- Add `RobotOS / PyCall` based interface for writing bagfiles with `RosbagWriter`.
- Add `_PCL` export functions to go from `Caesar._PCL.PointCloud` out to `PCLPointCloud2` and `ROS.PointCloud2` types.
- Finally adding a NEWS.md to Caesar.jl.
- Refactored `ScatterAlign` to support both `ScatterAlignPose2` and `ScatterAlignPose3`.
- Improved `_PCL.apply` to now transform both 2D and 3D pointclouds using `Manifolds.SpecialEuclidean(2)` and `Manifolds.SpecialEuclidean(3)`.
- Added more testing on `_PCL` conversions and transforms.
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,17 @@ julia = "1.6"
AprilTags = "f0fec3d5-a81e-5a6a-8c28-d2b34f3659de"
BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004"
GraphPlot = "a2cc645c-3eea-5389-862e-a155d0052231"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RoMEPlotting = "238d586b-a4bf-555c-9891-eda6fc5e55a2"
RobotOS = "22415677-39a4-5241-a37a-00beabbbdae8"
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
ZMQ = "c2297ded-f4af-51ae-bb23-16f91089e4e1"

[targets]
test = ["AprilTags", "BSON", "Colors", "Gadfly", "GraphPlot", "Images", "PyCall", "Random", "RobotOS", "Test", "ZMQ"]
test = ["AprilTags", "BSON", "Colors", "FixedPointNumbers", "Gadfly", "GraphPlot", "Images", "PyCall", "Random", "RobotOS", "Serialization", "Test", "ZMQ"]
24 changes: 14 additions & 10 deletions src/3rdParty/_PCL/services/PointCloud.jl
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ function PointCloud(
# the slow way of building the point.data entry
ptdata = zeros(datatype, 4)
for (i,mapping) in enumerate(field_map)
@info "test" i mapping maxlog=3
# @info "test" i mapping maxlog=3
midx = trunc(Int,mapping.serialized_offset/mapping.size) + 1
# Copy individual points as columns from mat -- i.e. memcpy
# TODO copy only works if all elements have the same type -- suggestion, ptdata::ArrayPartition instead
Expand Down Expand Up @@ -328,15 +328,12 @@ end
# 2D, do similar or better for 3D
# FIXME, to optimize, this function will likely be slow
# TODO, consolidate with transformPointcloud(::ScatterAlign,..) function
function apply( M_::typeof(SpecialEuclidean(2)),
function apply( M_::Union{<:typeof(SpecialEuclidean(2)),<:typeof(SpecialEuclidean(3))},
rPp::Union{<:ProductRepr,<:Manifolds.ArrayPartition},
pc::PointCloud{T} ) where T
#

rTp = affine_matrix(M_, rPp)
pV = MVector(0.0,0.0,1.0)
_data = MVector(0.0,0.0,0.0,0.0)

# allocate destination
_pc = PointCloud(;header=pc.header,
points = Vector{T}(),
width=pc.width,
Expand All @@ -346,13 +343,20 @@ function apply( M_::typeof(SpecialEuclidean(2)),
sensor_orientation_=pc.sensor_orientation_ )
#

rTp = affine_matrix(M_, rPp)
nc = size(rTp,1)-1
pV = MVector(zeros(nc)...,1.0)
_data = MVector(0.0,0.0,0.0,0.0)

# rotate the elements from the old point cloud into new static memory locations
# NOTE these types must match the types use for PointCloud and PointXYZ
# TODO not the world's fastest implementation
for pt in pc.points
pV[1] = pt.x
pV[2] = pt.y
_data[1:3] .= rTp*pV
push!(_pc.points, PointXYZ(;color=pt.color, data=SVector{4,eltype(pt.data)}(_data[1], _data[2], pt.data[3:4]...)) )
pV[1:nc] = pt.data[1:nc]
_data[1:nc] = (rTp*pV)[1:nc]
_data[4] = pt.data[4]
npt = PointXYZ(;color=pt.color, data=SVector{4,eltype(pt.data)}(_data...))
push!(_pc.points, npt )
end

# return the new point cloud
Expand Down
89 changes: 88 additions & 1 deletion test/pcl/testPointCloud2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Colors
using Caesar
using BSON
using Serialization
using FixedPointNumbers

using Test
using Pkg
Expand Down Expand Up @@ -88,6 +90,27 @@ show(pc)
# @test isapprox( PointCloudRef[1][i,1:3], pt.data[1:3]; atol=1e-6)
# end

##

@info "test `apply` transform SpecialEuclidean(2) to 2D pointcloud."

M = SpecialEuclidean(2)
rPc = ArrayPartition([1.;0], [1 0; 0 1.])

pc_ = Caesar._PCL.apply(M, rPc, pc)


@test isapprox( [1-0,0,0], pc_.points[1].data[1:3], atol=5e-3)
@test isapprox( [1-1.56486,1.09851,0], pc_.points[2].data[1:3], atol=5e-3)
@test isapprox( [1-793.383,556.945,0], pc_.points[3].data[1:3], atol=5e-3)
@test isapprox( [1-0,0,0], pc_.points[4].data[1:3], atol=5e-3)
@test isapprox( [1-1.56148,1.10331,0], pc_.points[5].data[1:3], atol=5e-3)
@test isapprox( [1-788.548,557.169,0], pc_.points[6].data[1:3], atol=5e-3)
@test isapprox( [1-790.109,558.273,0], pc_.points[7].data[1:3], atol=5e-3)
@test isapprox( [1-791.671,559.376,0], pc_.points[8].data[1:3], atol=5e-3)
@test isapprox( [1-793.232,560.479,0], pc_.points[9].data[1:3], atol=5e-3)
@test isapprox( [1-794.794,561.583,0], pc_.points[10].data[1:3], atol=5e-3)


##
end
Expand All @@ -96,7 +119,10 @@ end
@testset "PandarXT test point cloud conversion test" begin
##

@warn "TODO, see testdata/_pandar_PCLPointCloud2.jldat which via `Serialization.serialize` of a `Caesar._PCL.PCLPointCloud2` object, at JL 1.7.3, CJL v0.13.1+"
# Alternative approach, see more hardcoded test data example (only .data writen to binary) for _PCLPointCloud2_15776.dat"
@info "Loading testdata/_pandar_PCLPointCloud2.jldat which via `Serialization.serialize` of a `Caesar._PCL.PCLPointCloud2` object, at JL 1.7.3, CJL v0.13.1+"
datafile = joinpath( pkgdir(Caesar), "test", "testdata", "_pandar_PCLPointCloud2.jldat")
pc2 = Serialization.deserialize(datafile)
# pc2.fields
# 6-element Vector{Caesar._PCL.PointField}:
# Caesar._PCL.PointField("x", 0x00000000, Caesar._PCL._PCL_FLOAT32, 0x00000001)
Expand All @@ -106,6 +132,67 @@ end
# Caesar._PCL.PointField("timestamp", 0x00000018, Caesar._PCL._PCL_FLOAT64, 0x00000001)
# Caesar._PCL.PointField("ring", 0x00000020, Caesar._PCL._PCL_UINT16, 0x00000001)

##

pc = Caesar._PCL.PointCloud(pc2)

@test UInt32(1) === pc.height
@test UInt32(58015) === pc.width
@test 58015 === length(pc.points)
@test pc.points[1] isa Caesar._PCL.PointXYZ{RGBA{FixedPointNumbers.N0f8}, Float32}
@test pc.is_dense
@test pc.header.seq === UInt32(24285)

# check actual points
@test isapprox( Float32[0.009075656, 3.714255, 0.99023366, 0.0], pc.points[1].data[1:4], atol=5e-3)
@test isapprox( Float32[0.008430854, 3.715781, 0.92004687, 0.0], pc.points[2].data[1:4], atol=5e-3)
@test isapprox( Float32[0.0084575275, 3.727537, 0.8534482, 0.0], pc.points[3].data[1:4], atol=5e-3)
@test isapprox( Float32[0.008463516, 3.7301762, 0.78552955, 0.0], pc.points[4].data[1:4], atol=5e-3)
@test isapprox( Float32[0.0032057164, 1.3119546, 0.25231096, 0.0], pc.points[5].data[1:4], atol=5e-3)

## convert back to PCLPointCloud2

@info "test back conversion from _PCL.PointCloud to _PCL.PCLPointCloud2, and again _PCL.PointCloud"

_pc2 = Caesar._PCL.PCLPointCloud2(pc)
_pc = Caesar._PCL.PointCloud(_pc2)

@test UInt32(1) === _pc.height
@test UInt32(58015) === _pc.width
@test 58015 === length(_pc.points)
@test _pc.points[1] isa Caesar._PCL.PointXYZ{RGBA{FixedPointNumbers.N0f8}, Float32}
@test _pc.is_dense
@test _pc.header.seq === UInt32(24285)

# check actual points
@test isapprox( Float32[0.009075656, 3.714255, 0.99023366, 0.0], _pc.points[1].data[1:4], atol=5e-3)
@test isapprox( Float32[0.008430854, 3.715781, 0.92004687, 0.0], _pc.points[2].data[1:4], atol=5e-3)
@test isapprox( Float32[0.0084575275, 3.727537, 0.8534482, 0.0], _pc.points[3].data[1:4], atol=5e-3)
@test isapprox( Float32[0.008463516, 3.7301762, 0.78552955, 0.0], _pc.points[4].data[1:4], atol=5e-3)
@test isapprox( Float32[0.0032057164, 1.3119546, 0.25231096, 0.0], _pc.points[5].data[1:4], atol=5e-3)


## test SpecialEuclidean(3) transform application

M = SpecialEuclidean(3)
rPc = ArrayPartition([-1;0;10.], [1 0 0; 0 1 0; 0 0 1.])

pc_3D = Caesar._PCL.apply(M, rPc, pc)


@test UInt32(1) === pc_3D.height
@test UInt32(58015) === pc_3D.width
@test 58015 === length(pc_3D.points)
@test pc_3D.points[1] isa Caesar._PCL.PointXYZ{RGBA{FixedPointNumbers.N0f8}, Float32}
@test pc_3D.is_dense
@test pc_3D.header.seq === UInt32(24285)

@test isapprox( Float32[-1+0.009075656, 3.714255, 10+ 0.99023366, 0.0], pc_3D.points[1].data[1:4], atol=5e-3)
@test isapprox( Float32[-1+0.008430854, 3.715781, 10+ 0.92004687, 0.0], pc_3D.points[2].data[1:4], atol=5e-3)
@test isapprox( Float32[-1+0.0084575275, 3.727537, 10+ 0.8534482, 0.0], pc_3D.points[3].data[1:4], atol=5e-3)
@test isapprox( Float32[-1+0.008463516, 3.7301762, 10+ 0.78552955, 0.0], pc_3D.points[4].data[1:4], atol=5e-3)
@test isapprox( Float32[-1+0.0032057164, 1.3119546,10+ 0.25231096, 0.0], pc_3D.points[5].data[1:4], atol=5e-3)


##
end
Expand Down
3 changes: 2 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ if TEST_GROUP in ["all", "basic_functional_group"]
include("testPose2AprilTag4Corner.jl")
include("testScatterAlignPose2.jl")
include("testStashing_SAP.jl")
include("multilangzmq/runtests.jl")
@error "restore ZMQ tests after deprecations in IIF"
# include("multilangzmq/runtests.jl")
end


Expand Down