示例#1
0
def mercator2ortho(mercator_image_size, latitude, angular_width, out_width):
    phi0 = latitude  #latitude and longitude of the

    sin_phi0 = sin(phi0)
    cos_phi0 = cos(phi0)
    z0 = cos_phi0
    x0 = sin_phi0
    #y0 = 0
    #Absolute coordinate of the point on the sphere

    swidth, sheight = mercator_image_size
    out_height = int(sheight / swidth * out_width)

    y_merc0 = asinh(tan(phi0))

    def ortho2merc_tfm(xp, yp):
        r2 = xp**2 + yp**2
        if r2 > 1: return None  #Out of domain
        zp = sqrt(1 - r2)

        #XYZ are coordinates in the rotated coordinate system
        #Rotate them by phi (perpendicular to equator), in the xz plane
        x,z = zp * cos_phi0 - yp * sin_phi0, \
              zp * sin_phi0 + yp * cos_phi0
        y = xp
        #now (x, y, z) are global coordinates of the projected point on a sphere

        #Convert them back to angles...
        r_xy = sqrt(x**2 + y**2)
        #phi2 = atan2( z, r_xy )

        if r_xy == 0:
            return None
        return (
            atan2(y, x),  #lambda2 
            asinh(z / r_xy) - y_merc0)  #asinh(tan(phi2))

    #angular size of 1 pixel
    src_pixel_size = angular_width / swidth

    #Determine the size of the projected map piece, in the units where Earth radius = 1.
    projection_width = orthogonal_projection_width(mercator_image_size,
                                                   latitude, angular_width)

    #
    dst_pixel_size = angular_width / out_width
    dst_pixel_size = projection_width / out_width

    scaled_ortho2merc_tfm = compose(
        translate_tfm(swidth * 0.5, sheight * 0.5),
        scale_tfm(-1.0 / src_pixel_size), ortho2merc_tfm,
        scale_tfm(-dst_pixel_size),
        translate_tfm(-out_width * 0.5, -out_height * 0.5))

    return (out_width, out_height), scaled_ortho2merc_tfm, dst_pixel_size
示例#2
0
def inv_logpolar_transform(image_size, y0, out_width, out_height, alpha0 = 0):
    """Inverse log polar transform
    """
    xc = out_width/2
    yc = out_height/2
    center = (xc,yc)
    

    swidth, sheight = image_size

    log_rmax = log(xc**2+yc**2)*0.5
    
    #source image scale (pixels per unit)
    # image width must be 2PI units
    source_scale = (swidth-1)/2/pi
    
    
    
    def logz(xf,yf):
        if xf == 0 and yf == 0:
            return 0, 1e-2
        else:
            return atan2(yf, xf), log(xf*xf+yf*yf)*0.5

        
    tfm_func1 = compose(
        #without translate, min y is: -log_rmax*source_scale. It must be y0.
        translate_tfm( source_scale*pi, log_rmax*source_scale+y0 ),
        scale_tfm( source_scale, -source_scale ),
        logz,
        translate_tfm(-xc, -yc)
    )

    return tfm_func1
示例#3
0
def logpolar_transform(image_size, center, out_width=None, out_height=None, alpha0 = 0):
    swidth, sheight = image_size
    if center is None:
        center = (swidth/2, sheight/2)

    if out_width is None:
        #Automatically determine output width
        #Should be enough for mostly loseless transform
        out_width = (swidth+sheight)*2

    x0,y0 = center

    min_log = log(0.5)
    max_log = log(max(x0, swidth-x0)**2 + max(y0,sheight-y0)**2)*0.5

    #Determine appropriate height of the output image, requiring that whole original
    # image fits into it, and highest zoom levels is single pixel.
    if out_height is None:
        out_height = int(out_width / (2*pi) * (max_log-min_log))
    out_size = (out_width, out_height)
    out_scale = 2*pi/out_width


    def expz(xf,yf):
        ey = exp(yf)
        return cos(xf)*ey, sin(xf)*ey

    tfm_func1 = compose(
        translate_tfm(x0, y0),
        expz,
        translate_tfm( alpha0, max_log ),
        scale_tfm( out_scale, -out_scale)
    )

    def tfm_func(x,y):
        xf = x*out_scale + alpha0
        yf = max_log-y*out_scale #Put highest resolution at the top
        ey = exp(yf)
        yfs = sin(xf)*ey
        xfs = cos(xf)*ey
        return xfs + x0, yfs + y0

    return (out_width, out_height), tfm_func
