imageutil.java

来自「world wind java sdk 源码」· Java 代码 · 共 1,510 行 · 第 1/5 页

JAVA
1,510
字号
     * coordinates.     *     * @param sourceImage the source image to transform.     * @param worldFileParams world file parameters which define an affine transform.     * @param destImage the destination image to receive the transformed source imnage.     *     * @return bounding sector for the geographically aligned destination image.     * @throws IllegalArgumentException if any of <code>sourceImage</code>, <code>destImage</code> or     *                                  <code>worldFileParams</code> is null.     */    public static Sector warpImageWithWorldFile(BufferedImage sourceImage, AVList worldFileParams,        BufferedImage destImage)    {        if (sourceImage == null)        {            String message = Logging.getMessage("nullValue.SourceImageIsNull");            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        if (worldFileParams == null)        {            String message = Logging.getMessage("nullValue.ParamsIsNull");            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        if (destImage == null)        {            String message = Logging.getMessage("nullValue.DestinationImageIsNull");            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        Matrix imageToGeographic = Matrix.fromImageToGeographic(worldFileParams);        if (imageToGeographic == null)        {            String message = Logging.getMessage("WorldFile.UnrecognizedValues", "");            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        List<LatLon> corners = computeImageCorners(sourceImage.getWidth(), sourceImage.getHeight(), imageToGeographic);        Sector destSector = Sector.boundingSector(corners);        if (Sector.isSector(corners) && destSector.isSameSector(corners))        {            drawImageOnCanvas(sourceImage, destImage);        }        else        {            Matrix transform = Matrix.IDENTITY;            transform = transform.multiply(Matrix.fromGeographicToImage(worldFileParams));            transform = transform.multiply(Matrix.fromImageToGeographic(destImage.getWidth(), destImage.getHeight(),                destSector));            warpImageWithTransform(sourceImage, destImage, transform);        }        return destSector;    }    /**     * Computes which three control points out of four provide the best estimate an image's geographic location. The     * result is placed in the output parameters <code>outImagePoints</code> and <code>outGeoPoints</code>, both of     * which must be non-null and at least length 3.     *     * @param imagePoints four control points in the image.     * @param geoPoints four geographic locations corresponding to the four <code>imagePoints</code>.     * @param outImagePoints three control points that best estimate the image's location.     * @param outGeoPoints three geographic locations correstponding to the three <code>outImagePoints</code>.     *     * @throws IllegalArgumentException if any of <code>imagePoints</code>, <code>geoPoints</code>,     *                                  <code>outImagePoints</code> or <code>outGeoPoints</code> is null, or if     *                                  <code>imagePoints</code> or <code>geoPoints</code> have length less than 4,     *                                  or if <code>outImagePoints</code> or <code>outGeoPoints</code> have length     *                                  less than 3.     */    public static void computeBestFittingControlPoints4(java.awt.geom.Point2D[] imagePoints, LatLon[] geoPoints,        java.awt.geom.Point2D[] outImagePoints, LatLon[] outGeoPoints)    {        String message = validateControlPoints(4, imagePoints, geoPoints);        if (message != null)        {            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        message = validateControlPoints(3, outImagePoints, outGeoPoints);        if (message != null)        {            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        // Compute the error for each combination of three points, and choose the combination with the least error.        java.awt.geom.Point2D[] bestFitImagePoints = null;        LatLon[] bestFitGeoPoints = null;        double minError = Double.MAX_VALUE;        for (int[] indices : new int[][] {            {0, 1, 2},            {0, 1, 3},            {1, 2, 3},            {0, 2, 3}})        {            java.awt.geom.Point2D[] points = new java.awt.geom.Point2D[] {                imagePoints[indices[0]], imagePoints[indices[1]], imagePoints[indices[2]]};            LatLon[] locations = new LatLon[] {geoPoints[indices[0]], geoPoints[indices[1]], geoPoints[indices[2]]};            Matrix m = Matrix.fromImageToGeographic(points, locations);            double error = 0.0;            for (int j = 0; j < 4; j++)            {                Vec4 vec = new Vec4(imagePoints[j].getX(), imagePoints[j].getY(), 1.0).transformBy3(m);                LatLon ll = LatLon.fromDegrees(vec.y, vec.x);                LatLon diff = geoPoints[j].subtract(ll);                double d = diff.getLatitude().degrees * diff.getLatitude().degrees                    + diff.getLongitude().degrees * diff.getLongitude().degrees;                error += d;            }            if (error < minError)            {                bestFitImagePoints = points;                bestFitGeoPoints = locations;                minError = error;            }        }        if (bestFitImagePoints != null)        {            System.arraycopy(bestFitImagePoints, 0, outImagePoints, 0, 3);            System.arraycopy(bestFitGeoPoints, 0, outGeoPoints, 0, 3);        }    }    /**     * Returns the geographic corners of an image with the specified dimensions, and a transform that maps image     * coordinates to geographic coordinates.     *     * @param imageWidth width of the image grid.     * @param imageHeight height of the image grid.     * @param imageToGeographic Matrix that maps image coordinates to geographic coordinates.     *     * @return List of the image's corner locations in geographic coordinates.     * @throws IllegalArgumentException if either <code>imageWidth</code> or <code>imageHeight</code> are less than 1,     *                                  or if <code>imageToGeographic</code> is null.     */    public static List<LatLon> computeImageCorners(int imageWidth, int imageHeight, Matrix imageToGeographic)    {        if (imageWidth < 1 || imageHeight < 1)        {            String message = Logging.getMessage("generic.InvalidImageSize", imageWidth, imageHeight);            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        if (imageToGeographic == null)        {            String message = Logging.getMessage("nullValue.MatrixIsNull");            Logging.logger().severe(message);            throw new IllegalArgumentException(message);        }        ArrayList<LatLon> corners = new ArrayList<LatLon>();        // Lower left corner.        Vec4 vec = new Vec4(0, imageHeight, 1).transformBy3(imageToGeographic);        corners.add(LatLon.fromDegrees(vec.y, vec.x));        // Lower right corner.        vec = new Vec4(imageWidth, imageHeight, 1).transformBy3(imageToGeographic);        corners.add(LatLon.fromDegrees(vec.y, vec.x));        // Upper right corner.        vec = new Vec4(imageWidth, 0, 1).transformBy3(imageToGeographic);        corners.add(LatLon.fromDegrees(vec.y, vec.x));        // Upper left corner.        vec = new Vec4(0, 0, 1).transformBy3(imageToGeographic);        corners.add(LatLon.fromDegrees(vec.y, vec.x));        return corners;    }    private static String validateControlPoints(int numExpected,        java.awt.geom.Point2D[] imagePoints, LatLon[] geoPoints)    {        if (imagePoints == null)        {            return Logging.getMessage("nullValue.ImagePointsIsNull");        }        if (geoPoints == null)        {            return Logging.getMessage("nullValue.GeoPointsIsNull");        }        if (imagePoints.length < numExpected)        {            return Logging.getMessage("generic.ArrayInvalidLength", imagePoints.length);        }        if (geoPoints.length < numExpected)        {            return Logging.getMessage("generic.ArrayInvalidLength", imagePoints.length);        }        return null;    }    /**     * Merge an image into another image. This method is typically used to assemble a composite, seamless image from     * several individual images. The receiving image, called here the canvas because it's analogous to the Photoshop     * notion of a canvas, merges the incoming image according to the specified aspect ratio.     *     * @param canvasSector the sector defining the canvas' location and range.     * @param imageSector  the sector defining the image's locaion and range.     * @param aspectRatio  the aspect ratio, width/height, of the assembled image. If the aspect ratio is greater than     *                     or equal to one, the assembled image uses the full width of the canvas; the height used is     *                     proportional to the inverse of the aspect ratio. If the aspect ratio is less than one, the     *                     full height of the canvas is used; the width used is proportional to the aspect ratio.     *                     <p/>     *                     The aspect ratio is typically used to maintain consistent width and height units while     *                     assembling multiple images into a canvas of a different aspect ratio than the canvas sector,     *                     such as drawing a non-square region into a 1024x1024 canvas. An aspect ratio of 1 causes the     *                     incoming images to be stretched as necessary in one dimension to match the aspect ratio of     *                     the canvas sector.     * @param image        the image to merge into the canvas.     * @param canvas       the canvas into which the images are merged. The canvas is not changed if the specified image     *                     and canvas sectors are disjoint.     *     * @throws IllegalArgumentException if the any of the reference arguments are null or the aspect ratio is less than     *                                  or equal to zero.     */    public static void mergeImage(Sector canvasSector, Sector imageSector, double aspectRatio, BufferedImage image,        BufferedImage canvas)    {        if (canvasSector == null || imageSector == null)        {            String message = Logging.getMessage("nullValue.SectorIsNull");            Logging.logger().severe(message);            throw new IllegalStateException(message);        }        if (canvas == null || image == null)        {            String message = Logging.getMessage("nullValue.ImageSource");            Logging.logger().severe(message);            throw new IllegalStateException(message);        }        if (aspectRatio <= 0)        {            String message = Logging.getMessage("Util.AspectRatioInvalid", aspectRatio);            Logging.logger().severe(message);            throw new IllegalStateException(message);        }        if (!(canvasSector.intersects(imageSector)))            return;        // Create an image with the desired aspect ratio within an enclosing canvas of possibly different aspect ratio.        int subWidth = aspectRatio >= 1 ? canvas.getWidth() : (int) (canvas.getWidth() * aspectRatio);        int subHeight = aspectRatio >= 1 ? (int) (canvas.getHeight() / aspectRatio) : canvas.getHeight();        // yShift shifts image down to change origin from upper-left to lower-left        double yShift = aspectRatio >= 1 ? (1d - 1d / aspectRatio) * canvas.getHeight() : 0;        double sh = ((double) subHeight / (double) image.getHeight())            * (imageSector.getDeltaLat().divide(canvasSector.getDeltaLat()));        double sw = ((double) subWidth / (double) image.getWidth())            * (imageSector.getDeltaLon().divide(canvasSector.getDeltaLon()));        double dh = subHeight *            (-imageSector.getMaxLatitude().subtract(canvasSector.getMaxLatitude()).degrees                / canvasSector.getDeltaLat().degrees);        double dw = subWidth *            (imageSector.getMinLongitude().subtract(canvasSector.getMinLongitude()).degrees                / canvasSector.getDeltaLon().degrees);        Graphics2D g = canvas.createGraphics();        g.translate(dw, dh + yShift);        g.scale(sw, sh);        g.drawImage(image, 0, 0, null);    }    public static Sector positionImage(BufferedImage sourceImage, Point[] imagePoints, LatLon[] geoPoints,        BufferedImage destImage)    {        if (imagePoints.length == 3)            return positionImage3(sourceImage, imagePoints, geoPoints, destImage);        else if (imagePoints.length == 4)            return positionImage4(sourceImage, imagePoints, geoPoints, destImage);        else            return null;    }    public static Sector positionImage3(BufferedImage sourceImage, Point[] imagePoints, LatLon[] geoPoints,        BufferedImage destImage)    {        // TODO: check args        BarycentricTriangle sourceLatLon = new BarycentricTriangle(geoPoints[0], geoPoints[1], geoPoints[2]);        BarycentricTriangle sourcePixels = new BarycentricTriangle(imagePoints[0], imagePoints[1], imagePoints[2]);        ArrayList<LatLon> extremes = new ArrayList<LatLon>(4);        // Lower left corner.        double[] bc = sourcePixels.getBarycentricCoords(new Vec4(0, sourceImage.getHeight(), 0));        extremes.add(sourceLatLon.getLocation(bc));        // Lower right corner.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?