Description Usage Arguments Details Value References See Also Examples

View source: R/colorSpec.product.R

Take a sequence of **colorSpec** objects and compute their product.
The product is associative.
Only certain types of sequences are allowed, see **Details**.

1 2 |

`...` |
Unnamed arguments are |

To explain the allowable product sequences it is helpful to introduce some simple notation for the objects:

notation | colorSpec `type` | description of the object |

L | `light` | a light source |

M | `material` | a material |

R_L | `responsivity.light` | a light responder (aka detector) |

R_M | `responsivity.material` | a material responder |

It is also helpful to define a sequence of positive integers
to be *conformable* iff it has at most one value greater than 1.
For example,
a sequence of all 1s is conformable. A sequence of all *q*'s is conformable.
The sequences `c(1,3)`

and `c(1,1,4,1,1,4,1)`

are conformable,
but `c(1,1,4,1,3,4,1)`

is not.

There are 6 types of sequences for which the product is defined:

1. * M_1 * M_2 * ... * M_m * ↦ *M'*

The product of *m* materials is another material.
Think of a stack of *m* transmitting filters effectively forming a new filter.
If we think of each object as a matrix (with the spectra in the columns),
then the product is element-by-element using **R**'s `*`

- the Hadamard product.
The numbers of spectra in the terms must be conformable.
If some objects have 1 spectrum and all the others have *q*,
then the column-vector spectrums are repeated *q* times to form a
matrix with *q* columns.
If the numbers of spectra are not conformable,
it is an ERROR and the function returns `NULL`

.

As an example, suppose *M_1* has 1 spectrum and *M_2* has *q* spectra,
and *m=2*.
Then the product is a material with *q* spectra.
Think of an IR-blocking filter followed by the RGB filters in a 3-CCD camera.

2. * L * M_1 * M_2 * ... * M_m * ↦ *L'*

The product of a light source followed by *m* materials is a light source.
Think of a light source
followed by a stack of *m* transmitting filters, effectively forming a new light source.
The numbers of spectra in the terms must be conformable as in sequence 1,
and the matrices are multiplied element by element.

As an example, suppose *L* has 1 spectrum and *M_1* has *q* spectra,
and *m=1*.
Then the product is a light source with *q* spectra.
Think of a light source followed by a filter wheel with *q* filters.

3. * M_1 * M_2 * ... * M_m * R_L * ↦ *R_L'*

The product of *m* materials followed by a light responder, is a light responder.
Think of a stack of *m* transmitting filters in front of a camera, effectively forming a new camera.
The numbers of spectra in the terms must be conformable as in sequence 1,
and the matrices are multiplied element by element.

As an example, suppose *R_L* has 1 spectrum and *M_1* has *q* spectra,
and *m=1*.
Then the product is a light responder with *q* spectra.
Think of a 3-CCD camera in which all 3 CCDs have exactly the same responsivity
and so can be modeled with a single object *R_L*.

4. * L * M_1 * M_2 * ... * M_m * R_L * ↦ *matrix*

