利用java实现视频人像分割及视频背景替换

视频人像分割是将视频中的人体从原视频中分割出来,得到透明背景的人体视频。如何基于算法分割后的人像结果进行再加工。

  • 基于现有的视频人像分割API对视频进行解析,将视频中的人像区域mask(掩模)作为视频序列返回。返回的mask通道视频类似于这种。

实现以上的效果是基于阿里云视觉智能开放平台的视频人像分割,平台提供有示例代码,

1、需要安装Alibaba Cloud SDK for Javaaliyun-java-sdk-core

SDK包为阿里云Java核心库,无论使用哪个产品的SDK,都必须先安装该核心库。

2、推荐使用Maven管理Java项目,可以通过在pom.xml文件中添加Maven依赖安装Java SDK,依赖如下:

<dependency>

    <groupId>com.aliyun</groupId>

    <artifactId>aliyun-java-sdk-videoseg</artifactId>

    <version>${aliyun.videoseg.version}</version>

</dependency>

调用API接口的示例代码如下:

package com.aliyun.sample;

import com.aliyun.tea.*;

import com.aliyun.videoseg20200320.*;

import com.aliyun.videoseg20200320.models.*;

import com.aliyun.teaopenapi.*;

import com.aliyun.teaopenapi.models.*;

import com.aliyun.teautil.*;

import com.aliyun.teautil.models.*;

public class Sample {

    /**

     * 使用AK&SK初始化账号Client

     * @param accessKeyId

     * @param accessKeySecret

     * @return Client

     * @throws Exception

     */

    public static com.aliyun.videoseg20200320.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {

        Config config = new Config()

                // 您的 AccessKey ID

                .setAccessKeyId(accessKeyId)

                // 您的 AccessKey Secret

                .setAccessKeySecret(accessKeySecret);

        // 访问的域名

        config.endpoint = "videoseg.cn-shanghai.aliyuncs.com";

        return new com.aliyun.videoseg20200320.Client(config);

    }

    public static void main(String[] args_) throws Exception {

        java.util.List<String> args = java.util.Arrays.asList(args_);

        com.aliyun.videoseg20200320.Client client = Sample.createClient("accessKeyId", "accessKeySecret");

        SegmentVideoBodyRequest segmentVideoBodyRequest = new SegmentVideoBodyRequest();

        RuntimeOptions runtime = new RuntimeOptions();

        try {

            // 复制代码运行请自行打印 API 的返回值

            client.segmentVideoBodyWithOptions(segmentVideoBodyRequest, runtime);

        } catch (TeaException error) {

            // 如有需要,请打印 error

            com.aliyun.teautil.Common.assertAsString(error.message);

        } catch (Exception _error) {

            TeaException error = new TeaException(_error.getMessage(), _error);

            // 如有需要,请打印 error

            com.aliyun.teautil.Common.assertAsString(error.message);

        }       

    }

}

  • 对算法输出的视频Mask通道进行覆盖,先让原视频生成背景透明的视频流,采用视频中的一帧看下输出的结果如下:

替换背景之后的效果如下:

下面将使用java 的方法完成上面的效果,首先是将API输出的Mask通道视频和原视频进行叠加,生成新的背景透明视频,然后在背景透明的视频状态下,再替换视频的背景。视频是有一帧帧的图片序列组成的,所以本次的java方法也是针对图片序列进行操作。

import java.awt.AlphaComposite;

import java.awt.Graphics2D;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;

import javax.imageio.ImageIO;

public class NewImageUtils {

    /**

     *

     * @Title: 构造图片

     * @Description: 生成水印并返回java.awt.image.BufferedImage

     * @param file

     *            源文件(图片)

     * @param waterFile

     *            水印文件(图片)

     * @param x

     *            距离右下角的X偏移量

     * @param y

     *            距离右下角的Y偏移量

     * @param alpha

     *            透明度, 选择值从0.0~1.0: 完全透明~完全不透明

     * @return BufferedImage

     * @throws IOException

     */

    public static BufferedImage watermark(File file, File waterFile, int x, int y, float alpha) throws IOException {

        // 获取底图

        BufferedImage buffImg = ImageIO.read(file);

        // 获取层图

        BufferedImage waterImg = ImageIO.read(waterFile);

        // 创建Graphics2D对象,用在底图对象上绘图

        Graphics2D g2d = buffImg.createGraphics();

        int waterImgWidth = waterImg.getWidth();// 获取层图的宽度

        int waterImgHeight = waterImg.getHeight();// 获取层图的高度

        // 在图形和图像中实现混合和透明效果

        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

        // 绘制

        g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null);

        g2d.dispose();// 释放图形上下文使用的系统资源

        return buffImg;

    }

    /**

     * 输出水印图片

     *

     * @param buffImg

     *            图像加水印之后的BufferedImage对象

     * @param savePath

     *            图像加水印之后的保存路径

     */

    private void generateWaterFile(BufferedImage buffImg, String savePath) {

        int temp = savePath.lastIndexOf(".") + 1;

        try {

            ImageIO.write(buffImg, savePath.substring(temp), new File(savePath));

        } catch (IOException e1) {

            e1.printStackTrace();

        }

    }

    /**

     *

     * @param args

     * @throws IOException

     *             IO异常直接抛出了

     * @author bls

     */

    public static void main(String[] args) throws IOException {

        String sourceFilePath = "D://img//di.png";

        String waterFilePath = "D://img//ceng.png";

        String saveFilePath = "D://img//new.png";

        NewImageUtils newImageUtils = new NewImageUtils();

        // 构建叠加层

        BufferedImage buffImg = NewImageUtils.watermark(new File(sourceFilePath), new File(waterFilePath), 0, 0, 1.0f);

        // 输出水印图片

        newImageUtils.generateWaterFile(buffImg, saveFilePath);

    }

}

猜你喜欢

转载自blog.csdn.net/xiayexuyou/article/details/126153737