示例#4
0
def logpolar_transform(image_size,
                       center,
                       out_width=None,
                       out_height=None,
                       alpha0=0):
    swidth, sheight = image_size
    if center is None:
        center = (swidth / 2, sheight / 2)

    if out_width is None:
        #Automatically determine output width
        #Should be enough for mostly loseless transform
        out_width = (swidth + sheight) * 2

    x0, y0 = center

    min_log = log(0.5)
    max_log = log(max(x0, swidth - x0)**2 + max(y0, sheight - y0)**2) * 0.5

    #Determine appropriate height of the output image, requiring that whole original
    # image fits into it, and highest zoom levels is single pixel.
    if out_height is None:
        out_height = int(out_width / (2 * pi) * (max_log - min_log))
    out_size = (out_width, out_height)
    out_scale = 2 * pi / out_width

    def expz(xf, yf):
        ey = exp(yf)
        return cos(xf) * ey, sin(xf) * ey

    tfm_func1 = compose(translate_tfm(x0, y0), expz,
                        translate_tfm(alpha0, max_log),
                        scale_tfm(out_scale, -out_scale))

    def tfm_func(x, y):
        xf = x * out_scale + alpha0
        yf = max_log - y * out_scale  #Put highest resolution at the top
        ey = exp(yf)
        yfs = sin(xf) * ey
        xfs = cos(xf) * ey
        return xfs + x0, yfs + y0

    return (out_width, out_height), tfm_func
示例#5
0
def download_and_glue(coordinates,
                      zoom_range=(0, 19),
                      fragment_size=(512, 512),
                      out_width=1024,
                      alpha_gradient_size=10,
                      map_type="roadmap",
                      mercator_to_ortho=True,
                      mesh_step=8,
                      scale=2,
                      margins=(0, 0, 0, 0)):

    #Increasing zoom by one level offsets image by this amount in the logarithmic view
    zoom_level_offset = (0.5 * log(2) / pi) * out_width

    fragment_size_scaled = tuple(s * scale for s in fragment_size)

    #Prepare alpha
    alpha = make_alpha(fragment_size_scaled, alpha_gradient_size, margins)

    z0, z1 = zoom_range
    out_height = int(zoom_level_offset * (z1 - z0 + 1))
    print("Output image size: {out_width}x{out_height}".format(**locals()))
    out_image = Image.new("RGBA", (out_width, out_height))
    dy_base = None
    for zoom in range(z0, z1 + 1):
        print("Downloading fragment, zoom={zoom}... ".format(**locals()),
              end='',
              flush=True)
        fragment = get_map_cached(coordinates, zoom, fragment_size, map_type,
                                  scale)
        fragment.putalpha(alpha)
        print("done, downloaded size: {fragment.size}".format(**locals()))

        if not mercator_to_ortho:
            dy = (zoom - z0) * zoom_level_offset
            _, tfm = logpolar_transform(fragment.size,
                                        scale_tfm(0.5)(*fragment.size),
                                        out_width=out_width)

        else:
            longitude_extent = (2 * pi) * fragment.size[0] / 256 / scale * (
                0.5)**zoom
            #Make a transform from mercator to orthogonal
            out_ortho_size, merc2otrho_tfm, ortho_pix_size = mercator2ortho(
                fragment.size,
                coordinates[0] / 180 * pi,  #latitude
                longitude_extent,
                out_width)
            _, log_tfm = logpolar_transform(
                out_ortho_size,
                center=scale_tfm(0.5)(*out_ortho_size),
                out_width=out_width)

            if dy_base is None:
                dy_base = (0.5 / pi * log(ortho_pix_size)) * out_width
                dy = 0
            else:
                dy = dy_base - (0.5 / pi * log(ortho_pix_size)) * out_width
            tfm = compose(merc2otrho_tfm, log_tfm)

        transformed_size = (out_width, int(zoom_level_offset * 3))

        #Put transformed image to the output
        print("    Transforming fragment...", end='', flush=True)
        transformed = transform_image(fragment,
                                      tfm,
                                      transformed_size,
                                      mesh_step=mesh_step)
        print("Done, created {transformed.size} image.".format(**locals()))
        paste_with_alpha(out_image, transformed, (0, int(dy)))
        print("Done")
    return out_image
