Source code for mmseg.datasets.pipelines.misc_utils
from pathlib import Path
from osgeo import gdal
import numpy as np
import json
import os
from tqdm import tqdm
from PIL import Image
UNITS_PER_METER_CONVERSION_FACTORS = {"cm": 100.0, "m": 1.0}
[docs]def save_image(img_path, img):
"""Note this function does not utilize conversion factors to meters, so implicitly assumes units are in meters."""
rows = img.shape[0]
cols = img.shape[1]
bands = 1
if np.ndim(img) == 3:
bands = img.shape[2]
if img.dtype == np.uint8:
data_type = gdal.GDT_Byte
else:
data_type = gdal.GDT_Float32
driver = gdal.GetDriverByName("GTiff").Create(
str(img_path), rows, cols, bands, data_type, ["COMPRESS=LZW"]
)
if bands == 1:
driver.GetRasterBand(1).WriteArray(img[:, :])
else:
for i in range(bands):
driver.GetRasterBand(i + 1).WriteArray(img[:, :, i])
driver.FlushCache()
driver = None
def load_image(
image_path,
args,
dtype_out="float32",
units_per_meter_conversion_factors=UNITS_PER_METER_CONVERSION_FACTORS,
):
image_path = Path(image_path)
if not image_path.exists():
return None
image = gdal.Open(str(image_path))
image = image.ReadAsArray()
# convert AGL units and fill nan placeholder with nan
if "AGL" in image_path.name:
image = image.astype(dtype_out)
np.putmask(image, image == args.nan_placeholder, np.nan)
# e.g., (cm) / (cm / m) = m
units_per_meter = units_per_meter_conversion_factors[args.unit]
image = (image / units_per_meter).astype(dtype_out)
# transpose if RGB
if len(image.shape) == 3:
image = np.transpose(image, [1, 2, 0])
return image
def load_vflow(
vflow_path,
agl,
args,
dtype_out="float32",
units_per_meter_conversion_factors=UNITS_PER_METER_CONVERSION_FACTORS,
return_vflow_pred_mat=False,
):
vflow_path = Path(vflow_path)
vflow_data = json.load(vflow_path.open("r"))
# e.g., (pixels / cm) * (cm / m) = (pixels / m)
units_per_meter = units_per_meter_conversion_factors[args.unit]
vflow_data["scale"] = vflow_data["scale"] * units_per_meter
xdir, ydir = np.sin(vflow_data["angle"]), np.cos(vflow_data["angle"])
mag = agl * vflow_data["scale"]
vflow_items = [mag.astype(dtype_out), xdir.astype(dtype_out), ydir.astype(dtype_out), vflow_data]
if return_vflow_pred_mat:
vflow = np.zeros((agl.shape[0],agl.shape[1],2))
vflow[:,:,0] = mag * xdir
vflow[:,:,1] = mag * ydir
vflow_items.insert(0, vflow)
return vflow_items
def get_r2(error_sum, gt_sq_sum, data_sum, count):
return 1 - error_sum / (gt_sq_sum - (data_sum ** 2) / count)
def get_rms(errors):
return np.sqrt(np.mean(np.square(errors)))
def get_angle_error(dir_pred, dir_gt):
dir_pred /= np.linalg.norm(dir_pred)
dir_gt /= np.linalg.norm(dir_gt)
cos_ang = np.dot(dir_pred, dir_gt)
sin_ang = np.linalg.norm(np.cross(dir_pred, dir_gt))
rad_diff = np.arctan2(sin_ang, cos_ang)
angle_error = np.degrees(rad_diff)
return angle_error
def get_r2_info(data_gt, data_pred):
data_pred = np.squeeze(data_pred)
not_nan = ~np.isnan(data_gt)
count = np.sum(not_nan)
diff = data_pred - data_gt
error_sum = np.sum(np.square(diff[not_nan]))
rms = get_rms(diff[not_nan])
data_sum = np.sum(data_gt[not_nan])
gt_sq_sum = np.sum(np.square(data_gt[not_nan]))
return count, error_sum, rms, data_sum, gt_sq_sum
[docs]def convert_and_compress_prediction_dir(
predictions_dir,
to_unit="cm",
agl_dtype="uint16",
compression_type="tiff_adobe_deflate",
conversion_factors=UNITS_PER_METER_CONVERSION_FACTORS,
):
"""Convert and compress prediction directory.
Default parameters are consistent with DrivenData platform submission requirements.
"""
predictions_dir = Path(predictions_dir)
converted_predictions_dir = predictions_dir.with_name(
f"{predictions_dir.name}_converted_{to_unit}_compressed_{agl_dtype}"
)
converted_predictions_dir.mkdir(exist_ok=True, parents=True)
conversion_factor = conversion_factors[to_unit]
agl_paths = list(predictions_dir.glob("*_AGL.tif"))
json_paths = list(
pth.with_name(pth.name.replace("_AGL", "_VFLOW")).with_suffix(".json")
for pth in agl_paths
)
for agl_path, json_path in tqdm(zip(agl_paths, json_paths), total=len(agl_paths)):
# convert and compress agl tif
imarray = np.array(Image.open(agl_path))
imarray = np.round(imarray * conversion_factor).astype(agl_dtype)
new_image = Image.fromarray(imarray)
new_image_path = converted_predictions_dir / agl_path.name
new_image.save(str(new_image_path), "TIFF", compression=compression_type)
# convert and compress vflow json
vflow = json.load(json_path.open("r"))
vflow["scale"] = vflow["scale"] / conversion_factor
new_json_path = converted_predictions_dir / json_path.name
json.dump(vflow, new_json_path.open("w"))