Skip to content

Commit

Permalink
Added support for automatic false color generation
Browse files Browse the repository at this point in the history
  • Loading branch information
racerxdl committed Mar 8, 2019
1 parent d5c0e24 commit 8a47f87
Show file tree
Hide file tree
Showing 59 changed files with 336 additions and 77 deletions.
5 changes: 4 additions & 1 deletion Demuxer/DirectDemuxer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ type DirectDemuxer struct {
demux *ccsds.Demuxer
}

func MakeDirectDemuxer(outFolder, tmpFolder string) *DirectDemuxer {
func MakeDirectDemuxer(outFolder, tmpFolder string, drawMap, reproject, falseColor bool) *DirectDemuxer {
d := &DirectDemuxer{}

d.demux = ccsds.MakeDemuxer()
d.demux.SetOutputFolder(outFolder)
d.demux.SetTemporaryFolder(tmpFolder)
d.demux.SetDrawMap(drawMap)
d.demux.SetReprojectImage(reproject)
d.demux.SetFalseColor(falseColor)

SLog.Info("Starting direct Demuxer with: ")
SLog.Info(" Output Folder: %s", aurora.Bold(outFolder).Green())
Expand Down
120 changes: 119 additions & 1 deletion ImageProcessor/GOESABI.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package ImageProcessor

import (
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/ImageData"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/ImageTools"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/Projector"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/Structs"
"github.com/opensatelliteproject/SatHelperApp/Logger"
"github.com/opensatelliteproject/SatHelperApp/Tools"
"github.com/opensatelliteproject/SatHelperApp/XRIT"
"github.com/opensatelliteproject/SatHelperApp/XRIT/Geo"
"os"
"path"
"path/filepath"
"regexp"
"strings"
)

var NOAANameRegex = regexp.MustCompile(`OR_ABI-(.*)-(.*)_(.*)_(s.*).*`)

const visChan = "C02"
const irChan = "C14"

func ProcessGOESABI(ip *ImageProcessor, filename string, xh *XRIT.Header) {
if xh.NOAASpecificHeader.ProductSubID == 0 { // Mesoscales and unknown data
PlainLRITImage(ip, filename, xh)
Expand Down Expand Up @@ -38,7 +49,114 @@ func ProcessGOESABI(ip *ImageProcessor, filename string, xh *XRIT.Header) {
delete(ip.MultiSegmentCache, name)

if purgeFiles {
ms.Purge()
if !ip.GetFalseColor() || !ms.FirstSegmentHeader.IsFalseColorPiece() {
ms.Purge()
}
}

if ms.FirstSegmentHeader.IsFalseColorPiece() {
folder := path.Dir(ms.FirstSegmentFilename)
nomapFile := path.Join(folder, ImageTools.GetNoMapName(ms.Name))
ProcessFalseColor(ip, ms.FirstSegmentHeader, nomapFile)
}
}
}

func ProcessFalseColor(ip *ImageProcessor, xh *XRIT.Header, filename string) {
if !NOAANameRegex.MatchString(path.Base(filename)) {
SLog.Debug("Filename %s does not match noaa name. Not continuing...", filename)
return
}

// 0 => full string, 1 => Level-Product, 2 => Mode/Channel, 3 => Satellite Name, 4 => Group, 5 => File Stamp
groups := NOAANameRegex.FindStringSubmatch(path.Base(filename))

mdch := groups[2]
md := mdch[:2]
name := groups[4]

vismdch := md + visChan
irmdch := md + irChan

visFilename := strings.Replace(filename, mdch, vismdch, -1)
irFilename := strings.Replace(filename, mdch, irmdch, -1)
fsclrFileName := strings.Replace(filename, mdch, md+"99", -1)
fsclrFileName = strings.Replace(fsclrFileName, "-nomap", "", -1)

if !Tools.Exists(visFilename) || !Tools.Exists(irFilename) {
// Not Ready
return
}

if Tools.Exists(fsclrFileName) {
SLog.Debug("Skipping generating false color. File exists...")
return
}

SLog.Info("Generating false color for %s", name)

vis, err := ImageTools.LoadImageGrayScale(visFilename)
if err != nil {
SLog.Error("Error loading visible image at %s: %s", visFilename, err)
return
}

ir, err := ImageTools.LoadImageGrayScale(irFilename)
if err != nil {
SLog.Error("Error loading infrared image at %s: %s", irFilename, err)
return
}

curveManipulator := ImageData.GetVisibleCurveManipulator()
falseLut := ImageData.GetFalseColorLUT()

err = curveManipulator.ApplyCurve(vis)
if err != nil {
SLog.Error("Error applying curve to visible image: %s", err)
return
}

fsclr, err := falseLut.Apply(vis, ir)
if err != nil {
SLog.Error("Error applying false color LUT: %s", err)
return
}

gc, err := Geo.MakeGeoConverterFromXRIT(xh)

if err == nil {
mapDrawer := ip.GetMapDrawer()

if mapDrawer != nil {
SLog.Debug("Map Drawer Enabled, drawing at FalseColor")
mapDrawer.DrawMap(fsclr, gc)
}

if ip.GetReproject() {
SLog.Debug("Reprojection Enabled, reprojecting FalseColor")
proj := Projector.MakeProjector(gc)
fsclr = proj.ReprojectLinearMultiThread(fsclr)
}
} else {
SLog.Error("Cannot crate GeoConverter: %s", err)
}

err = ImageTools.SaveImage(fsclrFileName, fsclr)
if err != nil {
SLog.Error("Error saving false color image to %s: %s", fsclrFileName, err)
return
}

SLog.Debug("Removing %s", visFilename)
err = os.Remove(visFilename)
if err != nil {
SLog.Error("Error erasing %s: %s", visFilename, err)
}
SLog.Debug("Removing %s", irFilename)
err = os.Remove(irFilename)
if err != nil {
SLog.Error("Error erasing %s: %s", irFilename, err)
}

SLog.Info("New image %s", fsclrFileName)
}
31 changes: 31 additions & 0 deletions ImageProcessor/ImageData/tools.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ImageData

import (
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/ImageTools"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/MapDrawer"
"github.com/opensatelliteproject/SatHelperApp/Logger"
"io/ioutil"
Expand All @@ -11,8 +12,11 @@ import (

const shpFileName = "ne_50m_admin_0_countries.shp"
const dbfFileName = "ne_50m_admin_0_countries.dbf"
const falseColorLutName = "wx-star.com_GOES-R_ABI_False-Color-LUT.png"

var mapDrawer *MapDrawer.MapDrawer
var fsclrLut *ImageTools.Lut2D
var visCurve *ImageTools.CurveManipulator

// ExtractShapeFiles extracts the shapefiles to temp folder and return path for shp file
func ExtractShapeFiles() (string, error) {
Expand Down Expand Up @@ -70,3 +74,30 @@ func GetDefaultMapDrawer() *MapDrawer.MapDrawer {

return mapDrawer
}

func GetVisibleCurveManipulator() *ImageTools.CurveManipulator {
if visCurve == nil {
visCurve = ImageTools.MakeDefaultCurveManipulator()
}

return visCurve
}

func GetFalseColorLUT() *ImageTools.Lut2D {
if fsclrLut == nil {
lutData, err := Asset(falseColorLutName)
if err != nil {
SLog.Error("Cannot load False Color LUT data: %s", err)
return nil
}
lut2d, err := ImageTools.MakeLut2DFromMemory(lutData)

if err != nil {
SLog.Error("Error creating False Color LUT: %s", err)
} else {
fsclrLut = lut2d
}
}

return fsclrLut
}
16 changes: 16 additions & 0 deletions ImageProcessor/ImageProcessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ImageProcessor

import (
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/ImageData"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/ImageTools"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/MapDrawer"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/Structs"
"github.com/opensatelliteproject/SatHelperApp/Logger"
Expand All @@ -19,6 +20,7 @@ type ImageProcessor struct {
mapDrawer *MapDrawer.MapDrawer
reproject bool
drawmap bool
falsecolor bool
}

func MakeImageProcessor() *ImageProcessor {
Expand All @@ -27,9 +29,19 @@ func MakeImageProcessor() *ImageProcessor {
mapDrawer: ImageData.GetDefaultMapDrawer(),
reproject: false,
drawmap: false,
falsecolor: false,
}
}

func (ip *ImageProcessor) SetFalseColor(fsclr bool) {
ip.falsecolor = fsclr
if fsclr {
SLog.Warn("False color is enabled, so it will also save plain images with no map")
ImageTools.SetSaveNoMap(true) // Needed for FSCLR
}

}

func (ip *ImageProcessor) SetDrawMap(drawMap bool) {
ip.drawmap = drawMap
}
Expand All @@ -38,6 +50,10 @@ func (ip *ImageProcessor) SetReproject(reproject bool) {
ip.reproject = reproject
}

func (ip *ImageProcessor) GetFalseColor() bool {
return ip.falsecolor
}

func (ip *ImageProcessor) GetDrawMap() bool {
return ip.drawmap
}
Expand Down
79 changes: 62 additions & 17 deletions ImageProcessor/ImageTools/MultiSegmentDump.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package ImageTools

import (
"encoding/json"
"fmt"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/MapDrawer"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/Projector"
"github.com/opensatelliteproject/SatHelperApp/ImageProcessor/Structs"
"github.com/opensatelliteproject/SatHelperApp/Logger"
"github.com/opensatelliteproject/SatHelperApp/Tools"
"github.com/opensatelliteproject/SatHelperApp/XRIT"
"github.com/opensatelliteproject/SatHelperApp/XRIT/Geo"
"github.com/opensatelliteproject/SatHelperApp/XRIT/PacketData"
Expand All @@ -19,6 +19,17 @@ import (
"path"
)

var saveNoMap = false
var saveNoProj = false

func SetSaveNoMap(s bool) {
saveNoMap = s
}

func SetSaveNoProj(s bool) {
saveNoProj = s
}

func DrawGray8At(data []byte, px, py int, image *image.Gray) {
b := image.Bounds()
p := b.Dx()*py + px
Expand Down Expand Up @@ -68,19 +79,45 @@ func MultiSegmentAssemble(msi *Structs.MultiSegmentImage) (error, image.Image) {
return nil, img
}

func SaveImage(filename string, img image.Image) error {
f, err := os.Create(filename)
if err != nil {
SLog.Error("Error creating file %s: %s\n", filename, err)
return err
}

defer f.Close()

err = png.Encode(f, img)

if err != nil {
return err
}

return nil
}

func GetNoMapName(filename string) string {
// Remove file timestamp
return filename[:len(filename)-16] + "-nomap.png"
}
func GetNoProjName(filename string) string {
// Remove file timestamp
return filename[:len(filename)-16] + "-noproj.png"
}

func DumpMultiSegment(msi *Structs.MultiSegmentImage, mapDrawer *MapDrawer.MapDrawer, reproject bool) (error, string) {
folder := path.Dir(msi.FirstSegmentFilename)

newFilename := path.Join(folder, msi.Name+".png")
newFilenameNoMap := path.Join(folder, GetNoMapName(msi.Name))
newFilenameNoProj := path.Join(folder, GetNoProjName(msi.Name))

f, err := os.Create(newFilename)
if err != nil {
SLog.Error("Error creating file %s: %s\n", newFilename, err)
return err, ""
if Tools.Exists(newFilename) {
SLog.Info("File %s already exists, skipping...", newFilename)
return nil, newFilename
}

defer f.Close()

err, img := MultiSegmentAssemble(msi)
if err != nil {
return err, ""
Expand All @@ -92,6 +129,13 @@ func DumpMultiSegment(msi *Structs.MultiSegmentImage, mapDrawer *MapDrawer.MapDr
}

if mapDrawer != nil {
if saveNoMap && !Tools.Exists(newFilenameNoMap) {
SLog.Debug("Saving No Map Image: %s", newFilenameNoMap)
err := SaveImage(newFilenameNoMap, img)
if err != nil {
SLog.Error("Error saving %s: %s", newFilenameNoMap, err)
}
}
SLog.Debug("Map Drawer enabled. Drawing maps...")
newImg := image.NewRGBA(img.Bounds())
draw.Draw(newImg, img.Bounds(), img, img.Bounds().Min, draw.Src)
Expand All @@ -100,29 +144,30 @@ func DumpMultiSegment(msi *Structs.MultiSegmentImage, mapDrawer *MapDrawer.MapDr
}

if reproject {
if saveNoProj && !Tools.Exists(newFilenameNoProj) {
SLog.Debug("Saving No Projection Image: %s", newFilenameNoProj)
err := SaveImage(newFilenameNoProj, img)
if err != nil {
SLog.Error("Error saving %s: %s", newFilenameNoProj, err)
}
}
SLog.Debug("Reprojecting Image to Linear")

proj := Projector.MakeProjector(gc)
img2 := proj.ReprojectLinearMultiThread(img)
img = img2
}

err = png.Encode(f, img)
err = SaveImage(newFilename, img)

if err != nil {
return err, ""
}

meta, err := json.MarshalIndent(msi.FirstSegmentHeader, "", " ")

metaName := path.Join(folder, msi.Name+".json")
err = ioutil.WriteFile(metaName, []byte(msi.FirstSegmentHeader.ToJSON()), os.ModePerm)
if err != nil {
SLog.Error("Cannot generate JSON for metadata file: %s", err)
} else {
metaName := path.Join(folder, msi.Name+".json")
err := ioutil.WriteFile(metaName, meta, os.ModePerm)
if err != nil {
SLog.Error("Cannot write Meta file %s: %s", metaName, err)
}
SLog.Error("Cannot write Meta file %s: %s", metaName, err)
}

return nil, newFilename
Expand Down
Loading

0 comments on commit 8a47f87

Please sign in to comment.