|
30 | 30 | return pop(v) * inv(v[end])
|
31 | 31 | end
|
32 | 32 |
|
33 |
| -Base.@pure Base.isapprox(::PerspectiveMap, ::PerspectiveMap; kwargs...) = true |
| 33 | +Base.isapprox(::PerspectiveMap, ::PerspectiveMap; kwargs...) = true |
34 | 34 |
|
35 | 35 | """
|
36 |
| - cameramap(property = value, ...) |
| 36 | + cameramap() |
| 37 | + cameramap(scale) |
| 38 | + cameramap(scale, offset) |
37 | 39 |
|
38 | 40 | Create a transformation that takes points in real space (e.g. 3D) and projects
|
39 | 41 | them through a perspective transformation onto the focal plane of an ideal
|
40 | 42 | (pinhole) camera with the given properties.
|
41 | 43 |
|
42 |
| -All properties are optional. Valid properties include: |
| 44 | +The `scale` sets the scale of the screen. For a standard digital camera, this |
| 45 | +would be `scale = focal_length / pixel_size`. Non-square pixels are supported |
| 46 | +by providing a pair of scales in a tuple, `scale = (scale_x, scale_y)`. Positive |
| 47 | +scales represent a camera looking in the +z axis with a virtual screen in front |
| 48 | +of the camera (the x,y coordinates are not inverted compared to 3D space). Note |
| 49 | +that points behind the camera (with negative z component) will be projected |
| 50 | +(and inverted) onto the image coordinates and it is up to the user to cull |
| 51 | +such points as necessary. |
43 | 52 |
|
44 |
| - * `focal_length` (in physical units) |
45 |
| - * `pixel_size` (in physical units) or `pixel_size_x` and `pixel_size_y` |
46 |
| - * `offset_x` and `offset_y` (in pixels) |
47 |
| - * `origin` (a vector) and `orientation` (a rotation matrix) |
48 |
| -
|
49 |
| -By default, the camera looks towards the postive-`z` axis from `(0,0,0)` and |
50 |
| -the sign of the `x` and `y` components is preserved for objects in front of the |
51 |
| -camera (objects behind the camera are also projected and therefor inverted - it |
52 |
| -is up to the user to cull these as necessary). |
53 |
| -
|
54 |
| -If `origin` and `orientation` are specified, the camera is translated to `origin` |
55 |
| -and rotated by `orientation` before the perspective map is applied. |
| 53 | +The `offset = (offset_x, offset_y)` is used to define the origin in the imaging |
| 54 | +plane. For instance, you may wish to have the point (0,0) represent the top-left |
| 55 | +corner of your imaging sensor. This measurement is in the units after applying |
| 56 | +`scale` (e.g. pixels). |
56 | 57 |
|
57 | 58 | (see also `PerspectiveMap`)
|
58 | 59 | """
|
59 |
| -function cameramap(;focal_length = nothing, |
60 |
| - pixel_size = nothing, |
61 |
| - pixel_size_x = nothing, |
62 |
| - pixel_size_y = nothing, |
63 |
| - offset_x = nothing, |
64 |
| - offset_y = nothing, |
65 |
| - origin = nothing, |
66 |
| - orientation = nothing) |
67 |
| - |
68 |
| - trans = PerspectiveMap() |
69 |
| - |
70 |
| - if pixel_size === nothing # (this form of if-else-end is handled well by the compiler... the author is looking forward to v0.6 where !(::Bool) is pure...) |
71 |
| - else |
72 |
| - pixel_size_x = pixel_size |
73 |
| - pixel_size_y = pixel_size |
74 |
| - end |
75 |
| - |
76 |
| - # Apply camera rotations, if necessary |
77 |
| - if origin === nothing && orientation === nothing |
78 |
| - else |
79 |
| - trans = trans ∘ inv(AffineMap(orientation, origin)) |
80 |
| - end |
81 |
| - |
82 |
| - # Apply camera scaling, if necessary |
83 |
| - if isa(focal_length, Void) && isa(pixel_size_x, Void) && isa(pixel_size_y, Void) |
84 |
| - else |
85 |
| - trans = LinearMap(UniformScaling(focal_length/pixel_size)) ∘ trans |
86 |
| - end |
87 |
| - |
88 |
| - # Apply pixel offset, if necessary |
89 |
| - if isa(offset_x, Void) && isa(offset_y, Void) |
90 |
| - else |
91 |
| - trans = Translation(SVector(-offset_x, -offset_y)) ∘ trans |
92 |
| - end |
93 |
| - |
94 |
| - return trans |
95 |
| -end |
| 60 | +cameramap() = PerspectiveMap() |
| 61 | +cameramap(scale::Number) = |
| 62 | + LinearMap(UniformScaling(focal_length/pixel_size)) ∘ PerspectiveMap() |
| 63 | +cameramap(scale::Tuple{Number, Number}) = |
| 64 | + LinearMap(SMatrix{2,2}(scale[1],0,0,scale[2])) ∘ PerspectiveMap() |
| 65 | +cameramap(scale::Number, offset::Tuple{Number,Number}) = |
| 66 | + AffineMap(UniformScaling(focal_length/pixel_size), SVector(-offset[1], -offset[2])) ∘ PerspectiveMap() |
| 67 | +cameramap(scale::Tuple{Number, Number}, offset::Tuple{Number,Number})) = |
| 68 | + AffineMap(SMatrix{2,2}(scale[1],0,0,scale[2]), SVector(-offset[1], -offset[2]))) ∘ PerspectiveMap() |
0 commit comments