raysect / source

The main source repository for the Raysect project.
http://www.raysect.org
BSD 3-Clause "New" or "Revised" License
86 stars 23 forks source link

Help: Modelling diffuse reflectance from a known emitter and capture with camera #431

Open a-mruiz opened 3 months ago

a-mruiz commented 3 months ago

Hello!,

First of all, thank you for this amazing software. I'm digging more and more into what it can do, and it's really wonderful.

I am working on a project involving a multispectral camera, which I believe can be modeled using Raysect. The problem is as follows:

I have a 2D surface that emits spectra (which I have already characterized) in known directions. If the surface is divided into voxels, each voxel emits a different spectrum with little variations depending on the angle it is emitting angle.

Then, I have a multispectral camera that captures the light emitted from this surface.

To illustrate, I've included this diagram: image

What I aim to achieve is the resulting spectra for each pixel in the camera, which will vary depending on the distance and the angle of the camera with respect to the surface.

I include also the latest code that I have, I've been trying to make this work but I'm unable. In the comments of the code, I include the key points in which I do not know how to carry on.

Thank you for your assistance.

Best regards.

# Emitter dimensions
Nx = 50
Nz = 50

# known emission spectra and wavelengths (for now imagine that all voxels and all directions emit the same spectra)
known_spectra = [0.66, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0]
wavelengths = [650, 660, 670, 680, 690, 700, 710, 720]

# 1.- Create a custom material that emits the known spectra
# ---------------------------------------------------------
# What i understand from this is:
# 1. This creates a custom material that emits the given spectra (known_spectra) -> Question: How to set the wavelengths of that spectra?
# 2. The cosine argument is the cosine of the angle between the normal of the surface and the direction of the light ray, such that the emission can be anisotropic (such as a Lambertian surface).
#       However, do i need to provide this argument? or this is provided elsewhere from the library (for example when computing the ray from the emission voxel to the camera)?
# 3. This is a material for 1 homogeneous area, if i need like a surface that emits different spectra in different areas, i need to create a material for each area? How to do that?
class CustomEmitterMaterial(AnisotropicSurfaceEmitter):
    def emission_function(self, spectrum, cosine, back_face):
        spectrum.samples[:] = known_spectra
        return spectrum

# 2.- Create a box with the custom material
# ------------------------------------------
# The same as before, this box will emit the known spectra in all the areas of the faces? No way to provide like a map of the spectra to emit?
emitterAnisotropic = Box(
    lower=Point3D(0, 0, 0),
    upper=Point3D(Nx, 0.1, Nz),
    material=CustomEmitterMaterial(),
    transform=rotate(0, 0, 0),
    name="Known diffuse reflectance",
)

# 3. Add Observer
# --------------
#! Q: How to add an observer to the scene that captures the light emitted by the box in the different wavelengths?
camera = PinholeCamera((384, 384), transform=translate(25, 90, 25) * rotate_x(90), pipelines=[SpectralRadiancePipeline2D()])
camera.fov = 45
camera.pixel_samples = 100
camera.pipelines[0].accumulate = False

# 4. Add the objects to the world
world = World()
emitterAnisotropic.parent = world
camera.parent = world

# 5. Observe
# ----------
# This is raising  "could not broadcast input array from shape (8,) into shape (15,)", which I imagine comes from the material definition having 8 samples,
# however, i don't know how to set the number of wavelengths (samples) to be the same as the material (known_spectra)
camera.observe()

# 6. Lastly, how can i obtain like multiespectral cube from the camera? I mean, a cube in which for each pixel of the camera sensor i have the spectral information of the light that hit that pixel.