Loading autocnet/cg/change_detection.py +155 −9 Original line number Diff line number Diff line Loading @@ -2,9 +2,9 @@ import numpy as np from matplotlib.path import Path from shapely.geometry import Point, MultiPoint import geopandas as gpd import cv2 from sklearn.cluster import OPTICS from plio.io.io_gdal import GeoDataset from autocnet.utils.utils import bytescale from autocnet.matcher.cpu_extractor import extract_features Loading @@ -18,16 +18,161 @@ def image_diff(arr1, arr2): diff = arr1-arr2 diff[np.isnan(diff)] = 0 return bytescale(diff) return diff def okubogar_detector(image1, image2, nbins=50, extractor_method="orb", image_func=image_diff, extractor_kwargs={"nfeatures": 2000, "scaleFactor": 1.1, "nlevels": 1}): """ Simple change detection algorithm which produces an overlay image of change hotspots (i.e. a 2d histogram image of detected change density). Largely based on a method created by Chris Okubo and Brendon Bogar. Histogram step was added for readability. image1 \ image subtraction/ratio -> feature_extraction -> feature_histogram / image2 TODO: Paper/abstract might exist, cite Parameters ---------- image1 : np.array, plio.GeoDataset Image representing the "before" state of the ROI, can be a 2D numpy array or plio GeoDataset image2 : np.array, plio.GeoDataset Image representing the "after" state of the ROI, can be a 2D numpy array or plio GeoDataset image_func : callable Function used to create a derived image from image1 and image2, which in turn is the input for the feature extractor. The first two arguments are 2d numpy arrays, image1 and image2, and must return a 2d numpy array. Default function returns a difference image. Example func: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> def ratio(image1, image2): >>> # do stuff with image1 and image2 >>> new_image = image1/image2 >>> return new_image # must return a single variable, a 2D numpy array >>> results = okubogar_detector(image1, image2, image_func=ratio) def okubogar_detector(image1, image2, nbins=50, extractor_method="orb", extractor_kwargs={"nfeatures": 2000, "scaleFactor": 1.1, "nlevels": 1}, cluster_params={"min_samples": 10, "max_eps": 10, "eps": .5, "xi":.5}, image_func=image_diff): arr1 = image1.read_array() arr2 = image2.read_array() arr1[arr1 == arr1.min()] = 0 arr2[arr2 == arr2.min()] = 0 arr1 = bytescale(arr1) arr2 = bytescale(arr2) Or, alternatively: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> results = okubogar_detector(image1, image2, image_func=lambda im1, im2: im1/im2) nbins : int number of bins to use in the 2d histogram extractor_method : {'orb', 'sift', 'fast', 'surf', 'vl_sift'} The detector method to be used. Note that vl_sift requires that vlfeat and cyvlfeat dependencies be installed. extractor_kwargs : dict A dictionary containing OpenCV SIFT parameters names and values. See Also -------- feature extractor: autocnet.matcher.cpu_extractor.extract_features """ if isinstance(image1, GeoDataset): image1 = image1.read_array() if isinstance(image2, GeoDataset): image2 = image2.read_array() image1[image1 == image1.min()] = 0 image2[image2 == image2.min()] = 0 arr1 = bytescale(image1) arr2 = bytescale(image2) bdiff = image_func(arr1, arr2) keys, descriptors = extract_features(bdiff, extractor_method, extractor_parameters=extractor_kwargs) x,y = keys["x"], keys["y"] points = [Point(xval, yval) for xval,yval in zip(x,y)] heatmap, xedges, yedges = np.histogram2d(y, x, bins=nbins, range=[[0, bdiff.shape[0]], [0, bdiff.shape[1]]]) heatmap = cv2.resize(heatmap, dsize=(bdiff.shape[1], bdiff.shape[0]), interpolation=cv2.INTER_NEAREST) return points, heatmap, bdiff def okbm_detector(image1, image2, nbins=50, extractor_method="orb", image_func=image_diff, extractor_kwargs={"nfeatures": 2000, "scaleFactor": 1.1, "nlevels": 1}, cluster_params={"min_samples": 10, "max_eps": 10, "eps": .5, "xi":.5}): """ okobubogar modified detector, experimental feature based change detection algorithmthat expands on okobubogar to allow for programmatic change detection. Returns detected feature changes as weighted polygons. Parameters ---------- image1 : GeoDataset Image representing the "before" state of the ROI, can be a 2D numpy array or plio GeoDataset image2 : GeoDataset Image representing the "after" state of the ROI, can be a 2D numpy array or plio GeoDataset image_func : callable Function used to create a derived image from image1 and image2, which in turn is the input for the feature extractor. The first two arguments are 2d numpy arrays, image1 and image2, and must return a 2d numpy array. Default function returns a difference image. Example func: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> def ratio(image1, image2): >>> # do stuff with image1 and image2 >>> new_image = image1/image2 >>> return new_image # must return a single variable, a 2D numpy array >>> results = okbm_detector(image1, image2, image_func=ratio) Or, alternatively: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> results = okbm_detector(image1, image2, image_func=lambda im1, im2: im1/im2) nbins : int number of bins to use in the 2d histogram extractor_method : {'orb', 'sift', 'fast', 'surf', 'vl_sift'} The detector method to be used. Note that vl_sift requires that vlfeat and cyvlfeat dependencies be installed. extractor_kwargs : dict A dictionary containing OpenCV SIFT parameters names and values. cluster_params : dict A dictionary containing sklearn.cluster.OPTICS parameters """ if isinstance(image1, GeoDataset): image1 = image1.read_array() if isinstance(image2, GeoDataset): image2 = image2.read_array() image1[image1 == image1.min()] = 0 image2[image2 == image2.min()] = 0 arr1 = bytescale(image1) arr2 = bytescale(image2) bdiff = image_func(arr1, arr2) Loading Loading @@ -70,3 +215,4 @@ def okubogar_detector(image1, image2, nbins=50, extractor_method="orb", extracto return polys, weights, bdiff autocnet/graph/edge.py +2 −1 Original line number Diff line number Diff line Loading @@ -343,6 +343,7 @@ class Edge(dict, MutableMapping): _, mask = self.clean(clean_keys) s_keypoints, d_keypoints = self.get_match_coordinates(clean_keys=clean_keys) self.fundamental_matrix, fmask = fm.compute_fundamental_matrix(s_keypoints, d_keypoints, **kwargs) fmask = fmask.flatten() if isinstance(self.fundamental_matrix, np.ndarray): # Convert the truncated RANSAC mask back into a full length mask Loading Loading
autocnet/cg/change_detection.py +155 −9 Original line number Diff line number Diff line Loading @@ -2,9 +2,9 @@ import numpy as np from matplotlib.path import Path from shapely.geometry import Point, MultiPoint import geopandas as gpd import cv2 from sklearn.cluster import OPTICS from plio.io.io_gdal import GeoDataset from autocnet.utils.utils import bytescale from autocnet.matcher.cpu_extractor import extract_features Loading @@ -18,16 +18,161 @@ def image_diff(arr1, arr2): diff = arr1-arr2 diff[np.isnan(diff)] = 0 return bytescale(diff) return diff def okubogar_detector(image1, image2, nbins=50, extractor_method="orb", image_func=image_diff, extractor_kwargs={"nfeatures": 2000, "scaleFactor": 1.1, "nlevels": 1}): """ Simple change detection algorithm which produces an overlay image of change hotspots (i.e. a 2d histogram image of detected change density). Largely based on a method created by Chris Okubo and Brendon Bogar. Histogram step was added for readability. image1 \ image subtraction/ratio -> feature_extraction -> feature_histogram / image2 TODO: Paper/abstract might exist, cite Parameters ---------- image1 : np.array, plio.GeoDataset Image representing the "before" state of the ROI, can be a 2D numpy array or plio GeoDataset image2 : np.array, plio.GeoDataset Image representing the "after" state of the ROI, can be a 2D numpy array or plio GeoDataset image_func : callable Function used to create a derived image from image1 and image2, which in turn is the input for the feature extractor. The first two arguments are 2d numpy arrays, image1 and image2, and must return a 2d numpy array. Default function returns a difference image. Example func: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> def ratio(image1, image2): >>> # do stuff with image1 and image2 >>> new_image = image1/image2 >>> return new_image # must return a single variable, a 2D numpy array >>> results = okubogar_detector(image1, image2, image_func=ratio) def okubogar_detector(image1, image2, nbins=50, extractor_method="orb", extractor_kwargs={"nfeatures": 2000, "scaleFactor": 1.1, "nlevels": 1}, cluster_params={"min_samples": 10, "max_eps": 10, "eps": .5, "xi":.5}, image_func=image_diff): arr1 = image1.read_array() arr2 = image2.read_array() arr1[arr1 == arr1.min()] = 0 arr2[arr2 == arr2.min()] = 0 arr1 = bytescale(arr1) arr2 = bytescale(arr2) Or, alternatively: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> results = okubogar_detector(image1, image2, image_func=lambda im1, im2: im1/im2) nbins : int number of bins to use in the 2d histogram extractor_method : {'orb', 'sift', 'fast', 'surf', 'vl_sift'} The detector method to be used. Note that vl_sift requires that vlfeat and cyvlfeat dependencies be installed. extractor_kwargs : dict A dictionary containing OpenCV SIFT parameters names and values. See Also -------- feature extractor: autocnet.matcher.cpu_extractor.extract_features """ if isinstance(image1, GeoDataset): image1 = image1.read_array() if isinstance(image2, GeoDataset): image2 = image2.read_array() image1[image1 == image1.min()] = 0 image2[image2 == image2.min()] = 0 arr1 = bytescale(image1) arr2 = bytescale(image2) bdiff = image_func(arr1, arr2) keys, descriptors = extract_features(bdiff, extractor_method, extractor_parameters=extractor_kwargs) x,y = keys["x"], keys["y"] points = [Point(xval, yval) for xval,yval in zip(x,y)] heatmap, xedges, yedges = np.histogram2d(y, x, bins=nbins, range=[[0, bdiff.shape[0]], [0, bdiff.shape[1]]]) heatmap = cv2.resize(heatmap, dsize=(bdiff.shape[1], bdiff.shape[0]), interpolation=cv2.INTER_NEAREST) return points, heatmap, bdiff def okbm_detector(image1, image2, nbins=50, extractor_method="orb", image_func=image_diff, extractor_kwargs={"nfeatures": 2000, "scaleFactor": 1.1, "nlevels": 1}, cluster_params={"min_samples": 10, "max_eps": 10, "eps": .5, "xi":.5}): """ okobubogar modified detector, experimental feature based change detection algorithmthat expands on okobubogar to allow for programmatic change detection. Returns detected feature changes as weighted polygons. Parameters ---------- image1 : GeoDataset Image representing the "before" state of the ROI, can be a 2D numpy array or plio GeoDataset image2 : GeoDataset Image representing the "after" state of the ROI, can be a 2D numpy array or plio GeoDataset image_func : callable Function used to create a derived image from image1 and image2, which in turn is the input for the feature extractor. The first two arguments are 2d numpy arrays, image1 and image2, and must return a 2d numpy array. Default function returns a difference image. Example func: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> def ratio(image1, image2): >>> # do stuff with image1 and image2 >>> new_image = image1/image2 >>> return new_image # must return a single variable, a 2D numpy array >>> results = okbm_detector(image1, image2, image_func=ratio) Or, alternatively: >>> from numpy import random >>> image1, image2 = random.random((50,50)), random.random((50,50)) >>> results = okbm_detector(image1, image2, image_func=lambda im1, im2: im1/im2) nbins : int number of bins to use in the 2d histogram extractor_method : {'orb', 'sift', 'fast', 'surf', 'vl_sift'} The detector method to be used. Note that vl_sift requires that vlfeat and cyvlfeat dependencies be installed. extractor_kwargs : dict A dictionary containing OpenCV SIFT parameters names and values. cluster_params : dict A dictionary containing sklearn.cluster.OPTICS parameters """ if isinstance(image1, GeoDataset): image1 = image1.read_array() if isinstance(image2, GeoDataset): image2 = image2.read_array() image1[image1 == image1.min()] = 0 image2[image2 == image2.min()] = 0 arr1 = bytescale(image1) arr2 = bytescale(image2) bdiff = image_func(arr1, arr2) Loading Loading @@ -70,3 +215,4 @@ def okubogar_detector(image1, image2, nbins=50, extractor_method="orb", extracto return polys, weights, bdiff
autocnet/graph/edge.py +2 −1 Original line number Diff line number Diff line Loading @@ -343,6 +343,7 @@ class Edge(dict, MutableMapping): _, mask = self.clean(clean_keys) s_keypoints, d_keypoints = self.get_match_coordinates(clean_keys=clean_keys) self.fundamental_matrix, fmask = fm.compute_fundamental_matrix(s_keypoints, d_keypoints, **kwargs) fmask = fmask.flatten() if isinstance(self.fundamental_matrix, np.ndarray): # Convert the truncated RANSAC mask back into a full length mask Loading