In [24]:
%pwd
Out[24]:
In [25]:
%pylab inline
On Ubuntu, I set up my environment like this:
#!bash
conda config --add channels conda-forge
conda create -n srp python=2
source activate srp
conda install -y anaconda
conda install -y laspy
conda install -y fiona
conda install -y shapely
conda install -y rasterio
pip install tqdm
pip install pyproj
In [26]:
import os
import laspy
import fiona
import shapely
import shapely.geometry
import rasterio
from pprint import pprint
from tqdm import tnrange
In [27]:
import rasterio.crs
In [28]:
from tqdm import tnrange, tqdm
from glob import glob
from time import sleep
import gc
In [29]:
import traceback
In [30]:
from tqdm import tqdm_notebook
from multiprocessing import Pool, cpu_count
print cpu_count(), "cpu cores on this machine"
In [31]:
VECTOR_DATA_FN = r'/home/liux13/Desktop/tmp/boxes_section11.shp'
assert os.path.isfile(VECTOR_DATA_FN)
In [32]:
GROUND_FN = r'/mnt/wwn-0x5000c5008aadf02c-part2/ASU_LiDAR_Processing/section11/merged_ground.asc'
assert os.path.isfile(GROUND_FN)
In [33]:
OUTPUT_METERS_PER_PIXEL = .05 # five centimeters, about 2 inches
OUTPUT_PADDING = 5 # expand output region 5 meters (to fit a local neighborhood into the image at the edges)
In [34]:
SLICE_THICKNESS = 0.313
In [35]:
OUTPUT_FN = './stack.vrt'
In [36]:
vector_file = fiona.open(VECTOR_DATA_FN)
In [37]:
minx, miny, maxx, maxy = vector_file.bounds
# Expand the region so that a local windo centered at points on the edges
# does not goi outside the grid
minx -= OUTPUT_PADDING
miny -= OUTPUT_PADDING
maxx += OUTPUT_PADDING
maxy += OUTPUT_PADDING
print "Region of interest (based on vector data)"
print minx, miny, "--", maxx, maxy
In [15]:
width_in_meters = maxx-minx
height_in_meters = maxy-miny
print 'width (m):', width_in_meters
print 'height (m):', height_in_meters
In [16]:
grid_width = int(round(width_in_meters/OUTPUT_METERS_PER_PIXEL))
grid_height = int(round(height_in_meters/OUTPUT_METERS_PER_PIXEL))
print 'grid width (cols):', grid_width
print 'grid height (rows):', grid_height
In [38]:
pattern = os.path.join(r'/mnt/wwn-0x5000c5008aadf02c-part2/ASU_LiDAR_Processing/section11/tiled/50/*.laz')
las_files = glob(pattern)
print len(las_files)
In [18]:
def save_stack(stack, las_fn, min_point, max_point, las_width, las_height):
output_transform = rasterio.transform.from_bounds(min_point[0], min_point[1],
max_point[0], max_point[1],
las_width, las_height)
output_crs = rasterio.crs.from_epsg(26949)
output_fn = os.path.split(las_fn)[1][:-3] + 'tif'
if os.path.isfile(output_fn):
os.remove(output_fn)
output_file = rasterio.open(output_fn, 'w',
driver=u'GTiff',
crs = output_crs,
transform=output_transform,
dtype=rasterio.uint16,
count=3,
width=las_width,
height=las_height)
output_file.write(indexes=(1,2,3), src=stack.astype(np.uint16))
output_file.close()
return output_fn
In [39]:
def process_las_file(las_fn):
"""Processes a single LAS/LAZ file
This function either returns the name of a file, or an exception object.
It is intended to be used in multiprocwesing.Pool.imap
"""
output_fn = ''
gc.collect()
try:
las_file = laspy.file.File(las_fn)
X = las_file.x
Y = las_file.y
Z = las_file.z
min_point = las_file.header.min
max_point = las_file.header.max
las_file.close()
las_min_x = int(floor((min_point[0]-minx) / OUTPUT_METERS_PER_PIXEL))
las_min_y = int(floor((min_point[1]-miny) / OUTPUT_METERS_PER_PIXEL))
las_max_x = int(floor((max_point[0]-minx) / OUTPUT_METERS_PER_PIXEL))
las_max_y = int(floor((max_point[1]-miny) / OUTPUT_METERS_PER_PIXEL))
las_width = las_max_x - las_min_x+1
las_height = las_max_y - las_min_y+1
if max_point[0] < minx or min_point[0] > maxx or max_point[1] < miny or min_point[1] > maxy:
return "Skipping {}, out-of-bounds file".format(os.path.split(las_fn)[1])
ground_file = rasterio.open(GROUND_FN)
ground_min_x, ground_min_y = ~(ground_file.affine)*(min_point[0], min_point[1])
ground_max_x, ground_max_y = ~(ground_file.affine)*(max_point[0], max_point[1])
ground_min_x = int(round(ground_min_x))
ground_min_y = int(round(ground_min_y))
ground_max_x = int(round(ground_max_x))
ground_max_y = int(round(ground_max_y))
flipped = False
if ground_max_y < ground_min_y:
ground_min_y, ground_max_y = ground_max_y, ground_min_y
flipped = True
ground_width = ground_max_x-ground_min_x + 1
ground_height = ground_max_y - ground_min_y + 1
ground = ground_file.read(1, window=((ground_min_y, ground_max_y+1), (ground_min_x, ground_max_x+1)),
boundless=True)
if flipped:
ground = ground[::-1,:]
ground_file.close()
C = np.floor(((X - minx)/OUTPUT_METERS_PER_PIXEL)).astype(int) - las_min_x
R = np.floor(((Y - miny)/OUTPUT_METERS_PER_PIXEL)).astype(int) - las_min_y
height_above_ground = Z - ground[(R*ground_height)/las_height, (C*ground_width)/las_width]
level = np.floor((height_above_ground)/SLICE_THICKNESS).astype(int)
def _generate_level(lvl):
bc = np.bincount(R[level==lvl]*las_width + C[level==lvl], minlength=las_width*las_height)
output = bc.reshape((las_height, las_width)).astype(float)
return output
stack = np.stack([_generate_level(lvl) for lvl in 1,2,3])
# I seem to be working upside-down...
output_fn = save_stack(stack[:,::-1,:], las_fn, min_point, max_point, las_width, las_height)
except e:
return (e, traceback.format_exc())
return output_fn
In [40]:
print process_las_file(las_files[41])
print process_las_file(las_files[-1])
In [41]:
jobs = las_files
for i in 0, 1, 2:
print '{:04}'.format(i), jobs[i]
print "..."
for i in len(jobs)-3, len(jobs)-2, len(jobs)-1:
print '{:04}'.format(i), jobs[i]
In [44]:
import gc
gc.collect()
Out[44]:
In [45]:
if not os.path.isfile('./try2/stack.vrt'):
workers = Pool(processes=20)
try:
pbar = tqdm_notebook(total=len(jobs))
completed = []
for output_fn in workers.imap(process_las_file, jobs):
print output_fn
completed.append(output_fn)
pbar.update(1)
finally:
workers.terminate()
workers.close()
pbar.close()
In [48]:
!gdalbuildvrt stack.vrt tile_*.tif
In [49]:
output_ds = rasterio.open('try2/stack.vrt')
:NOTE: Somehow fiona was unable to open the shapefil, so I converted it to a GeoJSON file with
ogr2ogr boxe_section11.json boxes_section11.shp -f GeoJSON
In [ ]:
vector_file = fiona.open('./boxes11/boxes_section11.json')
print vector_file.meta
In [ ]:
hotspots = [shapely.geometry.shape(f['geometry']).centroid for f in vector_file if f['geometry'] is not None]
In [ ]:
hs = hotspots[randint(len(hotspots))]
ctr = np.concatenate(hs.xy)
In [ ]:
print ctr
cr = np.asarray(~output_ds.affine * ctr).astype(int)
c, r = cr
print cr
data = output_ds.read(window=((r-32, r+32), (c-32, c+32)), boundless=True)
imshow((data.transpose(1,2,0)/20.).clip(0, 1))
In [ ]:
rgb = rasterio.open('./rgb/rgb.vrt')
In [ ]:
import pyproj
In [ ]:
EPSG2223 = pyproj.Proj(init="epsg:2223", preserve_units=True)
EPSG26949 = pyproj.Proj(init="epsg:26949", preserve_units=True)
print EPSG2223.srs
print EPSG26949.srs
In [ ]:
rgb_ctr = pyproj.transform(EPSG26949, EPSG2223, ctr[0], ctr[1])
print ctr, rgb_ctr
In [ ]:
rgb_cr = np.asarray(~rgb.affine * rgb_ctr).astype(int)
print rgb_cr
rgb_data = rgb.read(window=((rgb_cr[1]-8, rgb_cr[1]+8), (rgb_cr[0]-8, rgb_cr[0]+8)), boundless=True)
imshow(rgb_data.transpose(1,2,0))
In [ ]:
%%file data_provider.py
import pyproj
import rasterio
import numpy as np
import scipy.ndimage
from scipy.ndimage import zoom
from math import cos, sin, radians, atan2, degrees
from collections import namedtuple
Predictions = namedtuple('Predictions', ['x', 'y', 'label', 'dx', 'dy', 'angle'])
Sample = namedtuple('Sample', ['data', 'predicted'])
EPSG2223 = pyproj.Proj(init="epsg:2223", preserve_units=True)
EPSG26949 = pyproj.Proj(init="epsg:26949", preserve_units=True)
def normalize_angle(angle):
angle = radians(angle)
angle = atan2(sin(angle), cos(angle))
angle = degrees(angle)
return angle
class DataProvider(object):
def __init__(self, radius_in_pixels=32, jitter=0.25):
self.densities_path = '/home/shared/srp/try2/stack.vrt'
self.colors_path = '/home/shared/srp/rgb/rgb.vrt'
self.sample_path = '/home/shared/srp/sample_locations_epsg26949.npz'
self.radius_in_pixels = radius_in_pixels
self.jitter = jitter
self._open_datasets()
def _open_datasets(self):
self.densities = rasterio.open(self.densities_path)
self.colors = rasterio.open(self.colors_path)
samples= np.load(self.sample_path)
self.pos_xy = samples['pos_xy']
self.neg_xy = samples['neg_xy']
self.pos_angles = samples['pos_angles']
def random_positive(self, jitter=None, rotate=True):
jitter = self.jitter if jitter is None else jitter
index = np.random.randint(len(self.pos_xy))
dx, dy = jitter*np.random.randn(2)
x, y = self.pos_xy[index]
x -= dx
y -= dy
label=1
if rotate:
rotation = np.random.randint(0, 360)
patch = self.get_patch_xyr(x, y, rotation)
angle = normalize_angle(rotation + self.pos_angles[index])
else:
patch = self.get_patch_xy(x, y)
angle = self.pos_angles[index]
return Sample(patch, Predictions(x, y, label, dx, dy, angle))
def random_negative(self, jitter=None, rotate=True):
jitter = self.jitter if jitter is None else jitter
index = np.random.randint(len(self.neg_xy))
dx, dy = jitter*np.random.randn(2)
x, y = self.neg_xy[index]
x -= dx
y -= dy
label = 0
if rotate:
rotation = np.random.randint(0, 360)
patch = self.get_patch_xyr(x, y, rotation)
angle = normalize_angle(rotation)
else:
patch = self.get_patch_xy(x, y)
angle = 0
return Sample(patch, Predictions(x, y, label, dx, dy, angle))
def random_sample(self, jitter=None, rotate=True, prob_positive=0.5):
jitter = self.jitter if jitter is None else jitter
if np.random.rand() > prob_positive:
return self.random_negative(jitter, rotate)
else:
return self.random_positive(jitter, rotate)
def get_patch_xyr(self, x, y, angle, radius_in_pixels=None):
radius_in_pixels = radius_in_pixels or self.radius_in_pixels
source_patch = self.get_patch_xy(x, y, radius_in_pixels*2)
width = height = 2*radius_in_pixels
radians = np.radians(angle)
c, s = cos(radians), sin(radians)
R = np.matrix([[c, -s],
[s, c]])
X = np.asarray([width, height])
X = np.asarray(X-R.dot(X)).flatten()
rotated_patch = np.empty_like(source_patch)
for i in range(len(rotated_patch)):
scipy.ndimage.affine_transform(source_patch[i],
matrix=R, offset=X,
output_shape = rotated_patch[i].shape,
output=rotated_patch[i])
x, y = int((source_patch.shape[2]-width)/2), int( (source_patch.shape[1]-height)/2)
cropped_patch = rotated_patch[:, y:y+height, x:x+width].copy()
return cropped_patch
def get_patch_xy(self, x, y, radius_in_pixels=None):
radius_in_pixels = radius_in_pixels or self.radius_in_pixels
R = radius_in_pixels
x_2223, y_2223 = pyproj.transform(EPSG26949, EPSG2223, x, y)
c_2223, r_2223 = np.asarray(~self.colors.affine * (x_2223, y_2223)).astype(int)
c, r = np.asarray(~self.densities.affine*(x, y)).astype(int)
colors = self.colors.read(window=((r_2223-R, r_2223+R), (c_2223-R, c_2223+R)),
boundless=True).astype(np.float32)/255.
densities = self.densities.read(window=((r-R, r+R), (c-R, c+R)),
boundless=True).astype(np.float32)
combined = np.concatenate([colors, densities])
return combined
In [46]:
import data_provider
reload(data_provider)
DataProvider = data_provider.DataProvider
In [ ]:
from pandas import DataFrame
In [ ]:
gtp = DataProvider(radius_in_pixels=32, jitter = 0.25)
In [ ]:
patch, labels = gtp.random_positive()
print patch.shape
subplot(1,2,1)
imshow(patch[:3,:,:].transpose(1,2,0).clip(0,1))
title('colors')
subplot(1,2,2)
imshow((patch[3:6,:,:]/40).transpose(1,2,0).clip(0,1))
title('densities');
display(DataFrame([labels], columns=data_provider.Predictions._fields))
In [ ]:
patch, labels = gtp.random_sample()
subplot(1,2,1)
imshow(patch[:3,:,:].transpose(1,2,0).clip(0,1))
title('colors')
subplot(1,2,2)
imshow((patch[3:6,:,:]/20).transpose(1,2,0).clip(0,1))
title('densities')
display(DataFrame([labels], columns=data_provider.Predictions._fields))
In [ ]:
def make_datum(patch, labels):
#Create a Datum
datum = Datum()
datum.channels, datum.height, datum.width = patch.shape
datum.data = patch.tobytes()
datum.label = labels.label
return datum
In [ ]:
from tqdm import tnrange
import lmdb
from caffe.proto.caffe_pb2 import Datum
def make_lmdb(dbname, nsamples, data_generator):
train_data_env = lmdb.open(dbname)
train_data_env.set_mapsize(1e12)
for i in tnrange(nsamples):
sample = data_generator.random_sample()
datum = make_datum(sample.data, sample.predicted)
key = '{:06}{:06}'.format(int(100*sample.predicted.x), int(100*sample.predicted.y))
with train_data_env.begin(write=True) as txn:
print '\r', key,
txn.put(key, datum.SerializeToString())
In [ ]:
make_lmdb('/home/shared/srp/ds1.lmdb', 1000, gtp)
In [ ]:
import caffe, caffe.net_spec
In [ ]:
from caffe import layers as L
from caffe import params as P
In [ ]:
batch_size=64
n = caffe.NetSpec()
n.data, n.label = L.DummyData(shape=[dict(dim=[batch_size, 1, 28, 28]),
dict(dim=[batch_size, 1, 1, 1])],
transform_param=dict(scale=1./255), ntop=2)
n.conv1 = L.Convolution(n.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
n.pool1 = L.Pooling(n.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.conv2 = L.Convolution(n.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
n.ip1 = L.InnerProduct(n.pool2, num_output=500, weight_filler=dict(type='xavier'))
n.relu1 = L.ReLU(n.ip1, in_place=True)
n.ip2 = L.InnerProduct(n.relu1, num_output=10, weight_filler=dict(type='xavier'))
n.loss = L.SoftmaxWithLoss(n.ip2, n.label, )
In [47]:
from caffe.draw import draw_net
In [ ]:
import pydot
g = caffe.draw.get_pydot_graph(n.to_proto(), 'TB')
from IPython.display import Image, display
Image(g.create_png())
In [ ]:
from IPython.display import Image, display
Image(g.create_png())