- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我没有图像或图形方面的背景,所以请耐心等待 :)
我正在使用 JavaCV在我的一个项目中。在examples , 构建了一个 Frame
,它有一个 certain size 的缓冲区.
在Android中使用public void onPreviewFrame(byte[] data, Camera camera)
函数时,复制这个data
字节数组是没有问题的,如果你声明Frame
as new Frame(frameWidth, frameHeight, Frame.DEPTH_UBYTE, 2);
其中 frameWidth
和 frameHeight
声明为
Camera.Size previewSize = cameraParam.getPreviewSize();
int frameWidth = previewSize.width;
int frameHeight = previewSize.height;
最近,Android 添加了一种捕获屏幕的方法。自然地,我想抓取这些图像并将它们转换为 Frame
。我修改了the example code from Google使用 ImageReader .
此 ImageReader
构造为 ImageReader.newInstance(DISPLAY_WIDTH, DISPLAY_HEIGHT, PixelFormat.RGBA_8888, 2);
。所以目前它使用 RGBA_8888 像素格式。我使用以下代码将字节复制到 Frame
,它被实例化为 new Frame(DISPLAY_WIDTH, DISPLAY_HEIGHT, Frame.DEPTH_UBYTE, 2);
:
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
mImage.close();
((ByteBuffer) frame.image[0].position(0)).put(bytes);
但这给了我一个 java.nio.BufferOverflowException
。我打印了两个缓冲区的大小,Frame 的缓冲区大小为 691200,而上面的 bytes
数组的大小为 1413056
。由于I ran into this native call,弄清楚后一个数字是如何构造的失败了。 .很明显,这是行不通的。
经过大量挖掘后,我发现 NV21 image format是“相机预览图像的默认格式,当没有使用 setPreviewFormat(int) 设置时”,但是 ImageReader class does not support the NV21 format (请参阅格式参数)。所以运气不好。在文档中它还读到“对于 android.hardware.camera2 API,建议使用 YUV_420_888 格式代替 YUV 输出。”
所以我尝试创建一个像这样的 ImageReader ImageReader.newInstance(DISPLAY_WIDTH, DISPLAY_HEIGHT, ImageFormat.YUV_420_888, 2);
,但这给了我 java.lang.UnsupportedOperationException: The producer output缓冲区格式 0x1 与 ImageReader 配置的缓冲区格式 0x23 不匹配。
因此这也不起作用。
作为最后的手段,我尝试自己将 RGBA_8888 转换为 YUV,例如使用this post ,但我不明白如何根据答案获得 int[] rgba
。
所以,长话短说 我怎样才能像在 Android 的 public void onPreviewFrame(byte[] data, Camera camera)
相机函数中获取 NV21 图像数据来实例化我的 Frame
并使用 Android 的 ImageReader(和 Media Projection)处理它?</strong>
我创建了以下可运行的转换以从 RGBA 格式转换为 NV21 格式:
private class updateImage implements Runnable {
private final Image mImage;
public updateImage(Image image) {
mImage = image;
}
@Override
public void run() {
int mWidth = mImage.getWidth();
int mHeight = mImage.getHeight();
// Four bytes per pixel: width * height * 4.
byte[] rgbaBytes = new byte[mWidth * mHeight * 4];
// put the data into the rgbaBytes array.
mImage.getPlanes()[0].getBuffer().get(rgbaBytes);
mImage.close(); // Access to the image is no longer needed, release it.
// Create a yuv byte array: width * height * 1.5 ().
byte[] yuv = new byte[mWidth * mHeight * 3 / 2];
RGBtoNV21(yuv, rgbaBytes, mWidth, mHeight);
((ByteBuffer) yuvImage.image[0].position(0)).put(yuv);
}
void RGBtoNV21(byte[] yuv420sp, byte[] argb, int width, int height) {
final int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int A, R, G, B, Y, U, V;
int index = 0;
int rgbIndex = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
R = argb[rgbIndex++];
G = argb[rgbIndex++];
B = argb[rgbIndex++];
A = argb[rgbIndex++]; // Ignored right now.
// RGB to YUV conversion according to
// https://en.wikipedia.org/wiki/YUV#Y.E2.80.B2UV444_to_RGB888_conversion
Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
// NV21 has a plane of Y and interleaved planes of VU each sampled by a factor
// of 2 meaning for every 4 Y pixels there are 1 V and 1 U.
// Note the sampling is every other pixel AND every other scanline.
yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
if (i % 2 == 0 && index % 2 == 0) {
yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
}
index++;
}
}
}
}
yuvImage
对象被初始化为 yuvImage = new Frame(DISPLAY_WIDTH, DISPLAY_HEIGHT, Frame.DEPTH_UBYTE, 2);
,DISPLAY_WIDTH
和DISPLAY_HEIGHT
只是指定显示大小的两个整数。这是后台处理程序处理 onImageReady 的代码:
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
mBackgroundHandler.post(new updateImage(reader.acquireNextImage()));
}
};
...
mImageReader = ImageReader.newInstance(DISPLAY_WIDTH, DISPLAY_HEIGHT, PixelFormat.RGBA_8888, 2);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
这些方法有效,我至少没有收到任何错误,但输出图像格式不正确。我的转换出了什么问题?正在创建的示例图像:
我已将 RGBtoNV21
函数修改为以下内容:
void RGBtoNV21(byte[] yuv420sp, int width, int height) {
try {
final int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int pixelStride = mImage.getPlanes()[0].getPixelStride();
int rowStride = mImage.getPlanes()[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
Bitmap bitmap = Bitmap.createBitmap(getResources().getDisplayMetrics(), width, height, Bitmap.Config.ARGB_8888);
int A, R, G, B, Y, U, V;
int offset = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Useful link: https://stackoverflow.com/questions/26673127/android-imagereader-acquirelatestimage-returns-invalid-jpg
R = (buffer.get(offset) & 0xff) << 16; // R
G = (buffer.get(offset + 1) & 0xff) << 8; // G
B = (buffer.get(offset + 2) & 0xff); // B
A = (buffer.get(offset + 3) & 0xff) << 24; // A
offset += pixelStride;
int pixel = 0;
pixel |= R; // R
pixel |= G; // G
pixel |= B; // B
pixel |= A; // A
bitmap.setPixel(j, i, pixel);
// RGB to YUV conversion according to
// https://en.wikipedia.org/wiki/YUV#Y.E2.80.B2UV444_to_RGB888_conversion
// Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
// U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
// V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
Y = (int) Math.round(R * .299000 + G * .587000 + B * .114000);
U = (int) Math.round(R * -.168736 + G * -.331264 + B * .500000 + 128);
V = (int) Math.round(R * .500000 + G * -.418688 + B * -.081312 + 128);
// NV21 has a plane of Y and interleaved planes of VU each sampled by a factor
// of 2 meaning for every 4 Y pixels there are 1 V and 1 U.
// Note the sampling is every other pixel AND every other scanline.
yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
if (i % 2 == 0 && j % 2 == 0) {
yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
}
}
offset += rowPadding;
}
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath(), "/Awesomebitmap.png");
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
Timber.e(e, "Converting image to NV21 went wrong.");
}
}
现在图像不再畸形,但色度已关闭。
右侧是在该循环中创建的位图,左侧是保存到图像的 NV21。所以 RGB 像素被正确处理。显然色度已关闭,但 RGB 到 YUV 的转换应该与维基百科描述的相同。这里可能出了什么问题?
最佳答案
一般来说,ImageReader 的目的是让您以最小的开销原始访问发送到 Surface 的像素,因此尝试让它执行颜色转换没有意义。
对于相机,您可以选择两种输出格式(NV21 或 YV12)中的一种,因此请选择 YV12。那是你的原始 YUV 数据。对于屏幕捕获,输出将始终为 RGB,因此您需要选择 RGBA_8888
(format 0x1)对于您的 ImageReader,而不是 YUV_420_888
(format 0x23) .如果为此需要 YUV,则必须自己进行转换。 ImageReader 为您提供了一系列 Plane
对象,而不是 byte[]
,因此您需要适应它。
关于Android ImageReader 获取 NV21 格式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35709241/
现在使用 nv.d3 示例中的 stackedAreaChart(),当您将鼠标悬停在时间序列中的某个点上时,您会得到一个工具提示。 我垂直对齐了 3 个时间序列。如果鼠标悬停在其中任何一个点上,我希
我正在尝试使用一些非核心硬件计数器,例如:skx_unc_imc0-5::UNC_M_WPQ_INSERTS .它应该计算写入挂起队列的分配数量。该机有2颗Intel Xeon Gold 5218 C
我正在使用 NVD3.js 库来生成图形。我尝试在其中添加折线图并得到上述错误。如何解决? 我正在尝试这个 here 最佳答案 其实我发现,问题是文件夹结构。 angular-nvd3 网站自带的例子
Closed. This question needs debugging details。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic用于堆栈溢出。 4年前关闭。 I
我遇到了一些奇怪的事情!我为此使用了源代码:http://nvd3.org/ghpages/stackedArea.html#source_code 我在开头添加了这两行: 但是当我运行它时,它说
我是 Ubuntu 和网络开发的新手。我已经使用 nvd3 在我的一个项目中构建了一些折线图。最近我需要自定义这些折线图,我通过在 nv.d3.js 文件中进行一些编辑来实现。现在我正在尝试缩小该文件
v()有什么区别和 nv() oracle Apex中的功能? 我遇到了 nv()函数,我唯一能让谷歌吐出来的是 nvl()功能。 apex_custom_auth.post_login(
我留下了使用前一位开发人员的 nv.d3.js 构建的数据可视化图表,我目前正在尝试编辑饼图以将饼图定位在顶部,将标签定位在底部。这是一个视觉示例的 fiddle 。 https://jsfiddle
在我开始防止它变成一英里长的只写公式之前,我需要一些关于如何改进我的概念的想法...... 我正在尝试做的,以图形方式,是这样的: 我有两行有 4 个必需单元格(直线)和 4 个可选单元格(虚线),我
我正在尝试使用此处正确区域中的 NC/NV 服务器在 Azure 上创建 Windows 10 Pro VM:https://azure.microsoft.com/en-au/regions/ser
我有以下命令行交互说明的问题: $ wget www.google.com -nv >> out.log 2014-10-28 21:41:43 URL:http://www.google.com/
当从客户端使用此库的 sendBinary 时,我在服务器中得到的全是 0 ;( 此页面要求我添加更多描述,但下面的代码简单明了,应该可以 self 解释...... 客户端代码: private W
是否有任何方法可以捕获第 1/3 层 RF 相关信息或从 Android、Qualcomm 设备获取 NV 项目? 我从androiddocumentation中找到了一些参数我也试过 Qualcom
我使用“ssh -X machine”连接到远程 Linux 计算机,然后运行图形应用程序,因此它的窗口使用 X Window 显示在我的本地 OS X Lion 计算机上。我收到错误 “Xlib:显
我使用 nvd3 有用的预打包图表制作了一个堆积折线图。 我的图表可以很好地完成大部分功能,但每当我单击特定系列时,都会出现错误“未捕获类型错误:无法读取未定义的属性“y””,并且图表不会调整大小以仅
我正在尝试在node.js项目中创建一个virtualenv来管理nodejs依赖项,例如grunt、bower等。 尝试使用nodeenv来实现这一点。 但它没有得到认可。我同时使用了 npm in
所以我有一些看起来像这样的 HTML: 用相应的CSS like, svg { /*display: block;*/
我的数据框包含大约 26k 行和 129 个变量。我已经确保所有变量都是数字并且没有任何 NA 值(使用 na.omit)。在我的数据框上使用函数 prcomp() 告诉我“x 中有无限值或缺失值”。
我正在使用 nv.models.lineWithFocusChart ,我在这里展示了一些每小时的测量值。所以 x 域是日期。 我需要的是在 X 轴上每小时显示一个刻度: 00:00 01:00 02
我尝试在 ClustOfVar 包中应用稳定性函数并收到如下错误消息: Error in La.svd(x, nu, nv) : error code 1 from Lapack routine 'd
我是一名优秀的程序员,十分优秀!