Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XGboost Changes for ocean-prefilter #14

Merged
merged 14 commits into from
Jul 23, 2024
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ This module implements the [`rdk:service:vision` API](https://docs.viam.com/ml/v

When you configure a machine with this module, the module:
- Locates the horizon, crops the image to only include the water, and then divides the water into patches.
- Turns the resulting patches into histograms, which it interprets as probability distrubutions for their color/intensity values.
- Conducts a Kolmogorov-Smirnov test on the histograms from before and after images and determines if the scenes are consistent or if a new element has appeared.
- Performs feature extraction on the resulting patches, average pooling the the patches with a window size of (10, 2) and taking the mean of the R, G, B channels for each resulting sub-patch
- Classifies the frame using XGBoost - this will trigger if any patch in the given image is found "interesting"

Strong motion of the waves or bobbing up-and-down of the boat can trigger the pre-filter.
This vision service only returns one label classification called `TRIGGER` with a confidence of `1.0`.
Expand Down Expand Up @@ -56,7 +56,14 @@ Copy and paste the following attribute template into your vision service's attri

| Name | Type | Inclusion | Description | Value |
|-------|-------|-----------|-------------| ------|
| `camera_name` | string | **Required** | Links the pre-filter to a specific camera and continuously monitors the camera stream for changes or triggers in the background. | The name of your camera component. |
| `camera_name` | string | Optional | Links the pre-filter to a specific camera and continuously monitors the camera stream for changes or triggers in the background. | The name of your camera component. If the camera name is not provided, you can input your own image from the VIAM API |
| `threshold` | int | Optional | Determines the sensitivity of the pre-filter trigger. This enables the pre-filter to detect significant motion such as boat or wave movements, and identifies objects like other boats, buoys, or any deviations from typical water patterns. | 0 to 1<br/> Default: `0.25` |
| `max_frequency_hz`| int | Optional | Determines the frequency that the vision service monitors the background camera stream for changes. If your scene changes very slowly set this below 1. | 1 to 10<br/> Default: `10` |
| `excluded_region` | object | Optional | Specifies areas within the cameras view to ignore. This is useful for excluding static parts of the camera stream, like parts of the boat. | A list of coordinates in frame. |

### Example
The test module example gives an example of how to run/use the service
provide your test directory to the module in the form of a command line argument
```
run main.go <your directory here>
```
53 changes: 53 additions & 0 deletions example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
_ "embed"
"fmt"
"image"
"os"
"path/filepath"

xgb "github.com/Elvenson/xgboost-go"
"github.com/Elvenson/xgboost-go/activation"
"github.com/viamrobotics/ocean-prefilter/oceanprefilter"
)

//go:embed xg_boost_dump.json
var modelbytes []byte
bhaney marked this conversation as resolved.
Show resolved Hide resolved

