Documentation ¶
Overview ¶
Package gomosaic provides methods for generating mosaic images given a database (= set) of images. It takes a query image and returns a composition of the query with images from the database.
Different metrics can be used to find matching images, also the size of the tiles in the result is configurable.
It ships with a executable program to generate mosaic images and administrate image databases on the filesystem.
Index ¶
- Constants
- Variables
- func CanberraDistance(p, q []float64) float64
- func CdCommand(state *ExecutorState, args ...string) error
- func ChessboardDistance(p, q []float64) float64
- func ComposeMosaic(storage ImageStorage, symbolicTiles [][]ImageID, mosaicDivison TileDivision, ...) (image.Image, error)
- func ComputeHeaps(storage ImageStorage, metric ImageMetric, query image.Image, dist TileDivision, ...) ([][]*ImageHeap, error)
- func CosineSimilarity(p, q []float64) float64
- func EuclideanDistance(p, q []float64) float64
- func Execute(handler CommandHandler, commandMap CommandMap)
- func ForceResize(resizer ImageResizer, tileWidth, tileHeight uint, img image.Image) image.Image
- func GCHCommand(state *ExecutorState, args ...string) error
- func GCHFileName(k uint, ext string) string
- func GenHeapViews(heaps [][]*ImageHeap) [][][]ImageHeapEntry
- func GetHistogramMetricNames() []string
- func GetInterP(quality uint) resize.InterpolationFunction
- func ImageStorageCommand(state *ExecutorState, args ...string) error
- func InitTilesHelper(storage ImageStorage, query image.Image, dist TileDivision, numRoutines int, ...) error
- func IntAbs(a int) int
- func IntMax(a, b int) int
- func IntMin(a, b int) int
- func InterPFromString(s string) (resize.InterpolationFunction, error)
- func InterPString(interP resize.InterpolationFunction) string
- func JPGAndPNG(ext string) bool
- func KeepRatioHeight(originalWidth, originalHeight, width int) int
- func KeepRatioWidth(originalWidth, originalHeight, height int) int
- func LCHCommand(state *ExecutorState, args ...string) error
- func LCHFileName(k, schemeSize uint, ext string) string
- func Manhattan(p, q []float64) float64
- func MaxUint32(a uint32, elements ...uint32) uint32
- func MaxUint8(a uint8, elements ...uint8) uint8
- func MinDistance(p, q []float64) float64
- func MinUint32(a uint32, elements ...uint32) uint32
- func MinUint8(a uint8, elements ...uint8) uint8
- func MosaicCommand(state *ExecutorState, args ...string) error
- func Parameterized(r io.Reader, args ...string) (io.Reader, error)
- func ParameterizedFromStrings(commands []string, args ...string) io.Reader
- func ParseCommand(s string) ([]string, error)
- func ParseDimensions(s string) (int, int, error)
- func ParseDimensionsEmpty(s string) (int, int, error)
- func ParsePercent(s string) (float64, error)
- func ProgressIgnore(num int)
- func PwdCommand(state *ExecutorState, args ...string) error
- func QuantizeC(val uint8, k uint) uint8
- func RGBID(r, g, b, k uint) uint
- func ReaderFromCmdLines(lines []string) io.Reader
- func RegisterHistogramMetric(name string, metric HistogramMetric) bool
- func SetVarCommand(state *ExecutorState, args ...string) error
- func StatsCommand(state *ExecutorState, args ...string) error
- func SubImage(img image.Image, r image.Rectangle) (image.Image, error)
- type AverageColor
- type CmdVarietySelector
- type Command
- type CommandFunc
- type CommandHandler
- type CommandMap
- type DistanceHeapSelector
- type DivideMode
- type ExecutorState
- type FSImageDB
- type FSMapper
- func (m *FSMapper) Clear()
- func (m *FSMapper) GetID(path string) (ImageID, bool)
- func (m *FSMapper) GetPath(id ImageID) (string, bool)
- func (m *FSMapper) Gone(paths []string) []string
- func (m *FSMapper) Len() int
- func (m *FSMapper) Load(path string, recursive bool, filter SupportedImageFunc) error
- func (m *FSMapper) NumImages() ImageID
- func (m *FSMapper) Register(path string) (ImageID, bool)
- type FiveLCHScheme
- type FixedNumDivider
- type FixedSizeDivider
- type FourLCHScheme
- type HeapImageSelector
- type HeapSelector
- type Histogram
- func CreateAllHistograms(storage ImageStorage, normalize bool, k uint, numRoutines int, ...) ([]*Histogram, error)
- func CreateHistograms(ids []ImageID, storage ImageStorage, normalize bool, k uint, numRoutines int, ...) ([]*Histogram, error)
- func CreateHistogramsSequential(storage ImageStorage, normalize bool, k uint, progress ProgressFunc) ([]*Histogram, error)
- func GenHistogram(img image.Image, k uint, normalize bool) *Histogram
- func GenHistogramFromList(k uint, normalize bool, images ...image.Image) *Histogram
- func NewHistogram(k uint) *Histogram
- type HistogramFSController
- func (c *HistogramFSController) AddtionalEntries(m *FSMapper) []string
- func (c *HistogramFSController) CheckData(k uint, checkK bool, checkNormalized bool) error
- func (c *HistogramFSController) Map() map[string]*Histogram
- func (c *HistogramFSController) MissingEntries(m *FSMapper, histMap map[string]*Histogram) []string
- func (c *HistogramFSController) ReadFile(path string) error
- func (c *HistogramFSController) ReadGobFile(path string) error
- func (c *HistogramFSController) ReadJSONFile(path string) error
- func (c *HistogramFSController) Remove(paths []string)
- func (c *HistogramFSController) WriteFile(path string) error
- func (c *HistogramFSController) WriteGobFile(path string) error
- func (c *HistogramFSController) WriteJSON(path string) error
- type HistogramFSEntry
- type HistogramImageMetric
- type HistogramMetric
- type HistogramStorage
- type ImageCache
- type ImageDivider
- type ImageHeap
- type ImageHeapEntry
- type ImageID
- type ImageMetric
- type ImageMetricMinimizer
- func GCHSelector(histStorage HistogramStorage, delta HistogramMetric, numRoutines int) *ImageMetricMinimizer
- func LCHSelector(storage LCHStorage, scheme LCHScheme, metric HistogramMetric, numRoutines int) *ImageMetricMinimizer
- func NewImageMetricMinimizer(metric ImageMetric, numRoutines int) *ImageMetricMinimizer
- type ImageResizer
- type ImageSelector
- type ImageStorage
- type LCH
- func CreateAllLCHs(scheme LCHScheme, storage ImageStorage, normalize bool, k uint, ...) ([]*LCH, error)
- func CreateLCHs(scheme LCHScheme, ids []ImageID, storage ImageStorage, normalize bool, k uint, ...) ([]*LCH, error)
- func GenLCH(scheme LCHScheme, img image.Image, k uint, normalize bool) (*LCH, error)
- func NewLCH(histograms []*Histogram) *LCH
- type LCHFSController
- func (c *LCHFSController) Map() map[string]*LCH
- func (c *LCHFSController) ReadFile(path string) error
- func (c *LCHFSController) ReadGobFile(path string) error
- func (c *LCHFSController) ReadJSONFile(path string) error
- func (c *LCHFSController) WriteFile(path string) error
- func (c *LCHFSController) WriteGobFile(path string) error
- func (c *LCHFSController) WriteJSON(path string) error
- type LCHFSEntry
- type LCHImageMetric
- type LCHScheme
- type LCHStorage
- type MemoryHistStorage
- type MemoryLCHStorage
- type NfntResizer
- type ProgressFunc
- type RGB
- type RandomHeapSelector
- type ReplHandler
- func (h ReplHandler) After(s *ExecutorState)
- func (h ReplHandler) Before(s *ExecutorState)
- func (h ReplHandler) Init() *ExecutorState
- func (h ReplHandler) OnError(s *ExecutorState, err error, cmd Command) bool
- func (h ReplHandler) OnInvalidCmd(s *ExecutorState, cmd string) bool
- func (h ReplHandler) OnParseErr(s *ExecutorState, err error) bool
- func (h ReplHandler) OnScanErr(s *ExecutorState, err error)
- func (h ReplHandler) OnSuccess(s *ExecutorState, cmd Command)
- func (h ReplHandler) Start(s *ExecutorState)
- type ResizeStrategy
- type ScriptHandler
- func (h ScriptHandler) After(s *ExecutorState)
- func (h ScriptHandler) Before(s *ExecutorState)
- func (h ScriptHandler) Init() *ExecutorState
- func (h ScriptHandler) OnError(s *ExecutorState, err error, cmd Command) bool
- func (h ScriptHandler) OnInvalidCmd(s *ExecutorState, cmd string) bool
- func (h ScriptHandler) OnParseErr(s *ExecutorState, err error) bool
- func (h ScriptHandler) OnScanErr(s *ExecutorState, err error)
- func (h ScriptHandler) OnSuccess(s *ExecutorState, cmd Command)
- func (h ScriptHandler) Start(s *ExecutorState)
- type SubImager
- type SupportedImageFunc
- type TileDivision
- type Tiles
- type VectorMetric
Constants ¶
const ( // Debug is true if code should be compiled in debug mode, printing // more stuff and performing checks. Debug = true // Version is the version of gomosaic. Version = "1.1" )
const MaxInt = int(MaxUint >> 1)
const MaxUint = ^uint(0)
const MinInt = -MaxInt - 1
const MinUint = 0
const ( // QuantizeFactor is used during quantiation, it's the number of values in // each rgb component. QuantizeFactor uint = 256 )
Variables ¶
var ( // RunSimple contains script code that when executed loads images from memory, // creates all GCHs and then creates the mosaic. No GCHs are stored on the // filesystem. // It is parameterized by five parameters: First the directory containing the // database images, second the name of the input file, third the name of the // output file fourth the number of tiles in the mosaic and last the // dimensions of the output. Because the last element can actually be omitted // we can create a mosaic with just four parameters. // // It is at the moment the easiest way to create a mosaic. // But it can be very slow if the database is quite large. // // Example usage: RunSimple ~/Pictures/ input.jpg output.png 20x30 x // // This would create output.png with 20x30 tiles from input.jpg with images // from ~/Pictures/. The output image would have the same size as the input // image (no dimension given). RunSimple = `storage load $1 gch create mosaic $2 $3 gch-euclid $4 $5` // RunMetric is similar to RunSimple but takes an additional argument: The // metric name. // // Example usage: RunMetric ~/Pictures/ input.jpg output.png 20x30 x cosine // // This would do the same as RunSimple but using cosine-similarity. RunMetric = `storage load $1 gch create mosaic $2 $3 gch-$6 $4 $5` // CompareMetrics is similar to RunSimple but generates multiple output // images based on different metrics. Thus the third argument is not an path // for a file but a directory. In this directory multiple mosaics will be // generated. // // Example usage: CompareMetrics ~/Pictures/ input.jpg ./output/ 20x30 x CompareMetrics = `` /* 326-byte string literal not displayed */ )
var ( // BufferSize is the (default) size of buffers. Some methods create buffered // channels, this parameter controls how big such buffers might be. // Usually such buffers store no big data (ints, bools etc.). BufferSize = 1000 )
var ( // DefaultResizer is the resizer that is used by default, if you're // looking for a resizer default argument this seems useful. DefaultResizer = NewNfntResizer(resize.MitchellNetravali) )
var ( // ErrCmdSyntaxErr is returned by a CommandFunc if the syntax for the command // is invalid. ErrCmdSyntaxErr = errors.New("invalid command syntax") )
var ( // ImageCacheSize is the default size of images caches. Some procedures // (especially the composition of mosaics) might be much more performant if // they're allowed to cache images. This variable controls the size of such // caches. It must be a value ≥ 1. ImageCacheSize = 15 )
Functions ¶
func CanberraDistance ¶
CanberraDistance is a weighted version of the manhattan distance, see https://en.wikipedia.org/wiki/Canberra_distance
func CdCommand ¶
func CdCommand(state *ExecutorState, args ...string) error
CdCommand is a command that changes the current directory.
func ChessboardDistance ¶
ChessboardDistance is the max over all absolute distances, see https://reference.wolfram.com/language/ref/ChessboardDistance.html
func ComposeMosaic ¶
func ComposeMosaic(storage ImageStorage, symbolicTiles [][]ImageID, mosaicDivison TileDivision, resizer ImageResizer, s ResizeStrategy, numRoutines, cacheSize int, progress ProgressFunc) (image.Image, error)
ComposeMosaic concurrently composes a mosaic image given the distribution in tiles and the selected images for each tile. Images are loaded by the storage. The resizer and the resize strategy are used to resize database images to fit in tiles. The mosaic division must start from (0, 0) and the rectangles are not allowed to overlap, in short it has be what we intuively would call a distribution into tiles.
Scaled database images are cached to speed up the generation process. The cache size parameter is the size of the cache used. The more elements in the cache the faster the composition process is, but it also increases memory consumption. If cache size is ≤ 0 the DefaultCacheSize is used.
func ComputeHeaps ¶
func ComputeHeaps(storage ImageStorage, metric ImageMetric, query image.Image, dist TileDivision, k, numRoutines int, progress ProgressFunc) ([][]*ImageHeap, error)
ComputeHeaps computes the image heap for each tile given k (the number of images to store in each heap).
Metric will not be initialized, that must happen before.
func CosineSimilarity ¶
CosineSimilarity returns 1 - cos(∡(p, q)). The result is between 0 and 2, as special case is that the length of p or q is 0, in this case the result is 2.1
func EuclideanDistance ¶
EuclideanDistance returns the euclidean distance of two vectors, that is sqrt( (p1 - q1)² + ... + (pn - qn)² ).
func Execute ¶
func Execute(handler CommandHandler, commandMap CommandMap)
Execute implements the high-level execution loop as described in the documentation of CommandHandler. commandMap is used to lookup commands.
func ForceResize ¶
ForceResize is a resize strategy that resizes to the given width and height, ignoring the ration of the original image.
func GCHCommand ¶
func GCHCommand(state *ExecutorState, args ...string) error
GCHCommand can create histograms for all images in storage, save and load files.
func GCHFileName ¶
GCHFileName returns the proposed filename for a file containing global color histograms. When saving HistogramFSController instances (that's the type used for storing GCHs) the file should be saved by this file name. The scheme is "gch-k.(gob|json)". k is the value as defined in histogram and ext is the extension (gob for gob encoded files and json for json encoded files).
For example histograms with 8 sub-divions encoded as json would be stored in a file "gch-8.json".
func GenHeapViews ¶
func GenHeapViews(heaps [][]*ImageHeap) [][][]ImageHeapEntry
GenHeapViews can be used to transform the image heaps into the actual list of images in that heap. It's only a shortcut calling GetView on each heap.
func GetHistogramMetricNames ¶
func GetHistogramMetricNames() []string
GetHistogramMetricNames returns a list of all registered named histogram metrics. See RegisterHistogramMetric for details.
func GetInterP ¶
func GetInterP(quality uint) resize.InterpolationFunction
GetInterP returns an interpolation function given a desired quality. The higher the quality the better the interpolation should be, but execution time is higher. Currently supported are values between 0 and 4, each selecting a different interpolation function. Values greater than 4 are treated as 4.
This method assumes that the interpolation functions provided by nfnt/resize can be sorted according to their quality. This should be a reasonable assumption.
func ImageStorageCommand ¶
func ImageStorageCommand(state *ExecutorState, args ...string) error
ImageStorageCommand is a command that executes tasks with the fs mapper and therefor the image storage (the user doesn't need to know about details as mapper and storage, so it's simply called storage). This command without arguments just prints the number of databases in the storage. With the single argument "list" it prints the path of each image in the storage. With the argument "load" a second argument "DIR" is required, this will load all images from the directory in the storage. If a third argument is provided this must be a bool that is true if the directory should be scanned recursively. The default is not to scan recursively.
Note that jpg and png files are considered valid image types, thus image.jpeg and image.png should be included if you're planning to use this function.
func InitTilesHelper ¶
func InitTilesHelper(storage ImageStorage, query image.Image, dist TileDivision, numRoutines int, init func(tiles Tiles) error, onTile func(i, j int, tileImage image.Image) error) error
InitTilesHelper is a helper function to easily create a concurrent InitTiles function for ImageMetrics.
It will do the following: First it creates the actual tiles of the image and then it will call the init function. In this function you don't have to create metric values or something, just initialize the datastructure that holds information. It then gets concurrently filled by calls of onTile which is concurrently called for each tile of the image.
func InterPFromString ¶
func InterPFromString(s string) (resize.InterpolationFunction, error)
InterPFromString parses s as an interpreation function, valid values include: "nearest-neighbor", "bilinear", "bicubic", "mitchell-netravali", "lanczos2" and "lanczos3".
func InterPString ¶
func InterPString(interP resize.InterpolationFunction) string
InterPString returns a string representation of the interpolation function since resize doesn't seem to provide a String() function.
func JPGAndPNG ¶
JPGAndPNG is an implementation of SupportedImageFunc accepting jpg and png file extensions.
func KeepRatioHeight ¶
KeepRatioHeight computes the new height given the original width and height s.t. the ration remains unchanged. The original values must be > 0.
func KeepRatioWidth ¶
KeepRatioWidth computes the new width given the original width and height s.t. the ration remains unchanged. The original values must be > 0.
func LCHCommand ¶
func LCHCommand(state *ExecutorState, args ...string) error
func LCHFileName ¶
LCHFileName returns the proposed filename for a file containing lchs. When saving LCHFSController instances (that's the type used for storing GCHs) the file should be saved by this file name. The scheme is "lch-scheme-k.(gob|json)". k is the value as defined in histogram and ext is the extension (gob for gob encoded files and json for json encoded files). Scheme is the scheme size, currently implemented are two parting techniques. This naming is ambiguous (someone could come up with another technique to build 5 blocks) but that should be well enough.
For example LCHs with 8 sub-divions encoded as json with the 5 parts scheme would be stored in a file "lch-5-8.json".
func Manhattan ¶
Manhattan returns the manhattan distance of two vectors, that is |p1 - q1| + ... + |pn - qn|.
func MinDistance ¶
MinDistance returns 1 - ( min(p1, q1) + ... + min(pn, qn) ).
func MosaicCommand ¶
func MosaicCommand(state *ExecutorState, args ...string) error
MosaicCommand creates a mosaic images. For details see the entry created in the init() method / the description text of the command our the online documentation. Usage example: mosaic in.jpg out.jpg gch-cosine 20x30 1024x768
func Parameterized ¶
Parameterized is used to transform parameterized commands into executable commands, that means replacing variables $i with the provided argument. Example: The command "gch load $1" can be called with one argument that will replace the placeholder $1. It should work with an arbitrary number of variables (let's hope so).
The current implementation works by reading the whole original reader and then transforming the elements, given that scripts are not too long the overhead should be manageable.
If no parameters are given it is best practise to avoid calling this method and use the original reader.
func ParameterizedFromStrings ¶
ParameterizedFromStrings runs the commands provided in commands (each entry is considered to be a command) and replaces placeholders by args. For placeholder details see Parameterized.
func ParseCommand ¶
ParseCommand parses a command of the form "COMMAND ARG1 ... ARGN". Examples:
foo bar is the command "foo" with argument "bar". Arguments might also be enclosed in quotes, so foo "bar bar" is parsed as command foo with argument bar bar (a single argument).
func ParseDimensions ¶
ParseDimensions parses a string of the form "AxB" where A and B are positive integers.
func ParseDimensionsEmpty ¶
ParseDimensionsEmpty works as ParseDimensions of the form "AxB" but also also A and / or B to be empty. That is "1024x" would be valid as well as "x768" and "x". Empty values are returned as -1.
func ParsePercent ¶
func ProgressIgnore ¶
func ProgressIgnore(num int)
ProgressIgnore is a ProgressFunc that does nothing.
func PwdCommand ¶
func PwdCommand(state *ExecutorState, args ...string) error
PwdCommand is a command that prints the current working directory.
func QuantizeC ¶
QuantizeC quantizes the color component c (sub-divison in k values). That is it returns c * (k / 256). k must be a number between 1 and 256.
func RGBID ¶
RGBID assigns each RGB color (k sub-divisions) a unique id. That id is given by r + k * g + k² * b.
RGBs Id method uses this function, it's just more convenient if the id can be computed without creating an RGB object.
func ReaderFromCmdLines ¶
ReaderFromCmdLines returns a reader for a script source that reads the content of the combined lines.
func RegisterHistogramMetric ¶
func RegisterHistogramMetric(name string, metric HistogramMetric) bool
RegisterHistogramMetric is used to register a named histogram metric. It will only add the metric if the name does not exist yet. The result is true if the metric was successfully registered and false otherwise. Some metrics are registered by default. All names must be lowercase strings, the register and get methods will always transform a string to lowercase.
All metrics should be registered by an init method.
func SetVarCommand ¶
func SetVarCommand(state *ExecutorState, args ...string) error
SetVarCommand sets a variable to a new value.
func StatsCommand ¶
func StatsCommand(state *ExecutorState, args ...string) error
StatsCommand is a command that prints variable / value pairs.
Types ¶
type AverageColor ¶
type AverageColor RGB
AverageColor describes the average of several RGB colors.
func ComputeAverageColor ¶
func ComputeAverageColor(img image.Image) AverageColor
ComputeAverageColor computes the average color of an image.
func (AverageColor) Dist ¶
func (c AverageColor) Dist(other AverageColor, metric VectorMetric) float64
Dist returns the distance between the two average color vectors given the metric for the component vectors.
type CmdVarietySelector ¶
type CmdVarietySelector int
const ( CmdVarietyNone CmdVarietySelector = iota CmdVarietyRand CmdVarietyMetric )
func ParseCMDVarietySelector ¶
func ParseCMDVarietySelector(s string) (CmdVarietySelector, error)
func (CmdVarietySelector) DisplayString ¶
func (s CmdVarietySelector) DisplayString() string
type Command ¶
type Command struct { Exec CommandFunc Usage string Description string }
Command a command consists of a function to actually execute the command and some information about the command.
type CommandFunc ¶
type CommandFunc func(state *ExecutorState, args ...string) error
CommandFunc is a function that is applied to the current states and arguments to that command.
type CommandHandler ¶
type CommandHandler interface { Init() *ExecutorState Start(s *ExecutorState) Before(s *ExecutorState) After(s *ExecutorState) OnParseErr(s *ExecutorState, err error) bool OnInvalidCmd(s *ExecutorState, cmd string) bool OnSuccess(s *ExecutorState, cmd Command) OnError(s *ExecutorState, err error, cmd Command) bool OnScanErr(s *ExecutorState, err error) }
CommandHandler together with Execute implements a high-level command execution loop. CommandFuncs are applied to the current state until there are no more commands to execute (no more input).
We won't go into the details, please read the source for details (yes, that's probably not the best practise but is so much easier in this case).
A command has the form "COMMAND ARG1 ... ARGN" where COMMAND is the command name and ARG1 to ARGN are the arguments for the command.
Here's a rough summary of what Execute will do: First it creates an initial state by calling Init. After that it immediately calls Start to notify the handler that the execution begins.
We use to different methods to separate object creation from execution. Before a command is executed the Before method is called to notify the handler that a command will be executed.
Then a loop will begin that reads all lines from the state's reader. If there is a command line the line will be parsed, if an error during parsing occurred the handler gets notified via OnParseErr. This method should return true if the execution should continue despite the error. Then a lookup in the provided command man happens: If the command was found the corresponding Command object is executed. If it was not found the OnInvalidCmd function is called on the handler. Again it should return true if the exeuction should continue despite the error. If this execution was successful the OnSuccess function is called with the executed command. If the execution was unsuccessful the OnError function will be called. Commands should return ErrCmdSyntaxErr if the syntax of the command is incorrect (for example invalid number of arguments) and OnError can do special handling in this case. Again OnError returns true if execution should continue. OnScanErr is called if there is an error while reading a command line from the state's reader.
Errors while writing to the provided out stream might be reported, but this is not a requirement.
type CommandMap ¶
CommandMap maps command names to Commands.
var DefaultCommands CommandMap
DefaultCommands contains some commands that are often used.
type DistanceHeapSelector ¶
type DistanceHeapSelector struct { Metric ImageMetric K int NumRoutines int }
func NewDistanceHeapSelector ¶
func NewDistanceHeapSelector(metric ImageMetric, k, numRoutines int) *DistanceHeapSelector
func (*DistanceHeapSelector) Init ¶
func (selector *DistanceHeapSelector) Init(storage ImageStorage) error
func (*DistanceHeapSelector) SelectImages ¶
func (selector *DistanceHeapSelector) SelectImages(storage ImageStorage, query image.Image, dist TileDivision, progress ProgressFunc) ([][]ImageID, error)
type DivideMode ¶
type DivideMode int
DivideMode is used to describe in which way to handle remaining pixels in image division. The exact meaning might differ (depending on the arranger) but as an example consider an image with 99 pixels width. If we want to divide the image into tiles with 10 pixels. This leads to a 9 tiles with 10 pixels, but 9 pixels are left. DivideMode now describes what to do with the remaining 9 pixels: Crop would mean to crop the image and discard the remaining pixels. Adjust would mean to adjust the last tile to have a width of 9 and pad would mean to add an additional tile with width 10 (and thus describing a tile that does not intersect with the image everywhere).
const ( // DivideCrop is the mode in which remaining pixels are discarded. DivideCrop DivideMode = iota // DivideAdjust is the mode in which a tile is adjusted to the remaining // pixels. DivideAdjust // DividePad is the mode in which a tile of a certain size is created even // if not enough pixels are remaining. DividePad )
func (DivideMode) String ¶
func (mode DivideMode) String() string
type ExecutorState ¶
type ExecutorState struct { // WorkingDir is the current directory. It must always be an absolute path. WorkingDir string // Mapper is the current file system mapper. Mapper *FSMapper // ImgStorage is image database, backed by Mapper. ImgStorage *FSImageDB // NumRoutines is the number of go routines used for different tasks during // mosaic generation. NumRoutines int // GCHStorage stores the global color histograms. Whenever new images are // loaded the old histograms become invalid (set to nil again) and must // be reloaded / created. GCHStorage *MemoryHistStorage // LCHStorage stores the local color histograms. Whenever new images are // loaded the old histograms become invalid (set to nil again) and must // be reloaded / created. LCHStorage *MemoryLCHStorage // Verbose is true if detailed output should be generated. Verbose bool // In is the source to read commands from (line by line). In io.Reader // Out is used to write state information. Out io.Writer // CutMosaic describes whether the mosaic should be "cut". // Cutting means to cut the resulting image s.t. each tile has the same bounds. // Example: Suppose you want to divide an image with width 99 and want ten // tiles horizontally. This leads to an image where each tile has // a width of 9. Ten tiles yields to a final width of 90. As you see 9 pixels // are "left over". The distribution in ten tiles is fixed, so we can't add // another tile. But in order to enforce the original proposed width // we can enlarge the last tile by 9 pixels. So we would have 9 tiles with // width 9 and one tile with width 18. // // Cut controls what to do with those remaining pixels: If cut is set // to true we skip the 9 pixels and return an image of size 90. If set to // false we enlarge the last tile and return an image with size 99. // Usually the default is false. CutMosaic bool // JPGQuality is the quality between 1 and 100 used when storing images. // The higher the value the better the quality. We use a default quality of // 100. JPGQuality int // InterP is the interpolation functions used when resizing the images. InterP resize.InterpolationFunction // Cache size is the size of the image cache during mosaic composition. // The more elements in the cache the faster the composition process is, but // it also increases memory consumption. If cache size is < 0 the // DefaultCacheSize is used. CacheSize int // VarietySelector is the current variety selector, defaults to // cmdVarietyNone. VarietySelector CmdVarietySelector // BestFit is the percent value (between 0 and 1) that describes how much // percent of the input images are considered in the variety heaps. BestFit float64 }
ExecutorState is the state during a CommandHandler execution, see that type for more details of the workflow.
The variables in the state are shared among the executions of the command functions.
func (*ExecutorState) GetBestFitImages ¶
func (state *ExecutorState) GetBestFitImages(numImages int) int
GetBestFitImages multiplies that best fit factor (BestFit) with num images to get the number of best fit images for the variety selectors. It sets same sane defaults in the case something weird happens.
func (*ExecutorState) GetPath ¶
func (state *ExecutorState) GetPath(path string) (string, error)
GetPath returns the absolute path given some other path. The idea is the following: If the user inputs a path we have two cases: The user used an absolute path, in this case we use this absolute path to perform tasks with. If it is a relative path we join the working directory with this path and thus retrieve the absolute path we work on.
The home directory can be used like on Unix: ~/Pictures is the Pictures directory in the home directory of the user.
type FSImageDB ¶
type FSImageDB struct {
// contains filtered or unexported fields
}
FSImageDB implements ImageStorage. It uses images stored on the filesystem and opens them on demand. Files are retrieved from a FSMapper.
func NewFSImageDB ¶
NewFSImageDB returns a new data base given the filesystem mapper.
func (FSImageDB) LoadConfig ¶
LoadConfig loads the image configuration for the image with the given id from the filesystem.
type FSMapper ¶
FSMapper is a mapping between filesystem images and internal ids. It maps both, ids to images and images to ids, implementing a bijective mapping.
A problem arises when we store for example histograms. Images may be deleted or new images added, thus the histograms stored (e.g. in an array) can't be directly used.
FSMapper provides methods to keep such things synched.
A mapper maps absolute paths to image ids (and vice versa). Meaning that the mapping can't just be transferred to another machine.
func CreateFSMapper ¶
func CreateFSMapper(root string, recursive bool, filter SupportedImageFunc) (*FSMapper, error)
CreateFSMapper creates an FSMapper containing images from the root directory. All files for which filter returns true will be registered to the mapping. If recursive is true also subdirectories of root will be scanned, otherwise only root is scanned.
The filter function can be nil and is then set to JPGAndPNG. Any error while scanning the directory / the directories is returned together with nil.
This is the same as creating a new FSMapper and then calling its load method. The only difference is that on an error nil will be returned (not a mapper containing some images).
func NewFSMapper ¶
func NewFSMapper() *FSMapper
NewFSMapper creates a new mapper without any values (empty mappings). To create a mapper with content (i.e. reading a list of files from the filesystem) use CreateFSMapper.
func (*FSMapper) Clear ¶
func (m *FSMapper) Clear()
Clear removes all registered images from the mappings.
func (*FSMapper) GetID ¶
GetID returns the id of an absolute image path. If the image wasn't registered the id will be invalid and the boolean false.
func (*FSMapper) GetPath ¶
GetPath returns the absolute path of the image with the given id. If no image with that id exists the returned path is the empty string and the boolean false.
func (*FSMapper) Gone ¶
Gone returns images that are gone, i.e. images that are not registered in the mapper. This is useful for storages that store for example histograms. These storages can test which images are gone ("missing") from the filesystem.
The result contains all images from paths that are not registered in the mapper.
A storage can implement a "Mising" method by simply iterating over all elements in the mapper and testing if it has an entry for that.
func (*FSMapper) Load ¶
func (m *FSMapper) Load(path string, recursive bool, filter SupportedImageFunc) error
Load scans path for images supported by gomosaic.
All files for which filter returns true will be registered to the mapping. If recursive is true also subdirectories of root will be scanned, otherwise only root is scanned.
The filter function can be nil and is then set to JPGAndPNG. Any error while scanning the directory / the directories is returned together with nil.
Note that if an error occurs it is still possible that some images were added to the storage.
func (*FSMapper) NumImages ¶
NumImages returns the number of images in the mapper as an ImageID. Values between 0 and NumImages - 1 are considered valid ids.
func (*FSMapper) Register ¶
Register registers an image to the mapping and returns the id of the image. If an image with that path is already present in the storage the images will not get added.
path must be an absolute path to an image resource, this is however not checked / enforced in Register. Ensure this before calling the function. The returned value is the newly assigned ImageID; however if the image is already present the second return value is false and the ImageID is not valid. So only if the returned bool is true the ImageID may be used.
Register adjusts both mappings and is not safe for concurrent use.
type FiveLCHScheme ¶
type FiveLCHScheme struct{}
FiveLCHScheme implements the scheme with vie parts: north, west, south, east and center.
It implements LCHScheme, the LCH contains the GCHs for the parts in the order described above.
func NewFiveLCHScheme ¶
func NewFiveLCHScheme() FiveLCHScheme
NewFiveLCHScheme returns a new FourLCHScheme.
type FixedNumDivider ¶
FixedNumDivider is an ImageDivider that divides an image into a given number of tiles. Cut describes whether the image should be "cut". Cutting means to cut the resulting image s.t. each tile has the same bounds. Example: Suppose you want to divide an image with width 99 and want ten tiles horizontally. This leads to an image where each tile has a width of 9. Ten tiles yields to a final width of 90. As you see 9 pixels are "left over". The distribution in ten tiles is fixed, so we can't add another tile. But in order to enforce the original proposed width we can enlarge the last tile by 9 pixels. So we would have 9 tiles with width 9 and one tile with width 18.
Cut controls what to do with those remaining pixels: If cut is set to true we skip the 9 pixels and return an image of size 90. If set to false we enlarge the last tile and return an image with size 99.
func NewFixedNumDivider ¶
func NewFixedNumDivider(numX, numY int, cut bool) *FixedNumDivider
NewFixedNumDivider returns a new FixedNumDivider given the number of tiles in x and y direction.
func (*FixedNumDivider) Divide ¶
func (divider *FixedNumDivider) Divide(bounds image.Rectangle) TileDivision
Divide implements the Divide method of ImageDivider.
type FixedSizeDivider ¶
type FixedSizeDivider struct {
Width, Height int
Mode DivideMode
}
FixedSizeDivider divides an image into tiles where each tile has the given width and height. It implements ImageDivider. The DivideMode describes how to deal with "remaining" pixel.
func NewFixedSizeDivider ¶
func NewFixedSizeDivider(width, height int, mode DivideMode) FixedSizeDivider
NewFixedSizeDivider returns a new FixedSizeDivider.
func (FixedSizeDivider) Divide ¶
func (divider FixedSizeDivider) Divide(bounds image.Rectangle) TileDivision
Divide implements the Divide method of ImageDivider.
type FourLCHScheme ¶
type FourLCHScheme struct{}
FourLCHScheme implements the scheme with four parts: north, west, south and east.
It implements LCHScheme, the LCH contains the GCHs for the parts in the order described above.
func NewFourLCHScheme ¶
func NewFourLCHScheme() FourLCHScheme
NewFourLCHScheme returns a new FourLCHScheme.
type HeapImageSelector ¶
type HeapImageSelector struct { Metric ImageMetric Selector HeapSelector K int NumRoutines int }
HeapImageSelector implements ImageSelector. It first computes the image heaps given the metric and then uses the provided HeapSelector to select the actual images from the heaps.
func NewHeapImageSelector ¶
func NewHeapImageSelector(metric ImageMetric, selector HeapSelector, k, numRoutines int) *HeapImageSelector
NewHeapImageSelector returns a new selector. Metric is the image metric that is used for the image heaps, selector is used to select the actual images from the heaps. k is the number of images stored in each image heap (that is the k best images are stored in the heaps). NumRoutines is the number of things that happen concurrently (not exactly, but guidance level),
func RandomHeapImageSelector ¶
func RandomHeapImageSelector(metric ImageMetric, k, numRoutines int) *HeapImageSelector
RandomHeapImageSelector returns a HeapImageSelector using a random selection. Thus it can be used as an ImageSelector.
func (*HeapImageSelector) Init ¶
func (sel *HeapImageSelector) Init(storage ImageStorage) error
Init just calls InitStorage on the provided image metric.
func (*HeapImageSelector) SelectImages ¶
func (sel *HeapImageSelector) SelectImages(storage ImageStorage, query image.Image, dist TileDivision, progress ProgressFunc) ([][]ImageID, error)
SelectImages first calls InitTiles on the provided metric, then computes the heaps and applies the selector on the heaps.
type HeapSelector ¶
type HeapSelector interface {
Select(storage ImageStorage, query image.Image, dist TileDivision, heaps [][]*ImageHeap) ([][]ImageID, error)
}
HeapSelector is used to select the actual images after creating the image heaps.
type Histogram ¶
type Histogram struct { // Entries contains for each r, g, b color the frequency. The histogram does // not save each possible r, g, b color but the quantizd version. // That is it stores frequencies (r, g, b) where r, g, b < k. Entries []float64 // K is the number of sub-divisions used to create the histogram. // It must be a number between 1 and 256. K uint }
Histogram describes a color histogram for an image. It counts the number of pixels with a certain color or the relative frequency of the color (normalized histogram).
An entry for color r, g, b quantized to k sub-divisions is stored at position r + k * g + k * k * b.
To compute the id of an r, g, b color use RGBID or ID on RGB objects.
func CreateAllHistograms ¶
func CreateAllHistograms(storage ImageStorage, normalize bool, k uint, numRoutines int, progress ProgressFunc) ([]*Histogram, error)
CreateAllHistograms creates all histograms for images in the storage. It is a shortcut using CreateHistograms, see this documentation for details.
func CreateHistograms ¶
func CreateHistograms(ids []ImageID, storage ImageStorage, normalize bool, k uint, numRoutines int, progress ProgressFunc) ([]*Histogram, error)
CreateHistograms creates histograms for all images in the ids list and loads the images through the given storage. If you want to create all histograms for a given storage you can use CreateAllHistograms as a shortcut. It runs the creation of histograms concurrently (how many go routines run concurrently can be controlled by numRoutines). k is the number of sub-divisons as described in the histogram type, If normalized is true the normalized histograms are computed. progress is a function that is called to inform about the progress, see doucmentation for ProgressFunc.
func CreateHistogramsSequential ¶
func CreateHistogramsSequential(storage ImageStorage, normalize bool, k uint, progress ProgressFunc) ([]*Histogram, error)
CreateHistogramsSequential works as CreateAllHistograms but does not use concurrency.
func GenHistogram ¶
GenHistogram creates a histogram given an image and the number of sub-divions in each direction (k), k must be a number between 1 and 256. The histogram contains the freuqency of each color after quantiation in k sub-divisions.
func GenHistogramFromList ¶
GenHistogramFromList generates a histogram containing an entry for each image in the images list. k is the number of sub-divisons. If normalize is true the normalized histogram will be computed instead of the frequency histogram.
func NewHistogram ¶
NewHistogram creates a new histogram given the number of sub-divions in each direction. k must be a number between 1 and 256.
func (*Histogram) Add ¶
Add creates the histogram given an image, that is it counts how often a color appears in the image. k is the number of sub-divisions in each direction, it must be a number between 1 and 256. The histogram contains the freuqency of each color after quantiation in k sub-divisions.
This method can be called multiple times to accumulate the histograms of multiple image,s it is however not save to concurrently call this method on the same histogram.
To create a histogram for one image you can also use GenHistogram.
func (*Histogram) Equals ¶
Equals checks if two histograms are equal. epsilon is the difference between that is allowed to still consider them equal.
func (*Histogram) Normalize ¶
Normalize computes the normalized histogram of h if h contains the number of occurrences in the image. pixels is the total number of pixels in the original image the historam was created for. If pixels is a negative number or 0 the number of pixels will be computed as the sum of all entries in the original histogram. If no pixels exist in the image all result entries are set to 0.
type HistogramFSController ¶
type HistogramFSController struct { Entries []HistogramFSEntry K uint Version string }
HistogramFSController is used to store histograms (wrapped by HistogramFSEntry) on the filesystem.
Its intended use is to write an instance to a file (or whatever), making it possible to safe histograms connected to a named image (path).
The idea is: Load histogram data from the filesystem and transform the histograms to HistogramStorage, maybe perform some tests if all images in the database are present in the controller.
It also has a version field that is set to the Version variable when saving. This can be useful if the definition should ever change.
See MissingEntries, AddtionalEntries and MemHistStorageFromFSMapper for some examples.
func CreateHistFSController ¶
func CreateHistFSController(ids []ImageID, mapper *FSMapper, storage HistogramStorage) (*HistogramFSController, error)
CreateHistFSController creates a histogram filesystem controller given some input data. ids is the list of all image ids to be included in the controler, mapper is used to get the absolute path of an image (stored alongside the histogram data) and the storage is used to lookup the histograms.
If you want to create a fs controller with all ids from a storage you can use IDList to create a list of all ids.
func NewHistogramFSController ¶
func NewHistogramFSController(capacity int, k uint) *HistogramFSController
NewHistogramFSController creates an empty file system controller with the given capacity.
To create a new file system controller initialized with some content use CreateHistFSController.
func (*HistogramFSController) AddtionalEntries ¶
func (c *HistogramFSController) AddtionalEntries(m *FSMapper) []string
AddtionalEntries computes all images files that are present in the histogram controller but not in the mapper. Usually that means that the image has been deleted and is no longer required.
func (*HistogramFSController) CheckData ¶
func (c *HistogramFSController) CheckData(k uint, checkK bool, checkNormalized bool) error
CheckData is used to verify (parts) of the controller data. It tests if the controller is defined for the same k as the argument k (tested only if checK is true). If you don't want to check k just set checK to false and k to some arbitrary value. It also checks if each histogram in the controler is defined for the same k (the k defined in the controller). If checkNormalized is set it also checks if each histogram only contains values between 0 and 1.
This method should not be used in production code because it's rather slow, but it's useful for debugging.
If the returned error is nil the check passed, otherwise an error != nil is returned describing all failed tests.
Usually we deal with incorrectly stored files during mosaic generation: If there is an error with one of the histogram ojbects (wrong k) the metrics return an error. If somehow not-normalized histograms are stored the error is not detected, it should just lead to weird results.
func (*HistogramFSController) Map ¶
func (c *HistogramFSController) Map() map[string]*Histogram
Map computes the mapping filename ↦ histogram. That is useful sometimes, especially when computing the diff between this and an FSMapper.
func (*HistogramFSController) MissingEntries ¶
func (c *HistogramFSController) MissingEntries(m *FSMapper, histMap map[string]*Histogram) []string
MissingEntries computes the set of all images that are present in the mapping m but have no matching entry in the histogram.
That is: For these images new histograms must be computed. HistMap is the map as computed by the Map() function. It is an argument to avoid multiple compoutations of it if used more often. Just set it to nil and it will be computed with the map function.
func (*HistogramFSController) ReadFile ¶
func (c *HistogramFSController) ReadFile(path string) error
ReadFile reads the content of the controller from the specified file. The read method depends on the file extension which must be either .json or .gob.
func (*HistogramFSController) ReadGobFile ¶
func (c *HistogramFSController) ReadGobFile(path string) error
ReadGobFile reads the content of the controller from the specified file. The file must be encoded in gob.
func (*HistogramFSController) ReadJSONFile ¶
func (c *HistogramFSController) ReadJSONFile(path string) error
ReadJSONFile reads the content of the controller from the specified file. The file must be encoded in json.
func (*HistogramFSController) Remove ¶
func (c *HistogramFSController) Remove(paths []string)
Remove removes all entries from the controller whose path is in the paths element. Example usage: Use AddtionalEntries to compute histograms that are probably not required any more and then Remove them.
func (*HistogramFSController) WriteFile ¶
func (c *HistogramFSController) WriteFile(path string) error
WriteFile writes the content of the controller to a file depending on the file extension hich must be either .json or .gob.
func (*HistogramFSController) WriteGobFile ¶
func (c *HistogramFSController) WriteGobFile(path string) error
WriteGobFile writes the histograms to a file encoded gob format.
func (*HistogramFSController) WriteJSON ¶
func (c *HistogramFSController) WriteJSON(path string) error
WriteJSON writes the histograms to a file encoded in json format.
type HistogramFSEntry ¶
HistogramFSEntry is used to store a histogram on the filesystem. It contains the path of the image the histogram was created for as well as the histogram data.
It also has a field checksum that is not used yet. Later it can be adjusted s.t. an histogram is stored together with the checksum (e.g. just plain md5 encoded with e.g. base64) of the image the histogram was created for. This way we can test if the content of an image has changed, and thus the histogram became invalid. At the moment we don't recognize if an image has changed.
This is however not supported at the moment. An empty string signals that no checksum was computed.
func NewHistogramFSEntry ¶
func NewHistogramFSEntry(path string, histogram *Histogram, checksum string) HistogramFSEntry
NewHistogramFSEntry returns a new entry with the given content.
type HistogramImageMetric ¶
type HistogramImageMetric struct { HistStorage HistogramStorage Metric HistogramMetric TileData [][]*Histogram K uint NumRoutines int }
HistogramImageMetric implements ImageMetric by keeping a histogram storage and computing histograms for a query image.
func NewHistogramImageMetric ¶
func NewHistogramImageMetric(storage HistogramStorage, metric HistogramMetric, numRoutines int) *HistogramImageMetric
NewHistogramImageMetric returns a new histogram image metric given a metric function between to histograms and the histogram storage to back the image metric. NumRoutines is the number of things that run concurrently when initializing the tile histograms.
func (*HistogramImageMetric) Compare ¶
func (m *HistogramImageMetric) Compare(storage ImageStorage, image ImageID, tileY, tileX int) (float64, error)
Compare compares a database image and a query image based on the histogram metric function.
func (*HistogramImageMetric) InitStorage ¶
func (m *HistogramImageMetric) InitStorage(storage ImageStorage) error
InitStorage does at the moment nothing.
func (*HistogramImageMetric) InitTiles ¶
func (m *HistogramImageMetric) InitTiles(storage ImageStorage, query image.Image, dist TileDivision) error
InitTiles concurrently computes the histograms of the tiles of the query image.
type HistogramMetric ¶
HistogramMetric is a function that compares images based on histograms. It has no other input than the histograms, especially it has no access to the image. More complicated ImageMetrics based on histogram should be defined by another type. A HistogramMetric can assume that both histograms are defined for the same k. The smaller the metric value is the more equal the images are considered.
Usually histogram metrics operate on normalized histograms. The metric value should be ≥ 0.
func GetHistogramMetric ¶
func GetHistogramMetric(name string) (HistogramMetric, bool)
GetHistogramMetric returns a registered histogram metric. Returns the metric and true on success and nil and false otherwise. See RegisterHistogramMetric for details.
func HistogramVectorMetric ¶
func HistogramVectorMetric(vm VectorMetric) HistogramMetric
HistogramVectorMetric converts a vector metric to a histogram metric.
type HistogramStorage ¶
type HistogramStorage interface { // GetHistogram returns the histogram for a previously registered ImageID. GetHistogram(id ImageID) (*Histogram, error) // Divisions returns the number of sub-divisons in each direction (called k // in the histogram documentation). All histograms from this storage should // have this number of sub-divisions. Divisions() uint }
HistogramStorage maps image ids to histograms. By default the histograms should be normalized.
Implementations must be safe for concurrent use.
type ImageCache ¶
type ImageCache struct {
// contains filtered or unexported fields
}
ImageCache is used to cache resized versions of images during mosaic generation. The same image with the same size might appear often in a mosaic (or the same area). This and the fact that resizing an image is not very fast makes it useful to cache the images.
Caches are safe for concurrent use.
func NewImageCache ¶
func NewImageCache(size int) *ImageCache
NewImageCache returns an empty image cache. size is the number of images that will be cached. size must be ≥ 1.
type ImageDivider ¶
type ImageDivider interface {
Divide(image.Rectangle) TileDivision
}
ImageDivider is a type to divide an image into tiles. That is it creates the areas which should be replaced by images from the database.
The returned distribution has to meet the following requirements:
(1) It returns a matrix of rectangles. That is the results contains rows and each row has the same length. So the element at (0, 0) describes the first rectangle in the image (top left corner).
(2) Rectangles might be of different size.
(3) The rectangle is not required to be a part of the image. In fact it must not even overlap with the image at some point, but usually it should.
(4) The result may be empty (or nil); rows may be empty.
(5) Images are stored in coordinates [y][x], that means each entry in the tile division describes a column.
type ImageHeap ¶
type ImageHeap struct {
// contains filtered or unexported fields
}
ImageHeap is a container that stores images sorted according to a float value.
func NewImageHeap ¶
NewImageHeap returns a new image heap with a given bound. If bound ≥ 0 it is used as the upper limit of entries stored in the heap. That is only the bound smallest images are stored.
func (*ImageHeap) AddEntry ¶
func (h *ImageHeap) AddEntry(entry ImageHeapEntry)
AddEntry adds a new entry to the heap, truncating the heap if bounds is ≥ 0.
func (*ImageHeap) GetView ¶
func (h *ImageHeap) GetView() []ImageHeapEntry
GetView returns the sorted collection of entries in the heap, that is images with smallest values first. The length of the result slice is between 0 and bounds. The complexity is O(n * log(n)) where n is the size of the heap.
type ImageHeapEntry ¶
ImageHeapEntry is an entry stored in an image heap. It consists of an image (by id) and the value of that image.
func NewImageHeapEntry ¶
func NewImageHeapEntry(image ImageID, value float64) ImageHeapEntry
NewImageHeapEntry returns a new heap entry.
type ImageID ¶
type ImageID int
ImageID is used to unambiguously identify an image.
const ( // NoImageID is used to signal errors etc. on images. // It is usually never used and you don't have to care about ImageID < 0. // Certain functions however use this value in a specific way. NoImageID ImageID = -1 )
func IDList ¶
func IDList(storage ImageStorage) []ImageID
IDList returns the list [0, 1, ..., storage.NumImages - 1].
type ImageMetric ¶
type ImageMetric interface { InitStorage(storage ImageStorage) error InitTiles(storage ImageStorage, query image.Image, dist TileDivision) error Compare(storage ImageStorage, image ImageID, tileY, tileX int) (float64, error) }
ImageMetric is used to compare a database image (image identified by an id) and a tile (previously registered) and return a metric value between the database image and the tile.
It is used in ImageMetricMinimizer which contains more information.
You might want to use InitTilesHelper to easily crate a concurrent InitTiles function.
An example implementation is given in HistogramImageMetric.
type ImageMetricMinimizer ¶
type ImageMetricMinimizer struct { Metric ImageMetric NumRoutines int }
ImageMetricMinimizer implements ImageSelector and selects the image with the smallest distance to the tile.
It relies on a ImageMetric. The Init method simply calls the InitStorage method of the provided metric.
Each time images should be selected it calls InitTiles on the metric and selects the best images.
Thus the workflow is as follows: First the InitStorage method of the metric is called. Again, it is not the job of the metric to keep in sync with a filesystem / web resource whatever. Then for a query once InitTiles is called on the metric. In this step information about the query image are computed, for example computing GCHs of the query tiles. Then multiple calls to compare are made. To get the actual tiles from an image and a distribution use DivideImage.
A note for more sophisticated storage approaches: At the moment all metric storages (for example histogram storage) have all the data fastly available in memory. This makes it easy to access an histogram. Here we iterate for each tile and then over each database image. This might be bad if the histograms for the database images are not loaded in memory and need to be opened from a file or database. Caches won't work fine because we iterate all database images, process to the next tile and repeat that. Thus an alternative version should be implemented iterating over the database images and then over the tiles, making it easier to cache things. However this requires more communication that is not necessary at the moment and so this implementation works fine as long as all information is in memory.
The minimizer ignores metric errors in the way that whenever Compare returns an error != nil the candidate will be omitted. However a message will be logged in this case.
func GCHSelector ¶
func GCHSelector(histStorage HistogramStorage, delta HistogramMetric, numRoutines int) *ImageMetricMinimizer
GCHSelector is an image selector that selects images that minimize the histogram metric function Δ. Formally it is an ImageMetricMinimizer and thus implements ImageSelector.
func LCHSelector ¶
func LCHSelector(storage LCHStorage, scheme LCHScheme, metric HistogramMetric, numRoutines int) *ImageMetricMinimizer
LCHSelector is an image selector that selects images that minimize the LCH distance |Δ(h1[1], h2[1])| + ... + |Δ(h1[n], h2[n])| where Δ is a histogram metric. Formally it is an ImageMetricMinimizer and thus implements ImageSelector.
func NewImageMetricMinimizer ¶
func NewImageMetricMinimizer(metric ImageMetric, numRoutines int) *ImageMetricMinimizer
NewImageMetricMinimizer returns a new metric minimizer given the metric to use and the number of go routines to run when selecting images.
func (*ImageMetricMinimizer) Init ¶
func (min *ImageMetricMinimizer) Init(storage ImageStorage) error
Init just calls InitStorage of the metric.
func (*ImageMetricMinimizer) SelectImages ¶
func (min *ImageMetricMinimizer) SelectImages(storage ImageStorage, query image.Image, dist TileDivision, progress ProgressFunc) ([][]ImageID, error)
SelectImages selects the image that minimizes the metric for each tile. It computes the most fitting image for NumRoutines tiles concurrently.
type ImageResizer ¶
ImageResizer resizes an image to the given width and height.
type ImageSelector ¶
type ImageSelector interface { // Init is called each time the storage changes and at creation. // Note that in general a selector is not responsible for syncing histograms // with filesystem files etc. This should happen outside the storage. Init(storage ImageStorage) error // SelectImage is called after Init and returns the most fitting images for // the query. The returned images matrix must be of the same size as the // dist matrix. // // This step usually involves iterating over the precomputed data (for example // histograms for a database of images) and selecting the most fitting one. // // ImageMetricMinimizer is an example implementation. // // If no image can be selected (for example empty database) the id in the // result should be set to NoImageID. SelectImages(storage ImageStorage, query image.Image, dist TileDivision, progress ProgressFunc) ([][]ImageID, error) }
ImageSelector is used to select images for all tiles. The workflow is as follows: The selector gets initialized by calling Init, then images are selected with SelectImages.
This is because we might want to use an selector multiple times, though no such approach is implemented at the moment.
type ImageStorage ¶
type ImageStorage interface { // NumImages returns the number of images in the storage as an ImageID. // All ids < than NumImages are considered valid and can be retrieved via // LoadImage. NumImages() ImageID // LoadImage loads an image into memory. LoadImage(id ImageID) (image.Image, error) // LoadConfig loads the config of the image with the given id. LoadConfig(id ImageID) (image.Config, error) }
ImageStorage is used to administrate a collection or database of images. Images are not stored in memory but are identified by an id and can be loaded into memory when required. A storage has a maximal id and can be used to access images with ids smaller than the the number of images. The access methods should return an error if the image id is not associated with any image data or if there is an error reading the image (e.g. from the filesystem).
Implementations must be safe for concurrent use.
type LCH ¶
type LCH struct {
Histograms []*Histogram
}
LCH is a sorted collection of global color histograms. Different schemes yield to a different number of LCHs, but for each image the same number of GCHs is computed.
All histograms should be generated with the same k (sub-divisons).
func CreateAllLCHs ¶
func CreateAllLCHs(scheme LCHScheme, storage ImageStorage, normalize bool, k uint, numRoutines int, progress ProgressFunc) ([]*LCH, error)
CreateAllLCHs creates all lchs for images in the storage. It is a shortcut using CreateLCHs, see this documentation for details.
func CreateLCHs ¶
func CreateLCHs(scheme LCHScheme, ids []ImageID, storage ImageStorage, normalize bool, k uint, numRoutines int, progress ProgressFunc) ([]*LCH, error)
CreateLCHs creates histograms for all images in the ids list and loads the images through the given storage. If you want to create all histograms for a given storage you can use CreateAllLCHs as a shortcut. It runs the creation of LCHs concurrently (how many go routines run concurrently can be controlled by numRoutines). k is the number of sub-divisons as described in the histogram type, If normalized is true the normalized histograms are computed. progress is a function that is called to inform about the progress, see doucmentation for ProgressFunc.
func GenLCH ¶
GenLCH computes the LCHs an image. It uses the scheme to compute the image parts and then concurrently creates the GCHs for each list. k and normalize are defined as for the GCH method: k is the number of histogram sub-divisions and if normalize is true the GCHs are normalized.
func (*LCH) Dist ¶
func (lch *LCH) Dist(other *LCH, delta HistogramMetric) (float64, error)
Dist returns the distance between two LCHs parameterized by a HistogramMetric two compare the histograms. It returns |Δ(h1[1], h2[1])| + ... + |Δ(h1[n], h2[n])| if n is the number of GCHs of the LCH.
If the LCHs are of different dimensions or the GCHs inside the LCHs are of different dimensions an error != nil is returned.
type LCHFSController ¶
type LCHFSController struct { Entries []LCHFSEntry K uint Size uint Version string }
LCHFSController is used to store LCHs (wrapped by LCHFSEntry) on the filesystem.
It's the same idea as with HistogramFSController, see details there. Some of the functions implemented for HistogramFSController are not implemented here because they're not needed at the moment. But they could be implemented similar to those in HistogramFSController.
func CreateLCHFSController ¶
func CreateLCHFSController(ids []ImageID, mapper *FSMapper, storage LCHStorage) (*LCHFSController, error)
CreateLCHFSController creates a histogram filesystem controller given some input data. ids is the list of all image ids to be included in the controler, mapper is used to get the absolute path of an image (stored alongside the LCH data) and the storage is used to lookup the LCHs.
If you want to create a fs controller with all ids from a storage you can use IDList to create a list of all ids.
func NewLCHFSController ¶
func NewLCHFSController(k, schemeSize uint, capacity int) *LCHFSController
NewLCHFSController returns an empty file system controller with the given capacity. Too create a new file system controller initialized with some content use CreateLCHFSController.
func (*LCHFSController) Map ¶
func (c *LCHFSController) Map() map[string]*LCH
Map computes the mapping filename ↦ lch. That is useful sometimes, especially when computing the diff between this and an FSMapper.
func (*LCHFSController) ReadFile ¶
func (c *LCHFSController) ReadFile(path string) error
ReadFile reads the content of the controller from the specified file. The read method depends on the file extension which must be either .json or .gob.
func (*LCHFSController) ReadGobFile ¶
func (c *LCHFSController) ReadGobFile(path string) error
ReadGobFile reads the content of the controller from the specified file. The file must be encoded in gob.
func (*LCHFSController) ReadJSONFile ¶
func (c *LCHFSController) ReadJSONFile(path string) error
ReadJSONFile reads the content of the controller from the specified file. The file must be encoded in json.
func (*LCHFSController) WriteFile ¶
func (c *LCHFSController) WriteFile(path string) error
WriteFile writes the content of the controller to a file depending on the file extension hich must be either .json or .gob.
func (*LCHFSController) WriteGobFile ¶
func (c *LCHFSController) WriteGobFile(path string) error
WriteGobFile writes the LCH to a file encoded gob format.
func (*LCHFSController) WriteJSON ¶
func (c *LCHFSController) WriteJSON(path string) error
WriteJSON writes the LCHs to a file encoded in json format.
type LCHFSEntry ¶
LCHFSEntry is used to store LCHs on the filesystem. It contains the path of the image the LCH was created for as well as the LCH data.
It also has a field checksum that is not used yet. Later it can be adjusted s.t. an histgram is stored together with the checksum (e.g. just plain md5 encoded with e.g. base64) of the image the histogram was created for. This way we can test if the content of an image has changed, and thus the histogram became invalid. At the moment we don't recognize if an image has changed.
This is however not supported at the moment. An empty string signals that no checksum was computed.
func NewLCHFSEntry ¶
func NewLCHFSEntry(path string, lch *LCH, checksum string) LCHFSEntry
NewLCHFSEntry returns a new entry with the given content.
type LCHImageMetric ¶
type LCHImageMetric struct { LCHStorage LCHStorage Scheme LCHScheme Metric HistogramMetric TileData [][]*LCH // we don't really have to save it, but it won't hurt // better than calling storage.Divisions again and again K uint NumRoutines int }
LCHImageMetric implements ImageMetric by building the LCH sum, that is |Δ(h1[1], h2[1])| + ... + |Δ(h1[n], h2[n])| where Δ is a histogram metric.
func NewLCHImageMetric ¶
func NewLCHImageMetric(storage LCHStorage, scheme LCHScheme, metric HistogramMetric, numRoutines int) *LCHImageMetric
NewLCHImageMetric returns a new LCH based metric.
func (*LCHImageMetric) Compare ¶
func (m *LCHImageMetric) Compare(storage ImageStorage, image ImageID, tileY, tileX int) (float64, error)
Compare compares a database image and a query image based on the histogram metric function.
func (LCHImageMetric) InitStorage ¶
func (m LCHImageMetric) InitStorage(storage ImageStorage) error
InitStorage does nothing.
func (*LCHImageMetric) InitTiles ¶
func (m *LCHImageMetric) InitTiles(storage ImageStorage, query image.Image, dist TileDivision) error
InitTiles concurrently computes the LCHs of the tiles of the query image.
type LCHScheme ¶
LCHScheme returns the distribution of an image into sub images. Note that a sub image can be contained in multiple lists and not all lists must be of the same length. For example the four parts scheme: The first list could contain both top sub images. The western list would contain the bot left sub images. They both contain the to-left image.
Schemes always return a fixed number of image lists.
type LCHStorage ¶
type LCHStorage interface { // GetLCH returns the LCH for a previously registered ImageID. GetLCH(id ImageID) (*LCH, error) // Divisions returns the number of sub-divisions used in the gchs of an LCH. Divisions() uint // SchemeSize returns the number of gchs stored for each lch. SchemeSize() uint }
LCHStorage maps image ids to LCHs. By default the histograms of the LCHs should be normalized.
Implementations must be safe for concurrent use.
type MemoryHistStorage ¶
MemoryHistStorage implements HistogramStorage by keeping a list of histograms in memory.
func MemHistStorageFromFSMapper ¶
func MemHistStorageFromFSMapper(mapper *FSMapper, fileContent *HistogramFSController, histMap map[string]*Histogram) (*MemoryHistStorage, error)
MemHistStorageFromFSMapper creates a new memory histogram storage that contains an entry for each image described by the filesystem mapper. If no histogram for an image is found an error is returned. An error is also returned if there is an invalid histogram (wrong k, wrong size of entries).
HistMap is the map as computed by the Map() function of the histogram controller. It is an argument to avoid multiple compoutations of it if used more often. Just set it to nil and it will be computed with the map function.
func NewMemoryHistStorage ¶
func NewMemoryHistStorage(k uint, capacity int) *MemoryHistStorage
NewMemoryHistStorage returns a new memory histogram storage storing histograms with k sub-divisons. Capacity is the capacity of the underlying histogram array, negative values yield to a default capacity.
func (*MemoryHistStorage) Divisions ¶
func (s *MemoryHistStorage) Divisions() uint
Divisions returns the number of sub-divisions k.
func (*MemoryHistStorage) GetHistogram ¶
func (s *MemoryHistStorage) GetHistogram(id ImageID) (*Histogram, error)
GetHistogram implements the HistogramStorage interface function by returning the histogram on position id in the list. If id is not a valid position inside the the list an error is returned.
type MemoryLCHStorage ¶
MemoryLCHStorage implements LCHStorage by keeping a list of LCHs in memory.
func MemLCHStorageFromFSMapper ¶
func MemLCHStorageFromFSMapper(mapper *FSMapper, fileContent *LCHFSController, lchMap map[string]*LCH) (*MemoryLCHStorage, error)
MemLCHStorageFromFSMapper creates a new memory LCH storage that contains an entry MemLCHStorageFromFSMapper each image described by the filesystem mapper. If no lch for an image is found an error is returned.
HistMap is the map as computed by the Map() function of the LCH controller. It is an argument to avoid multiple compoutations of it if used more often. Just set it to nil and it will be computed with the map function.
func NewMemoryLCHStorage ¶
func NewMemoryLCHStorage(k, schemeSize uint, capacity int) *MemoryLCHStorage
NewMemoryLCHStorage returns a new memory LCH storage storing LCHs of size schemeSize with k sub-divisions. Capacity is the capacity of the underlying histogram array, negative values yield to a default capacity.
func (*MemoryLCHStorage) Divisions ¶
func (s *MemoryLCHStorage) Divisions() uint
Divisions returns the number of sub-divisions k.
func (*MemoryLCHStorage) GetLCH ¶
func (s *MemoryLCHStorage) GetLCH(id ImageID) (*LCH, error)
GetLCH implements the LCHStorage interface function by returning the LCH on position id in the list. If id is not a valid position inside the the list an error is returned.
func (*MemoryLCHStorage) SchemeSize ¶
func (s *MemoryLCHStorage) SchemeSize() uint
SchemeSize returns the number of GCHs stored for each LCH in the storage.
type NfntResizer ¶
type NfntResizer struct { // InterP is the interpolation function to use. InterP resize.InterpolationFunction }
NfntResizer uses the nfnt/resize package to resize an image.
func NewNfntResizer ¶
func NewNfntResizer(interP resize.InterpolationFunction) NfntResizer
NewNfntResizer returns a new resizer given the interpolation function.
type ProgressFunc ¶
type ProgressFunc func(num int)
ProgressFunc is a function that is used to inform a caller about the progress of a called function. For example if we process thousands of images we might wish to know how far the call is and give feedback to the user. The called method calls the process function after each iteration.
func LoggerProgressFunc ¶
func LoggerProgressFunc(prefix string, max, step int) ProgressFunc
LoggerProgressFunc is a parameterized ProgressFunc that logs to log. The output describes the progress (how many of how many objects processed). Log messages may have an addition prefix. max is the total number of elements to process and step describes how often to print to the log (for example step = 100 every 100 items).
func StdProgressFunc ¶
func StdProgressFunc(w io.Writer, prefix string, max, step int) ProgressFunc
StdProgressFunc is a parameterized ProgressFunc that logs to the specified writer. The output describes the progress (how many of how many objects processed). Log messages may have an addition prefix. max is the total number of elements to process and step describes how often to print to the log (for example step = 100 every 100 items).
type RGB ¶
type RGB struct {
R, G, B uint8
}
RGB is a color containing r, g and b components.
func ConvertRGB ¶
ConvertRGB converts a generic color into the internal RGB representation.
type RandomHeapSelector ¶
type RandomHeapSelector struct {
// contains filtered or unexported fields
}
RandomHeapSelector implements HeapSelector by using just a random element from each heap.
Note that instances of this selector are not safe for concurrent use.
func NewRandomHeapSelector ¶
func NewRandomHeapSelector(randGen *rand.Rand) *RandomHeapSelector
NewRandomHeapSelector returns a new random selector. The provided random generator is used to generate random numbers. You can use nil and a random generator will be created.
Note that rand.Rand instances are not safe for concurrent use. Thus using the same generator on two instances that run concurrently is not allowed.
func (*RandomHeapSelector) Select ¶
func (sel *RandomHeapSelector) Select(storage ImageStorage, query image.Image, dist TileDivision, heaps [][]*ImageHeap) ([][]ImageID, error)
Select implements the HeapSelector interface, it selects the random images.
type ReplHandler ¶
type ReplHandler struct{}
ReplHandler implements CommandHandler by reading commands from stdin and writing output to stdout.
func (ReplHandler) After ¶
func (h ReplHandler) After(s *ExecutorState)
func (ReplHandler) Before ¶
func (h ReplHandler) Before(s *ExecutorState)
func (ReplHandler) Init ¶
func (h ReplHandler) Init() *ExecutorState
Init creates an initial ExecutorState. It creates a new mapper and image database and sets the working directory to the current directory. This method might panic if something with filepath is wrong, this should however usually not be the case.
func (ReplHandler) OnError ¶
func (h ReplHandler) OnError(s *ExecutorState, err error, cmd Command) bool
func (ReplHandler) OnInvalidCmd ¶
func (h ReplHandler) OnInvalidCmd(s *ExecutorState, cmd string) bool
func (ReplHandler) OnParseErr ¶
func (h ReplHandler) OnParseErr(s *ExecutorState, err error) bool
func (ReplHandler) OnScanErr ¶
func (h ReplHandler) OnScanErr(s *ExecutorState, err error)
func (ReplHandler) OnSuccess ¶
func (h ReplHandler) OnSuccess(s *ExecutorState, cmd Command)
func (ReplHandler) Start ¶
func (h ReplHandler) Start(s *ExecutorState)
type ResizeStrategy ¶
type ResizeStrategy func(resizer ImageResizer, tileWidth, tileHeight uint, img image.Image) image.Image
ResizeStrategy is a function that scales an image (img) to an image of exyctly the size defined by tileWidth and tileHeight. This is used to compose the mosaic when the selected database images must be resized to fit in the tiles.
The difference between ResizeStrategy and ImageResizer is that we think of an ImageResizer as an "engine", for example a libarary, that performs the of scaling an image exactly to a specific width and height. A ResizeStrategy might first resize an image to some other size and then return a subimage. That is we think of a resizer as something that does the work and a ResizeStrategy as something that decides how to nicely scale an image s.t. it fits nicely.
type ScriptHandler ¶
ScriptHandler implements CommandHandler. It writes the output to stdout and reads from a specified reader. It stops whenever an error is enountered.
func NewScriptHandler ¶
func NewScriptHandler(source io.Reader) ScriptHandler
NewScriptHandler returns a new script handler that reads input from the given source.
func ScriptHandlerFromCmds ¶
func ScriptHandlerFromCmds(lines []string) ScriptHandler
ScriptHandlerFromCmds is a function to create a script handler from a predefined set of lines. This allows us for easy execution of predefined scripts.
func (ScriptHandler) After ¶
func (h ScriptHandler) After(s *ExecutorState)
func (ScriptHandler) Before ¶
func (h ScriptHandler) Before(s *ExecutorState)
func (ScriptHandler) Init ¶
func (h ScriptHandler) Init() *ExecutorState
Init creates an initial ExecutorState. It creates a new mapper and image database and sets the working directory to the current directory. This method might panic if something with filepath is wrong, this should however usually not be the case.
func (ScriptHandler) OnError ¶
func (h ScriptHandler) OnError(s *ExecutorState, err error, cmd Command) bool
func (ScriptHandler) OnInvalidCmd ¶
func (h ScriptHandler) OnInvalidCmd(s *ExecutorState, cmd string) bool
func (ScriptHandler) OnParseErr ¶
func (h ScriptHandler) OnParseErr(s *ExecutorState, err error) bool
func (ScriptHandler) OnScanErr ¶
func (h ScriptHandler) OnScanErr(s *ExecutorState, err error)
func (ScriptHandler) OnSuccess ¶
func (h ScriptHandler) OnSuccess(s *ExecutorState, cmd Command)
func (ScriptHandler) Start ¶
func (h ScriptHandler) Start(s *ExecutorState)
type SupportedImageFunc ¶
SupportedImageFunc is a function that takes a file extension and decides if this file extension is supported. Usually our library should support jpg and png files, but this may change depending on what image protocols are loaded.
The extension passed to this function could be for example ".txt" or ".jpg". JPGAndPNG is an implementation accepting jpg and png files.
type TileDivision ¶
TileDivision represents the divison of an image into rectangles. See ImageDivider for details about divisions.
Divisons are stored column wise, that is each entry in division is a column. division[0] is the first column etc.
func RepairDistribution ¶
func RepairDistribution(distribution TileDivision, numX, numY int) TileDivision
RepairDistribution is used to ensure that distribution contains a matrix of numY rows and in each row numX columns. Usually this method does not do anything (and hopefully never will). But just to be sure we add it here. It will never decrease the number of rectangles, only increase if required.
This function is usally only triggered in debug mode.
func (TileDivision) Size ¶
func (div TileDivision) Size() int
Size returns the total number of rectangles.
type Tiles ¶
Tiles are the tiles of an image. They're genrated from a TileDivision and the image matrix is of the same size as the TileDivision.
Tiles are stored column wise, that is each entry in tiles is a column. tiles[0] is the first column etc.
func DivideImage ¶
DivideImage computes the actual tiles from an image and the distribution into tile rectangles. The returned images should all be part of the image, thus must not have the same size as suggested by the distribution.
type VectorMetric ¶
VectorMetric is a function that takes two vectors of the same length and returns a metric value ("distance") of the two.
Vector metrics therefor can be used for comparing histograms.