关于视频抽帧调用虹软人脸识别的BufferedImage读取优化策略
背景说明:
1、在使用 FfmpegFrameGrabber 调用本地视频文件,逐帧读取视频内容
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(file); // 不读取音频,否则frame.image = null grabber.setAudioStream(-1); grabber.start();
2、遍历所有帧
while(true){ // 抓取目标帧 Frame frame = grabber.grabFrame(); if(frame == null){ break; } if(frame.image == null){ continue; } }
3、frame转BufferedImage
在大部分的网站搜索中,通常使用Java2DFrameConverter 函数进行frame提取转换,
但占用过多CPU
import com.arcsoft.face.FaceInfo; import com.arcsoft.face.enums.ImageFormat; import com.arcsoft.face.toolkit.ImageFactory; import com.arcsoft.face.toolkit.ImageInfo;import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; Java2DFrameConverter jfc = new Java2DFrameConverter(); BufferedImage bufferedImage = jfc.getBufferedImage(frame); ImageInfo imageInfo = ImageFactory.bufferedImage2ImageInfo(bufferedImage);
4、采用读取Frame.image直接获取
ImageInfo imageInfo = new ImageInfo(); imageInfo.setWidth(frame.imageWidth); imageInfo.setHeight(frame.imageHeight); imageInfo.setImageFormat(ImageFormat.CP_PAF_RGB24); imageInfo.setImageData(convertByteArray((ByteBuffer)frame.image[0]));
private byte[] convertByteArray(ByteBuffer buffer) { int length = buffer.remaining(); // 创建目标 byte[] 数组 byte[] result = new byte[length]; int offset = 0; // 复制每个 DirectByteBuffer 的内容到 byte[] 数组 buffer.get(result, offset, length); buffer.rewind(); // 重置缓冲区位置 return result; }
部分参数的变动需要参考读取帧Frame对象的内容做适当调整
参考 Java2DFrameConverter 的 getBufferedImageType()
public static int getBufferedImageType(Frame frame) {
int type = 0;
if (frame.imageChannels == 1) {
if (frame.imageDepth != 8 && frame.imageDepth != -8) {
if (frame.imageDepth == 16) {
type = 11;
}
} else {
type = 10;
}
} else if (frame.imageChannels == 3) {
if (frame.imageDepth == 8 || frame.imageDepth == -8) {
type = 5;
}
} else if (frame.imageChannels == 4 && (frame.imageDepth == 8 || frame.imageDepth == -8)) {
type = 6;
}
return type;
}