source: josm/trunk/src/org/openstreetmap/josm/tools/ImageWarp.java@ 11864

Last change on this file since 11864 was 11864, checked in by Don-vip, 7 years ago

see #7427 - sonar - squid:UselessImportCheck - Useless imports should be removed

  • Property svn:eol-style set to native
File size: 5.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.awt.Color;
5import java.awt.Dimension;
6import java.awt.geom.Point2D;
7import java.awt.geom.Rectangle2D;
8import java.awt.image.BufferedImage;
9
10/**
11 * Image warping algorithm.
12 *
13 * Deforms an image geometrically according to a given transformation formula.
14 */
15public class ImageWarp {
16
17 /**
18 * Transformation that translates the pixel coordinates.
19 */
20 public static interface PointTransform {
21 Point2D transform(Point2D pt);
22 }
23
24 /**
25 * Interpolation method.
26 */
27 public enum Interpolation {
28 /**
29 * Nearest neighbor.
30 *
31 * Simplest possible method. Faster, but not very good quality.
32 */
33 NEAREST_NEIGHBOR(1),
34 /**
35 * Bilinear.
36 *
37 * Decent quality.
38 */
39 BILINEAR(2);
40
41 private final int margin;
42
43 private Interpolation(int margin) {
44 this.margin = margin;
45 }
46
47 /**
48 * Number of pixels to scan outside the source image.
49 * Used to get smoother borders.
50 * @return the margin
51 */
52 public int getMargin() {
53 return margin;
54 }
55 }
56
57 /**
58 * Warp an image.
59 * @param srcImg the original image
60 * @param targetDim dimension of the target image
61 * @param invTransform inverse transformation (translates pixel coordinates
62 * of the target image to pixel coordinates of the original image)
63 * @param interpolation the interpolation method
64 * @return the warped image
65 */
66 public static BufferedImage warp(BufferedImage srcImg, Dimension targetDim, PointTransform invTransform, Interpolation interpolation) {
67 BufferedImage imgTarget = new BufferedImage(targetDim.width, targetDim.height, BufferedImage.TYPE_INT_ARGB);
68 Rectangle2D srcRect = new Rectangle2D.Double(0, 0, srcImg.getWidth(), srcImg.getHeight());
69 for (int j = 0; j < imgTarget.getHeight(); j++) {
70 for (int i = 0; i < imgTarget.getWidth(); i++) {
71 Point2D srcCoord = invTransform.transform(new Point2D.Double(i, j));
72 if (isInside(srcCoord, srcRect, interpolation.getMargin())) {
73 int rgb;
74 switch (interpolation) {
75 case NEAREST_NEIGHBOR:
76 rgb = getColor((int) Math.round(srcCoord.getX()), (int) Math.round(srcCoord.getY()), srcImg).getRGB();
77 break;
78 case BILINEAR:
79 int x0 = (int) Math.floor(srcCoord.getX());
80 double dx = srcCoord.getX() - x0;
81 int y0 = (int) Math.floor(srcCoord.getY());
82 double dy = srcCoord.getY() - y0;
83 Color c00 = getColor(x0, y0, srcImg);
84 Color c01 = getColor(x0, y0 + 1, srcImg);
85 Color c10 = getColor(x0 + 1, y0, srcImg);
86 Color c11 = getColor(x0 + 1, y0 + 1, srcImg);
87 int red = (int) Math.round(
88 (c00.getRed() * (1-dx) + c10.getRed() * dx) * (1-dy) +
89 (c01.getRed() * (1-dx) + c11.getRed() * dx) * dy);
90 int green = (int) Math.round(
91 (c00.getGreen()* (1-dx) + c10.getGreen() * dx) * (1-dy) +
92 (c01.getGreen() * (1-dx) + c11.getGreen() * dx) * dy);
93 int blue = (int) Math.round(
94 (c00.getBlue()* (1-dx) + c10.getBlue() * dx) * (1-dy) +
95 (c01.getBlue() * (1-dx) + c11.getBlue() * dx) * dy);
96 int alpha = (int) Math.round(
97 (c00.getAlpha()* (1-dx) + c10.getAlpha() * dx) * (1-dy) +
98 (c01.getAlpha() * (1-dx) + c11.getAlpha() * dx) * dy);
99 rgb = new Color(red, green, blue, alpha).getRGB();
100 break;
101 default:
102 throw new AssertionError();
103 }
104 imgTarget.setRGB(i, j, rgb);
105 }
106 }
107 }
108 return imgTarget;
109 }
110
111 private static boolean isInside(Point2D p, Rectangle2D rect, double margin) {
112 return isInside(p.getX(), rect.getMinX(), rect.getMaxX(), margin) &&
113 isInside(p.getY(), rect.getMinY(), rect.getMaxY(), margin);
114 }
115
116 private static boolean isInside(double x, double xMin, double xMax, double margin) {
117 return x + margin >= xMin && x - margin <= xMax;
118 }
119
120 private static Color getColor(int x, int y, BufferedImage img) {
121 // border strategy: continue with the color of the outermost pixel,
122 // but change alpha component to fully translucent
123 boolean transparent = false;
124 if (x < 0) {
125 x = 0;
126 transparent = true;
127 } else if (x >= img.getWidth()) {
128 x = img.getWidth() - 1;
129 transparent = true;
130 }
131 if (y < 0) {
132 y = 0;
133 transparent = true;
134 } else if (y >= img.getHeight()) {
135 y = img.getHeight() - 1;
136 transparent = true;
137 }
138 Color clr = new Color(img.getRGB(x, y));
139 if (!transparent)
140 return clr;
141 // keep color components, but set transparency to 0
142 // (the idea is that border fades out and mixes with next tile)
143 return new Color(clr.getRed(), clr.getGreen(), clr.getBlue(), 0);
144 }
145}
Note: See TracBrowser for help on using the repository browser.