-
Notifications
You must be signed in to change notification settings - Fork 116
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
New options: Percent coverage selection and weighting #136
base: master
Are you sure you want to change the base?
Changes from all commits
34dff52
ba627d7
6725da1
4ffe2ad
c0d9bc3
a03eb04
795d86e
a9a4a3c
cfa198a
7000632
b52a368
85f62a1
76c8667
cb87d40
644ddc3
143a7cf
7a59a52
41222f9
6955476
1c39067
2fe6d66
d986437
46fcebc
fc558c2
c475b58
a52055f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,10 @@ | |
from __future__ import absolute_import | ||
from __future__ import division | ||
import sys | ||
import numpy as np | ||
from rasterio import features | ||
from affine import Affine | ||
from numpy import min_scalar_type | ||
from shapely.geometry import box, MultiPolygon | ||
from .io import window_bounds | ||
|
||
|
@@ -45,10 +48,54 @@ def rasterize_geom(geom, like, all_touched=False): | |
fill=0, | ||
dtype='uint8', | ||
all_touched=all_touched) | ||
|
||
return rv_array.astype(bool) | ||
|
||
|
||
# https://stackoverflow.com/questions/8090229/ | ||
# resize-with-averaging-or-rebin-a-numpy-2d-array/8090605#8090605 | ||
def rebin_sum(a, shape, dtype): | ||
sh = shape[0],a.shape[0]//shape[0],shape[1],a.shape[1]//shape[1] | ||
return a.reshape(sh).sum(-1, dtype=dtype).sum(1, dtype=dtype) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't dug into this code but why choose this implementation over other methods of resampling? Specifically, using Rasterio's resampling techniques would give us more control over the resampling methods versus assuming "rebin" implies categorizing pixel values, I think "upsample" or similar would be a more accurate function name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think I looked into Rasterio's resampling methods, but I tested out a couple of different implementations (one was a proof of concept you put together for Rasterio, rasterio/rasterio#232, another was a more generalized aggregation scheme I pulled from another project of mine which had way too much overhead for what was needed here) and this method was a fair bit faster with less code. My main concern with any method here is going to be minimizing the additional time/memory required to run when using this feature. Did you have a use case in mind that would require using a method other than sum? I am on board with renaming to something more accurate, I had just kept it similar to the original function from SO I used. |
||
|
||
|
||
class objectview(object): | ||
def __init__(self, d): | ||
self.__dict__ = d | ||
|
||
def rasterize_pctcover_geom(geom, like, scale=None, all_touched=False): | ||
""" | ||
Parameters | ||
---------- | ||
geom: GeoJSON geometry | ||
like: raster object with desired shape and transform | ||
scale: scale at which to generate percent cover estimate | ||
|
||
Returns | ||
------- | ||
ndarray: float32 | ||
""" | ||
scale = scale if scale is not None else 10 | ||
min_dtype = min_scalar_type(scale**2) | ||
|
||
pixel_size_lon = like.affine[0]/scale | ||
pixel_size_lat = like.affine[4]/scale | ||
|
||
topleftlon = like.affine[2] | ||
topleftlat = like.affine[5] | ||
|
||
new_affine = Affine(pixel_size_lon, 0, topleftlon, | ||
0, pixel_size_lat, topleftlat) | ||
|
||
new_shape = (like.shape[0]*scale, like.shape[1]*scale) | ||
|
||
new_like = objectview({'shape': new_shape, 'affine': new_affine}) | ||
|
||
rv_array = rasterize_geom(geom, new_like, all_touched=all_touched) | ||
rv_array = rebin_sum(rv_array, like.shape, min_dtype) | ||
|
||
return rv_array.astype('float32') / (scale**2) | ||
|
||
|
||
def stats_to_csv(stats): | ||
if sys.version_info[0] >= 3: | ||
from io import StringIO as IO # pragma: no cover | ||
|
@@ -146,3 +193,30 @@ def boxify_points(geom, rast): | |
geoms.append(box(*window_bounds(win, rast.affine)).buffer(buff)) | ||
|
||
return MultiPolygon(geoms) | ||
|
||
|
||
|
||
def rs_mean(masked, cover_weights=None): | ||
if cover_weights is not None: | ||
val = float( | ||
np.sum(masked * cover_weights) / | ||
np.sum(~masked.mask * cover_weights)) | ||
else: | ||
val = float(masked.mean()) | ||
return val | ||
|
||
|
||
def rs_count(masked, cover_weights=None): | ||
if cover_weights is not None: | ||
val = float(np.sum(~masked.mask * cover_weights)) | ||
else: | ||
val = int(masked.count()) | ||
return val | ||
|
||
|
||
def rs_sum(masked, cover_weights=None): | ||
if cover_weights is not None: | ||
val = float(np.sum(masked * cover_weights)) | ||
else: | ||
val = float(masked.sum()) | ||
return val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why we need to limit to integers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reshape
performed in therebin_sum
function requires intshttps://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html