示例#6
0
def download_and_glue(coordinates,
                      zoom_range=(0,19), 
                      fragment_size=(512,512), 
                      out_width = 1024, 
                      alpha_gradient_size=10, 
                      map_type="roadmap", 
                      mercator_to_ortho=True, 
                      mesh_step=8,
                      scale=2,
                      margins=(0,0,0,0)):


    #Increasing zoom by one level offsets image by this amount in the logarithmic view
    zoom_level_offset = (0.5*log(2)/pi)*out_width

    fragment_size_scaled = tuple(s*scale for s in fragment_size)

    #Prepare alpha
    alpha = make_alpha(fragment_size_scaled, alpha_gradient_size, margins)

    z0, z1 = zoom_range
    out_height = int(zoom_level_offset * (z1-z0+1))
    print ("Output image size: {out_width}x{out_height}".format(**locals()))
    out_image = Image.new("RGBA",(out_width, out_height))
    dy_base = None
    for zoom in range(z0,z1+1):
        print ("Downloading fragment, zoom={zoom}... ".format(**locals()), end='', flush=True)
        fragment = get_map_cached(coordinates, zoom, fragment_size, map_type, scale)
        fragment.putalpha(alpha)
        print ("done, downloaded size: {fragment.size}".format(**locals()))

        if not mercator_to_ortho:
            dy = (zoom-z0) * zoom_level_offset
            _, tfm = logpolar_transform(
                fragment.size, 
                scale_tfm(0.5)(*fragment.size),
                out_width=out_width)

        else:
            longitude_extent = (2*pi)*fragment.size[0]/256/scale*(0.5)**zoom
            #Make a transform from mercator to orthogonal
            out_ortho_size, merc2otrho_tfm, ortho_pix_size = mercator2ortho(
                fragment.size,
                coordinates[0]/180*pi,  #latitude
                longitude_extent, 
                out_width
            )
            _, log_tfm = logpolar_transform(
                out_ortho_size, 
                center = scale_tfm(0.5)(*out_ortho_size),
                out_width=out_width
            )

            if dy_base is None:
                dy_base = (0.5/pi*log(ortho_pix_size))*out_width
                dy = 0
            else:
                dy = dy_base - (0.5/pi*log(ortho_pix_size))*out_width
            tfm = compose( merc2otrho_tfm, log_tfm )


        transformed_size = (out_width, int(zoom_level_offset*3))
        
        #Put transformed image to the output
        print("    Transforming fragment...", end='', flush=True)
        transformed=transform_image(fragment, tfm, transformed_size, mesh_step=mesh_step)
        print("Done, created {transformed.size} image.".format(**locals()))
        paste_with_alpha(out_image, 
                         transformed,
                         (0, int(dy)))
        print ("Done")
    return out_image
示例#7
0
def main():
    from optparse import OptionParser
    parser = OptionParser(usage = "%prog [options] INPUT_IMAGE OUTPUT_IMAGE\n"
                          "Log-Polar image transform. Generated image always have RGBA format")

    parser.add_option("-c", "--center", dest="center",
                      help="Center point position, x:y", metavar="X:Y")

    parser.add_option("-A", "--angle", dest="angle", type=float, default=0.0,
                      help="Angle, corresponding left side of the transformed image, in graduses. 0 is horizontal, left to right.", metavar="ANGLE")

    parser.add_option("-w", "--width", dest="width", type=int,
                      help="Width of the output image. Default is auto-detect, based on the source inmage dimensions (the size is usually quite big)", metavar="PIXELS")

    parser.add_option("-H", "--height", dest="height", type=int,
                      help="Height of the output image. Default is auto-detect, based on width", metavar="PIXELS")

    parser.add_option("", "--mesh-step", dest="mesh_step", type=int, default=8,
                      help="Step of the output mesh. Default is 8", metavar="PIXELS")

    parser.add_option("", "--mercator2ortho", dest="mercator2ortho",
                      help="Treat source image as a piece of the map in Mercator projection. Map in converted to orthogonal projection regarding the point in the center of the map.", metavar="CENTER_LAT:LNG_WIDTH")

    (options, args) = parser.parse_args()
    
    if len(args) < 1:
        parser.error("No input file specified")

    input =args[0]
    if len(args) >= 2:
        output = args[1]
    else:
        output = None

    if options.mercator2ortho:
        if options.center:
            parser.error("Center not supported in mercator map pieces. It is always at the center of the image")
            
        try:
            lat_center_s, lng_extent_s = options.mercator2ortho.split(":",2)
            mercator2ortho_options = {
                "center_lat": float(lat_center_s)/180*pi,
                "lng_extent": float(lng_extent_s)/180*pi
            }
        except Exception as err:
            parser.error("Error parsing mercator projection options: {0}".format(err))
    else:
        mercator2ortho_options = None

    if options.center is None:
        center = None
    else:
        center = tuple(map(int, options.center.split(":",2)))

    img = Image.open(input)


    #Image conversions
    #  SOurce image can be one of:
    #    - RGB
    #    - RGBA  - has alpha
    #    - I     - may have alpha
    #    - L
    #    - 1

    # Target image:
    #   always have alpha.
    
    if img.mode != "RGBA":
        img =img.convert("RGBA")

    if mercator2ortho_options:
        from mercator2ortho import mercator2ortho
        out_ortho_size, merc2otrho_tfm, _ = mercator2ortho(img.size,
                                                        mercator2ortho_options["center_lat"], 
                                                        mercator2ortho_options["lng_extent"], 
                                                        max(img.size)
                                                    )

        out_size, ortho2log_tfm = logpolar_transform(out_ortho_size,
                                                     center=scale_tfm(0.5)(*out_ortho_size), 
                                                     out_width = options.width,
                                                     alpha0 = options.angle/180*pi)
        #Create composite transform: first convert Mercator map to orthogonal projection, then apply log-transform to it.
        transform = compose(
            merc2otrho_tfm,
            ortho2log_tfm )

    else:
        out_size, transform = logpolar_transform(img.size,
                                                 center=center, 
                                                 out_width = options.width,
                                                 alpha0 = options.angle/180*pi)

    img = transform_image(img, transform, out_size, mesh_step=options.mesh_step)

    if output:
        img.save(output)
    else:
        img.show()
