使用GL着色器语言的相机帧yuv到rgb转换

2024-01-31

我从字节数组中的 android 相机预览回调获取相机帧并将其传递给 jni 代码。由于我们不能在 C++ 中使用字节,因此我将其转换为整数数组,如下所示:

    JNIEXPORT void JNICALL Java_com_omobio_armadillo_Armadillo_onAndroidCameraFrameNative(
            JNIEnv* env, jobject, jbyteArray data, jint dataLen, jint width,
            jint height, jint bitsPerComponent) {
        Armadillo *armadillo = Armadillo::singleton();

        jbyte *jArr = env->GetByteArrayElements(data, NULL);
        int dataChar[dataLen];
        for (int i = 0; i < dataLen; i++) {
            dataChar[i] = (int) jArr[i];
    }

然后我将其传递给图像以创建纹理,如下所示:

 void AppClass::drawAndroidCameraFrame() {

CCLOG("drawAndroidCameraFrame");
int nextBufferIndex = !_bufferIndex;
if (mIsNewFrameReceived) {
    mIsNewFrameReceived = false;
    return;
}
CCLOG("drawAndroidCameraFrame - creating CCImage");
_image[nextBufferIndex] = new CCImage();
_image[nextBufferIndex]->initWithImageData(mFramePData, mFrameDataLen,
        mFrameFormat, mFrameWidth, mFrameHeight, mBitsPerComponent);
if (mIsNewFrameReceived) {
    CCLOG("drawAndroidCameraFrame = relasing frame image");
    _image[nextBufferIndex]->release();
    mIsNewFrameReceived = false;
    CCLOG("camera frame process cancelled 2");
    return;
}
CCLOG("drawAndroidCameraFrame - creating texture2d");
_texture[nextBufferIndex] = new CCTexture2D();
_texture[nextBufferIndex]->initWithImage(_image[nextBufferIndex]);

    if (!_videoSprite) {
    CCLOG("Creating new sprite");

    if (mIsNewFrameReceived) {
        CCLOG("drawAndroidCameraFrame - releasing image an texture");
        _image[nextBufferIndex]->release();
        _texture[nextBufferIndex]->release();
        mIsNewFrameReceived = false;
        CCLOG("camera frame process cancelled 3");
        return;
    }

    CCLOG("drawAndroidCameraFrame - creating video sprite");
    _videoSprite = new CollisionBitmapSprite();
    _videoSprite->initWithTexture(_texture[nextBufferIndex]);

    //get director
    CCDirector *director = CCDirector::sharedDirector();

    // ask director the window size
    CCSize size = director->getWinSize();
    // position the sprite on the center of the screen
    _videoSprite->setPosition(ccp(size.width/2, size.height/2));

    //get scale factor
    CCSize* imageSize = new CCSize(_image[nextBufferIndex]->getWidth(),
            _image[nextBufferIndex]->getHeight());

    CCSize scale = getCameraFrameScaleFactor(*imageSize);
    //      CCLOG ("Scale factor is x=%f and y=%f", scale.width, scale.height);

    _videoSprite->setScaleX(scale.width);
    _videoSprite->setScaleY(scale.height);

    if (mIsNewFrameReceived) {
        _image[nextBufferIndex]->release();
        _texture[nextBufferIndex]->release();
        mIsNewFrameReceived = false;
        CCLOG("camera frame process cancelled 4");
        return;
    }

    _videoSprite->setTexture(_texture[nextBufferIndex]);

                Shaders::addProgram(_videoSprite, (char *)     Shaders::textureVertShader,
    mFrameWidth, mFrameHeight);
    GLuint i =Shaders::addProgram(_videoSprite, (char *) Shaders::vertShader,
            (char *) Shaders::yuvtorgb);
        Shaders::setYuvtorgbParameters(_videoSprite,i);
    addChild(_videoSprite, -1);

} else {
    _videoSprite->setTexture(_texture[nextBufferIndex]);
}
//  CCLOG ("Armadillo::drawCameraFrame completed successfully");
//release memory
if (_image[_bufferIndex]) {
    _image[_bufferIndex]->release();
}

if (_texture[_bufferIndex]) {
    _texture[_bufferIndex]->release();
}

_bufferIndex = nextBufferIndex;

 }

由于图像采用 YUV(N21) 格式,因此我将着色器应用到帧,它可以将图像帧转换为 RGB。着色器程序如下:

片段着色器:

const char *Shaders::yuvtorgb = MULTI_LINE_STRING(
        precision highp float;
        varying vec2 v_yTexCoord;
        varying vec4 v_effectTexCoord;

        uniform sampler2D y_texture;
        uniform sampler2D u_texture;
        uniform sampler2D v_texture;

        void main()
        {
            float y = texture2D(y_texture, v_yTexCoord).r;
            float u = texture2D( u_texture, v_yTexCoord ).r;
            float v = texture2D( v_texture, v_yTexCoord ).r;


            y = 1.1643 * ( y - 0.0625 );

            u = u - 0.5;
            v = v - 0.5;

            float r = y + 1.5958 * v;
            float g = y - 0.39173 * u - 0.81290 * v;
            float b = y + 2.017 * u;

            gl_FragColor = vec4(r,g,b, 1.0);
        }
);

顶点着色器:

const char *Shaders::vertShader = MULTI_LINE_STRING(
        attribute vec4 a_position;
        attribute vec2 a_yTexCoord;
        attribute vec4 a_effectTexCoord;

        varying vec2 v_yTexCoord;
        varying vec4 v_effectTexCoord;
        uniform mat4 u_MVPMatrix;
        void main()
        {
            v_yTexCoord = a_yTexCoord;
            v_effectTexCoord = a_effectTexCoord;
            gl_Position = u_MVPMatrix * a_position;
        }
);

添加程序方法:

GLuint Shaders::addProgram(CCSprite *sprite, char *vertShader,
            char*fragShader) {
        CCGLProgram *glProgram = new CCGLProgram();
        if (!glProgram->initWithVertexShaderByteArray(vertShader, fragShader)) {
        CCLOG("Shader problem: %s\n %s \n%s", glProgram->vertexShaderLog(), glProgram->fragmentShaderLog(), glProgram->programLog());
    }

    glProgram->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
    glProgram->addAttribute(kCCAttributeNameTexCoord,
            kCCVertexAttrib_TexCoords);
    if (!glProgram->link()) {
        CCLOG(
                "Shader problem: %s\n %s \n%s",      glProgram->vertexShaderLog(), glProgram->fragmentShaderLog(), glProgram->programLog());
    }
    glProgram->updateUniforms();

    sprite->setShaderProgram(glProgram);
    return glProgram->getProgram();
}

然后我将着色器应用到帧精灵:

GLuint i =Shaders::addProgram(_videoSprite, (char *) Shaders::vertShader,
                (char *) Shaders::yuvtorgb);

我收到绿色和粉色的图像框。黑暗部分变为绿色,明亮部分显示为粉红色。

The resulting image url is as follows: enter image description here

我被她困住了,找不到任何合适的解决方案。 任何人都可以帮助解决这个问题吗?


我不确定您是否试图从相机获取 RGB 以便在手机外部使用它。但也许你可以在android中将YUV转换为RGB,然后传递RGB像素数组?

这是我用来转换为 RGB 的代码:

为了打开相机,我使用了:

try {
    camera = Camera.open();
    cameraParam = camera.getParameters();
    cameraParam.setPreviewFormat(ImageFormat.NV21);
    List<int[]> fps = cameraParam.getSupportedPreviewFpsRange();
    camera.setDisplayOrientation(90);
    camera.setParameters(cameraParam);
    cameraParam = camera.getParameters();
    camera.startPreview();

    // wait for frames to come in
    camera.setPreviewCallback(new PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            frameHeight = camera.getParameters().getPreviewSize().height;
             frameWidth = camera.getParameters().getPreviewSize().width;
             int rgb[] = new int[frameWidth * frameHeight]; // number of pixels
             // the following returns a pixel array in RGB format
             byte[] bytes = decodeYUV420SP(rgb, data, frameWidth, frameHeight);
        }
    });
} catch (Exception e) {
    Log.e("camera", "  error camera  ");
}

