def getGdcTransformFromPixelTransform(imageSize, pixelTransform, refImageGdcTransform): '''Converts an image-to-image transform chained with a GDC transform to a pixel to GDC transform for this image.''' # Convert the image-to-image transform parameters to a class temp = numpy.array([tform[0:3], tform[3:6], tform[6:9]] ) imageToRefTransform = transform.ProjectiveTransform(temp) newImageSize = ImageFetcher.miscUtilities.getImageSize(newImagePath) # Generate a list of point pairs imagePoints = [] gdcPoints = [] # Loop through an evenly spaced grid of pixels in the new image # - For each pixel, compute the desired output coordinate pointPixelSpacing = (newImageSize[0] + newImageSize[1]) / 20 # Results in about 100 points for r in range(0, newImageSize[0], pointPixelSpacing): for c in range(0, newImageSize[1], pointPixelSpacing): # Get pixel in new image and matching pixel in the reference image, # then pass that into the GDC transform. thisPixel = numpy.array([float(c), float(r)]) pixelInRefImage = pixelTransform.forward(thisPixel) gdcCoordinate = refImageGdcTransform.forward(pixelInRefImage) imagePoints.append(thisPixel) gdcPoints.append(gdcCoordinate) # Compute a transform object that converts from the new image to projected coordinates imageToGdcTransform = transform.getTransform(numpy.asarray(worldPoints), numpy.asarray(gdcPoints)) return imageToGdcTransform
def getPixelToGdcTransform(imagePath, pixelToProjectedTransform=None): '''Returns a pixel to GDC transform. The input image must either be a nicely georegistered image from Earth Engine or a pixel to projected coordinates transform must be provided.''' if pixelToProjectedTransform: # Have image to projected transform, convert it to an image to GDC transform. # Use the simple file info call (the input file may not have geo information) (width, height) = IrgGeoFunctions.getImageSize(imagePath) imagePoints = [] gdcPoints = [] # Loop through a spaced out grid of pixels in the image pointPixelSpacing = (width + height) / 20 # Results in about 100 points for r in range(0, width, pointPixelSpacing): for c in range(0, height, pointPixelSpacing): # This pixel --> projected coords --> lonlat coord thisPixel = numpy.array([float(c), float(r)]) projectedCoordinate = pixelToProjectedTransform.forward( thisPixel) gdcCoordinate = transform.metersToLatLon(projectedCoordinate) imagePoints.append(thisPixel) gdcPoints.append(gdcCoordinate) # Solve for a transform with all of these point pairs pixelToGdcTransform = transform.getTransform( numpy.asarray(gdcPoints), numpy.asarray(imagePoints)) else: # Using a reference image from EE which will have nice bounds. # Use the more thorough file info call stats = IrgGeoFunctions.getImageGeoInfo(imagePath, False) (width, height) = stats['image_size'] (minLon, maxLon, minLat, maxLat) = stats['lonlat_bounds'] # Make a transform from ref pixel to GDC using metadata on disk xScale = (maxLon - minLon) / width yScale = (maxLat - minLat) / height transformMatrix = numpy.array([[xScale, 0, minLon], [0, -yScale, maxLat], [0, 0, 1]]) pixelToGdcTransform = transform.LinearTransform(transformMatrix) return pixelToGdcTransform
def updateAlignment(self): toPts, fromPts = transform.splitPoints(self.extras.points) tform = transform.getTransform(toPts, fromPts) self.extras.transform = tform.getJsonDict()
289.4999999999986 ], [ -10824770.036926387, 2994035.003758455, 335.50000000000034, 424.50000000000097 ] ] TO_PTS, FROM_PTS = transform.splitPoints(POINTS) N = len(POINTS) def testTransformClass(cls): tform = cls.fit(TO_PTS, FROM_PTS) toPtsApprox = transform.forwardPts(tform, FROM_PTS) #print toPtsApprox print ('%s: %e' % (cls.__name__, numpy.linalg.norm(toPtsApprox - TO_PTS) / N)) testTransformClass(transform.TranslateTransform) testTransformClass(transform.RotateScaleTranslateTransform) testTransformClass(transform.AffineTransform) testTransformClass(transform.ProjectiveTransform) testTransformClass(transform.QuadraticTransform) testTransformClass(transform.QuadraticTransform2) print transform.getTransform(TO_PTS, FROM_PTS)
def qualityGdalwarp(imagePath, outputPath, imagePoints, gdcPoints): '''Use some workarounds to get a higher quality gdalwarp output than is normally possible.''' # Generate a high resolution grid of fake GCPs based on a transform we compute, # then call gdalwarp using a high order polynomial to accurately match our transform. #trans = transform.ProjectiveTransform.fit(numpy.asarray(gdcPoints),numpy.asarray(imagePoints))ls trans = transform.getTransform(numpy.asarray(gdcPoints),numpy.asarray(imagePoints)) transformName = trans.getJsonDict()['type'] tempPath = outputPath + '-temp.tif' # Generate a temporary image containing the grid of fake GCPs cmd = ('gdal_translate -co "COMPRESS=LZW" -co "tiled=yes" -co "predictor=2" -a_srs "' + OUTPUT_PROJECTION +'" '+ imagePath +' '+ tempPath) # Generate the GCPs in a grid, keeping the total under about 500 points so # that GDAL does not complain. (width, height) = IrgGeoFunctions.getImageSize(imagePath) xStep = width /22 yStep = height/22 MAX_DEG_SIZE = 20 minLon = 999 # Keep track of the lonlat size and don't write if it is too big. minLat = 999 # - This would work better if it was in pixels, but how to get that size? maxLon = -999 maxLat = -999 for r in range(0,height,yStep): for c in range(0,width,xStep): pixel = (c,r) lonlat = trans.forward(pixel) cmd += ' -gcp '+ str(c) +' '+str(r) +' '+str(lonlat[0]) +' '+str(lonlat[1]) if lonlat[0] < minLon: minLon = lonlat[0] if lonlat[1] < minLat: minLat = lonlat[1] if lonlat[0] > maxLon: maxLon = lonlat[0] if lonlat[1] > maxLat: maxLat = lonlat[1] #print cmd os.system(cmd) if max((maxLon - minLon), (maxLat - minLat)) > MAX_DEG_SIZE: raise Exception('Warped image is too large to generate!\n' '-> LonLat bounds: ' + str((minLon, minLat, maxLon, maxLat))) # Now generate a warped geotiff. # - "order 2" looks terrible with fewer GCPs, but "order 1" does not accurately # capture the footprint of higher tilt images. # - tps seems to work well with the evenly spaced grid of virtual GCPs. cmd = ('gdalwarp -co "COMPRESS=LZW" -co "tiled=yes" -co "predictor=2"' + ' -dstalpha -overwrite -tps -multi -r cubic -t_srs "' + OUTPUT_PROJECTION +'" ' + tempPath +' '+ outputPath) print cmd os.system(cmd) # Check output and cleanup os.remove(tempPath) if not os.path.exists(outputPath): raise Exception('Failed to create warped geotiff file: ' + outputPath) return transformName
], [ -13045724.330780469, 3825669.8715011734, 68.50000000000003, 289.4999999999986 ], [ -10824770.036926387, 2994035.003758455, 335.50000000000034, 424.50000000000097 ]] TO_PTS, FROM_PTS = transform.splitPoints(POINTS) N = len(POINTS) def testTransformClass(cls): tform = cls.fit(TO_PTS, FROM_PTS) toPtsApprox = transform.forwardPts(tform, FROM_PTS) #print toPtsApprox print('%s: %e' % (cls.__name__, numpy.linalg.norm(toPtsApprox - TO_PTS) / N)) testTransformClass(transform.TranslateTransform) testTransformClass(transform.RotateScaleTranslateTransform) testTransformClass(transform.AffineTransform) testTransformClass(transform.ProjectiveTransform) testTransformClass(transform.QuadraticTransform) testTransformClass(transform.QuadraticTransform2) print transform.getTransform(TO_PTS, FROM_PTS)