The product of a light source, followed by *m* materials,
followed by a light responder, is a matrix!
The numbers of spectra in the terms must splittable into
a conformable left part (*L'* from sequence 2.)
and a conformable right part (*R_L'* from sequence 3.).
There is a row for each spectrum in *L'*,
and a column for each spectrum in *R_L'*.
Suppose the element-by-element product of the left part is
*n*×*p*
and the element-by-element product of the right part is
and *n*×*q*,
where *n* is the number of wavelengths.
Then the output matrix is the usual matrix product `%*%`

of the transpose of the left part times and right part,
which is *p*×*q*.

As an example, think of a light source followed by a
reflective color target with 24 patches
followed by an RGB camera.
The sequence of spectra is `c(1,24,3)`

which is splittable into `c(1,24)`

and `c(3)`

.
The product matrix is 24×3.
See the **gallery** vignette for a worked-out example.

Note that is OK for there to be no materials in this product;
it is OK if *m=0*.
See the **blueflame** vignette for a worked-out example.

5. *L * M_1 * ... ** • ** ... * M_m * R_L * ↦ *R_M'*

This is the strangest product.
The bullet symbol • means that a variable material is inserted at that slot
in the sequence (or light path).
For each material spectrum inserted there is a response from *R_L*.
Therefore the product of this sequence is a material responder *R_M*.
Think of a light source *L* going through
a transparent object • on a flatbed scanner and into a camera *R_L*.
For more about the mathematics of this product,
see the **colorSpec-guide.pdf** in the doc directory.
These material responder spectra are the same as the
*effective spectral responsivities* in Digital Color Management.
The numbers of spectra in the terms must be conformable as in sequence 1.

In the function `product()`

the location of the • is marked
by any character string whatsoever - it's up to the user who might choose
something that describes the typical material.
For example one might choose:

`scanner = product( A.1nm, 'photo', Flea2.RGB, wave='auto') `

to model a scanner that is most commonly used to scan photographs.
Other possible strings could be `'artwork'`

, `'varmaterial'`

,
or even `'slot'`

.
See the **gallery** vignette for a worked-out example.

6. * M_1 * M_2 * ... * M_m * R_M * ↦ *matrix*

The product of *m* materials followed by a material responder, is a matrix !
The sequence of numbers of spectra must be splittable into left and right
parts as in sequence 4, and the product matrix is formed the same way.
One reason for computing this matrix in 2 steps is that one can
`calibrate`

the material responder separately in a customizable way.
See the **gallery** vignette for a worked-out example with a flatbed scanner.

Note that sequences 4. and 6. are the only ones that
use the usual matrix product `%*%`

.

The argument `wavelength`

can also be `'auto'`

or `NULL`

.
In this case the intersection of all the wavelength ranges of the objects is computed.
If the intersection is empty, it is an ERROR and the function returns `NULL`

.
The wavelength step `step.wl`

is taken to be the smallest over all the object wavelength sequences.
If the minimum `step.wl`

is less than 1 nanometer,
it is rounded off to the nearest power of 2 (e.g 1, 0.5, 0.25, ...).

Although the function signature shows the colorSpec objects,
followed by `wavelength`

, followed by more arguments,
actually they can come in any order.
The unnamed arguments are taken to be colorSpec objects
and the named arguments are taken to be arguments for `resample`

.

`product()`

returns a **colorSpec** object or a matrix, see **Details**.
In case of a **colorSpec** object, the `organization`

is
`'matrix'`

or `'vector'`

; any `extradata`

is lost.
However, all terms in the product are saved in `attr(*,'sequence')`

.
One can use `str`

to inspect this attribute.

All terms are converted to `radiometric`

on-the-fly and the returned
**colorSpec** object is also radiometric.

In case of ERROR it returns `NULL`

.

Edward J. Giorgianni and Thomas E. Madden.
**Digital Color Management: Encoding Solutions.** 2nd Edition
John Wiley. 2009.
Figure 10.11a. page 141.

Wikipedia.
**Hadamard product (matrices)**.
http://en.wikipedia.org/wiki/Hadamard_product_%28matrices%29

`wavelength`

,
`type`

,
`resample`

,
`calibrate`

,
`radiometric`

,
`step.wl`

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ```
# sequence 1.
path = system.file( "extdata/objects/Midwest-SP700-2014.txt", package='colorSpec' )
blocker.IR = readSpectra( path )
product( blocker.IR, Hoya, wave='auto' )
# sequence 2.
product( subset(solar.irradiance,1), atmosphere2003, blocker.IR, Hoya, wave='auto' )
# sequence 3.
plumbicon = readSpectra( system.file( "extdata/cameras/plumbicon30mm.txt", package='colorSpec' ) )
product( blocker.IR, subset(Hoya,1:3), plumbicon, wave='auto' )
# sequence 4.
product( D65.1nm, Flea2.RGB ) # a 1x3 matrix, no materials
product( D65.1nm, neutralMaterial(0.01), Flea2.RGB, wave='auto' ) # a 1x3 matrix, 1 material
path = system.file( "extdata/sources/Lumencor-SpectraX.txt", package='colorSpec' )
lumencor = readSpectra( path, wave=340:660 )
product( lumencor, Flea2.RGB, wave='auto' ) # a 7x3 matrix, no materials
# sequence 5.
# make an RGB scanner
bluebalancer = subset(Hoya,'LB')
# combine tungsten light source A.1nm with blue light-balance filter
# use the string 'artwork' to mark the variable material slot
scanner = product( A.1nm, bluebalancer, 'artwork', Flea2.RGB, wave='auto' )
# sequence 6.
scanner = calibrate( scanner )
target = readSpectra( system.file( "extdata/targets/N130501.txt", package='colorSpec') )
product( target, scanner, wave='auto' ) # a 288x3 matrix
``` |

Embedding an R snippet on your website

Add the following code to your website.

For more information on customizing the embed code, read Embedding Snippets.