旋转无人机图像以补偿航向和风引起的错误

时间:2016-07-14 08:22:43

标签: java image gps image-stitching geopositioning

目前我正在开发一个Java项目,该项目将缝合从无人机安装的GoPro中获取的图像。随着图像也出现GPS数据,分配给每个相机拍摄:

                      Latitude    Longitude   Altitude        Roll  Pitch   Yaw
CAM, 467270000, 1895, 58.3705557, 31.0359788, 131.30, 109.88, 0.73, -10.70, 172.79
CAM, 467273600, 1895, 58.3702211, 31.0354466, 126.43, 105.01, -1.02, -4.61, 218.37
CAM, 467277400, 1895, 58.3699252, 31.0348309, 127.61, 106.19, -6.50, -2.75, 233.71
CAM, 467281400, 1895, 58.3695767, 31.0342934, 120.87, 99.45, -0.52, 7.95, 229.61
CAM, 467284800, 1895, 58.3692659, 31.0337095, 131.80, 110.38, -8.02, 6.47, 225.28
CAM, 467288800, 1895, 58.3689556, 31.0331251, 132.72, 111.30, -5.50, -7.32, 223.22
CAM, 467292800, 1895, 58.3685826, 31.0326798, 132.01, 110.59, -16.65, 0.24, 215.20
CAM, 467297400, 1895, 58.3682075, 31.0330935, 127.13, 105.71, -37.07, 9.32, 143.64
CAM, 467300600, 1895, 58.3683265, 31.0339103, 132.22, 110.80, -24.37, 3.29, 102.24
CAM, 467303800, 1895, 58.3686659, 31.034442, 131.46, 110.04, -9.07, -1.69, 76.16

这是我用于算法的输入数据。首先,我创建了ArrayList latitudelongitudealtitude

  • distanceList(连续2张图像的中心之间的距离);
  • azimuthList(图片的方位角);
  • coordinateAngleList(下一个图像相对于前一个图像的角度);
  • pixelSizeList(以米为单位的一个像素的大小)。

以下是我用来计算列出值的算法:

  • distanceListazimuthList

    private static double calculateDistanceOrAzimuthAngle(Double llat1, Double llong1, Double llat2, Double llong2, String mode) {
        double pi = Math.PI;
        //===== Earth radius in meters
        int rad = 6372795;
        //===== Coordinates in radians
        double phi1 = Math.toRadians(llat1);
        double phi2 = Math.toRadians(llat2);
        double lam1 = Math.toRadians(llong1);
        double lam2 = Math.toRadians(llong2);
    
        double lambda = lam2 - lam1;
    
        //===== Cos and Sin of latitudes and delta of longitudes
        double c11 = Math.cos(phi1);
        double c12 = Math.cos(phi2);
        double s11 = Math.sin(phi1);
        double s12 = Math.sin(phi2);
        double cdelta = Math.cos(lambda);
        double sdelta = Math.sin(lambda);
    
        switch (mode) {
            case "distance": {
                //===== Calculating lengths of bigger circle
                double x = s11 * s12 + c11 * c12 * cdelta;
                double y = Math.sqrt(Math.pow(c12 * sdelta, 2) + Math.pow(c11 * s12 - s11 * c12 * cdelta, 2));
                double ad = Math.atan2(y, x);
                return ad * rad;
            }
            case "azimuth": {
                double x = (c11 * s12) - (s11 * c12 * cdelta);
                double y = sdelta * c12;
                double z = Math.toDegrees(Math.atan(-y / x));
    
                if (x < 0) z = z + 180;
    
                double z2 = (z + 180) % 360 - 180;
                z2 = Math.toRadians(-z2);
                double anglerad2 = z2 - ((2 * pi) * Math.floor((z2 / (2 * pi))));
                double anglerad = (anglerad2 * 180.) / pi;
                anglerad = 360 - (anglerad - 90);
                if (anglerad > 360) anglerad -= 360;
                return anglerad;
    
            }
            default:
                return 0;
        }
    }
    
  • coordinateAngleList

    private static double angleFromCoordinate(Double slat1, Double slong1, Double slat2, Double slong2) {
    
    double long1 = slong1;
    double long2 = slong2;
    
    double lat1 = Math.toRadians(slat1);
    double lat2 = Math.toRadians(slat2);
    
    double dLon = Math.toRadians(long2 - long1);
    
    double y = Math.sin(dLon) * Math.cos(lat2);
    double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
            * Math.cos(lat2) * Math.cos(dLon);
    
    return (Math.toDegrees(Math.atan2(y, x)) + 360) % 360;
    }
    
  • pixelSizeList

    private static double calculatePixelSize(double altitude, double FOV, double imgWidth, double imgHeight) {
    double halfFOV = FOV / 2;
    double angleA = 180 - 90 - halfFOV;
    
    double hypotenuse = altitude / Math.sin(angleA);
    double imageDiagonalInMeters = Math.sqrt(Math.pow(hypotenuse, 2) - Math.pow(altitude, 2));
    double imageDiagonalInPixels = Math.sqrt(Math.pow(imgWidth, 2) + Math.pow(imgHeight, 2));
    return imageDiagonalInMeters / imageDiagonalInPixels;
    }
    

