纯java实现全景图切割(无需opencv)

现在博客上面看到的都是opencv的,opencv还要安装它的组件库太麻烦,linux环境还好,如果上镜像环境,安装是个大麻烦。所以改造成去掉opencv的。
全景图切成六个面
private BufferedImage sideCubeMapImage(int width,int height,int type, int sideId, int sideWidth, int sideHeight,String saveUrl, int[] rgbArray) {
        log.error("==========handle " + sideId + " start ===========");
        double[][] imageTransform =
                {
                        {0, 0},
                        {Math.PI / 2, 0},
                        {Math.PI, 0},
                        {-Math.PI / 2, 0},
                        {0, -Math.PI / 2},
                        {0, Math.PI / 2}
                };
        // 新的图片坐标点与原始图片坐标的映射关系
        double[][] mapx = new double[sideHeight][sideWidth];
        double[][] mapy = new double[sideHeight][sideWidth];
        //计算相邻ak和相反an的三角形张成球体中心
        final double an = Math.sin(Math.PI / 4);
        final double ak = Math.cos(Math.PI / 4);

        double ftu = imageTransform[sideId][0];
        double ftv = imageTransform[sideId][1];

        //对于每个像素点计算相应的源坐标,具体计算公式参考球面转立方体映射
        for (int y = 0; y < sideHeight; y++) {
            for (int x = 0; x < sideWidth; x++) {
                //将坐标映射在平面上
                float nx = (float) y / (float) sideHeight - 0.5f;
                float ny = (float) x / (float) sideWidth - 0.5f;

                nx *= 2;
                ny *= 2;

                nx *= an;
                ny *= an;

                double u, v;

                if (Double.compare(ftv,0) == 0) {
                    u = Math.atan2(nx, ak);
                    v = Math.atan2(ny * Math.cos(u), ak);
                    u += ftu;
                } else if (ftv > 0) {
                    // Bottom face 低面
                    double d = Math.sqrt(nx * nx + ny * ny);
                    v = Math.PI / 2 - Math.atan2(d, ak);
                    u = Math.atan2(ny, nx);
                } else {
                    // Top face 顶面
                    double d = Math.sqrt(nx * nx + ny * ny);
                    v = -Math.PI / 2 + Math.atan2(d, ak);
                    u = Math.atan2(-ny, nx);
                }

                // Map from angular coordinates to [-1, 1], respectively.
                u = u / (Math.PI);
                v = v / (Math.PI / 2);

                // Warp around, if our coordinates are out of bounds.
                while (v < -1) {
                    v += 2;
                    u += 1;
                }
                while (v > 1) {
                    v -= 2;
                    u += 1;
                }

                while (u < -1) {
                    u += 2;
                }
                while (u > 1) {
                    u -= 2;
                }

                // Map from [-1, 1] to in texture space
                u = u / 2.0f + 0.5f;
                v = v / 2.0f + 0.5f;

                u = u * (width - 1);
                v = v * (height - 1);

                mapx[y][x]=u;
                mapy[y][x]=v;
            }
        }

        int[] newRgbArray = new int[sideWidth * sideHeight];
        for(int y = 0; y < sideHeight; y++ ) {
            for(int x = 0; x < sideWidth; x++) {
                int newx = (int)Math.round(mapx[y][x]);
                int newy = (int)Math.round(mapy[y][x]);
                // 这里似乎要旋转,暂不清楚为什么
                newRgbArray[x * sideHeight + y] = rgbArray[newy * width + newx];
            }
        }
        BufferedImage result = new BufferedImage(sideWidth,sideHeight,type);
        result.setRGB(0,0,sideWidth, sideHeight,newRgbArray, 0 ,sideWidth);
        // 没有其它格式的前景图,先写死jpg格式
        if (sideId == 0) {
            bufferSave(saveUrl+File.separator+"f.jpg", result);
        } else if (sideId == 1) {
            bufferSave(saveUrl+File.separator+"r.jpg", result);
        } else if (sideId == 2) {
            bufferSave(saveUrl+File.separator+"b.jpg", result);
        } else if (sideId == 3) {
            bufferSave(saveUrl+File.separator+"l.jpg", result);
        } else if (sideId == 4) {
            //旋转角度
            BufferedImage bufferedImage = new BufferedImage(result.getWidth(), result.getHeight(), result.getType());
            Graphics2D graphics = bufferedImage.createGraphics();
            graphics.translate(0,0);
            graphics.rotate(Math.PI / 2, result.getWidth() / 2.0, result.getHeight() /2.0);
            graphics.drawImage(result, null,null);
            bufferSave(saveUrl+File.separator+"u.jpg", bufferedImage);
            return bufferedImage;
        } else {
            //旋转角度
            BufferedImage bufferedImage = new BufferedImage(result.getWidth(), result.getHeight(), result.getType());
            Graphics2D graphics = bufferedImage.createGraphics();
            graphics.translate(0,0);
            graphics.rotate((-1) * Math.PI / 2, result.getWidth() / 2.0, result.getHeight() /2.0);
            graphics.drawImage(result, null,null);
            bufferSave(saveUrl+File.separator+"d.jpg", bufferedImage);
            return bufferedImage;
        }
        log.error("==========handle " + sideId + " over ===========");
        return result;
    }

获取像素点上的三色数组

int[] rgbArray = source.getRGB(0, 0, source.getWidth(), source.getHeight(), null, 0, source.getWidth());

每个面再进行切割成不同层级和像素

private void spiltMatrix(List<BufferedImage> mats,int size,String level,String savePathLocal,int tilesize) throws IOException {
        List<String> dirPrefixName= Arrays.asList("l", "f", "r", "b", "u", "d");
        // 取余数(获取最后一列的宽高)
        int remainder=size % tilesize;
        int num=(size-remainder)/tilesize;
        // 遍历每个子矩阵
        for(int k = 0; k < mats.size(); k++){
            BufferedImage mat=mats.get(k);
            String dir=dirPrefixName.get(k);
            BufferedImage sliceImage;
            for (int i = 0; i < num+1; i++) {
                for (int j = 0; j < num+1; j++) {
                    int remI=size-i*tilesize;
                    int remJ=size-j*tilesize;
                    sliceImage=mat.getSubimage(j * tilesize, i * tilesize, Math.min(remJ, tilesize), Math.min(remI, tilesize));
                    BufferedImage outputImage = new BufferedImage(Math.min(remJ, tilesize), Math.min(remI, tilesize), BufferedImage.TYPE_INT_RGB);
                    Graphics2D g2d = outputImage.createGraphics();
                    // 设置绘图质量
                    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                    // 绘制并调整图片大小
                    g2d.drawImage(sliceImage, 0, 0, Math.min(remJ, tilesize), Math.min(remI, tilesize), null);
                    g2d.dispose();
                    // 保存切分后的图片
                    int numx=i+1;
                    int numy=j+1;
                    String jpgName=level+"_"+dir+"_"+numx+"_"+numy;
                    String finalNme=savePathLocal+File.separator+dir+File.separator+level+File.separator+numx;
                    //不存在则创建
                    File packFile = new File(finalNme);
                    if (!packFile.exists()) {
                        boolean mkdirs = packFile.mkdirs();
                    }
                    ImageIO.write(outputImage,"jpg",new File(finalNme+File.separator+jpgName+".jpg"));
                    outputImage.flush();
                }
            }
        }

    }

已上生产环境,不懂的可以私信我,看完好用记得点赞收藏

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值