我有一个图像(基本上,我得到原始图像数据为1024x1024像素)和图像中心像素的纬度/经度位置。
每个像素表示以米为单位的相同固定像素比例(例如,每像素30米)。
现在,我想将图像绘制到使用坐标参考系统" EPSG:4326" (WGS84)。
当我通过定义图像的纬度/经度中的角来绘制它时,取决于像素*像素比例的"图像尺寸"计算和转换从中心点到每个角落的纬度/经度坐标的距离,我想,图像没有正确地绘制到地图上。 通过术语"未正确绘制"我的意思是,图像似乎被移动了,而且图像的内容也不在我预期的地图位置。
我认为情况就是这样,因为我"混合"像素缩放图像和" EPSG:4326"坐标参考系。
现在,根据我给出的信息,我可以将整个像素矩阵从固定像素比例基础转换为" EPSG:4326"坐标参考系统,使用Geotools? 当然,转换必须依赖于纬度/经度的中心位置,我已经给出的,以及像素尺度。
我想知道使用这样的东西是否会指向正确的方向:
MathTransform transform = CRS.findMathTransform(DefaultGeocentricCRS.CARTESIAN, DefaultGeographicCRS.WGS84, true);
DirectPosition2D srcDirectPosition2D = new DirectPosition2D(DefaultGeocentricCRS.CARTESIAN, degreeLat.getDegree(), degreeLon.getDegree());
DirectPosition2D destDirectPosition2D = new DirectPosition2D();
transform.transform(srcDirectPosition2D, destDirectPosition2D);
double transX = destDirectPosition2D.x;
double transY = destDirectPosition2D.y;
int kmPerPixel = mapImage.getWidth / 1024; // It is known to me that my map is 1024x1024km ...
double x = zeroPointX + ((transX * 0.001) * kmPerPixel);
double y = zeroPointY + (((transX * -1) * 0.001) * kmPerPixel);
(从另一个SO线程获取此代码并且已经修改了一点,但仍然想知道这是否是我问题的正确起点。)
我只假设我的原始图像坐标参考系统是DefaultGeocentricCRS.CARTESIAN类型。有人可以证实这一点吗?
从现在开始,这是使用Geotools解决这类问题的正确开始,还是我走错了路?
此外,我想补充一点,这将用于安静的动态系统。所以我的图像更新大约是10Hz,并且必须经常相应地执行变换。 再一次,这是我最初的想法导致一个解决方案,还是你有其他解决方案来解决我的问题?
非常感谢, Kiamur
答案 0 :(得分:3)
这并不像听起来那么简单。您基本上是尝试使用扁平方形在球体上定义一个区域(技术上为椭圆体)。因此,没有"正确"这样做的方式,所以你总会有一些失真。如果不确切知道图像的来源,就无法准确回答这个问题,但以下代码为您提供了3种不同的答案:
前两个使用GeoTools' GeodeticCalculator
使用方位和距离计算角点。这些是蓝色" square"和绿色" square"以上。蓝色直接计算角落,而绿色计算边缘并推断交叉点的角落(这就是为什么它是方形的)。
final int width = 1024, height = 1024;
GeometryFactory gf = new GeometryFactory();
Point centre = gf.createPoint(new Coordinate(0,51));
WKTWriter writer = new WKTWriter();
//direct method
GeodeticCalculator calc = new GeodeticCalculator(DefaultGeographicCRS.WGS84);
calc.setStartingGeographicPoint(centre.getX(), centre.getY());
double height2 = height/2.0;
double width2 = width/2.0;
double dist = Math.sqrt(height2*height2+width2 *width2);
double bearing = 45.0;
Coordinate[] corners = new Coordinate[5];
for (int i=0;i<4;i++) {
calc.setDirection(bearing, dist*1000.0 );
Point2D corner = calc.getDestinationGeographicPoint();
corners[i] = new Coordinate(corner.getX(),corner.getY());
bearing+=90.0;
}
corners[4] = corners[0];
Polygon bbox = gf.createPolygon(corners);
System.out.println(writer.write(bbox));
double[] edges = new double[4];
bearing = 0;
for(int i=0;i<4;i++) {
calc.setDirection(bearing, height2*1000.0 );
Point2D corner = calc.getDestinationGeographicPoint();
if(i%2 ==0) {
edges[i] = corner.getY();
}else {
edges[i] = corner.getX();
}
bearing+=90.0;
}
corners[0] = new Coordinate( edges[1],edges[0]);
corners[1] = new Coordinate( edges[1],edges[2]);
corners[2] = new Coordinate( edges[3],edges[2]);
corners[3] = new Coordinate( edges[3],edges[0]);
corners[4] = corners[0];
bbox = gf.createPolygon(corners);
System.out.println(writer.write(bbox));
另一种方法是将中心点转换为更平坦的投影&#34;并使用简单的加法来计算角点,然后反转变换。为此,我们可以使用OGC WMS规范定义的AUTO
projection来生成以我们的点为中心的正交投影,这样可以得到红色&#34; square&#34;这与蓝色非常相似。
String code = "AUTO:42003," + centre.getX() + "," + centre.getY();
// System.out.println(code);
CoordinateReferenceSystem auto = CRS.decode(code);
// System.out.println(auto);
MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84,
auto);
MathTransform rtransform = CRS.findMathTransform(auto,DefaultGeographicCRS.WGS84);
Point g = (Point)JTS.transform(centre, transform);
width2 *=1000.0;
height2 *= 1000.0;
corners[0] = new Coordinate(g.getX()-width2,g.getY()-height2);
corners[1] = new Coordinate(g.getX()+width2,g.getY()-height2);
corners[2] = new Coordinate(g.getX()+width2,g.getY()+height2);
corners[3] = new Coordinate(g.getX()-width2,g.getY()+height2);
corners[4] = corners[0];
bbox = gf.createPolygon(corners);
bbox = (Polygon)JTS.transform(bbox, rtransform);
System.out.println(writer.write(bbox));
使用哪种解决方案是品味问题,取决于图像的来源,但我怀疑红色或蓝色是最好的。如果你需要在10Hz下进行此操作,那么你需要测试它们的速度,但我怀疑转换图像将成为瓶颈。
一旦您的边界框设置得令您满意,您可以使用以下方法将您(未引用)图像转换为地理参考覆盖:
GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
GridCoverage2D gc = factory.create("name", image, new ReferencedEnvelope(bbox.getEnvelopeInternal(),DefaultGeographicCRS.WGS84));
String fileName = "myImage.tif";
AbstractGridFormat format = GridFormatFinder.findFormat(fileName);
File out = new File(fileName);
GridCoverageWriter writer = format.getWriter(out);
try {
writer.write(gc, null);
writer.dispose();
} catch (IllegalArgumentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}