以下是每个列表的前10个值:

Distance: [48.46373238266117, 48.71355037065455, 49.85503769989944, 48.52930211808859, 48.510404299271855, 48.94825023128212, 48.19766435644759, 49.451021971786204, 48.85744749197166, 50.080448602974066]
Azimuth: [230.16731156516713, 222.50205323598703, 231.0321217131937, 225.42496727180497, 225.3540760894774, 237.94887148656915, 300.046347389977, 15.525254536580519, 50.593577501672826, 56.856166424208084]
Coordinate Angel: [39.832235289576545, 47.497422524511194, 38.96742063247876, 44.57453556828523, 44.645426326236986, 32.050749366729804, 329.9540048495128, 254.47544091635925, 219.40687520849113, 213.14423324262788]
Pixel size: [0.060905719060422164, 0.0586466874395215, 0.05919405033739887, 0.05606758768342138, 0.061137652491726126, 0.06156441000532543, 0.061235064532873786, 0.05897139424334705, 0.06133247657402146, 0.06097993775843944]

之后,图像的简单旋转就会发生。我已经尝试使用我收到的角度和其他值来用Photoshop旋转图像,但几乎发生了同样的事情。这是旋转算法:

private void rotate(int numToRotate) {
        //TODO correct rotation without cutting image
        try {
            for (int i = 0; i < numToRotate - 1; i++) {
                BufferedImage image = ImageIO.read(new File("/Users/Nick/Downloads/geotagged-1/input" + i + "_1.png"));

            // The required drawing location
            int drawLocationX = 500;
            int drawLocationY = 500;

            // Rotation information
            //double rotationRequired = azimuthList.get(i);
            double rotationRequired = coordinateAngleList.get(i);
            double locationX = image.getWidth() / 2;
            double locationY = image.getHeight() / 2;

            //AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(rotationRequired), locationX, locationY);
            //AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);

            AffineTransform transform = new AffineTransform();
            transform.rotate(Math.toRadians(rotationRequired), locationX, locationY);
            AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);

            // Drawing the rotated image at the required drawing locations
            BufferedImage opImage = op.filter(image, null);

            BufferedImage im = new BufferedImage((opImage.getWidth()), (opImage.getHeight()), BufferedImage.TYPE_INT_ARGB);
            im.getGraphics().drawImage(opImage, drawLocationX, drawLocationY, null);

            ImageIO.write(im, "png", new File("/Users/Nick/Dropbox/ЭЛСИ/ДЗЗ/AgroScan/rotated/" + i + ".png"));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

无论哪种方式,得到的图像都不会以稍微接近的直线结束。拼接基于创建一个大的BufferedImage并根据其中心之间的度量距离放置图像(对于之前计算的每个图像,pixelSize)。

旋转图像我做错了什么?我试过按方位角旋转,但这只会让它变得更糟。在我使用的任何算法中都有错误吗?

0 个答案:

没有答案