def colorize(crop_panchro, im_color, x, y, zoom, out_colorized, rmin,rmax): """ Colorizes a Pleiades gray crop using low-resolution color information. Args: crop_panchro: path to the panchro (ie gray) crop im_color: path to the full color image (tiff or jp2) x, y: coordinates of the top-left corner of crop_panchro, in the full Pleiade image frame. zoom: subsampling zoom-factor that was used to generate crop_panchro out_colorized: path to the output file """ # get a translated and zoomed crop from the color image. It has to be # sampled on exactly the same grid as the panchro crop. # To do that we compose the translation + zoom transformation with a 4x # zoom (because color pleiades images have 4x lower resolution). There is # also a small horizontal translation (4 pixels at the panchro resolution) # The resulting transformation is the composition of: # translation (-1 - x/4, -y/4) # zoom 4/z w, h = common.image_size_tiffinfo(crop_panchro) xx = np.floor(x / 4.0) yy = np.floor(y / 4.0) ww = np.ceil((x + w * zoom) / 4.0) - xx hh = np.ceil((y + h * zoom) / 4.0) - yy crop_ms = common.image_crop_TIFF(im_color, xx, yy, ww, hh) crop_ms = common.image_zoom_gdal(crop_ms, zoom/4.0) # crop_ms = common.image_safe_zoom_fft(crop_ms, zoom/4.0) # crop the crop_ms image to remove the extra-pixels due to the integer crop # followed by zoom x0 = max(0,x - 4*xx) y0 = max(0,y - 4*yy) crop_ms = common.image_crop_TIFF(crop_ms, x0, y0, w, h) assert(common.image_size_tiffinfo(crop_panchro) == common.image_size_tiffinfo(crop_ms)) # convert rgbi to rgb rgb = common.rgbi_to_rgb(crop_ms, out=None, tilewise=True) # blend intensity and color to obtain the result # each channel value r, g or b is multiplied by 3*y / (r+g+b), where y # denotes the panchro intensity tmp = common.tmpfile('.tif') pcmd = "dup split + + / * 3 *" os.environ['TMPDIR'] = os.path.join(cfg['temporary_dir'], 'meta/') cmd = 'tiffu meta \"plambda ^ ^1 \\\"%s\\\" -o @\" %s %s -- %s' % (pcmd, crop_panchro, rgb, tmp) common.run(cmd) if w * h > 25e6: # image larger than 5000 x 5000 pixels common.image_qauto_otb(out_colorized, tmp) else: #common.image_qauto(tmp, out_colorized) common.image_rescaleintensities(tmp, out_colorized, rmin, rmax) return
def colorize(crop_panchro, im_color, x, y, zoom, out_colorized, rmin, rmax): """ Colorizes a Pleiades gray crop using low-resolution color information. Args: crop_panchro: path to the panchro (ie gray) crop im_color: path to the full color image (tiff or jp2) x, y: coordinates of the top-left corner of crop_panchro, in the full Pleiade image frame. zoom: subsampling zoom-factor that was used to generate crop_panchro out_colorized: path to the output file """ # get a translated and zoomed crop from the color image. It has to be # sampled on exactly the same grid as the panchro crop. # To do that we compose the translation + zoom transformation with a 4x # zoom (because color pleiades images have 4x lower resolution). There is # also a small horizontal translation (4 pixels at the panchro resolution) # The resulting transformation is the composition of: # translation (-1 - x/4, -y/4) # zoom 4/z w, h = common.image_size_tiffinfo(crop_panchro) xx = np.floor(x / 4.0) yy = np.floor(y / 4.0) ww = np.ceil((x + w * zoom) / 4.0) - xx hh = np.ceil((y + h * zoom) / 4.0) - yy crop_ms = common.image_crop_TIFF(im_color, xx, yy, ww, hh) crop_ms = common.image_zoom_gdal(crop_ms, zoom / 4.0) # crop_ms = common.image_safe_zoom_fft(crop_ms, zoom/4.0) # crop the crop_ms image to remove the extra-pixels due to the integer crop # followed by zoom x0 = max(0, x - 4 * xx) y0 = max(0, y - 4 * yy) crop_ms = common.image_crop_TIFF(crop_ms, x0, y0, w, h) assert (common.image_size_tiffinfo(crop_panchro) == common.image_size_tiffinfo(crop_ms)) # convert rgbi to rgb rgb = common.rgbi_to_rgb(crop_ms, out=None, tilewise=True) # blend intensity and color to obtain the result # each channel value r, g or b is multiplied by 3*y / (r+g+b), where y # denotes the panchro intensity tmp = common.tmpfile('.tif') pcmd = "dup split + + / * 3 *" os.environ['TMPDIR'] = os.path.join(cfg['temporary_dir'], 'meta/') cmd = 'tiffu meta \"plambda ^ ^1 \\\"%s\\\" -o @\" %s %s -- %s' % ( pcmd, crop_panchro, rgb, tmp) common.run(cmd) if w * h > 25e6: # image larger than 5000 x 5000 pixels common.image_qauto_otb(out_colorized, tmp) else: #common.image_qauto(tmp, out_colorized) common.image_rescaleintensities(tmp, out_colorized, rmin, rmax) return
def plot_matches_pleiades(im1, im2, rpc1, rpc2, matches, x=None, y=None, w=None, h=None, outfile=None): """ Plot matches on Pleiades images Args: im1, im2: paths to full Pleiades images rpc1, rpc2: paths to xml files containing the rpc coefficients matches: 2D numpy array of size 4xN containing a list of matches (a list of pairs of points, each pair being represented by x1, y1, x2, y2). The coordinates are given in the frame of the full images. x, y, w, h (optional, default is None): ROI in the reference image outfile (optional, default is None): path to the output file. If None, the file image is displayed using the pvflip viewer Returns: path to the displayed output """ # if no matches, no plot if not matches.size: print "visualisation.plot_matches_pleiades: nothing to plot" return # read rpcs r1 = rpc_model.RPCModel(rpc1) r2 = rpc_model.RPCModel(rpc2) # determine regions to crop in im1 and im2 if x is not None: x1 = x else: x1 = np.min(matches[:, 0]) if y is not None: y1 = y else: y1 = np.min(matches[:, 1]) if w is not None: w1 = w else: w1 = np.max(matches[:, 0]) - x1 if h is not None: h1 = h else: h1 = np.max(matches[:, 1]) - y1 x2, y2, w2, h2 = rpc_utils.corresponding_roi(r1, r2, x1, y1, w1, h1) # x2 = np.min(matches[:, 2]) # w2 = np.max(matches[:, 2]) - x2 # y2 = np.min(matches[:, 3]) # h2 = np.max(matches[:, 3]) - y2 # # add 20 pixels offset and round. The image_crop_TIFF function will round # # off the coordinates before it does the crops. # x1 -= 20; x1 = np.round(x1) # y1 -= 20; y1 = np.round(y1) # x2 -= 20; x2 = np.round(x2) # y2 -= 20; y2 = np.round(y2) # w1 += 40; w1 = np.round(w1) # h1 += 40; h1 = np.round(h1) # w2 += 40; w2 = np.round(w2) # h2 += 40; h2 = np.round(h2) # do the crops crop1 = common.image_qauto(common.image_crop_TIFF(im1, x1, y1, w1, h1)) crop2 = common.image_qauto(common.image_crop_TIFF(im2, x2, y2, w2, h2)) # compute matches coordinates in the cropped images pts1 = matches[:, 0:2] - [x1, y1] pts2 = matches[:, 2:4] - [x2, y2] # plot the matches on the two crops to_display = plot_matches(crop1, crop2, np.hstack((pts1, pts2))) if outfile is None: os.system('v %s &' % (to_display)) else: common.run('cp %s %s' % (to_display, outfile)) return
def crop_and_apply_homography(im_out, im_in, H, w, h, subsampling_factor=1, convert_to_gray=False): """ Warps a piece of a Pleiades (panchro or ms) image with a homography. Args: im_out: path to the output image im_in: path to the input (tif) full Pleiades image H: numpy array containing the 3x3 homography matrix w, h: size of the output image subsampling_factor (optional, default=1): when set to z>1, will result in the application of the homography Z*H where Z = diag(1/z, 1/z, 1), so the output will be zoomed out by a factor z. The output image will be (w/z, h/z) convert_to_gray (optional, default False): it set to True, and if the input image has 4 channels, it is converted to gray before applying zoom and homographies. Returns: nothing The homography has to be used as: coord_out = H coord_in. The produced output image corresponds to coord_out in [0, w] x [0, h]. The warp is made by Pascal Monasse's binary named 'homography'. """ # crop a piece of the big input image, to which the homography will be # applied # warning: as the crop uses integer coordinates, be careful to round off # (x0, y0) before modifying the homograpy. You want the crop and the # translation representing it do exactly the same thing. pts = [[0, 0], [w, 0], [w, h], [0, h]] inv_H_pts = common.points_apply_homography(np.linalg.inv(H), pts) x0, y0, w0, h0 = common.bounding_box2D(inv_H_pts) x0, y0 = np.floor([x0, y0]) w0, h0 = np.ceil([w0, h0]) crop_fullres = common.image_crop_LARGE(im_in, x0, y0, w0, h0) # This filter is needed (for panchro images) because the original PLEAIDES # SENSOR PERFECT images are aliased if (common.image_pix_dim(crop_fullres) == 1 and subsampling_factor == 1 and cfg['use_pleiades_unsharpening']): tmp = image_apply_pleiades_unsharpening_filter(crop_fullres) common.run('rm -f %s' % crop_fullres) crop_fullres = tmp # convert to gray if common.image_pix_dim(crop_fullres) == 4: if convert_to_gray: crop_fullres = common.pansharpened_to_panchro(crop_fullres) # compensate the homography with the translation induced by the preliminary # crop, then apply the homography and crop. H = np.dot(H, common.matrix_translation(x0, y0)) # Since the objective is to compute a zoomed out homographic transformation # of the input image, to save computations we zoom out the image before # applying the homography. If Z is the matrix representing the zoom out and # H the homography matrix, this trick consists in applying Z*H*Z^{-1} to # the zoomed image Z*Im instead of applying Z*H to the original image Im. if subsampling_factor == 1: common.image_apply_homography(im_out, crop_fullres, H, w, h) return else: assert(subsampling_factor >= 1) # H becomes Z*H*Z^{-1} Z = np.eye(3); Z[0,0] = Z[1,1] = 1 / float(subsampling_factor) H = np.dot(Z, H) H = np.dot(H, np.linalg.inv(Z)) # w, and h are updated accordingly w = int(w / subsampling_factor) h = int(h / subsampling_factor) # the DCT zoom is NOT SAFE when the input image size is not a multiple # of the zoom factor tmpw, tmph = common.image_size(crop_fullres) tmpw, tmph = int(tmpw / subsampling_factor), int(tmph / subsampling_factor) crop_fullres_safe = common.image_crop_TIFF(crop_fullres, 0, 0, tmpw * subsampling_factor, tmph * subsampling_factor) common.run('rm -f %s' % crop_fullres) # zoom out the input image (crop_fullres) crop_zoom_out = common.image_safe_zoom_fft(crop_fullres_safe, subsampling_factor) common.run('rm -f %s' % crop_fullres_safe) # apply the homography to the zoomed out crop common.image_apply_homography(im_out, crop_zoom_out, H, w, h) return
def crop_and_apply_homography(im_out, im_in, H, w, h, subsampling_factor=1, convert_to_gray=False): """ Warps a piece of a Pleiades (panchro or ms) image with a homography. Args: im_out: path to the output image im_in: path to the input (tif) full Pleiades image H: numpy array containing the 3x3 homography matrix w, h: size of the output image subsampling_factor (optional, default=1): when set to z>1, will result in the application of the homography Z*H where Z = diag(1/z, 1/z, 1), so the output will be zoomed out by a factor z. The output image will be (w/z, h/z) convert_to_gray (optional, default False): it set to True, and if the input image has 4 channels, it is converted to gray before applying zoom and homographies. Returns: nothing The homography has to be used as: coord_out = H coord_in. The produced output image corresponds to coord_out in [0, w] x [0, h]. The warp is made by Pascal Monasse's binary named 'homography'. """ # crop a piece of the big input image, to which the homography will be # applied # warning: as the crop uses integer coordinates, be careful to round off # (x0, y0) before modifying the homograpy. You want the crop and the # translation representing it do exactly the same thing. pts = [[0, 0], [w, 0], [w, h], [0, h]] inv_H_pts = common.points_apply_homography(np.linalg.inv(H), pts) x0, y0, w0, h0 = common.bounding_box2D(inv_H_pts) x0, y0 = np.floor([x0, y0]) w0, h0 = np.ceil([w0, h0]) crop_fullres = common.image_crop_LARGE(im_in, x0, y0, w0, h0) # This filter is needed (for panchro images) because the original PLEAIDES # SENSOR PERFECT images are aliased if (common.image_pix_dim(crop_fullres) == 1 and subsampling_factor == 1 and cfg['use_pleiades_unsharpening']): tmp = image_apply_pleiades_unsharpening_filter(crop_fullres) common.run('rm -f %s' % crop_fullres) crop_fullres = tmp # convert to gray if common.image_pix_dim(crop_fullres) == 4: if convert_to_gray: crop_fullres = common.pansharpened_to_panchro(crop_fullres) # compensate the homography with the translation induced by the preliminary # crop, then apply the homography and crop. H = np.dot(H, common.matrix_translation(x0, y0)) # Since the objective is to compute a zoomed out homographic transformation # of the input image, to save computations we zoom out the image before # applying the homography. If Z is the matrix representing the zoom out and # H the homography matrix, this trick consists in applying Z*H*Z^{-1} to # the zoomed image Z*Im instead of applying Z*H to the original image Im. if subsampling_factor == 1: common.image_apply_homography(im_out, crop_fullres, H, w, h) return else: assert (subsampling_factor >= 1) # H becomes Z*H*Z^{-1} Z = np.eye(3) Z[0, 0] = Z[1, 1] = 1 / float(subsampling_factor) H = np.dot(Z, H) H = np.dot(H, np.linalg.inv(Z)) # w, and h are updated accordingly w = int(w / subsampling_factor) h = int(h / subsampling_factor) # the DCT zoom is NOT SAFE when the input image size is not a multiple # of the zoom factor tmpw, tmph = common.image_size(crop_fullres) tmpw, tmph = int(tmpw / subsampling_factor), int(tmph / subsampling_factor) crop_fullres_safe = common.image_crop_TIFF(crop_fullres, 0, 0, tmpw * subsampling_factor, tmph * subsampling_factor) common.run('rm -f %s' % crop_fullres) # zoom out the input image (crop_fullres) crop_zoom_out = common.image_safe_zoom_fft(crop_fullres_safe, subsampling_factor) common.run('rm -f %s' % crop_fullres_safe) # apply the homography to the zoomed out crop common.image_apply_homography(im_out, crop_zoom_out, H, w, h) return