def execute_pov(params): pov_filename, out_filename, dimensions, mode = params out_width, out_height = dimensions p_i("Generating %s" % out_filename) if mode == "color" or mode == "gradient": subprocess.call([ "povray", "+W%d" % out_width, "+H%d" % out_height, "Output_File_Type=N Bits_Per_Color=16 +Q8 +UR +A", "-GA", "+I" + pov_filename, "+O" + out_filename, ]) else: subprocess.call([ "povray", "+W%d" % out_width, "+H%d" % out_height, "Output_File_Type=N Bits_Per_Color=16 Display=off", "-GA", "Antialias=off Quality=0 File_Gamma=1.0", "+I" + pov_filename, "+O" + out_filename, ])
def vertical_stack_imshow_divider(im1, im2, title="Preview", div_thickness=3): try: _, im1_w, _ = im1.shape except ValueError: im1 = cv2.cvtColor(im1, cv2.COLOR_GRAY2BGR) _, im1_w, _ = im1.shape try: _, im2_w, _ = im2.shape except ValueError: im2 = cv2.cvtColor(im2, cv2.COLOR_GRAY2BGR) _, im2_w, _ = im2.shape m = min(im1_w, im2_w) if im1_w != im2_w: im1 = resizer(im1, im_width=m) im2 = resizer(im2, im_width=m) divider = np.zeros((div_thickness, m, 3), np.uint8) divider[:, 0:m] = (255, 255, 255) stack = np.vstack((im1, divider, im2)) to_save = custom_imshow(stack, title) if to_save: path = askdirectory(title="Select Folder") if path: filename = p_in("Filename: ") save_image(im2, filename, path) p_i("File was saved")
def structured_forest(image): p_i("Starting Structured Forest Edge Detection...") sf = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) sf = sf.astype(np.float32) / 512.0 edge_detector = cv2.ximgproc.createStructuredEdgeDetection( "assets/model.yml") edges = edge_detector.detectEdges(sf) * 512.0 p_i("Structured Forest Edge Detection complete!") return edges
def canny_edge_detection(image, interactive_window=True, blur_factor=5): p_i("Starting Canny Edge Detection...") # automatically set lb and ub values from the median color in the image gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) v = np.median(gray) sigma = 0.5 lb = int(max(0, (1.0 - sigma) * v)) ub = int(min(100, (1.0 + sigma) * v)) blurred = cv2.medianBlur(gray, blur_factor) if not interactive_window: p_i("Canny Edge Detection complete!") return cv2.Canny(blurred, lb, ub, apertureSize=5) p_i("Opening external window") n = "Canny Edge Detection" cv2.namedWindow(n) cv2.createTrackbar("Lower Bound", n, lb, 100, nothing) cv2.createTrackbar("Upper Bound", n, ub, 100, nothing) cv2.createTrackbar("Dilate Horizontal", n, 1, 20, nothing) cv2.createTrackbar("Dilate Vertical", n, 1, 20, nothing) while True: lb = cv2.getTrackbarPos("Lower Bound", n) ub = cv2.getTrackbarPos("Upper Bound", n) d_h = cv2.getTrackbarPos("Dilate Horizontal", n) d_v = cv2.getTrackbarPos("Dilate Vertical", n) edges = cv2.Canny(blurred, lb, ub) kernel = np.ones((d_v, d_h), np.uint8) dilated = cv2.dilate(edges, kernel, iterations=1) cv2.imshow(n, dilated) k = cv2.waitKey(1) & 0xFF if k == 27: # use escape for exiting window cv2.destroyAllWindows() p_i("Canny Edge Detection complete!") return dilated
def holistically_nested(image): p_i("Starting Holistically-Nested Edge Detection...") net = cv2.dnn.readNetFromCaffe( "data/hed_model/deploy.prototxt", "data/hed_model/" + "hed_pretrained_bsds.caffemodel", ) height, width = image.shape[:2] cv2.dnn_registerLayer("Crop", CropLayer) blob = cv2.dnn.blobFromImage(image, size=(width, height)) net.setInput(blob) hed = (255 * cv2.resize(net.forward()[0, 0], (width, height))).astype("uint8") p_i("Holistically-Nested Edge Detection complete!") cv2.dnn_unregisterLayer("Crop") return hed
def mark_image_seen(img_data): p_i('Marking image as seen') if img_data.view_direction is None: return make_folder(f"{UPLOAD_FOLDER}dev/") try: h = open(SEEN_IMAGES_PATH, "r") seen_images = h.readlines() h.close() if img_data.filename in seen_images or f"{img_data.filename}\n" in seen_images: return else: h = open(SEEN_IMAGES_PATH, "a") h.write(f"{img_data.filename}\n") h.close() except FileNotFoundError: h = open(SEEN_IMAGES_PATH, "a") h.write(f"{img_data.filename}\n") h.close()
def reset_image(im): p_i(f"Resetting image {im}") IMAGE_DATA = load_image_data(im) try: os.remove(IMAGE_DATA.overlay_path) except (AttributeError, FileNotFoundError): pass try: os.remove(IMAGE_DATA.ultrawide_path) except (AttributeError, FileNotFoundError): pass try: os.remove(IMAGE_DATA.warped_panorama_path) except (AttributeError, FileNotFoundError): pass IMAGE_DATA.view_direction = None IMAGE_DATA.fov_l = None IMAGE_DATA.fov_r = None IMAGE_DATA.location = None IMAGE_DATA.transform_matrix = None save_image_data(IMAGE_DATA)
def get_3d_location(camera_location, dataset, fov): def get_initial_bearing(camera_location, object_location): c_lon = radians(camera_location.longitude) c_lat = radians(camera_location.latitude) o_lon = radians(object_location.longitude) o_lat = radians(object_location.latitude) diff_lon = o_lon - c_lon x = sin(diff_lon) * cos(o_lat) y = cos(c_lat) * sin(o_lat) - sin(c_lat) * cos(o_lat) * cos(diff_lon) init_bearing = degrees(atan2(x, y)) compass_bearing = (init_bearing + 360) % 360 return compass_bearing def get_3d_placement(camera_location, item, generator): d = generator.get_distance_between_locations(camera_location, item.location) c_e = camera_location.elevation + 25 i_e = item.location.elevation diff = i_e - c_e h = (d**2 + diff**2)**0.5 pitch = degrees(asin(diff / h)) yaw = get_initial_bearing(camera_location, item.location) return yaw, pitch, d generator = Distance() new_ds = [] p_i(f"Field of View: {fov[0]}-{fov[1]}") for item in dataset: yaw, pitch, d = get_3d_placement(camera_location, item, generator) item.set_location_in_3d(Location3D(yaw=yaw, pitch=pitch, distance=d)) p_i(f"{item.name} at {item.location_in_3d}") if yaw < fov[0] or yaw > fov[1]: new_ds.append(item) return new_ds
def generate_viewshed(img_data): cropped_dem, coordinates, image_location, elevation = pickle.load( open(f"{img_data.folder}/vs.pkl", "rb")) ds_raster = rasterio.open(cropped_dem) p_i(f"Creating viewshed for {img_data.filename}") converter = LatLngToCrs(int(ds_raster.crs.to_authority()[1])) locxy = converter.convert(coordinates[0], coordinates[1]) vs_created = create_viewshed(cropped_dem, (locxy.GetX(), locxy.GetY()), img_data.folder) if not vs_created: p_e(f"Failed to create viewshed for {img_data.filename}") return False load_dotenv() api_key = os.getenv("MAPBOX_TOKEN") url = f"https://api.mapbox.com/geocoding/v5/mapbox.places/{image_location.longitude},{image_location.latitude}.json?access_token={api_key}" headers = CaseInsensitiveDict() headers["Accept"] = "application/json" resp = requests.get(url, headers=headers).json() place_name = resp["features"][0]["text"] img_data.place_name = place_name img_data.place_elevation = elevation save_image_data(img_data) return True
def tui_select(it, itt="", in_t="", e_t="", afd=False): formatted_text = [] for i in range(len(it)): formatted_text.append("%i: %s" % (i + 1, it[i])) formatted_text.append("0: exit") p_line() p_i(itt) p_line(formatted_text) while True: try: mode = p_in(in_t) if mode == "debug" and afd: return mode mode = int(mode) except ValueError: p_e(e_t) continue if mode == 0: exit() if mode < 1 or mode > len(it): p_e(e_t) continue return mode
def create_route_texture(dem_file, gpx_path, debugging=False): filename = gpx_path.split("/")[-1].split(".")[0] folder = "exports/%s/texture" % filename if debugging: im_path = "%s/%s-texture-debug.png" % (folder, filename) else: im_path = "%s/%s-texture.png" % (folder, filename) try: os.mkdir(folder) except FileExistsError: pass texture_bounds_path = "%s/%s-texture-bounds.pkl" % (folder, filename) texture_exist = os.path.isfile("%s" % im_path) bounds_exist = os.path.isfile("%s" % texture_bounds_path) if texture_exist and bounds_exist: with open(texture_bounds_path, "rb") as f: tex_bounds = pickle.load(f) return [im_path, tex_bounds] p_i(f"Creating route texture for {filename}") mns, minimums, maximums = read_hike_gpx(gpx_path) ds_raster = rasterio.open(dem_file) crs = int(ds_raster.crs.to_authority()[1]) converter = LatLngToCrs(crs) lower_left = converter.convert(minimums[0].latitude, minimums[1].longitude) upper_right = converter.convert(maximums[0].latitude, maximums[1].longitude) bbox = ( lower_left.GetX(), upper_right.GetY(), upper_right.GetX(), lower_left.GetY(), ) gdal.Translate(f"{folder}/{filename}-output_crop_raster.tif", dem_file, projWin=bbox) im = cv2.imread(f"{folder}/{filename}-output_crop_raster.tif") h, w, _ = im.shape rs = 1 if debugging: rs = 20 multiplier = 100 h = h * multiplier w = w * multiplier if not mns: return ["", ""] img = np.ones([h, w, 4], dtype=np.uint8) ds_raster = rasterio.open(dem_file) crs = int(ds_raster.crs.to_authority()[1]) b = ds_raster.bounds bounds = [b.left, b.bottom, b.right, b.top] converter = LatLngToCrs(crs) locs = [ convert_single_coordinate_pair(bounds, converter, i.latitude, i.longitude) for i in mns ] prev_lat = abs(int(((100.0 * locs[0][0]) / 100) * w)) prev_lon = h - abs(int(100.0 - ((100.0 * locs[0][1]) / 100.0) * h)) for i in locs: lat, lon = i x = h - abs(int(100.0 - ((100.0 * lon) / 100.0) * h)) y = abs(int(((100.0 * lat) / 100.0) * w)) cv2.line(img, (prev_lat, prev_lon), (y, x), (0, 0, 255, 255), 3 * rs) prev_lat, prev_lon = y, x min_lat_p = minimums[0] min_lon_p = minimums[1] max_lat_p = maximums[0] max_lon_p = maximums[1] min_x = convert_single_coordinate_pair(bounds, converter, min_lat_p.latitude, min_lat_p.longitude) min_y = convert_single_coordinate_pair(bounds, converter, min_lon_p.latitude, min_lon_p.longitude) max_x = convert_single_coordinate_pair(bounds, converter, max_lat_p.latitude, max_lat_p.longitude) max_y = convert_single_coordinate_pair(bounds, converter, max_lon_p.latitude, max_lon_p.longitude) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY) contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnt = contours[0] x, y, w, h = cv2.boundingRect(cnt) crop = img[y:y + h, x:x + w] cv2.imwrite(im_path, crop) tex_bounds = TextureBounds( min_lat=min_lat_p, min_lon=min_lon_p, max_lat=max_lat_p, max_lon=max_lon_p, min_x=min_x, min_y=min_y, max_x=max_x, max_y=max_y, ) p_i("Route texture complete") with open(texture_bounds_path, "wb") as f: pickle.dump(tex_bounds, f) subprocess.call( ["rm", "-r", f"{folder}/{filename}-output_crop_raster.tif"]) return [im_path, tex_bounds]
def plot_to_map( camera_pano_path, mountains_in_sight, coordinates, filename, dem_file, converter, locs=None, mountains=None, images=None, ): p_i("Creating Interactive Map") c_lat, c_lon, _, _ = coordinates ll, ul, ur, lr = location_handler.get_raster_bounds(dem_file) load_dotenv() MAPBOX_TOKEN = os.getenv("MAPBOX_TOKEN") MAPBOX_STYLE_URL = os.getenv("MAPBOX_STYLE_URL") m = folium.Map( [c_lat, c_lon], tiles=None, zoom_start=12, scrollWheelZoom=False, ) folium.TileLayer( location=[c_lat, c_lon], tiles=MAPBOX_STYLE_URL, API_key=MAPBOX_TOKEN, attr="Christian Hein", name="Settings", ).add_to(m) min_ele, max_ele = 10000, 0 for i in mountains: if i.location.elevation > max_ele: max_ele = i.location.elevation if i.location.elevation < min_ele: min_ele = i.location.elevation ########################################################################### ########################################################################### # All mountains in dataset if mountains: mountains_fg = folium.FeatureGroup(name="All Mountains", show=False) m.add_child(mountains_fg) [(folium.Marker( location=(i.location.latitude, i.location.longitude), popup="%s\n%im" % ( str(i.name), i.location.elevation, ), icon=folium.DivIcon(html=get_glyph( f"am-{i.name}-{int(i.location.elevation)}", "#755239", i.location.elevation, min_ele, max_ele)), zIndexOffset=1, ).add_to(mountains_fg)) for i in mountains] ########################################################################### ########################################################################### # Mountains in sight if mountains_in_sight: mountains_in_sight_fg = folium.FeatureGroup(name="Visible Mountains", show=True) m.add_child(mountains_in_sight_fg) [(folium.Marker( location=(i.location.latitude, i.location.longitude), popup="%s\n%im" % ( str(i.name), i.location.elevation, ), icon=folium.DivIcon(html=get_glyph( f"vm-{i.name}-{int(i.location.elevation)}", "#426877", i.location.elevation, min_ele, max_ele)), zIndexOffset=10, ).add_to(mountains_in_sight_fg)) for i in mountains_in_sight] ########################################################################### ########################################################################### # Other images in dataset if images: images_fg = folium.FeatureGroup(name="Visible Images", show=True) m.add_child(images_fg) for im in images: encoded = base64.b64encode(open(im.thumbnail_path, "rb").read()) html = f''' <!doctype html> <html> <head> <style> .redirect-button {{ color: #fff; cursor: pointer; background-color: #6c757d; border-color: #6c757d; display: inline-block; font-weight: 400; line-height: 1.5; text-align: center; text-decoration: none; vertical-align: middle; padding: .375rem .75rem; border-radius: .25rem; transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; }} .redirect-button:hover {{ color: #fff; background-color: #5c636a; border-color: #545b62; }} </style> <script type="text/javascript"> function redirect() {{ console.log("Redirecting to: ", "{im.name}"); window.parent.parent.postMessage("{im.name}", '*'); }} </script> </head> <body> <button class="redirect-button" onclick="redirect();">View image</button> <img src="data:image/JPG;base64,{encoded.decode("UTF-8")}"> </body> </html> ''' iframe = folium.IFrame(html, width=450 + 20, height=150 + 20) popup = folium.Popup(iframe, max_width=470) folium.Marker( location=(im.location.latitude, im.location.longitude), popup=popup, icon=folium.Icon(color="orange", icon="camera"), zIndexOffset=12, ).add_to(images_fg) ########################################################################### ########################################################################### # Current viewpoint encoded = base64.b64encode(open(camera_pano_path, "rb").read()) html = f''' <!doctype html> <html> <img src="data:image/JPG;base64,{encoded.decode("UTF-8")}"> </html> ''' iframe = folium.IFrame(html, width=450 + 20, height=150 + 20) popup = folium.Popup(iframe, max_width=450) folium.Marker( location=[c_lat, c_lon], popup=popup, icon=folium.Icon(color="green", icon="camera"), zIndexOffset=13, ).add_to(m) ########################################################################### ########################################################################### # Visible coordinates if locs: locs_fg = folium.FeatureGroup(name="Retrieved Coordinates", show=True) m.add_child(locs_fg) for i in locs: loc = converter.convert(*i) folium.Circle( location=(loc.latitude, loc.longitude), color="#0a6496", fill=True, fill_color="#0a6496", fill_opacity=1, radius=15, ).add_to(locs_fg) ########################################################################### ########################################################################### # Raster bounds raster_bounds = folium.FeatureGroup(name="Raster Bounds", show=False) m.add_child(raster_bounds) folium.PolyLine(locations=[ll, ul, ur, lr, ll], color="#d63e29", zIndexOffset=15).add_to(raster_bounds) ########################################################################### ########################################################################### # Legend template = """ {% macro html(this, kwargs) %} <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id='maplegend' class='maplegend' style='position: absolute; z-index:9999; border:2px solid grey; background-color:rgba(255, 255, 255, 0.8); border-radius:6px; padding: 10px 10px 1px; font-size:16px; font-weight:500; right: 20px; bottom: 24px;'> <div class='legend-scale'> <ul class='legend-labels'> <li><span style='background:#71b025;opacity:1.0;'></span>Current Viewpoint</li> <li><span style='background:#f69730;opacity:1.0;'></span>Images in dataset</li> <li><span style='background:#755239;opacity:1.0;'></span>All mountains in dataset</li> <li><span style='background:#426877;opacity:1.0;'></span>Mountains in sight</li> <li><span style='background:#d63e29;opacity:1.0;'></span>DEM bounding box</li> </ul> </div> </div> </body> </html> <style type='text/css'> .maplegend .legend-title { text-align: left; margin-bottom: 5px; font-weight: bold; font-size: 90%; } .maplegend .legend-scale ul { margin: 0; margin-bottom: 5px; padding: 0; float: left; list-style: none; } .maplegend .legend-scale ul li { font-size: 80%; list-style: none; margin-left: 0; line-height: 18px; margin-bottom: 2px; } .maplegend ul.legend-labels li span { display: block; float: left; height: 16px; width: 30px; margin-right: 5px; margin-left: 0; border: 1px solid #999; } .maplegend .legend-source { font-size: 80%; color: #777; clear: both; } .maplegend a { color: #777; } </style> {% endmacro %}""" macro = MacroElement() macro._template = Template(template) ########################################################################### ########################################################################### # Add to map folium.LayerControl().add_to(m) m.get_root().add_child(macro) # m.add_child(Fullscreen(position='topleft')) m.save(filename)
def mountain_lookup(img_data, gpx_file, plot=False): p_i(f"Beginning mountain lookup for {img_data.filename}") viewshed = f'{img_data.folder}/viewshed.tif' ds_viewshed = rasterio.open(viewshed) if not ds_viewshed: return False render_settings_path = "render_settings.json" with open(render_settings_path) as json_file: data = load(json_file) dem_file = data["dem_path"] json_file.close() cropped_dem, coordinates, _, _ = pickle.load( open(f"{img_data.folder}/vs.pkl", "rb")) ds_raster = rasterio.open(cropped_dem) crs = int(ds_raster.crs.to_authority()[1]) lat, lon = coordinates[0], coordinates[1] converter = LatLngToCrs(crs) camera_height = convert_coordinates(ds_raster, converter, lat, lon, True) camera_location = Location(lat, lon, camera_height) viewshed = f'{img_data.folder}/viewshed.tif' ds_viewshed = rasterio.open(viewshed) """ visible_hikes = {} for hike in get_hikes(): waypoints_in_sight = find_visible_items_in_ds( ds_viewshed, hike.waypoints ) waypoints_3d = get_3d_location( camera_location, waypoints_in_sight, ) visible_hikes[hike.name] = waypoints_3d """ fov = [img_data.fov_l, img_data.fov_r] images = read_image_locations(img_data.filename, "src/static/images", ds_raster, converter) images_in_sight = find_visible_items_in_ds(ds_viewshed, images) images_3d = get_3d_location(camera_location, images_in_sight, fov) mountains = read_mountain_gpx(gpx_file, converter) mountains_in_sight = find_visible_items_in_ds(ds_viewshed, mountains) mountains_3d = get_3d_location(camera_location, mountains_in_sight, fov) if plot: plotly_path = f"{img_data.folder}/{img_data.filename}-3d.json" if not os.path.exists(plotly_path): plot_3d(ds_raster, plotly_path) plot_filename = f"{img_data.folder}/{img_data.filename}-{gpx_file.split('/')[-1].split('.')[0]}.html" plot_to_map( img_data.thumbnail_path, mountains_3d, coordinates, plot_filename, dem_file, CrsToLatLng(crs), mountains=mountains, images=images, ) return mountains_3d, images_3d, {}