Documentation ¶
Index ¶
- Variables
- func AlignLayer(cfg Config, l1, l2 *Layer)
- func ColToGrayU16(c color.Color) uint16
- func DevelopByDNG(cfg Config, p *Pixel)
- func DevelopByLayer(cfg Config, p *Pixel)
- func DevelopByNone(cfg Config, p *Pixel)
- func DevelopByWhiteBalanceOnly(cfg Config, p *Pixel)
- func FuseByAverage(cfg Config, p *Pixel)
- func FuseByPickMostExposed(cfg Config, p *Pixel)
- func FuseBySector(cfg Config, p *Pixel)
- func GrowRectangle(r image.Rectangle, p image.Point) image.Rectangle
- func ImgDiff(cfg Config, l1, l2 *Layer, passName string, xform AlignmentTransform) float64
- func ListTonemappers() string
- func RectCenter(b image.Rectangle) image.Point
- func WritePNG(img image.Image, filename string) error
- type AlignmentTransform
- type Config
- type ExposureValue
- type FusedImage
- func (fi *FusedImage) AddLayer(l Layer)
- func (fi *FusedImage) Align()
- func (fi *FusedImage) ApplyTonemapper(op tmo.ToneMappingOperator, name string)
- func (fi FusedImage) At(x, y int) color.Color
- func (fi FusedImage) Bounds() image.Rectangle
- func (fi *FusedImage) CalculateInputArea() image.Rectangle
- func (fi FusedImage) ColorModel() color.Model
- func (fi *FusedImage) Fuse()
- func (fi FusedImage) HDRAt(x, y int) hdrcolor.Color
- func (fi *FusedImage) LoadFilesAndDirs(args ...string) error
- func (fi *FusedImage) Pix(x, y int) Pixel
- func (fi *FusedImage) PixRW(x, y int) *Pixel
- func (fi *FusedImage) SetupTonemapper(name string) tmo.ToneMappingOperator
- func (fi FusedImage) Size() int
- func (fi FusedImage) String() string
- func (fi *FusedImage) Tonemap()
- func (fi *FusedImage) WriteToHDR(filename string) error
- type Layer
- type LunarLimb
- type Pixel
- type PixelFunc
Constants ¶
This section is empty.
Variables ¶
var DebugPixels = []image.Point{} // Things in here get dumped in detail
var (
Tonemappers = []string{"drago03", "durand", "fattal02", "icam06", "linear", "reinhard05"}
)
Functions ¶
func AlignLayer ¶
AlignLayer figures out the transform that aligns `l2` to `l1`. it then uses it to generate l2.Image, which will be pixel-aligned with l1.Image.
func ColToGrayU16 ¶
Col2GrayU16 maps a color into a gray value in the range [0, 0xFFFF]. If we had more of a handle on the color, maybe we'd map it to XYZ and pick out the luminance; but this works just fine.
func DevelopByDNG ¶
DevelopDNG follows the DNG spec's algorithm for mapping a CameraNative sensor reading into a camera-neutral XYZ(D50) color, and then into a standard sRGB(D65) output color. This requires data from the camera, that is written into the DNG files - AsShotNeutral (the white balance correction) - ForwardMatrix (the camera's color correction matrix)
func DevelopByLayer ¶
DevelopAsLayer is for debugging - it colors the pixel based on which layer it came from. (White balances it too)
func DevelopByNone ¶
func FuseByAverage ¶
FuseByAverage averages the non-overexposed layers together. It produces poor results, with notable color fringes forming near the boundary of each layer's area.
func FuseByPickMostExposed ¶
FuseByPickMostExposed is the default algorithm for image fusion: look for the image that is most-exposed (i.e. has received the most photons and will thus have lowest noise), but not over-exposed at this pixel (e.g. no channel more than ~80%).
func FuseBySector ¶
FuseBySector cuts up the image into pie slices, and simply picks a source layer based on which pie segment the pixel lies inside. It's useful for comparing the source images to see how well they've been aligned.
func ImgDiff ¶
func ImgDiff(cfg Config, l1, l2 *Layer, passName string, xform AlignmentTransform) float64
ImgDiff compares two images, and returns an error metric; the less similar, the higher the value. It figures out the difference in XYZ luminance for each pixel (after normalizing for EV differences), and returns the average per-lotsof-pixels difference across the set of compared pixels.
If the pixel in either image is too dim or too bright on any channel, it is ignored, so we only really compare the subset of corona pixels that both images have a reasonable exposure for.
func ListTonemappers ¶
func ListTonemappers() string
Types ¶
type AlignmentTransform ¶
type AlignmentTransform struct { Name string TranslateByX float64 TranslateByY float64 RotationCenterX float64 RotationCenterY float64 RotateByDeg float64 ErrorMetric float64 }
An AlignmentTransform maps a pixel location in a later layer to a pixel location in the base layer, that corresponds to the same point in the sky.
If you use an equatorial mount, this is all redundant.
func AlignLayerFine ¶
func AlignLayerFine(cfg Config, l1, l2 *Layer, baseXform AlignmentTransform) AlignmentTransform
AlignLayerFine tries a wide range of possible finetune xforms in parallel, to find out which one fits best (i.e. has lowest error metric).
func (AlignmentTransform) String ¶
func (xform AlignmentTransform) String() string
func (AlignmentTransform) ToMatrix ¶
func (at AlignmentTransform) ToMatrix() emath.Aff3
func (AlignmentTransform) XFormImage ¶
func (xform AlignmentTransform) XFormImage(src image.Image) image.Image
type Config ¶
type Config struct { Verbosity int ManualOverrideAsShotNeutral emath.Vec3 // A white/neutral color in camera native RGB space ManualOverrideForwardMatrix emath.Mat3 // Maps white-balanced camera native RGB into XYZ(D50). DoEclipseAlignment bool DoFineTunedAlignment bool OutputWidthInSolarDiameters float64 Fuser string Developer string Tonemapper string FuserLuminance float64 // a var used by the fuser Alignments map[string]AlignmentTransform // Values we figure out elsewhere, and put here for access by rest of app CameraWhite emath.Vec3 // From a DNG file Layer{}, or overrides CameraToPCS emath.Mat3 // From a DNG file Layer{}, or overrides InputArea image.Rectangle OutputArea image.Rectangle }
func (Config) GetDeveloper ¶
type ExposureValue ¶
type ExposureValue struct { ISO int // 100, 800, etc. ApertureX10 int // f/5.6 is the integer 56. ShutterSpeed rat64 // 1/500, 1/1000, etc. EV int // The final EV value - https://en.wikipedia.org/wiki/Exposure_value // This is the only value used downstream; it is used to scale the // pixel values during image fusion. IlluminanceAtMaxExposure float64 // How many lux generate a channel exposure == 0xFFFF }
An ExposureValue details how the photograph was exposed, and allows us to figure out how much physical illumination (cd/m^2) was hitting the sensor, given a pixel color from the image.
This type figures out an 'EV' value, basicaly how many 'stops'; but it rounds off the shutterspeed & aperture-fnumber to the values that are "whole" stops.
func (ExposureValue) String ¶
func (ev ExposureValue) String() string
func (*ExposureValue) Validate ¶
func (ev *ExposureValue) Validate() error
type FusedImage ¶
type FusedImage struct { Config Layers []Layer // Ordered, ascending EV (descending "number of photons needed to fully expose") Pixels []Pixel }
FusedImage holds the image layers, and fuses them into a single image. Implements the image.Image interface.
func NewFusedImage ¶
func NewFusedImage() FusedImage
func (*FusedImage) AddLayer ¶
func (fi *FusedImage) AddLayer(l Layer)
func (*FusedImage) Align ¶
func (fi *FusedImage) Align()
Align does all the work to figure out how to align the various layers, and generates the final transformed image for each layer.
func (*FusedImage) ApplyTonemapper ¶
func (fi *FusedImage) ApplyTonemapper(op tmo.ToneMappingOperator, name string)
func (FusedImage) Bounds ¶
func (fi FusedImage) Bounds() image.Rectangle
func (*FusedImage) CalculateInputArea ¶
func (fi *FusedImage) CalculateInputArea() image.Rectangle
func (*FusedImage) Fuse ¶
func (fi *FusedImage) Fuse()
Fuse looks at the various layers for each pixel, and figures out a final merged value for that pixel. There are a few algorithms to pick from. Then it normalizes the brightness, so each pixel has the same EV. Finally it does color development, white balance etc.
func (*FusedImage) LoadFilesAndDirs ¶
func (fi *FusedImage) LoadFilesAndDirs(args ...string) error
func (*FusedImage) PixRW ¶
func (fi *FusedImage) PixRW(x, y int) *Pixel
func (*FusedImage) SetupTonemapper ¶
func (fi *FusedImage) SetupTonemapper(name string) tmo.ToneMappingOperator
Tweak the tmo parameters to better handle eclipse photos. By default, they almost always overexpose on the small but important bright areas.
func (FusedImage) Size ¶
func (fi FusedImage) Size() int
func (FusedImage) String ¶
func (fi FusedImage) String() string
func (*FusedImage) Tonemap ¶
func (fi *FusedImage) Tonemap()
func (*FusedImage) WriteToHDR ¶
func (fi *FusedImage) WriteToHDR(filename string) error
WriteToHDR outputs a HDR image. You can load this into photoshop or other HDR tools.
type Layer ¶
type Layer struct { LoadFilename string LoadedImage image.Image // The original photo image // Data we exctract from image metadata ExposureValue // The exposure value for the photo CameraWhite emath.Vec3 // A white/neutral color for the photo, given the color temp / white balance CameraToPCS emath.Mat3 // Maps camera native color to PCS (CIEXYZ(D50?), incl. white balancing // Data we compute LunarLimb // Our guess at where the moon is in the photo AlignmentTransform // How to map a point from the base image into this image // _This_ image is aligned across layers, so a pixel at [x,y] relates to the same bit of sky on every layer image.Image }
A Layer holds an image.Image loaded from an input file, with extra stuff that allow us to fuse the exposures
type LunarLimb ¶
type LunarLimb struct { LuminalCenter image.Point // The luminance-weighted "center" of the image. Hopefully will be inside the limb. Brightness uint16 // A rough average of the brightness of the pixels in the limb (floodfill needs to know this) Bounds image.Rectangle // A box around the limb }
The LunarLimb is the shadow/outline of the moon. We identify it and use it as a starting point for aligning images.
func FindLunarLimb ¶
FindLunarLimb returns a Rectangle that bounds the lunar limb, the outline of the moon. This is a fairly dumb routine; it finds the centroid of all the luminance in the image, assumes that is inside the lunar limb, and then floodfills out until it sees some bright pixels.
type Pixel ¶
type Pixel struct { OutputPos image.Point // In output coords RawInputs []color.Color In []ecolor.CameraNative Fused ecolor.CameraNative // The single CameraNative pixel fused from the source images DevelopedRGB hdrcolor.RGB // The white balanced, color-corrected HDR RGB value TonemappedRGB color.Color // The final LDR output, after HDR->LDR tonemapping LayerNumber int // which layer used; or how many layers used }