The decodeYUV420SP我从另一个帖子得到的,你可以找到它here http://www.akeric.com/blog/?p=1342.

这是上面帖子中的代码本身:

//  Byte decoder : ---------------------------------------------------------------------
int[] decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
    Log.e("camera", "   decodeYUV420SP  ");
    Log.e("camera", "   Clearing Sums and Pixel Arrays  ");
    sumRED = 0;
    sumGREEN = 0;
    sumBLUE = 0;
    rStandardDeviation.clear();
    gStandardDeviation.clear();
    bStandardDeviation.clear();
    // TODO Auto-generated method stub
    final int frameSize = width * height;

    for (int j = 0, yp = 0; j < height; j++) {
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (int i = 0; i < width; i++, yp++) {
            int y = (0xff & (yuv420sp[yp])) - 16;
            if (y < 0)
                y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0)
                r = 0;
            else if (r > 262143)
                r = 262143;
            if (g < 0)
                g = 0;
            else if (g > 262143)
                g = 262143;
            if (b < 0)
                b = 0;
            else if (b > 262143)
                b = 262143;

            rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

        }
    }
    return rgb;
} 

然后,一旦您通过运行读回返回 rgb 像素数组decodeYUV420SP您可以通过以下方式重建图像:

Bitmap bitmap= BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

