视频人像分割是将视频中的人体从原视频中分割出来,得到透明背景的人体视频。如何基于算法分割后的人像结果进行再加工。
一、基于现有的视频人像分割API对视频进行解析,将视频中的人像区域mask(掩模)作为视频序列返回。返回的mask通道视频类似于这种。
实现以上的效果是基于阿里云视觉智能开放平台的视频人像分割,平台提供有示例代码,
1、需要安装Alibaba Cloud SDK for Java:aliyun-java-sdk-core
该SDK包为阿里云Java核心库,无论使用哪个产品的SDK,都必须先安装该核心库。
2、推荐使用Maven管理Java项目,可以通过在pom.xml文件中添加Maven依赖安装Java SDK,依赖如下:
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-videoseg</artifactId>
<version>${aliyun.videoseg.version}</version>
调用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);
}
}