-
Notifications
You must be signed in to change notification settings - Fork 110
/
orb.go
96 lines (90 loc) · 2.75 KB
/
orb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package keypoints
import (
"encoding/json"
"errors"
"image"
"os"
"path/filepath"
"go.viam.com/utils"
)
// ORBConfig contains the parameters / configs needed to compute ORB features.
type ORBConfig struct {
Layers int `json:"n_layers"`
DownscaleFactor int `json:"downscale_factor"`
FastConf *FASTConfig `json:"fast"`
BRIEFConf *BRIEFConfig `json:"brief"`
}
// LoadORBConfiguration loads a ORBConfig from a json file.
func LoadORBConfiguration(file string) (*ORBConfig, error) {
var config ORBConfig
filePath := filepath.Clean(file)
configFile, err := os.Open(filePath)
defer utils.UncheckedErrorFunc(configFile.Close)
if err != nil {
return nil, err
}
jsonParser := json.NewDecoder(configFile)
err = jsonParser.Decode(&config)
if err != nil {
return nil, err
}
err = config.Validate(file)
if err != nil {
return nil, err
}
return &config, nil
}
// Validate ensures all parts of the ORBConfig are valid.
func (config *ORBConfig) Validate(path string) error {
if config.Layers < 1 {
return utils.NewConfigValidationError(path, errors.New("n_layers should be >= 1"))
}
if config.DownscaleFactor <= 1 {
return utils.NewConfigValidationError(path, errors.New("downscale_factor should be greater than 1"))
}
if config.FastConf == nil {
return utils.NewConfigValidationFieldRequiredError(path, "fast")
}
if config.BRIEFConf == nil {
return utils.NewConfigValidationFieldRequiredError(path, "brief")
}
return nil
}
// ComputeORBKeypoints compute ORB keypoints on gray image.
func ComputeORBKeypoints(im *image.Gray, sp *SamplePairs, cfg *ORBConfig) ([]Descriptor, KeyPoints, error) {
pyramid, err := GetImagePyramid(im)
if err != nil {
return nil, nil, err
}
if cfg.Layers <= 0 {
err = errors.New("number of layers should be > 0")
return nil, nil, err
}
if cfg.DownscaleFactor <= 1 {
err = errors.New("number of layers should be >= 2")
return nil, nil, err
}
if len(pyramid.Scales) < cfg.Layers {
err = errors.New("more layers than actual number of octaves in image pyramid")
return nil, nil, err
}
orbDescriptors := []Descriptor{}
orbPoints := make(KeyPoints, 0)
for i := 0; i < cfg.Layers; i++ {
currentImage := pyramid.Images[i]
currentScale := pyramid.Scales[i]
fastKps := NewFASTKeypointsFromImage(currentImage, cfg.FastConf)
rescaledKps := RescaleKeypoints(fastKps.Points, currentScale)
rescaledFASTKps := FASTKeypoints{
Points: rescaledKps,
Orientations: fastKps.Orientations,
}
orbPoints = append(orbPoints, rescaledFASTKps.Points...)
descs, err := ComputeBRIEFDescriptors(currentImage, sp, &rescaledFASTKps, cfg.BRIEFConf)
if err != nil {
return nil, nil, err
}
orbDescriptors = append(orbDescriptors, descs...)
}
return orbDescriptors, orbPoints, nil
}