geoai 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +4 -3
- package/geoai.js +515 -137
- package/index.d.ts +101 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.6] - 2026-07-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- ChangeStar ViT-B building footprint model (`geobase/changestar-building-segmentation-vitb`)
|
|
14
|
+
- Building segmentation factory to route Hub `modelId` to the correct runner
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- `building-footprint-segmentation` now defaults to ChangeStar; pass
|
|
18
|
+
`modelId: "geobase/building-footprint-segmentation"` for the lighter model
|
|
19
|
+
|
|
20
|
+
## [1.0.5] - 2026-07-15
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- WMS map provider with OGC GetMap support (EPSG:3857 bbox, WMS 1.1.1 / 1.3.0)
|
|
24
|
+
- `examples/06-wms-quickstart` — NRW orthophotos (`nw_dop_rgb`), draw-to-detect, NRW geocoder
|
|
25
|
+
- Interactive TMS and WMS providers in `live-examples-nextjs` task demos
|
|
26
|
+
- WMS documentation (`wms.mdx`), map-providers table update, and 17 WMS tests (including pipeline inference)
|
|
27
|
+
- Project roadmap (`_docs4devs/ROADMAP.md`) for use-case guides and quantization pipeline backlog
|
|
28
|
+
|
|
10
29
|
## [1.0.4] - 2026-07-11
|
|
11
30
|
|
|
12
31
|
### Added
|
package/README.md
CHANGED
|
@@ -40,12 +40,12 @@ You can also use GeoAI directly in the browser via CDN:
|
|
|
40
40
|
|
|
41
41
|
#### Unpkg CDN
|
|
42
42
|
```html
|
|
43
|
-
<script src="https://unpkg.com/geoai@1.0.
|
|
43
|
+
<script src="https://unpkg.com/geoai@1.0.6/geoai.js"></script>
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
#### jsDelivr CDN
|
|
47
47
|
```html
|
|
48
|
-
<script src="https://cdn.jsdelivr.net/npm/geoai@1.0.
|
|
48
|
+
<script src="https://cdn.jsdelivr.net/npm/geoai@1.0.6/geoai.min.js"></script>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
When using CDN, the library is available globally as `geoai`.
|
|
@@ -235,6 +235,7 @@ const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
|
|
|
235
235
|
|
|
236
236
|
- **Documentation**: [docs.geobase.app/geoai](https://docs.geobase.app/geoai) - Comprehensive documentation, examples, and API reference
|
|
237
237
|
- **Live Examples**: [docs.geobase.app/geoai-live](https://docs.geobase.app/geoai-live) - Interactive examples and demos
|
|
238
|
+
- **Roadmap**: [_docs4devs/ROADMAP.md](_docs4devs/ROADMAP.md) - Planned docs, quantization pipeline, and related backlog
|
|
238
239
|
- **Community**: [GitHub Discussions](https://github.com/decision-labs/geoai.js/discussions) - Ask questions, share ideas, and connect with other developers
|
|
239
240
|
- **Code**: [GitHub Repository](https://github.com/decision-labs/geoai.js) - Source code and contributions
|
|
240
241
|
- **Issues**: [GitHub Issues](https://github.com/decision-labs/geoai.js/issues) - Report bugs and request features
|
|
@@ -247,4 +248,4 @@ We welcome contributions! Please see our [contributing guide](CONTRIBUTING.md) f
|
|
|
247
248
|
|
|
248
249
|
MIT License - see [LICENSE.md](LICENSE.md) for details.
|
|
249
250
|
|
|
250
|
-
[//]: <> (Toggle CI
|
|
251
|
+
[//]: <> (Toggle CI off)
|
package/geoai.js
CHANGED
|
@@ -390,7 +390,7 @@ const postProcessYoloOutput = (model_outputs, pixel_values, rawImage, id2label)
|
|
|
390
390
|
return model_output;
|
|
391
391
|
};
|
|
392
392
|
const parametersChanged = (instance, model_id, providerParams, modelParams) => {
|
|
393
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
393
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
394
394
|
if (instance.model_id !== model_id) {
|
|
395
395
|
return true;
|
|
396
396
|
}
|
|
@@ -419,6 +419,12 @@ const parametersChanged = (instance, model_id, providerParams, modelParams) => {
|
|
|
419
419
|
if (((_h = instance.providerParams) == null ? void 0 : _h.baseUrl) !== (providerParams == null ? void 0 : providerParams.baseUrl)) {
|
|
420
420
|
return true;
|
|
421
421
|
}
|
|
422
|
+
break;
|
|
423
|
+
case "wms":
|
|
424
|
+
if (((_i = instance.providerParams) == null ? void 0 : _i.baseUrl) !== (providerParams == null ? void 0 : providerParams.baseUrl) || ((_j = instance.providerParams) == null ? void 0 : _j.layers) !== (providerParams == null ? void 0 : providerParams.layers) || ((_k = instance.providerParams) == null ? void 0 : _k.version) !== (providerParams == null ? void 0 : providerParams.version) || ((_l = instance.providerParams) == null ? void 0 : _l.crs) !== (providerParams == null ? void 0 : providerParams.crs)) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
422
428
|
}
|
|
423
429
|
if (modelParams) {
|
|
424
430
|
const instanceModelParams = instance.modelParams || {};
|
|
@@ -1283,6 +1289,97 @@ class Tms extends MapSource {
|
|
|
1283
1289
|
return url;
|
|
1284
1290
|
}
|
|
1285
1291
|
}
|
|
1292
|
+
function formatWmsBbox(bbox2, crs, version) {
|
|
1293
|
+
const [minX, minY, maxX, maxY] = bbox2;
|
|
1294
|
+
if (version === "1.3.0" && crs === "EPSG:4326") {
|
|
1295
|
+
return `${minY},${minX},${maxY},${maxX}`;
|
|
1296
|
+
}
|
|
1297
|
+
return `${minX},${minY},${maxX},${maxY}`;
|
|
1298
|
+
}
|
|
1299
|
+
function getTileBbox(tileCoords, crs, tileSize) {
|
|
1300
|
+
const [x, y, z] = tileCoords;
|
|
1301
|
+
if (crs === "EPSG:3857") {
|
|
1302
|
+
const toMeters = pixelsToMeters;
|
|
1303
|
+
const min = toMeters([x * tileSize, y * tileSize, z], tileSize);
|
|
1304
|
+
const max = toMeters([(x + 1) * tileSize, (y + 1) * tileSize, z], tileSize);
|
|
1305
|
+
return [
|
|
1306
|
+
Math.min(min[0], max[0]),
|
|
1307
|
+
Math.min(min[1], max[1]),
|
|
1308
|
+
Math.max(min[0], max[0]),
|
|
1309
|
+
Math.max(min[1], max[1])
|
|
1310
|
+
];
|
|
1311
|
+
}
|
|
1312
|
+
return tileToBBox(tileCoords);
|
|
1313
|
+
}
|
|
1314
|
+
function buildWmsGetMapUrl(config, tileCoords) {
|
|
1315
|
+
const version = config.version ?? "1.1.1";
|
|
1316
|
+
const crs = config.crs ?? "EPSG:3857";
|
|
1317
|
+
const tileSize = config.tileSize ?? 256;
|
|
1318
|
+
const bbox2 = getTileBbox(tileCoords, crs, tileSize);
|
|
1319
|
+
const bboxParam = formatWmsBbox(bbox2, crs, version);
|
|
1320
|
+
const params = {
|
|
1321
|
+
SERVICE: "WMS",
|
|
1322
|
+
REQUEST: "GetMap",
|
|
1323
|
+
VERSION: version,
|
|
1324
|
+
LAYERS: config.layers,
|
|
1325
|
+
STYLES: config.styles ?? "",
|
|
1326
|
+
FORMAT: config.format ?? "image/png",
|
|
1327
|
+
WIDTH: tileSize.toString(),
|
|
1328
|
+
HEIGHT: tileSize.toString(),
|
|
1329
|
+
BBOX: bboxParam,
|
|
1330
|
+
...version === "1.3.0" ? { CRS: crs } : { SRS: crs },
|
|
1331
|
+
...config.transparent ? { TRANSPARENT: "TRUE" } : {},
|
|
1332
|
+
...config.extraParams ?? {}
|
|
1333
|
+
};
|
|
1334
|
+
const url = new URL(config.baseUrl);
|
|
1335
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1336
|
+
url.searchParams.set(key, value);
|
|
1337
|
+
}
|
|
1338
|
+
return url.toString();
|
|
1339
|
+
}
|
|
1340
|
+
class Wms extends MapSource {
|
|
1341
|
+
constructor(config) {
|
|
1342
|
+
super();
|
|
1343
|
+
__publicField(this, "baseUrl");
|
|
1344
|
+
__publicField(this, "layers");
|
|
1345
|
+
__publicField(this, "version");
|
|
1346
|
+
__publicField(this, "crs");
|
|
1347
|
+
__publicField(this, "format");
|
|
1348
|
+
__publicField(this, "styles");
|
|
1349
|
+
__publicField(this, "transparent");
|
|
1350
|
+
__publicField(this, "attribution");
|
|
1351
|
+
__publicField(this, "tileSize");
|
|
1352
|
+
__publicField(this, "headers");
|
|
1353
|
+
__publicField(this, "extraParams");
|
|
1354
|
+
this.baseUrl = config.baseUrl;
|
|
1355
|
+
this.layers = config.layers;
|
|
1356
|
+
this.version = config.version ?? "1.1.1";
|
|
1357
|
+
this.crs = config.crs ?? "EPSG:3857";
|
|
1358
|
+
this.format = config.format ?? "image/png";
|
|
1359
|
+
this.styles = config.styles ?? "";
|
|
1360
|
+
this.transparent = config.transparent ?? false;
|
|
1361
|
+
this.attribution = config.attribution ?? "WMS Provider";
|
|
1362
|
+
this.tileSize = config.tileSize ?? 256;
|
|
1363
|
+
this.headers = config.headers;
|
|
1364
|
+
this.extraParams = config.extraParams;
|
|
1365
|
+
}
|
|
1366
|
+
getTileUrlFromTileCoords(tileCoords, instance) {
|
|
1367
|
+
return buildWmsGetMapUrl(
|
|
1368
|
+
{
|
|
1369
|
+
baseUrl: instance.baseUrl,
|
|
1370
|
+
layers: instance.layers,
|
|
1371
|
+
version: instance.version,
|
|
1372
|
+
crs: instance.crs,
|
|
1373
|
+
format: instance.format,
|
|
1374
|
+
styles: instance.styles,
|
|
1375
|
+
transparent: instance.transparent,
|
|
1376
|
+
tileSize: instance.tileSize,
|
|
1377
|
+
extraParams: instance.extraParams
|
|
1378
|
+
},
|
|
1379
|
+
tileCoords
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1286
1383
|
class BaseModel {
|
|
1287
1384
|
constructor(model_id, providerParams, modelParams) {
|
|
1288
1385
|
__publicField(this, "providerParams");
|
|
@@ -1337,6 +1434,21 @@ class BaseModel {
|
|
|
1337
1434
|
scheme: this.providerParams.scheme
|
|
1338
1435
|
});
|
|
1339
1436
|
break;
|
|
1437
|
+
case "wms":
|
|
1438
|
+
this.dataProvider = new Wms({
|
|
1439
|
+
baseUrl: this.providerParams.baseUrl,
|
|
1440
|
+
layers: this.providerParams.layers,
|
|
1441
|
+
version: this.providerParams.version,
|
|
1442
|
+
crs: this.providerParams.crs,
|
|
1443
|
+
format: this.providerParams.format,
|
|
1444
|
+
styles: this.providerParams.styles,
|
|
1445
|
+
transparent: this.providerParams.transparent,
|
|
1446
|
+
attribution: this.providerParams.attribution,
|
|
1447
|
+
tileSize: this.providerParams.tileSize,
|
|
1448
|
+
headers: this.providerParams.headers,
|
|
1449
|
+
extraParams: this.providerParams.extraParams
|
|
1450
|
+
});
|
|
1451
|
+
break;
|
|
1340
1452
|
case "sentinel":
|
|
1341
1453
|
throw new Error("Sentinel provider not implemented yet");
|
|
1342
1454
|
default:
|
|
@@ -2997,6 +3109,377 @@ const _OilStorageTankDetection = class _OilStorageTankDetection extends BaseMode
|
|
|
2997
3109
|
};
|
|
2998
3110
|
__publicField(_OilStorageTankDetection, "instance", null);
|
|
2999
3111
|
let OilStorageTankDetection = _OilStorageTankDetection;
|
|
3112
|
+
class BaseDenseSegmentationModel extends BaseModel {
|
|
3113
|
+
constructor(model_id, providerParams, modelParams) {
|
|
3114
|
+
super(model_id, providerParams, modelParams);
|
|
3115
|
+
__publicField(this, "model");
|
|
3116
|
+
__publicField(this, "processor");
|
|
3117
|
+
/** Tile edge length in pixels. */
|
|
3118
|
+
__publicField(this, "tileSize", 1024);
|
|
3119
|
+
/** Overlap between adjacent tiles for feather blending. */
|
|
3120
|
+
__publicField(this, "tileOverlap", 64);
|
|
3121
|
+
/** Default probability threshold for binarization. */
|
|
3122
|
+
__publicField(this, "defaultThreshold", 0.5);
|
|
3123
|
+
}
|
|
3124
|
+
async initializeModel() {
|
|
3125
|
+
if (this.model) return;
|
|
3126
|
+
this.processor = await ImageProcessor.from_pretrained(this.model_id);
|
|
3127
|
+
const pretrainedModel = await PreTrainedModel.from_pretrained(
|
|
3128
|
+
this.model_id,
|
|
3129
|
+
this.modelParams
|
|
3130
|
+
);
|
|
3131
|
+
this.model = pretrainedModel.sessions.model;
|
|
3132
|
+
}
|
|
3133
|
+
resolveProbabilityOutput(outputs) {
|
|
3134
|
+
const tensor = outputs[this.outputName];
|
|
3135
|
+
if (!tensor) {
|
|
3136
|
+
throw new Error(
|
|
3137
|
+
`Model output "${this.outputName}" not found; got [${Object.keys(outputs).join(", ")}]`
|
|
3138
|
+
);
|
|
3139
|
+
}
|
|
3140
|
+
const dims = tensor.dims;
|
|
3141
|
+
const raw = tensor.data ?? tensor.cpuData;
|
|
3142
|
+
return {
|
|
3143
|
+
type: tensor.type,
|
|
3144
|
+
dims,
|
|
3145
|
+
size: tensor.size,
|
|
3146
|
+
data: raw
|
|
3147
|
+
};
|
|
3148
|
+
}
|
|
3149
|
+
featherWeight(size, overlap) {
|
|
3150
|
+
const ramp = new Float32Array(size);
|
|
3151
|
+
ramp.fill(1);
|
|
3152
|
+
if (overlap > 0) {
|
|
3153
|
+
for (let i = 0; i < overlap; i++) {
|
|
3154
|
+
const t = i / (overlap - 1 || 1);
|
|
3155
|
+
ramp[i] = t;
|
|
3156
|
+
ramp[size - 1 - i] = t;
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
const weights = new Float32Array(size * size);
|
|
3160
|
+
for (let y = 0; y < size; y++) {
|
|
3161
|
+
for (let x = 0; x < size; x++) {
|
|
3162
|
+
weights[y * size + x] = ramp[y] * ramp[x];
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
return weights;
|
|
3166
|
+
}
|
|
3167
|
+
async runTile(tileImage) {
|
|
3168
|
+
if (!this.processor || !this.model) {
|
|
3169
|
+
throw new Error("Model or processor not initialized");
|
|
3170
|
+
}
|
|
3171
|
+
const inputs = await this.processor(tileImage);
|
|
3172
|
+
const pixelValues = inputs.pixel_values;
|
|
3173
|
+
const dataCopy = pixelValues.data instanceof Float32Array ? new Float32Array(pixelValues.data) : Float32Array.from(pixelValues.data);
|
|
3174
|
+
const feed = new Tensor("float32", dataCopy, pixelValues.dims);
|
|
3175
|
+
let outputs;
|
|
3176
|
+
try {
|
|
3177
|
+
outputs = await this.model.run({
|
|
3178
|
+
[this.inputName]: feed
|
|
3179
|
+
});
|
|
3180
|
+
} catch (err) {
|
|
3181
|
+
const detail = err instanceof Error ? err.message : typeof err === "number" ? `ONNX Runtime abort (${err}) — often WASM out-of-memory for this ${this.tileSize}px fp32 model. Try WebGPU (Chrome/Edge) or a smaller AOI.` : String(err);
|
|
3182
|
+
throw new Error(`Dense segmentation tile inference failed: ${detail}`);
|
|
3183
|
+
}
|
|
3184
|
+
const { data } = this.resolveProbabilityOutput(outputs);
|
|
3185
|
+
return {
|
|
3186
|
+
data,
|
|
3187
|
+
height: this.tileSize,
|
|
3188
|
+
width: this.tileSize
|
|
3189
|
+
};
|
|
3190
|
+
}
|
|
3191
|
+
/**
|
|
3192
|
+
* Overlapped tiled inference with feather blending, matching the
|
|
3193
|
+
* ChangeStar pipeline (tile_size / overlap / threshold).
|
|
3194
|
+
*/
|
|
3195
|
+
async inferDenseMask(geoRawImage, threshold) {
|
|
3196
|
+
const { height, width } = geoRawImage;
|
|
3197
|
+
const tileSize = this.tileSize;
|
|
3198
|
+
const overlap = Math.min(this.tileOverlap, tileSize - 1);
|
|
3199
|
+
const stride = tileSize - overlap;
|
|
3200
|
+
const feather = this.featherWeight(tileSize, overlap);
|
|
3201
|
+
const accum = new Float32Array(height * width);
|
|
3202
|
+
const weightSum = new Float32Array(height * width);
|
|
3203
|
+
for (let rowOff = 0; rowOff < height; rowOff += stride) {
|
|
3204
|
+
for (let colOff = 0; colOff < width; colOff += stride) {
|
|
3205
|
+
const winH = Math.min(tileSize, height - rowOff);
|
|
3206
|
+
const winW = Math.min(tileSize, width - colOff);
|
|
3207
|
+
const croppedRaw = await geoRawImage.crop([
|
|
3208
|
+
colOff,
|
|
3209
|
+
rowOff,
|
|
3210
|
+
colOff + winW - 1,
|
|
3211
|
+
rowOff + winH - 1
|
|
3212
|
+
]);
|
|
3213
|
+
const padH = tileSize - winH;
|
|
3214
|
+
const padW = tileSize - winW;
|
|
3215
|
+
const paddedRaw = padH > 0 || padW > 0 ? await croppedRaw.pad([0, padW, 0, padH]) : croppedRaw;
|
|
3216
|
+
const tileImage = GeoRawImage.fromRawImage(
|
|
3217
|
+
paddedRaw,
|
|
3218
|
+
geoRawImage.getBounds(),
|
|
3219
|
+
geoRawImage.getCRS()
|
|
3220
|
+
);
|
|
3221
|
+
const { data: prob } = await this.runTile(tileImage);
|
|
3222
|
+
for (let y = 0; y < winH; y++) {
|
|
3223
|
+
for (let x = 0; x < winW; x++) {
|
|
3224
|
+
const srcIdx = y * tileSize + x;
|
|
3225
|
+
const dstIdx = (rowOff + y) * width + (colOff + x);
|
|
3226
|
+
const w = feather[y * tileSize + x];
|
|
3227
|
+
accum[dstIdx] += prob[srcIdx] * w;
|
|
3228
|
+
weightSum[dstIdx] += w;
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
const binary = new Uint8Array(height * width);
|
|
3234
|
+
for (let i = 0; i < height * width; i++) {
|
|
3235
|
+
const w = weightSum[i] === 0 ? 1 : weightSum[i];
|
|
3236
|
+
binary[i] = accum[i] / w > threshold ? 255 : 0;
|
|
3237
|
+
}
|
|
3238
|
+
const scale = height > 512 || width > 512 ? 2 : 1;
|
|
3239
|
+
const contourH = Math.max(1, Math.floor(height / scale));
|
|
3240
|
+
const contourW = Math.max(1, Math.floor(width / scale));
|
|
3241
|
+
let contourBinary = binary;
|
|
3242
|
+
let contourImage = geoRawImage;
|
|
3243
|
+
if (scale > 1) {
|
|
3244
|
+
contourBinary = new Uint8Array(contourH * contourW);
|
|
3245
|
+
for (let y = 0; y < contourH; y++) {
|
|
3246
|
+
for (let x = 0; x < contourW; x++) {
|
|
3247
|
+
contourBinary[y * contourW + x] = binary[y * scale * width + x * scale];
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
contourImage = new GeoRawImage(
|
|
3251
|
+
contourBinary,
|
|
3252
|
+
contourW,
|
|
3253
|
+
contourH,
|
|
3254
|
+
1,
|
|
3255
|
+
geoRawImage.getBounds(),
|
|
3256
|
+
geoRawImage.getCRS()
|
|
3257
|
+
);
|
|
3258
|
+
}
|
|
3259
|
+
const maskTensor = new Tensor("uint8", contourBinary, [
|
|
3260
|
+
1,
|
|
3261
|
+
1,
|
|
3262
|
+
contourH,
|
|
3263
|
+
contourW
|
|
3264
|
+
]);
|
|
3265
|
+
const masksToFC = maskToGeoJSON({ mask: [maskTensor] }, contourImage);
|
|
3266
|
+
const features = [];
|
|
3267
|
+
masksToFC.forEach((fc) => {
|
|
3268
|
+
fc.features.forEach((feature2) => {
|
|
3269
|
+
feature2.properties = {
|
|
3270
|
+
...feature2.properties || {},
|
|
3271
|
+
class: "building"
|
|
3272
|
+
};
|
|
3273
|
+
features.push(feature2);
|
|
3274
|
+
});
|
|
3275
|
+
});
|
|
3276
|
+
return {
|
|
3277
|
+
type: "FeatureCollection",
|
|
3278
|
+
features
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
async inference(params) {
|
|
3282
|
+
const {
|
|
3283
|
+
inputs: { polygon: polygon2 },
|
|
3284
|
+
postProcessingParams: { confidenceThreshold } = {},
|
|
3285
|
+
mapSourceParams
|
|
3286
|
+
} = params;
|
|
3287
|
+
if (!polygon2) {
|
|
3288
|
+
throw new Error("Polygon input is required for dense segmentation");
|
|
3289
|
+
}
|
|
3290
|
+
if (!polygon2.geometry || polygon2.geometry.type !== "Polygon") {
|
|
3291
|
+
throw new Error("Input must be a valid GeoJSON Polygon feature");
|
|
3292
|
+
}
|
|
3293
|
+
if (!this.initialized) {
|
|
3294
|
+
await this.initialize();
|
|
3295
|
+
}
|
|
3296
|
+
if (!this.model || !this.processor || !this.dataProvider) {
|
|
3297
|
+
throw new Error("Model or data provider not initialized");
|
|
3298
|
+
}
|
|
3299
|
+
const geoRawImage = await this.polygonToImage(
|
|
3300
|
+
polygon2,
|
|
3301
|
+
mapSourceParams == null ? void 0 : mapSourceParams.zoomLevel,
|
|
3302
|
+
mapSourceParams == null ? void 0 : mapSourceParams.bands,
|
|
3303
|
+
mapSourceParams == null ? void 0 : mapSourceParams.expression
|
|
3304
|
+
);
|
|
3305
|
+
const threshold = typeof confidenceThreshold === "number" ? confidenceThreshold : this.defaultThreshold;
|
|
3306
|
+
const taskName = this.model_id.split("/").pop() ?? "dense-segmentation";
|
|
3307
|
+
const inferenceStartTime = performance.now();
|
|
3308
|
+
console.log(`[${taskName}] starting dense segmentation inference...`);
|
|
3309
|
+
const detections = await this.inferDenseMask(geoRawImage, threshold);
|
|
3310
|
+
const inferenceEndTime = performance.now();
|
|
3311
|
+
console.log(
|
|
3312
|
+
`[${taskName}] inference completed. Time taken: ${(inferenceEndTime - inferenceStartTime).toFixed(2)}ms`
|
|
3313
|
+
);
|
|
3314
|
+
return {
|
|
3315
|
+
detections,
|
|
3316
|
+
geoRawImage
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
const _ChangeStarBuildingSegmentation = class _ChangeStarBuildingSegmentation extends BaseDenseSegmentationModel {
|
|
3321
|
+
constructor(model_id, providerParams, modelParams) {
|
|
3322
|
+
super(model_id, providerParams, modelParams);
|
|
3323
|
+
__publicField(this, "inputName", "image");
|
|
3324
|
+
__publicField(this, "outputName", "building_prob");
|
|
3325
|
+
__publicField(this, "tileSize", 1024);
|
|
3326
|
+
__publicField(this, "tileOverlap", 64);
|
|
3327
|
+
__publicField(this, "defaultThreshold", 0.5);
|
|
3328
|
+
}
|
|
3329
|
+
static async getInstance(model_id, providerParams, modelParams) {
|
|
3330
|
+
if (!_ChangeStarBuildingSegmentation.instanceRef || parametersChanged(
|
|
3331
|
+
_ChangeStarBuildingSegmentation.instanceRef,
|
|
3332
|
+
model_id,
|
|
3333
|
+
providerParams,
|
|
3334
|
+
modelParams
|
|
3335
|
+
)) {
|
|
3336
|
+
_ChangeStarBuildingSegmentation.instanceRef = new _ChangeStarBuildingSegmentation(
|
|
3337
|
+
model_id,
|
|
3338
|
+
providerParams,
|
|
3339
|
+
modelParams
|
|
3340
|
+
);
|
|
3341
|
+
await _ChangeStarBuildingSegmentation.instanceRef.initialize();
|
|
3342
|
+
}
|
|
3343
|
+
return { instance: _ChangeStarBuildingSegmentation.instanceRef };
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
__publicField(_ChangeStarBuildingSegmentation, "instanceRef", null);
|
|
3347
|
+
__publicField(_ChangeStarBuildingSegmentation, "default_huggingface_id", "geobase/changestar-building-segmentation-vitb");
|
|
3348
|
+
let ChangeStarBuildingSegmentation = _ChangeStarBuildingSegmentation;
|
|
3349
|
+
const _ImageFeatureExtraction = class _ImageFeatureExtraction extends BaseModel {
|
|
3350
|
+
constructor(model_id, providerParams, modelParams) {
|
|
3351
|
+
super(model_id, providerParams, modelParams);
|
|
3352
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3353
|
+
__publicField(this, "extractor");
|
|
3354
|
+
__publicField(this, "patchSize");
|
|
3355
|
+
}
|
|
3356
|
+
static async getInstance(model_id, providerParams, modelParams) {
|
|
3357
|
+
if (!_ImageFeatureExtraction.instance || parametersChanged(
|
|
3358
|
+
_ImageFeatureExtraction.instance,
|
|
3359
|
+
model_id,
|
|
3360
|
+
providerParams,
|
|
3361
|
+
modelParams
|
|
3362
|
+
)) {
|
|
3363
|
+
_ImageFeatureExtraction.instance = new _ImageFeatureExtraction(
|
|
3364
|
+
model_id,
|
|
3365
|
+
providerParams,
|
|
3366
|
+
modelParams
|
|
3367
|
+
);
|
|
3368
|
+
await _ImageFeatureExtraction.instance.initialize();
|
|
3369
|
+
}
|
|
3370
|
+
return { instance: _ImageFeatureExtraction.instance };
|
|
3371
|
+
}
|
|
3372
|
+
async initializeModel() {
|
|
3373
|
+
this.extractor = await pipeline(
|
|
3374
|
+
"image-feature-extraction",
|
|
3375
|
+
this.model_id,
|
|
3376
|
+
this.modelParams
|
|
3377
|
+
);
|
|
3378
|
+
this.extractor.processor.image_processor.do_resize = false;
|
|
3379
|
+
this.patchSize = this.extractor.model.config.patch_size;
|
|
3380
|
+
}
|
|
3381
|
+
/**
|
|
3382
|
+
* Performs image feature extraction on a geographic area specified by a GeoJSON polygon.
|
|
3383
|
+
* Extracts dense feature representations using DINOv3 and computes patch-to-patch similarities.
|
|
3384
|
+
*
|
|
3385
|
+
* @param params - Inference parameters containing polygon and processing options
|
|
3386
|
+
* @returns Promise<ImageFeatureExtractionResults> containing feature vectors, similarity matrix, and metadata
|
|
3387
|
+
* @throws {Error} If data provider, model or processor are not properly initialized
|
|
3388
|
+
*/
|
|
3389
|
+
async inference(params) {
|
|
3390
|
+
var _a, _b;
|
|
3391
|
+
const {
|
|
3392
|
+
inputs: { polygon: polygon2 },
|
|
3393
|
+
postProcessingParams: { similarityThreshold = 0.5 } = {},
|
|
3394
|
+
mapSourceParams
|
|
3395
|
+
} = params;
|
|
3396
|
+
if (!polygon2) {
|
|
3397
|
+
throw new Error("Polygon input is required for feature extraction");
|
|
3398
|
+
}
|
|
3399
|
+
if (!polygon2.geometry || polygon2.geometry.type !== "Polygon") {
|
|
3400
|
+
throw new Error("Input must be a valid GeoJSON Polygon feature");
|
|
3401
|
+
}
|
|
3402
|
+
if (!this.initialized) {
|
|
3403
|
+
await this.initialize();
|
|
3404
|
+
}
|
|
3405
|
+
if (!this.extractor || !this.patchSize) {
|
|
3406
|
+
throw new Error("Feature extractor not properly initialized");
|
|
3407
|
+
}
|
|
3408
|
+
const geoRawImage = await this.polygonToImage(
|
|
3409
|
+
polygon2,
|
|
3410
|
+
mapSourceParams == null ? void 0 : mapSourceParams.zoomLevel,
|
|
3411
|
+
mapSourceParams == null ? void 0 : mapSourceParams.bands,
|
|
3412
|
+
mapSourceParams == null ? void 0 : mapSourceParams.expression
|
|
3413
|
+
);
|
|
3414
|
+
const inferenceStartTime = performance.now();
|
|
3415
|
+
console.log("[image-feature-extraction] starting inference...");
|
|
3416
|
+
try {
|
|
3417
|
+
const features = await this.extractor(geoRawImage, {
|
|
3418
|
+
pooling: "none"
|
|
3419
|
+
});
|
|
3420
|
+
const numRegisterTokens = this.extractor.model.config.num_register_tokens ?? 0;
|
|
3421
|
+
const startIndex = 1 + numRegisterTokens;
|
|
3422
|
+
const patchFeatures = features.slice(null, [startIndex, null]);
|
|
3423
|
+
const normalizedFeatures = patchFeatures.normalize(2, -1);
|
|
3424
|
+
const scores = await matmul(
|
|
3425
|
+
normalizedFeatures,
|
|
3426
|
+
normalizedFeatures.permute(0, 2, 1)
|
|
3427
|
+
);
|
|
3428
|
+
const similarityMatrix = (await scores.tolist())[0];
|
|
3429
|
+
const featureVectors = (await patchFeatures.tolist())[0];
|
|
3430
|
+
let filteredFeatures = featureVectors;
|
|
3431
|
+
let filteredSimilarityMatrix = similarityMatrix;
|
|
3432
|
+
if (similarityThreshold > 0) {
|
|
3433
|
+
const highSimilarityPatches = /* @__PURE__ */ new Set();
|
|
3434
|
+
for (let i = 0; i < similarityMatrix.length; i++) {
|
|
3435
|
+
for (let j = 0; j < similarityMatrix[i].length; j++) {
|
|
3436
|
+
if (i !== j && similarityMatrix[i][j] >= similarityThreshold) {
|
|
3437
|
+
highSimilarityPatches.add(i);
|
|
3438
|
+
highSimilarityPatches.add(j);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
const patchIndices = Array.from(highSimilarityPatches).sort(
|
|
3443
|
+
(a, b) => a - b
|
|
3444
|
+
);
|
|
3445
|
+
filteredFeatures = patchIndices.map((i) => featureVectors[i]);
|
|
3446
|
+
filteredSimilarityMatrix = patchIndices.map(
|
|
3447
|
+
(i) => patchIndices.map((j) => similarityMatrix[i][j])
|
|
3448
|
+
);
|
|
3449
|
+
}
|
|
3450
|
+
const inferenceEndTime = performance.now();
|
|
3451
|
+
console.log(
|
|
3452
|
+
`[image-feature-extraction] inference completed. Time taken: ${(inferenceEndTime - inferenceStartTime).toFixed(2)}ms`
|
|
3453
|
+
);
|
|
3454
|
+
const result = {
|
|
3455
|
+
features: filteredFeatures,
|
|
3456
|
+
similarityMatrix: filteredSimilarityMatrix,
|
|
3457
|
+
patchSize: this.patchSize,
|
|
3458
|
+
geoRawImage,
|
|
3459
|
+
metadata: {
|
|
3460
|
+
numPatches: filteredFeatures.length,
|
|
3461
|
+
featureDimensions: ((_a = filteredFeatures[0]) == null ? void 0 : _a.length) || 0,
|
|
3462
|
+
modelId: this.model_id
|
|
3463
|
+
}
|
|
3464
|
+
};
|
|
3465
|
+
console.log("[image-feature-extraction] Result structure:", {
|
|
3466
|
+
featuresLength: result.features.length,
|
|
3467
|
+
similarityMatrixLength: result.similarityMatrix.length,
|
|
3468
|
+
patchSize: result.patchSize,
|
|
3469
|
+
geoRawImageBounds: (_b = result.geoRawImage) == null ? void 0 : _b.getBounds(),
|
|
3470
|
+
metadata: result.metadata
|
|
3471
|
+
});
|
|
3472
|
+
return result;
|
|
3473
|
+
} catch (error) {
|
|
3474
|
+
console.error("Feature extraction error:", error);
|
|
3475
|
+
throw new Error(
|
|
3476
|
+
`Feature extraction failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
3477
|
+
);
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
};
|
|
3481
|
+
__publicField(_ImageFeatureExtraction, "instance", null);
|
|
3482
|
+
let ImageFeatureExtraction = _ImageFeatureExtraction;
|
|
3000
3483
|
const _BuildingFootPrintSegmentation = class _BuildingFootPrintSegmentation extends BaseModel {
|
|
3001
3484
|
constructor(model_id, providerParams, modelParams) {
|
|
3002
3485
|
super(model_id, providerParams, modelParams);
|
|
@@ -3166,141 +3649,42 @@ const _BuildingFootPrintSegmentation = class _BuildingFootPrintSegmentation exte
|
|
|
3166
3649
|
}
|
|
3167
3650
|
};
|
|
3168
3651
|
__publicField(_BuildingFootPrintSegmentation, "instance", null);
|
|
3652
|
+
__publicField(_BuildingFootPrintSegmentation, "default_huggingface_id", "geobase/building-footprint-segmentation");
|
|
3169
3653
|
let BuildingFootPrintSegmentation = _BuildingFootPrintSegmentation;
|
|
3170
|
-
const
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3654
|
+
const buildingFootprintFactory = (params, modelId, modelParams) => BuildingFootPrintSegmentation.getInstance(modelId, params, modelParams);
|
|
3655
|
+
const changeStarFactory = (params, modelId, modelParams) => ChangeStarBuildingSegmentation.getInstance(
|
|
3656
|
+
modelId,
|
|
3657
|
+
params,
|
|
3658
|
+
modelParams ?? { dtype: "fp32" }
|
|
3659
|
+
);
|
|
3660
|
+
const buildingSegmentationFactories = {
|
|
3661
|
+
[BuildingFootPrintSegmentation.default_huggingface_id]: buildingFootprintFactory,
|
|
3662
|
+
[ChangeStarBuildingSegmentation.default_huggingface_id]: changeStarFactory
|
|
3663
|
+
};
|
|
3664
|
+
const BuildingSegmentationFactory = {
|
|
3665
|
+
get knownModelIds() {
|
|
3666
|
+
return Object.keys(buildingSegmentationFactories);
|
|
3667
|
+
},
|
|
3668
|
+
getInstance(params, modelId, modelParams) {
|
|
3669
|
+
const resolvedId = modelId == null ? void 0 : modelId.trim();
|
|
3670
|
+
if (!resolvedId) {
|
|
3671
|
+
return Promise.reject(
|
|
3672
|
+
new Error(
|
|
3673
|
+
`Building segmentation modelId is required. Known ids: ${this.knownModelIds.join(", ")}`
|
|
3674
|
+
)
|
|
3188
3675
|
);
|
|
3189
|
-
await _ImageFeatureExtraction.instance.initialize();
|
|
3190
3676
|
}
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
this.modelParams
|
|
3198
|
-
);
|
|
3199
|
-
this.extractor.processor.image_processor.do_resize = false;
|
|
3200
|
-
this.patchSize = this.extractor.model.config.patch_size;
|
|
3201
|
-
}
|
|
3202
|
-
/**
|
|
3203
|
-
* Performs image feature extraction on a geographic area specified by a GeoJSON polygon.
|
|
3204
|
-
* Extracts dense feature representations using DINOv3 and computes patch-to-patch similarities.
|
|
3205
|
-
*
|
|
3206
|
-
* @param params - Inference parameters containing polygon and processing options
|
|
3207
|
-
* @returns Promise<ImageFeatureExtractionResults> containing feature vectors, similarity matrix, and metadata
|
|
3208
|
-
* @throws {Error} If data provider, model or processor are not properly initialized
|
|
3209
|
-
*/
|
|
3210
|
-
async inference(params) {
|
|
3211
|
-
var _a, _b;
|
|
3212
|
-
const {
|
|
3213
|
-
inputs: { polygon: polygon2 },
|
|
3214
|
-
postProcessingParams: { similarityThreshold = 0.5 } = {},
|
|
3215
|
-
mapSourceParams
|
|
3216
|
-
} = params;
|
|
3217
|
-
if (!polygon2) {
|
|
3218
|
-
throw new Error("Polygon input is required for feature extraction");
|
|
3219
|
-
}
|
|
3220
|
-
if (!polygon2.geometry || polygon2.geometry.type !== "Polygon") {
|
|
3221
|
-
throw new Error("Input must be a valid GeoJSON Polygon feature");
|
|
3222
|
-
}
|
|
3223
|
-
if (!this.initialized) {
|
|
3224
|
-
await this.initialize();
|
|
3225
|
-
}
|
|
3226
|
-
if (!this.extractor || !this.patchSize) {
|
|
3227
|
-
throw new Error("Feature extractor not properly initialized");
|
|
3228
|
-
}
|
|
3229
|
-
const geoRawImage = await this.polygonToImage(
|
|
3230
|
-
polygon2,
|
|
3231
|
-
mapSourceParams == null ? void 0 : mapSourceParams.zoomLevel,
|
|
3232
|
-
mapSourceParams == null ? void 0 : mapSourceParams.bands,
|
|
3233
|
-
mapSourceParams == null ? void 0 : mapSourceParams.expression
|
|
3234
|
-
);
|
|
3235
|
-
const inferenceStartTime = performance.now();
|
|
3236
|
-
console.log("[image-feature-extraction] starting inference...");
|
|
3237
|
-
try {
|
|
3238
|
-
const features = await this.extractor(geoRawImage, {
|
|
3239
|
-
pooling: "none"
|
|
3240
|
-
});
|
|
3241
|
-
const numRegisterTokens = this.extractor.model.config.num_register_tokens ?? 0;
|
|
3242
|
-
const startIndex = 1 + numRegisterTokens;
|
|
3243
|
-
const patchFeatures = features.slice(null, [startIndex, null]);
|
|
3244
|
-
const normalizedFeatures = patchFeatures.normalize(2, -1);
|
|
3245
|
-
const scores = await matmul(
|
|
3246
|
-
normalizedFeatures,
|
|
3247
|
-
normalizedFeatures.permute(0, 2, 1)
|
|
3248
|
-
);
|
|
3249
|
-
const similarityMatrix = (await scores.tolist())[0];
|
|
3250
|
-
const featureVectors = (await patchFeatures.tolist())[0];
|
|
3251
|
-
let filteredFeatures = featureVectors;
|
|
3252
|
-
let filteredSimilarityMatrix = similarityMatrix;
|
|
3253
|
-
if (similarityThreshold > 0) {
|
|
3254
|
-
const highSimilarityPatches = /* @__PURE__ */ new Set();
|
|
3255
|
-
for (let i = 0; i < similarityMatrix.length; i++) {
|
|
3256
|
-
for (let j = 0; j < similarityMatrix[i].length; j++) {
|
|
3257
|
-
if (i !== j && similarityMatrix[i][j] >= similarityThreshold) {
|
|
3258
|
-
highSimilarityPatches.add(i);
|
|
3259
|
-
highSimilarityPatches.add(j);
|
|
3260
|
-
}
|
|
3261
|
-
}
|
|
3262
|
-
}
|
|
3263
|
-
const patchIndices = Array.from(highSimilarityPatches).sort(
|
|
3264
|
-
(a, b) => a - b
|
|
3265
|
-
);
|
|
3266
|
-
filteredFeatures = patchIndices.map((i) => featureVectors[i]);
|
|
3267
|
-
filteredSimilarityMatrix = patchIndices.map(
|
|
3268
|
-
(i) => patchIndices.map((j) => similarityMatrix[i][j])
|
|
3269
|
-
);
|
|
3270
|
-
}
|
|
3271
|
-
const inferenceEndTime = performance.now();
|
|
3272
|
-
console.log(
|
|
3273
|
-
`[image-feature-extraction] inference completed. Time taken: ${(inferenceEndTime - inferenceStartTime).toFixed(2)}ms`
|
|
3274
|
-
);
|
|
3275
|
-
const result = {
|
|
3276
|
-
features: filteredFeatures,
|
|
3277
|
-
similarityMatrix: filteredSimilarityMatrix,
|
|
3278
|
-
patchSize: this.patchSize,
|
|
3279
|
-
geoRawImage,
|
|
3280
|
-
metadata: {
|
|
3281
|
-
numPatches: filteredFeatures.length,
|
|
3282
|
-
featureDimensions: ((_a = filteredFeatures[0]) == null ? void 0 : _a.length) || 0,
|
|
3283
|
-
modelId: this.model_id
|
|
3284
|
-
}
|
|
3285
|
-
};
|
|
3286
|
-
console.log("[image-feature-extraction] Result structure:", {
|
|
3287
|
-
featuresLength: result.features.length,
|
|
3288
|
-
similarityMatrixLength: result.similarityMatrix.length,
|
|
3289
|
-
patchSize: result.patchSize,
|
|
3290
|
-
geoRawImageBounds: (_b = result.geoRawImage) == null ? void 0 : _b.getBounds(),
|
|
3291
|
-
metadata: result.metadata
|
|
3292
|
-
});
|
|
3293
|
-
return result;
|
|
3294
|
-
} catch (error) {
|
|
3295
|
-
console.error("Feature extraction error:", error);
|
|
3296
|
-
throw new Error(
|
|
3297
|
-
`Feature extraction failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
3677
|
+
const create = buildingSegmentationFactories[resolvedId];
|
|
3678
|
+
if (!create) {
|
|
3679
|
+
return Promise.reject(
|
|
3680
|
+
new Error(
|
|
3681
|
+
`Unknown building segmentation modelId "${resolvedId}". Known ids: ${this.knownModelIds.join(", ")}`
|
|
3682
|
+
)
|
|
3298
3683
|
);
|
|
3299
3684
|
}
|
|
3685
|
+
return create(params, resolvedId, modelParams);
|
|
3300
3686
|
}
|
|
3301
3687
|
};
|
|
3302
|
-
__publicField(_ImageFeatureExtraction, "instance", null);
|
|
3303
|
-
let ImageFeatureExtraction = _ImageFeatureExtraction;
|
|
3304
3688
|
const modelRegistry = [
|
|
3305
3689
|
{
|
|
3306
3690
|
task: "zero-shot-object-detection",
|
|
@@ -3485,20 +3869,14 @@ const modelRegistry = [
|
|
|
3485
3869
|
{
|
|
3486
3870
|
task: "building-footprint-segmentation",
|
|
3487
3871
|
library: "geoai",
|
|
3488
|
-
description: "Segments the precise outlines (footprints) of buildings in imagery. Useful for mapping, urban planning, or disaster assessment.",
|
|
3872
|
+
description: "Segments the precise outlines (footprints) of buildings in imagery. Defaults to ChangeStar ViT-B; pass modelId for the lighter footprint model. Useful for mapping, urban planning, or disaster assessment.",
|
|
3489
3873
|
examples: [
|
|
3490
3874
|
"Segment building footprints in this city block.",
|
|
3491
3875
|
"Identify the outlines of all buildings in this image.",
|
|
3492
3876
|
"Find building perimeters in this urban area."
|
|
3493
3877
|
],
|
|
3494
3878
|
ioConfig: {},
|
|
3495
|
-
geobase_ai_pipeline: (params, modelId =
|
|
3496
|
-
return BuildingFootPrintSegmentation.getInstance(
|
|
3497
|
-
modelId,
|
|
3498
|
-
params,
|
|
3499
|
-
modelParams
|
|
3500
|
-
);
|
|
3501
|
-
}
|
|
3879
|
+
geobase_ai_pipeline: (params, modelId = ChangeStarBuildingSegmentation.default_huggingface_id, modelParams) => BuildingSegmentationFactory.getInstance(params, modelId, modelParams)
|
|
3502
3880
|
},
|
|
3503
3881
|
{
|
|
3504
3882
|
task: "image-feature-extraction",
|
package/index.d.ts
CHANGED
|
@@ -162,10 +162,46 @@ declare class Tms extends MapSource {
|
|
|
162
162
|
number
|
|
163
163
|
], instance: Tms): string;
|
|
164
164
|
}
|
|
165
|
+
export type WmsVersion = "1.1.1" | "1.3.0";
|
|
166
|
+
export type WmsCrs = "EPSG:3857" | "EPSG:4326";
|
|
167
|
+
export interface WmsGetMapConfig {
|
|
168
|
+
baseUrl: string;
|
|
169
|
+
layers: string;
|
|
170
|
+
version?: WmsVersion;
|
|
171
|
+
crs?: WmsCrs;
|
|
172
|
+
format?: string;
|
|
173
|
+
styles?: string;
|
|
174
|
+
transparent?: boolean;
|
|
175
|
+
tileSize?: number;
|
|
176
|
+
attribution?: string;
|
|
177
|
+
headers?: Record<string, string>;
|
|
178
|
+
extraParams?: Record<string, string>;
|
|
179
|
+
}
|
|
180
|
+
export interface WmsConfig extends WmsGetMapConfig {
|
|
181
|
+
}
|
|
182
|
+
declare class Wms extends MapSource {
|
|
183
|
+
baseUrl: string;
|
|
184
|
+
layers: string;
|
|
185
|
+
version: WmsVersion;
|
|
186
|
+
crs: WmsCrs;
|
|
187
|
+
format: string;
|
|
188
|
+
styles: string;
|
|
189
|
+
transparent: boolean;
|
|
190
|
+
attribution: string;
|
|
191
|
+
tileSize: number;
|
|
192
|
+
headers?: Record<string, string>;
|
|
193
|
+
extraParams?: Record<string, string>;
|
|
194
|
+
constructor(config: WmsConfig);
|
|
195
|
+
protected getTileUrlFromTileCoords(tileCoords: [
|
|
196
|
+
number,
|
|
197
|
+
number,
|
|
198
|
+
number
|
|
199
|
+
], instance: Wms): string;
|
|
200
|
+
}
|
|
165
201
|
declare abstract class BaseModel {
|
|
166
202
|
protected static instance: BaseModel | null;
|
|
167
203
|
protected providerParams: ProviderParams;
|
|
168
|
-
protected dataProvider: Mapbox | Geobase | Esri | Tms | undefined;
|
|
204
|
+
protected dataProvider: Mapbox | Geobase | Esri | Tms | Wms | undefined;
|
|
169
205
|
protected model_id: string;
|
|
170
206
|
protected initialized: boolean;
|
|
171
207
|
protected modelParams?: PretrainedModelOptions;
|
|
@@ -411,6 +447,7 @@ declare class BuildingFootPrintSegmentation extends BaseModel {
|
|
|
411
447
|
protected static instance: BuildingFootPrintSegmentation | null;
|
|
412
448
|
protected model: ort.InferenceSession | undefined;
|
|
413
449
|
protected processor: ImageProcessor | undefined;
|
|
450
|
+
static readonly default_huggingface_id = "geobase/building-footprint-segmentation";
|
|
414
451
|
private constructor();
|
|
415
452
|
static getInstance(model_id: string, providerParams: ProviderParams, modelParams?: PretrainedModelOptions): Promise<{
|
|
416
453
|
instance: BuildingFootPrintSegmentation;
|
|
@@ -438,6 +475,53 @@ declare class ImageFeatureExtraction extends BaseModel {
|
|
|
438
475
|
*/
|
|
439
476
|
inference(params: InferenceParams): Promise<ImageFeatureExtractionResults>;
|
|
440
477
|
}
|
|
478
|
+
declare abstract class BaseDenseSegmentationModel extends BaseModel {
|
|
479
|
+
protected model: ort.InferenceSession | undefined;
|
|
480
|
+
protected processor: ImageProcessor | undefined;
|
|
481
|
+
/** ONNX input feed name (e.g. "image"). */
|
|
482
|
+
protected abstract readonly inputName: string;
|
|
483
|
+
/** Soft-probability output tensor name (e.g. "building_prob"). */
|
|
484
|
+
protected abstract readonly outputName: string;
|
|
485
|
+
/** Tile edge length in pixels. */
|
|
486
|
+
protected readonly tileSize: number;
|
|
487
|
+
/** Overlap between adjacent tiles for feather blending. */
|
|
488
|
+
protected readonly tileOverlap: number;
|
|
489
|
+
/** Default probability threshold for binarization. */
|
|
490
|
+
protected readonly defaultThreshold: number;
|
|
491
|
+
protected constructor(model_id: string, providerParams: ProviderParams, modelParams?: PretrainedModelOptions);
|
|
492
|
+
protected initializeModel(): Promise<void>;
|
|
493
|
+
protected resolveProbabilityOutput(outputs: Record<string, any>): {
|
|
494
|
+
type: string;
|
|
495
|
+
dims: number[];
|
|
496
|
+
size: number;
|
|
497
|
+
data: Float32Array;
|
|
498
|
+
};
|
|
499
|
+
protected featherWeight(size: number, overlap: number): Float32Array;
|
|
500
|
+
protected runTile(tileImage: GeoRawImage): Promise<{
|
|
501
|
+
data: Float32Array;
|
|
502
|
+
height: number;
|
|
503
|
+
width: number;
|
|
504
|
+
}>;
|
|
505
|
+
/**
|
|
506
|
+
* Overlapped tiled inference with feather blending, matching the
|
|
507
|
+
* ChangeStar pipeline (tile_size / overlap / threshold).
|
|
508
|
+
*/
|
|
509
|
+
protected inferDenseMask(geoRawImage: GeoRawImage, threshold: number): Promise<GeoJSON.FeatureCollection>;
|
|
510
|
+
inference(params: InferenceParams): Promise<ObjectDetectionResults>;
|
|
511
|
+
}
|
|
512
|
+
declare class ChangeStarBuildingSegmentation extends BaseDenseSegmentationModel {
|
|
513
|
+
protected static instanceRef: ChangeStarBuildingSegmentation | null;
|
|
514
|
+
static readonly default_huggingface_id = "geobase/changestar-building-segmentation-vitb";
|
|
515
|
+
protected readonly inputName = "image";
|
|
516
|
+
protected readonly outputName = "building_prob";
|
|
517
|
+
protected readonly tileSize = 1024;
|
|
518
|
+
protected readonly tileOverlap = 64;
|
|
519
|
+
protected readonly defaultThreshold = 0.5;
|
|
520
|
+
private constructor();
|
|
521
|
+
static getInstance(model_id: string, providerParams: ProviderParams, modelParams?: PretrainedModelOptions): Promise<{
|
|
522
|
+
instance: ChangeStarBuildingSegmentation;
|
|
523
|
+
}>;
|
|
524
|
+
}
|
|
441
525
|
export type MapboxParams = {
|
|
442
526
|
provider: "mapbox";
|
|
443
527
|
apiKey: string;
|
|
@@ -470,6 +554,20 @@ export type TmsParams = {
|
|
|
470
554
|
headers?: Record<string, string>;
|
|
471
555
|
scheme?: "WebMercator" | "TMS";
|
|
472
556
|
};
|
|
557
|
+
export type WmsParams = {
|
|
558
|
+
provider: "wms";
|
|
559
|
+
baseUrl: string;
|
|
560
|
+
layers: string;
|
|
561
|
+
version?: "1.1.1" | "1.3.0";
|
|
562
|
+
crs?: "EPSG:3857" | "EPSG:4326";
|
|
563
|
+
format?: string;
|
|
564
|
+
styles?: string;
|
|
565
|
+
transparent?: boolean;
|
|
566
|
+
attribution?: string;
|
|
567
|
+
tileSize?: number;
|
|
568
|
+
headers?: Record<string, string>;
|
|
569
|
+
extraParams?: Record<string, string>;
|
|
570
|
+
};
|
|
473
571
|
export interface InferenceInputs {
|
|
474
572
|
polygon: GeoJSON.Feature;
|
|
475
573
|
classLabel?: string;
|
|
@@ -488,10 +586,10 @@ export interface InferenceParams {
|
|
|
488
586
|
postProcessingParams?: PostProcessingParams;
|
|
489
587
|
mapSourceParams?: MapSourceParams;
|
|
490
588
|
}
|
|
491
|
-
export type ProviderParams = MapboxParams | SentinelParams | GeobaseParams | EsriParams | TmsParams;
|
|
589
|
+
export type ProviderParams = MapboxParams | SentinelParams | GeobaseParams | EsriParams | TmsParams | WmsParams;
|
|
492
590
|
export type HuggingFaceModelTask = "mask-generation" | "zero-shot-object-detection" | "zero-shot-image-classification" | "object-detection" | "oriented-object-detection" | "image-feature-extraction";
|
|
493
591
|
export type GeobaseAiModelTask = "damage-assessment" | "vegetation-classification" | "land-cover-classification" | "land-use-classification" | "land-cover-change-detection" | "land-use-change-detection" | "solar-panel-detection" | "ship-detection" | "car-detection" | "wetland-segmentation" | "building-detection" | "oil-storage-tank-detection" | "building-footprint-segmentation";
|
|
494
|
-
export type ModelInstance = MaskGeneration | ZeroShotObjectDetection | ObjectDetection | OrientedObjectDetection | LandCoverClassification | SolarPanelDetection | ShipDetection | CarDetection | WetLandSegmentation | BuildingDetection | OilStorageTankDetection | BuildingFootPrintSegmentation | ImageFeatureExtraction;
|
|
592
|
+
export type ModelInstance = MaskGeneration | ZeroShotObjectDetection | ObjectDetection | OrientedObjectDetection | LandCoverClassification | SolarPanelDetection | ShipDetection | CarDetection | WetLandSegmentation | BuildingDetection | ChangeStarBuildingSegmentation | OilStorageTankDetection | BuildingFootPrintSegmentation | ImageFeatureExtraction;
|
|
495
593
|
export type ModelConfig = {
|
|
496
594
|
task: HuggingFaceModelTask | GeobaseAiModelTask;
|
|
497
595
|
library: string;
|