我使用camera2 API构建了自己的相机应用程序。我从示例“camera2Raw”开始,我添加了YUV_420_888支持而不是JPEG。但现在我想知道如何在ImageSaver中保存图像!?
这是我的run方法代码:
@Override
public void run() {
boolean success = false;
int format = mImage.getFormat();
switch(format) {
case ImageFormat.RAW_SENSOR:{
DngCreator dngCreator = new DngCreator(mCharacteristics, mCaptureResult);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
dngCreator.writeImage(output, mImage);
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
closeOutput(output);
}
break;
}
case ImageFormat.YUV_420_888:{
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
closeOutput(output);
}
break;
}
default:
Log.e(TAG, "Cannot save image, unexpected image format:" + format);
}
// Decrement reference count to allow ImageReader to be closed to free up resources.
mReader.close();
// If saving the file succeeded, update MediaStore.
if (success) {
MediaScannerConnection.scanFile(mContext, new String[] { mFile.getPath()},
/*mimeTypes*/ null, new MediaScannerConnection.MediaScannerConnectionClient() {
@Override
public void onMediaScannerConnected() {
// Do nothing
}
@Override
public void onScanCompleted(String path, Uri uri) {
Log.i(TAG, "Scanned " + path + ":");
Log.i(TAG, "-> uri=" + uri);
}
});
}
}
我试图将YUV图像保存为JPEG,但这样我只得到一个平面,保存的数据对我没有任何意义......
保存YUV图像的正确方法是什么?将它转换为RGB(那么YUV的意义是什么?)?或者使用YuvImage类?
答案 0 :(得分:4)
通常,您不将YUV图像保存为文件,因此没有内置函数可以这样做。而且,对于这种YUV数据没有标准的图像格式编码。 YUV通常是一种中间形式的数据,便于摄像机管道和之后转换成其他格式。
如果您真的想要这个,可以将三个通道的缓冲区作为未编码的字节数据写入文件,然后在其他地方打开并重新构建它。但是,请确保保存其他重要信息,例如步幅数据。这就是我的工作。以下是我使用的文件格式切换语句中的相关行,以及对推理的注释:
File file = new File(SAVE_DIR, mFilename);
FileOutputStream output = null;
ByteBuffer buffer;
byte[] bytes;
boolean success = false;
switch (mImage.getFormat()){
(... other image data format cases ...)
// YUV_420_888 images are saved in a format of our own devising. First write out the
// information necessary to reconstruct the image, all as ints: width, height, U-,V-plane
// pixel strides, and U-,V-plane row strides. (Y-plane will have pixel-stride 1 always.)
// Then directly place the three planes of byte data, uncompressed.
//
// Note the YUV_420_888 format does not guarantee the last pixel makes it in these planes,
// so some cases are necessary at the decoding end, based on the number of bytes present.
// An alternative would be to also encode, prior to each plane of bytes, how many bytes are
// in the following plane. Perhaps in the future.
case ImageFormat.YUV_420_888:
// "prebuffer" simply contains the meta information about the following planes.
ByteBuffer prebuffer = ByteBuffer.allocate(16);
prebuffer.putInt(mImage.getWidth())
.putInt(mImage.getHeight())
.putInt(mImage.getPlanes()[1].getPixelStride())
.putInt(mImage.getPlanes()[1].getRowStride());
try {
output = new FileOutputStream(file);
output.write(prebuffer.array()); // write meta information to file
// Now write the actual planes.
for (int i = 0; i<3; i++){
buffer = mImage.getPlanes()[i].getBuffer();
bytes = new byte[buffer.remaining()]; // makes byte array large enough to hold image
buffer.get(bytes); // copies image from buffer to byte array
output.write(bytes); // write the byte array to file
}
success = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
Log.v(appFragment.APP_TAG,"Closing image to free buffer.");
mImage.close(); // close this to free up buffer for other images
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
break;
}
因为设备可以完全取决于数据的隔行扫描方式,所以稍后从此编码信息中提取Y,U,V通道可能具有挑战性。要查看如何读取和提取这样的文件的MATLAB实现,请参阅here。
答案 1 :(得分:1)
如果您有YuvImage对象,那么您可以使用compressToJpeg函数将其转换为Jpeg。
if(new Date(data[row][2]) > new Date() || new Date(data[row][3]) > new Date())
您必须明确设置图像的宽度和高度。