- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题:有谁知道如何使用 Tango Java ( Jacobi ) API onFrameAvailable()
获取 Tango 的彩色相机图像缓冲区打回来?
背景:
我有一个增强现实应用程序,可以在 Tango 的背景中显示视频。我已经使用 Java API (Jacobi) 在 this example 之后成功创建了视频叠加示例。 .我的应用程序工作正常,视频在后台正确呈现。
作为应用程序的一部分,我想在用户按下按钮时存储视频后缓冲区的副本。因此,我需要访问相机的 RGB 数据。
根据Jacobi release notes ,任何想要访问相机 RGB 数据的类都应该实现新的 onFrameAvailable()
OnTangoUpdateListener
中的方法.我这样做了,但我没有看到任何实际获取像素的句柄或参数:
Java API
@Override
public void onFrameAvailable(int cameraId) {
//Log.w(TAG, "Frame available!");
if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) {
tangoCameraPreview.onFrameAvailable();
}
}
onFrameAvailable
只有一个参数,整数指定生成 View 的相机的 id。将此与 C 库回调进行对比,后者提供对图像缓冲区的访问:
TangoErrorType TangoService_connectOnFrameAvailable(
TangoCameraId id, void* context,
void (*onFrameAvailable)(void* context, TangoCameraId id,
const TangoImageBuffer* buffer));
TangoCameraPreview
类并将图像保存在那里,但我只得到黑色背景。
public class CameraSurfaceView extends TangoCameraPreview {
private boolean takeSnapShot = false;
public void takeSnapShot() {
takeSnapShot = true;
}
/**
* Grabs a copy of the surface (which is rendering the Tango color camera)
* https://stackoverflow.com/questions/14620055/how-to-take-a-screenshot-of-androids-surface-view
*/
public void screenGrab2(){
int width = this.getWidth();
int height = this.getHeight();
long fileprefix = System.currentTimeMillis();
View v= getRootView();
v.setDrawingCacheEnabled(true);
// this is the important code :)
// Without it the view will have a dimension of 0,0 and the bitmap will be null
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, width, height);
v.buildDrawingCache(true);
Bitmap image = v.getDrawingCache();
//TODO: make seperate subdirctories for each exploitation sessions
String targetPath =Environment.getExternalStorageDirectory() + "/RavenEye/Photos/";
String imageFileName = fileprefix + ".jpg";
if(!(new File(targetPath)).exists()) {
new File(targetPath).mkdirs();
}
try {
File targetDirectory = new File(targetPath);
File photo=new File(targetDirectory, imageFileName);
FileOutputStream fos=new FileOutputStream(photo.getPath());
image.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
Log.i(this.getClass().getCanonicalName(), "Grabbed an image in target path:" + targetPath);
} catch (FileNotFoundException e) {
Log.e(CameraPreview.class.getName(),"Exception " + e);
e.printStackTrace();
} catch (IOException e) {
Log.e(CameraPreview.class.getName(),"Exception " + e);
e.printStackTrace();
}
}
/**
* Grabs a copy of the surface (which is rendering the Tango color camera)
*/
public void screenGrab(){
int width = this.getWidth();
int height = this.getHeight();
long fileprefix = System.currentTimeMillis();
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawBitmap(image, 0, 0, null);
//TODO: make seperate subdirctories for each exploitation sessions
String targetPath =Environment.getExternalStorageDirectory() + "/RavenEye/Photos/";
String imageFileName = fileprefix + ".jpg";
if(!(new File(targetPath)).exists()) {
new File(targetPath).mkdirs();
}
try {
File targetDirectory = new File(targetPath);
File photo=new File(targetDirectory, imageFileName);
FileOutputStream fos=new FileOutputStream(photo.getPath());
image.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
Log.i(this.getClass().getCanonicalName(), "Grabbed an image in target path:" + targetPath);
} catch (FileNotFoundException e) {
Log.e(CameraPreview.class.getName(),"Exception " + e);
e.printStackTrace();
} catch (IOException e) {
Log.e(CameraPreview.class.getName(),"Exception " + e);
e.printStackTrace();
}
}
@Override
public void onFrameAvailable() {
super.onFrameAvailable();
if(takeSnapShot) {
screenGrab();
takeSnapShot = false;
}
}
public CameraSurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
}
onFrameAvailable
提示外部根进程的方法,例如其中之一:
最佳答案
好的,我想出了一个让它工作的方法。
更新:我的工作解决方案在这里:
https://github.com/stevehenderson/GoogleTango_AR_VideoCapture
我基本上在渲染管道上设置了一个“中间人(渲染器)”攻击。
这种方法拦截SetRenderer
来自 TangoCameraPreview
的电话基类,并允许访问
到基础渲染器的 OnDraw()
方法和 GL 上下文。然后我向这个扩展渲染器添加额外的方法,允许读取 GL 缓冲区。
一般方法
1) 扩展TangoCameraPreview
类(例如在我的示例中 ReadableTangoCameraPreview
)。覆盖 setRenderer(GLSurfaceView.Renderer renderer)
,保留对基本渲染器的引用,并用您自己的“包装”GLSUrface.Renderer
替换渲染器渲染器,它将添加方法以将后台缓冲区渲染到设备上的图像。
2) 创建自己的GLSurfaceView.Renderer
实现所有 ScreenGrabRenderer
的接口(interface)(例如我的 GLSurfaceView.Renderer
类)方法,将它们传递给在步骤 1 中捕获的基本渲染器。此外,当您想要抓取图像时,添加一些新方法来“提示”。
3) 执行ScreenGrabRenderer
在上面的步骤 2 中描述。
4) 使用回调接口(interface)(我的 TangoCameraScreengrabCallback
)在复制图像时进行通信
它工作得很好,并且允许人们在不生根设备的情况下抓取图像中的相机位。
注:我不需要将捕获的图像与点云紧密同步。所以我没有检查延迟。为获得最佳结果,您可能需要调用 Mark 提出的 C 方法。
这是我的每个类(class)的样子..
///Main Activity Class where bulk of Tango code is
.
.
.
// Create our Preview view and set it as the content of our activity.
mTangoCameraPreview = new ReadableTangoCameraPreview(getActivity());
RelativeLayout preview = (RelativeLayout) view.findViewById(R.id.camera_preview);
preview.addView(mTangoCameraPreview);
.
.
.
//When you want to take a snapshot, call the takeSnapShotMethod()
//(you can make this respond to a button)
mTangoCameraPreview.takeSnapShot();
.
.
.
.
.
//Main Tango Listeners
@Override
public void onFrameAvailable(final int cameraId) {
// Update the UI with TangoPose information
runOnUiThread(new Runnable() {
@Override
public void run() {
if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) {
tangoCameraPreview.onFrameAvailable();
}
}
});
}
public class ReadableTangoCameraPreview extends TangoCameraPreview implements TangoCameraScreengrabCallback {
Activity mainActivity;
private static final String TAG = ReadableTangoCameraPreview.class.getSimpleName();
//An intercept renderer
ScreenGrabRenderer screenGrabRenderer;
private boolean takeSnapShot = false;
@Override
public void setRenderer(GLSurfaceView.Renderer renderer) {
//Create our "man in the middle"
screenGrabRenderer= new ScreenGrabRenderer(renderer);
//Set it's call back
screenGrabRenderer.setTangoCameraScreengrabCallback(this);
//Tell the TangoCameraPreview class to use this intermediate renderer
super.setRenderer(screenGrabRenderer);
Log.i(TAG,"Intercepted the renderer!!!");
}
/**
* Set a trigger for snapshot. Call this from main activity
* in response to a use input
*/
public void takeSnapShot() {
takeSnapShot = true;
}
@Override
public void onFrameAvailable() {
super.onFrameAvailable();
if(takeSnapShot) {
//screenGrabWithRoot();
screenGrabRenderer.grabNextScreen(0,0,this.getWidth(),this.getHeight());
takeSnapShot = false;
}
}
public ReadableTangoCameraPreview(Activity context) {
super(context);
mainActivity = context;
}
public void newPhoto(String aNewPhotoPath) {
//This gets called when a new photo was grabbed created in the renderer
Log.i(TAG,"New image available at" + aNewPhotoPath);
}
}
/**
* This is an intermediate class that intercepts all calls to the TangoCameraPreview's
* default renderer.
*
* It simply passes all render calls through to the default renderer.
*
* When required, it can also use the renderer methods to dump a copy of the frame to a bitmap
*
* @author henderso
*
*/
public class ScreenGrabRenderer implements GLSurfaceView.Renderer {
TangoCameraScreengrabCallback mTangoCameraScreengrabCallback;
GLSurfaceView.Renderer tangoCameraRenderer;
private static final String TAG = ScreenGrabRenderer.class.getSimpleName();
private String lastFileName = "unset";
boolean grabNextScreen = false;
int grabX = 0;
int grabY = 0;
int grabWidth = 640;
int grabHeight = 320;
public void setTangoCameraScreengrabCallback(TangoCameraScreengrabCallback aTangoCameraScreengrabCallback) {
mTangoCameraScreengrabCallback = aTangoCameraScreengrabCallback;
}
/**
* Cue the renderer to grab the next screen. This is a signal that will
* be detected inside the onDrawFrame() method
*
* @param b
*/
public void grabNextScreen(int x, int y, int w, int h) {
grabNextScreen = true;
grabX=x;
grabY=y;
grabWidth=w;
grabHeight=h;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
tangoCameraRenderer.onSurfaceCreated(gl, config);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
tangoCameraRenderer.onSurfaceChanged(gl, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
tangoCameraRenderer.onDrawFrame(gl);
if(grabNextScreen) {
screenGrab(gl);
grabNextScreen=false;
}
}
/**
*
* Creates a bitmap given a certain dimension and an OpenGL context
*
* This code was lifted from here:
*
* http://stackoverflow.com/questions/5514149/capture-screen-of-glsurfaceview-to-bitmap
*/
private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl)
throws OutOfMemoryError {
int bitmapBuffer[] = new int[w * h];
int bitmapSource[] = new int[w * h];
IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
intBuffer.position(0);
try {
gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
int offset1, offset2;
for (int i = 0; i < h; i++) {
offset1 = i * w;
offset2 = (h - i - 1) * w;
for (int j = 0; j < w; j++) {
int texturePixel = bitmapBuffer[offset1 + j];
int blue = (texturePixel >> 16) & 0xff;
int red = (texturePixel << 16) & 0x00ff0000;
int pixel = (texturePixel & 0xff00ff00) | red | blue;
bitmapSource[offset2 + j] = pixel;
}
}
} catch (GLException e) {
Log.e(TAG,e.toString());
return null;
}
return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
}
/**
* Writes a copy of the GLSurface backbuffer to storage
*/
private void screenGrab(GL10 gl) {
long fileprefix = System.currentTimeMillis();
String targetPath =Environment.getExternalStorageDirectory() + "/RavenEye/Photos/";
String imageFileName = fileprefix + ".png";
String fullPath = "error";
Bitmap image = createBitmapFromGLSurface(grabX,grabY,grabWidth,grabHeight,gl);
if(!(new File(targetPath)).exists()) {
new File(targetPath).mkdirs();
}
try {
File targetDirectory = new File(targetPath);
File photo=new File(targetDirectory, imageFileName);
FileOutputStream fos=new FileOutputStream(photo.getPath());
image.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
fullPath =targetPath + imageFileName;
Log.i(TAG, "Grabbed an image in target path:" + fullPath);
///Notify the outer class(es)
if(mTangoCameraScreengrabCallback != null) {
mTangoCameraScreengrabCallback.newPhoto(fullPath);
} else {
Log.i(TAG, "Callback not set properly..");
}
} catch (FileNotFoundException e) {
Log.e(TAG,"Exception " + e);
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG,"Exception " + e);
e.printStackTrace();
}
lastFileName = fullPath;
}
/**
* Constructor
* @param baseRenderer
*/
public ScreenGrabRenderer(GLSurfaceView.Renderer baseRenderer) {
tangoCameraRenderer = baseRenderer;
}
}
/*
* The TangoCameraScreengrabCallback is a generic interface that provides callback mechanism
* to an implementing activity.
*
*/
interface TangoCameraScreengrabCallback {
public void newPhoto(String aNewPhotoPath);
}
关于google-project-tango - 在 Jacobi Google Tango API 中使用 onFrameAvailable(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29189781/
我在没有 WiFi 的公司环境中运行,因此除非我将设备带回家,否则我无法获得 OTA 更新。在阅读了上个月有关 onFrameAvailable() 回调的问题后,我对暂时进行任何更新持怀疑态度。我目
我是一名中国开发者,正在读研究生。实验室有一个项目需要用到tango。谷歌关闭了tango官网,关闭了开发者社区和文档,因为我刚刚入门,对Tango开发不熟悉。这导致我们的项目中断。所以现在我需要 T
我正在寻求开发户外应用程序,但不确定 tango 平板电脑是否可以在户外使用。那里的其他深度设备往往在室外效果不佳,因为它们依赖于从设备转换的红外光,然后在它从场景中的物体反射回来后进行观察。我一直在
我有一个 Project Tango 开发工具包。我对处理来自传感器的深度数据很感兴趣。我的机器上安装了 ADB。但是 Eclipse android 模拟器没有检测到 Tango Developme
我正在开发一个测量工具,就像Measure It一样。我陷入了将深度框架与彩色相机框架对齐的困境。我能够获得点云的平均深度,但无法获得完整的深度帧。 Tango SDK有没有提供简单的方法来获取深度帧
我正在尝试构建探戈“java_basic_examples”并尝试运行“hello_area_description”、“hello_depth_perception”和“hello_motion_t
新设备几天前开箱。无法使用 OTA 升级,表示当前软件是最新的,即使不是最新的。没有当前内核,我无法下载 tango core 等。因此,该设备开箱即用,基本上没有功能(除了普通的平板电脑 :-))。
我最近在做一个关于室内导航的小型演示项目。我选择了 Unity 项目探戈,我刚买了 lenovo Phab 2 Pro。然而我刚刚发现探戈已经被谷歌抛弃了...... 所以我想知道如果我只是想开发一个
我对使用 Project Tango 平板电脑使用任意点特征进行 3D 重建很感兴趣。在当前的 SDK 版本中,我们似乎可以访问以下数据。 1280 x 720 RGB 图像。 具有 0-~10,00
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
Ptoject Tango提供了点云,如何获取点云中3D点的像素位置(以米为单位)? 我尝试使用投影矩阵,但得到的值非常小(0.5、1.3 等),而不是 1234,324(以像素为单位)。 我包含了我
昨晚拿到了我的 Tango 平板电脑,并试图通过安装所需的软件包来让它运行。更新“Project Tango Core”应用程序失败。这是我得到的错误: 有没有其他人看到这个并知道如何解决它? 以下是
问题:有谁知道如何使用 Tango Java ( Jacobi ) API onFrameAvailable() 获取 Tango 的彩色相机图像缓冲区打回来? 背景: 我有一个增强现实应用程序,可以
我正在使用 Project Tango 开发增强现实。加载 adf 文件后,我将 3d 对象放置到区域学习过程中标记的每个位置,并添加 3d 对象 我期望 3D 对象是静态的,因为这些对象使用坐标对象
我正在使用 Project Tango 创建增强现实应用程序。其中一个重要部分是准确的位置跟踪。当然,我知道没有任何惯性跟踪系统是完美的,但到目前为止,Tango 似乎工作得很好。 然而,在过去的几天
我刚刚将我的设备更新到最新的(莱布尼茨)版本,这里有一些观察/问题: 1)我的应用程序中现在有长时间(2-3s)的间歇期,姿势数据无效。我认为问题出在驱动程序中,因为该问题也出现在 Tango Exp
我们将时间戳作为姿势、图片和点数据的 double 值 - 它们并不总是对齐 - 如何计算两个时间戳之间的时间距离?是的,我知道如何减去两个 double ,但我完全不确定增量与时间的对应关系。 最佳
探戈项目是否每帧提取任何视觉特征(例如 ORB 或 SIFT/SURF)?或者整个点云只是从深度相机中提取的 3D 点。如果是这样,是否有可能知道他们使用的是哪种算法?它只是角落吗? 我想转储 3D
在 D 语言中,我如何读取所有标准输入并将其分配给一个字符串(使用 Tango 库)? 最佳答案 直接复制自 http://www.dsource.org/projects/tango/wiki/Ch
所以我知道 setSurface,并且将它用作叠加层或其他任何东西都没有问题 - 它在表面控件上。也就是说,我对获取像素数据感到困惑 1)我已经尝试了所有我能想到的(控件、根等)来使用绘图缓存功能来获
我是一名优秀的程序员,十分优秀!