希望能帮助到你。我的代码可能有错误,请仔细检查内容,但总的来说它对我有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用GL着色器语言的相机帧yuv到rgb转换 的相关文章

  • 简单对话框中的 ViewPager

    我想在对话框中使用 ViewPager 但失败了 这是所有代码 对话框中显示两个片段 Layouts main xml
  • 尽管已被销毁,但多次打开子活动仍会导致 InstanceCountViolation

    我正在开发一个具有较低级别活动的项目 称为RecordView显示记录详细信息 例如图像 拍摄日期和时间以及纬度 经度信息 我不是尝试操纵相机进行地理标记并访问 exif 数据 而是尝试实现一个位置侦听器来获取首次拍摄图像的位置 按下按钮时
  • 在 Android 10/Q 上运行的 Android ACTIVITY_RECOGNITION 权限 SDK 28 (SDK 29)

    我的 Android 应用程序以 SDK 28 为目标 并连接到 Google Fit 以上传数据并读取其他一些数据 该应用程序使用 HistoryAPI 读取 com google step count delta 数据 本文档声称 如果
  • 您的手机中未安装应用程序

    我在模拟器中运行该应用程序 它成功运行 并且应用程序的图标显示在模拟器菜单中 但是当我尝试从模拟器菜单再次运行该应用程序时 它不允许我从中运行并显示 Toast 您的手机中未安装应用程序 在图像中 红色圆形是我的应用程序图标 如果您有您的M
  • 支持 API 28(Android Pie) 上的 Android StrongBox 的 Android 智能手机列表

    我需要 Android 9 中支持安全元件和 StrongBox 的 Android 手机列表 在哪里或如何找到该列表 我在 Samsung Galaxy S9 和 AVD Google Pixel XL API 28 上尝试了下面的代码
  • 有没有办法隐藏 TextView 中的文本?

    有没有办法隐藏 TextView 中的部分 但不是全部 文本 我尝试使用 AbsoluteSizeSpan 将大小设置为 0 但这没有任何我看到的视觉效果 你可以将大小设置为 1 但实际上你会得到凹凸不平的线条 而不是可读的文本 很可爱 但
  • 有没有办法获取 Android 扩展文件中特定文件的 Url?

    我正在构建一个 PhoneGap 应用程序 其中包含大型音频和视频文件 在 Android 中 媒体文件应位于扩展文件中 以使应用程序大小保持在 Google Play 50 MB 限制以下 我目前正在考虑两种播放视频文件的方法 将所需的视
  • 带有 ListTiles 和按钮行的 Flutter 下拉菜单

    我正在尝试构建一个自定义下拉菜单 如下所示 我已经成功地实现了ListTiles and Row of Buttons没有下拉菜单 但我不确定如何将所有内容嵌套在下拉菜单类中 这是我到目前为止所得到的 class HomePage exte
  • Android Studio:如果设置项目的背景颜色,ListView OnClick 动画将不起作用

    在我的项目中 我在 ListView 内设置了项目 由插入 ConstraintLayout 中的多个元素组成 的背景颜色 但如果背景颜色不是至少一点透明 则单击和长按的默认动画会消失 事实上 随着透明度的降低 点击元素的效果越来越不明显
  • 如何在android 4.2中显示选项菜单

    我正在尝试在我的测试应用程序中创建菜单选项 当我将清单中的主题设置为默认时 我可以看到菜单 菜单显示在顶部 如果我将清单中的主题设置为 NoTitleBar 我看不到菜单选项 我想在清单中设置主题 NoTitleBar 时获取菜单 如何修复
  • Android 拖放 ACTION_DRAG_ENDED 未触发

    我真的很花时间解决这个问题 到目前为止找不到任何有相关经验的朋友 这是我发布第一个应用程序之前的最后一个功能 所以在结局即将到来的情况下陷入困境让我发疯 如果我将对象放在可接受的区域中 我的拖放效果会非常好 但是 如果拖放到其他地方 我不会
  • 当 Android 上的脸部靠近屏幕时,以编程方式关闭屏幕

    我的应用程序是一个拨号器 当用户将手机靠近头部时 我需要关闭屏幕并防止单击控件 就像本机 Android 拨号器行为一样 我需要什么 API 级别以及如何以正确的方式做到这一点 我通过反汇编一个非常著名的 VoIP 应用程序找到了解决方案
  • 从 JSON 数组创建标记 php mySQL Google Maps v2 android

    我正在尝试从 mySQL 数据库在 Google Maps v2 上创建标记 但它不起作用 地图确实出现了 但没有标记 谁能告诉我出了什么问题以及我需要改变什么 我也尝试过让 getDouble 为 getDouble 0 和 getDou
  • 如何在应用程序中创建会话对象

    在我的应用程序中 我想创建一个用于登录和注销的会话 我不知道如何使用会话 任何人都可以通过提供一些示例来帮助我 我认为会话对象应该是在应用程序开始运行时声明和初始化的静态对象 我遇到了这个问题 并决定将我的会话对象放入 utils 类中 该
  • Gradle创建多项目Jar

    因此 从 Gradle 和 Android Studio 诞生之初起 我就一直在使用它们 然而 我发现自己用头撞墙的次数有时远远超过了它的价值 我花了一天半的时间试图解决我目前的困境 在我工作的地方 我们使用很多共享库项目 这意味着与 Gr
  • SQLiteConstraintException:错误代码19:约束失败——Android错误

    我已经看到了一些与此相关的其他问题 但没有一个答案似乎真正适用于我的代码 当我尝试插入数据库时 出现 SQLiteConstraintException 错误代码 19 约束失败 错误 这是插入操作的代码 db insert 现在返回 1
  • 如何为移动应用程序创建无密码登录

    我有兴趣在移动应用程序和 API 之间构建某种无密码登录 假设我可以控制两者 动机是必须登录对用户来说非常烦人并且存在安全风险 例如 用户将重复使用现有密码 我希望用户能够立即开始使用该应用程序 我想知道是否有一些可行的技术 例如 在移动设
  • Android 4.2以下如何设置layoutDirection为RTL

    尝试将布局元素设置为 RTL 顺序 4 2 及以上行 layoutDirection rtl 并在清单中 android supportsRtl true 工作得很好 但对于 4 2 以下则不然 解决方案有人吗 只需使用视图兼容使用 and
  • 是否可以在本机代码中读取/编辑共享首选项?

    我有一个 Android 应用程序 其中包含一个使用 NDK 执行一些代码的 C 库 在 C 库中 我想更新应用程序共享首选项 我的问题 是否可以在本机代码中读取 编辑共享首选项 您可以在本机代码中做任何您想做的事情 这只是很麻烦 您需要
  • 如何使用 javascript 迭代文件系统目录和文件?

    我正在使用 Javascript 编写一个应用程序 该应用程序将与 Phonegap 一起使用来制作 Android 应用程序 我正在使用 Phonegap File API 来读取目录和文件 相关代码如下所示 document addEv