func main() {
dir := os.Args[1]
fmt.Println(dir)
files, _ := os.ReadDir(dir)

rc := oceanprefilter.RunConfig{}
ensemble, err := xgb.LoadXGBoostFromJSONBytes(modelbytes,
"", 2, 8, &activation.Softmax{})

if err != nil {
fmt.Println(err)
}

rc.Model = ensemble
rc.Threshold = 0.25
rect := image.Rectangle{
Min: image.Point{X: 250, Y: 350},
Max: image.Point{X: 580, Y: 480},
}

rc.ExcludedZone = &rect
for _, file := range files {
fp := filepath.Join(dir, file.Name())
f, _ := os.Open(fp)

defer f.Close()
img, _, _ := image.Decode(f)

res, err := oceanprefilter.MakeInference(img, rc)
if err != nil {
fmt.Println("error making inference: ", err)
} else {
fmt.Printf("output is %t: ", res)
}
}
}
20 changes: 20 additions & 0 deletions example/test.libsvm

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions example/xg_boost_dump.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
[
{ "nodeid": 0, "depth": 0, "split": "f327", "split_condition": 110.783333, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "depth": 1, "split": "f14", "split_condition": 199.883331, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "depth": 2, "split": "f436", "split_condition": 108.216667, "yes": 7, "no": 8, "missing": 8 , "children": [
{ "nodeid": 7, "leaf": 0.96825397 },
{ "nodeid": 8, "leaf": -0 }
]},
{ "nodeid": 4, "leaf": -0 }
]},
{ "nodeid": 2, "depth": 1, "split": "f628", "split_condition": 107.199997, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": -0.800000012 },
{ "nodeid": 6, "leaf": 0.200000003 }
]}
]},
{ "nodeid": 0, "depth": 0, "split": "f327", "split_condition": 110.783333, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "depth": 1, "split": "f14", "split_condition": 199.883331, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "depth": 2, "split": "f436", "split_condition": 108.216667, "yes": 7, "no": 8, "missing": 8 , "children": [
{ "nodeid": 7, "leaf": -0.96825397 },
{ "nodeid": 8, "leaf": -0 }
]},
{ "nodeid": 4, "leaf": -0 }
]},
{ "nodeid": 2, "depth": 1, "split": "f628", "split_condition": 107.199997, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": 0.800000012 },
{ "nodeid": 6, "leaf": -0.200000003 }
]}
]},
{ "nodeid": 0, "depth": 0, "split": "f532", "split_condition": 140.75, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "depth": 1, "split": "f28", "split_condition": 204.416672, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "depth": 2, "split": "f401", "split_condition": 111.400002, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": 0.570969284 },
{ "nodeid": 6, "leaf": -0.183552772 }
]},
{ "nodeid": 4, "leaf": -0.117992692 }
]},
{ "nodeid": 2, "leaf": -0.571418047 }
]},
{ "nodeid": 0, "depth": 0, "split": "f532", "split_condition": 140.75, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "depth": 1, "split": "f28", "split_condition": 204.416672, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "depth": 2, "split": "f401", "split_condition": 111.400002, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": -0.570969284 },
{ "nodeid": 6, "leaf": 0.183552772 }
]},
{ "nodeid": 4, "leaf": 0.117992707 }
]},
{ "nodeid": 2, "leaf": 0.571418047 }
]},
{ "nodeid": 0, "depth": 0, "split": "f532", "split_condition": 140.75, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "depth": 1, "split": "f28", "split_condition": 204.416672, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "depth": 2, "split": "f410", "split_condition": 110.650002, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": 0.466001004 },
{ "nodeid": 6, "leaf": -0.0753230453 }
]},
{ "nodeid": 4, "leaf": -0.0537564792 }
]},
{ "nodeid": 2, "leaf": -0.356984079 }
]},
{ "nodeid": 0, "depth": 0, "split": "f532", "split_condition": 140.75, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "depth": 1, "split": "f28", "split_condition": 204.416672, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "depth": 2, "split": "f410", "split_condition": 110.650002, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": -0.466000974 },
{ "nodeid": 6, "leaf": 0.0753231421 }
]},
{ "nodeid": 4, "leaf": 0.0537564307 }
]},
{ "nodeid": 2, "leaf": 0.356984049 }
]},
{ "nodeid": 0, "depth": 0, "split": "f284", "split_condition": 101.400002, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.347005337 },
{ "nodeid": 2, "depth": 1, "split": "f300", "split_condition": 95.5, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "leaf": -0.381696463 },
{ "nodeid": 4, "depth": 2, "split": "f656", "split_condition": 104.199997, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": -0.073965922 },
{ "nodeid": 6, "leaf": 0.385791391 }
]}
]}
]},
{ "nodeid": 0, "depth": 0, "split": "f284", "split_condition": 101.400002, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.347005308 },
{ "nodeid": 2, "depth": 1, "split": "f300", "split_condition": 95.5, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "leaf": 0.381696492 },
{ "nodeid": 4, "depth": 2, "split": "f656", "split_condition": 104.199997, "yes": 5, "no": 6, "missing": 6 , "children": [
{ "nodeid": 5, "leaf": 0.0739660487 },
{ "nodeid": 6, "leaf": -0.385791391 }
]}
]}
]},
{ "nodeid": 0, "depth": 0, "split": "f743", "split_condition": 90.1333313, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.279968023 },
{ "nodeid": 2, "depth": 1, "split": "f290", "split_condition": 108.033333, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "leaf": -0.234077886 },
{ "nodeid": 4, "leaf": 0.147569537 }
]}
]},
{ "nodeid": 0, "depth": 0, "split": "f743", "split_condition": 90.1333313, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.279968172 },
{ "nodeid": 2, "depth": 1, "split": "f290", "split_condition": 108.033333, "yes": 3, "no": 4, "missing": 4 , "children": [
{ "nodeid": 3, "leaf": 0.234077781 },
{ "nodeid": 4, "leaf": -0.147569537 }
]}
]},
{ "nodeid": 0, "depth": 0, "split": "f633", "split_condition": 100.066666, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.197402045 },
{ "nodeid": 2, "leaf": -0.139941201 }
]},
{ "nodeid": 0, "depth": 0, "split": "f633", "split_condition": 100.066666, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.197402418 },
{ "nodeid": 2, "leaf": 0.13994123 }
]},
{ "nodeid": 0, "depth": 0, "split": "f53", "split_condition": 127.416664, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.166276604 },
{ "nodeid": 2, "leaf": -0.126794532 }
]},
{ "nodeid": 0, "depth": 0, "split": "f53", "split_condition": 127.416664, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.166276589 },
{ "nodeid": 2, "leaf": 0.126794517 }
]},
{ "nodeid": 0, "depth": 0, "split": "f712", "split_condition": 92.8833313, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.123596296 },
{ "nodeid": 2, "leaf": 0.151612476 }
]},
{ "nodeid": 0, "depth": 0, "split": "f712", "split_condition": 92.8833313, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.123594895 },
{ "nodeid": 2, "leaf": -0.151612416 }
]},
{ "nodeid": 0, "depth": 0, "split": "f633", "split_condition": 100.066666, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.113635384 },
{ "nodeid": 2, "leaf": -0.107038438 }
]},
{ "nodeid": 0, "depth": 0, "split": "f633", "split_condition": 100.066666, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.11363478 },
{ "nodeid": 2, "leaf": 0.107038461 }
]},
{ "nodeid": 0, "depth": 0, "split": "f602", "split_condition": 92.8499985, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": -0.1141828 },
{ "nodeid": 2, "leaf": 0.110286467 }
]},
{ "nodeid": 0, "depth": 0, "split": "f602", "split_condition": 92.8499985, "yes": 1, "no": 2, "missing": 2 , "children": [
{ "nodeid": 1, "leaf": 0.114181779 },
{ "nodeid": 2, "leaf": -0.110286497 }
]}
]
16 changes: 9 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.21.7
toolchain go1.21.12

require (
github.com/Elvenson/xgboost-go v0.1.4
github.com/disintegration/imaging v1.6.2
github.com/pkg/errors v0.9.1
go.viam.com/rdk v0.28.0
go.viam.com/test v1.1.1-0.20220913152726-5da9916c08a2
Expand All @@ -31,10 +33,10 @@ require (
github.com/campoy/embedmd v1.0.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/chewxy/math32 v1.10.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/edaniels/golog v0.0.0-20230215213219-28954395e8d0 // indirect
github.com/edaniels/lidario v0.0.0-20220607182921-5879aa7b96dd // indirect
Expand All @@ -59,7 +61,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/gonuts/binary v0.2.0 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
Expand Down Expand Up @@ -138,14 +140,14 @@ require (
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20230725012225-302865e7556b // indirect
golang.org/x/image v0.15.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/image v0.18.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gonum.org/v1/gonum v0.12.0 // indirect
gonum.org/v1/plot v0.12.0 // indirect
Expand Down
Loading
Loading