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 + -
显示快捷键?