随机推荐

  • 等待函数完成

    我有2个功能 第二个比第一个快 该函数怎么可能等待完成第一个的工作 function1 slow function2 fast JavaScript 是命令式的 单线程的 它只是works像这样 function2 不会开始直到functi
  • 从 JSON 到 NSObjects 的对象映射库

    我正在尝试构建一个解析器 objectMapper 它将为我从 REST 服务使用的 JSON 构建 Objective C 对象 我从 RestKit 中获得了一些灵感 让我的实体都包含一个 解码列表 它告诉映射器哪些 JSON 键与哪些
  • 使用 jQuery 阻止 onclick 操作

    有一些带有 onclick 事件操作的链接 a href Let s panic a a href I can t panic no more a 我需要防止事件动作在链接上执行disabled属性而不删除 onclick 操作 a dis
  • 实体框架 - 预加载两个多对多关系

    很抱歉这么长 但至少我认为我获得了所有信息以便能够理解并可能有所帮助 我想使用预加载从数据库加载数据 数据设置在五个表中 设置两个级别的 m n 关系 因此 存在三个包含数据的表 以从上到下的层次结构方式排序 CREATE TABLE db
  • 如何在 C 语言中使用文件的输入重定向? [复制]

    这个问题在这里已经有答案了 我的编码水平非常初级 C 是我一直在学习的唯一语言 我已经对文件的输入重定向进行了彻底的研究 试图弄清楚它是如何工作的 但我不明白在哪里使用该命令或到底如何使用它 我的问题是 我应该将重定向命令行到底放在程序中的
  • 如何实现 if(x >= '0' && x <= '9') 范围检查,如 MIPS 中的 isdigit ?

    我编写了以下函数来检查字符是否是数字 IsDigit tests a if a character a digit or not arguments a0 character byte return value v0 1 digit 0 n
  • 在 Visual Studio 中对控制台应用程序进行单元测试

    我在 Visual Studio 中有一个测试项目 我想用它来测试我的控制台应用程序 在同一解决方案中 我正在尝试设置使用特定参数调用控制台应用程序的测试 并将实际输出与我的预期进行比较 然后执行我通常的 Assert 语句以适当地通过 失
  • 在“选择”选项上添加 :after 元素[重复]

    这个问题在这里已经有答案了 我必须在 选择 的每个选项的右侧添加彩色边框框 我的html代码是
  • Unity & WPF - 通过属性注入将 DataContext 注入子控件

    我遵循 Jason Dollinger 的 MVVM 示例Lab49 http blog lab49 com archives 2650了解将 Unity 与 MVVM WPF 应用程序结合使用的基础知识 我按照他的基本架构构建了一个简单的
  • 正则表达式和xpath查询

    我有以下代码
  • 当混合数据类型相乘时,float 是否总是自动转换为 double?

    在Steven Prata的 C Primer Plus 一书中 有一节是关于类型转换的 其中 基本规则是 一节在规则1中指出 在 K R C 下 但在当前 C 下 float 会自动转换为 double http www 9wy net
  • bash 陷阱后恢复

    I ve a bash script with some file manipulations and I would like to process a loop until the end of the block after pres
  • Spark 中的潜在狄利克雷分配 (LDA) - 复制模型

    我想从 pyspark ml clustering 包中保存 LDA 模型 并在保存后将该模型应用于训练和测试数据集 然而 尽管设定了种子 结果还是存在差异 我的代码如下 1 导入包 from pyspark ml clustering i
  • 如何在钛合金中画一条线?

    如何在 Android 和 iPhone 上都适用的 Titanium 中绘制一条线 为了创建一条线 我使用 var view Ti UI createView height 180 width 300 var line Ti UI cre
  • 不可作弊的 Google Fit 计步器

    我有一个问题要向 Google Fit 咨询 我正在创建一个计步器 哦 奇怪g 到目前为止我已经做到了这一点 而且并不难 但现在我们来谈谈我的问题 我只是阅读传感器 API 的步骤 问题是 我可以通过 Google Fit 应用程序添加新数
  • Git 删除推送的提交

    我在我的项目中使用 git 存储库 我不小心推送了 2 个我不应该提交的提交 在这两者之间 有人已经承诺了这一点 是否可以删除我推送的提交 或者我必须删除我的代码更改并将其作为新提交推送 因为有人已经在其之上提交了 Git 主分支 由我提交
  • 我应该将 Google 的 JSON-LD 结构化数据放在哪里?

    我正在尝试创建谷歌的结构化数据 但不知道我在做什么 我将其设置为一个组织 然后对我的所有产品使用 SD 标记工具 我将每个 JSON LD 产品直接从标记工具与嵌套放入其自己的脚本标签中 然后我将其放入服务器上的 js 文件中 我将其与此链
  • 为什么我不能在 HTML 中使用名为“evaluate”的 JS 函数?

    我有点好奇为什么这不起作用 JavaScript function evaluate console log 42 HTML a Click Me a evaluate 是 html 一侧的保留关键字吗 document evaluate解
  • ASP.NET CodeFileBaseClass 属性与从 System.Web.UI.Page 继承

    我刚刚通过继承为我的页面创建了一个基类System Web UI Page public abstract class PageBase System Web UI Page 当我注意到您还可以在 ASP NET 视图中声明基页时 有人可以
  • 使用GL着色器语言的相机帧yuv到rgb转换

    我从字节数组中的 android 相机预览回调获取相机帧并将其传递给 jni 代码 由于我们不能在 C 中使用字节 因此我将其转换为整数数组 如下所示 JNIEXPORT void JNICALL Java com omobio armad