示例#8
0
def main():
    from optparse import OptionParser
    parser = OptionParser(
        usage="%prog [options] INPUT_IMAGE OUTPUT_IMAGE\n"
        "Log-Polar image transform. Generated image always have RGBA format")

    parser.add_option("-c",
                      "--center",
                      dest="center",
                      help="Center point position, x:y",
                      metavar="X:Y")

    parser.add_option(
        "-A",
        "--angle",
        dest="angle",
        type=float,
        default=0.0,
        help=
        "Angle, corresponding left side of the transformed image, in graduses. 0 is horizontal, left to right.",
        metavar="ANGLE")

    parser.add_option(
        "-w",
        "--width",
        dest="width",
        type=int,
        help=
        "Width of the output image. Default is auto-detect, based on the source inmage dimensions (the size is usually quite big)",
        metavar="PIXELS")

    parser.add_option(
        "-H",
        "--height",
        dest="height",
        type=int,
        help=
        "Height of the output image. Default is auto-detect, based on width",
        metavar="PIXELS")

    parser.add_option("",
                      "--mesh-step",
                      dest="mesh_step",
                      type=int,
                      default=8,
                      help="Step of the output mesh. Default is 8",
                      metavar="PIXELS")

    parser.add_option(
        "",
        "--mercator2ortho",
        dest="mercator2ortho",
        help=
        "Treat source image as a piece of the map in Mercator projection. Map in converted to orthogonal projection regarding the point in the center of the map.",
        metavar="CENTER_LAT:LNG_WIDTH")

    (options, args) = parser.parse_args()

    if len(args) < 1:
        parser.error("No input file specified")

    input = args[0]
    if len(args) >= 2:
        output = args[1]
    else:
        output = None

    if options.mercator2ortho:
        if options.center:
            parser.error(
                "Center not supported in mercator map pieces. It is always at the center of the image"
            )

        try:
            lat_center_s, lng_extent_s = options.mercator2ortho.split(":", 2)
            mercator2ortho_options = {
                "center_lat": float(lat_center_s) / 180 * pi,
                "lng_extent": float(lng_extent_s) / 180 * pi
            }
        except Exception as err:
            parser.error(
                "Error parsing mercator projection options: {0}".format(err))
    else:
        mercator2ortho_options = None

    if options.center is None:
        center = None
    else:
        center = tuple(map(int, options.center.split(":", 2)))

    img = Image.open(input)

    #Image conversions
    #  SOurce image can be one of:
    #    - RGB
    #    - RGBA  - has alpha
    #    - I     - may have alpha
    #    - L
    #    - 1

    # Target image:
    #   always have alpha.

    if img.mode != "RGBA":
        img = img.convert("RGBA")

    if mercator2ortho_options:
        from mercator2ortho import mercator2ortho
        out_ortho_size, merc2otrho_tfm, _ = mercator2ortho(
            img.size, mercator2ortho_options["center_lat"],
            mercator2ortho_options["lng_extent"], max(img.size))

        out_size, ortho2log_tfm = logpolar_transform(
            out_ortho_size,
            center=scale_tfm(0.5)(*out_ortho_size),
            out_width=options.width,
            alpha0=options.angle / 180 * pi)
        #Create composite transform: first convert Mercator map to orthogonal projection, then apply log-transform to it.
        transform = compose(merc2otrho_tfm, ortho2log_tfm)

    else:
        out_size, transform = logpolar_transform(img.size,
                                                 center=center,
                                                 out_width=options.width,
                                                 alpha0=options.angle / 180 *
                                                 pi)

    img = transform_image(img,
                          transform,
                          out_size,
                          mesh_step=options.mesh_step)

    if output:
        img.save(output)
    else:
        img.show()