android - 使用 OpenCV 图像处理的 Project Tango 渲染问题

标签 android android-camera yuv google-project-tango

我在 YUV 缓冲区上进行一些处理后渲染相机图像时遇到了一个问题。

我正在使用示例video-overlay-jni-example,并在方法OnFrameAvailable中,我使用cv::Mat创建一个新的帧缓冲区...

以下是我创建新帧缓冲区的方法:

cv::Mat frame((int) yuv_height_ + (int) (yuv_height_ / 2), (int) yuv_width_, CV_8UC1, (uchar *) yuv_temp_buffer_.data());

处理后,我将frame.data复制到yuv_temp_buffer_,以便将其渲染在纹理上:memcpy(&yuv_temp_buffer_[0], frame.数据,yuv_size_);

这工作正常......

当我尝试使用我之前创建的框架执行 OpenCV 方法 findChessboardCorners... 时,问题就出现了。

findChessboardCorners 方法的执行时间约为 90 毫秒(11 fps),但是,它的渲染速度似乎较慢。 (它在屏幕上的渲染速度似乎约为 0.5 fps)。

这是OnFrameAvailable方法的代码:

void AugmentedRealityApp::OnFrameAvailable(const TangoImageBuffer* buffer) {

    if (yuv_drawable_ == NULL){
        return;
    }

    if (yuv_drawable_->GetTextureId() == 0) {
        LOGE("AugmentedRealityApp::yuv texture id not valid");
        return;
    }

    if (buffer->format != TANGO_HAL_PIXEL_FORMAT_YCrCb_420_SP) {
        LOGE("AugmentedRealityApp::yuv texture format is not supported by this app");
        return;
    }

    // The memory needs to be allocated after we get the first frame because we
    // need to know the size of the image.
    if (!is_yuv_texture_available_) {
        yuv_width_ = buffer->width;
        yuv_height_ = buffer->height;
        uv_buffer_offset_ = yuv_width_ * yuv_height_;

        yuv_size_ = yuv_width_ * yuv_height_ + yuv_width_ * yuv_height_ / 2;

        // Reserve and resize the buffer size for RGB and YUV data.
        yuv_buffer_.resize(yuv_size_);
        yuv_temp_buffer_.resize(yuv_size_);
        rgb_buffer_.resize(yuv_width_ * yuv_height_ * 3);

        AllocateTexture(yuv_drawable_->GetTextureId(), yuv_width_, yuv_height_);
        is_yuv_texture_available_ = true;
    }

    std::lock_guard<std::mutex> lock(yuv_buffer_mutex_);
    memcpy(&yuv_temp_buffer_[0], buffer->data, yuv_size_);

    ///
    cv::Mat frame((int) yuv_height_ + (int) (yuv_height_ / 2), (int) yuv_width_, CV_8UC1, (uchar *) yuv_temp_buffer_.data());

    if (!stam.isCalibrated()) {
        Profiler profiler;
        profiler.startSampling();
        stam.initFromChessboard(frame, cv::Size(9, 6), 100);
        profiler.endSampling();
        profiler.print("initFromChessboard", -1);
    }
    ///

    memcpy(&yuv_temp_buffer_[0], frame.data, yuv_size_);
    swap_buffer_signal_ = true;
}

这里是方法initFromChessBoard的代码:

bool STAM::initFromChessboard(const cv::Mat& image, const cv::Size& chessBoardSize, int squareSize)
{
    cv::Mat rvec = cv::Mat(cv::Size(3, 1), CV_64F);
    cv::Mat tvec = cv::Mat(cv::Size(3, 1), CV_64F);

    std::vector<cv::Point2d> imagePoints, imageBoardPoints;
    std::vector<cv::Point3d> boardPoints;

    for (int i = 0; i < chessBoardSize.height; i++)
    {
        for (int j = 0; j < chessBoardSize.width; j++)
        {
            boardPoints.push_back(cv::Point3d(j*squareSize, i*squareSize, 0.0));
        }
    }

    //getting only the Y channel (many of the functions like face detect and align only needs the grayscale image)
    cv::Mat gray(image.rows, image.cols, CV_8UC1);
    gray.data = image.data;

    bool found = findChessboardCorners(gray, chessBoardSize, imagePoints, cv::CALIB_CB_FAST_CHECK);

#ifdef WINDOWS_VS
    printf("Number of chessboard points: %d\n", imagePoints.size());
#elif ANDROID
    LOGE("Number of chessboard points: %d", imagePoints.size());
#endif

    for (int i = 0; i < imagePoints.size(); i++) {
        cv::circle(image, imagePoints[i], 6, cv::Scalar(149, 43, 0), -1);
    }
}

在处理 YUV 缓冲区中的某些内容以在纹理上渲染后,有人遇到同样的问题吗?

我使用其他设备而不是使用camera2 API的Tango项目进行了测试,屏幕上的渲染过程似乎与OpenCV函数过程本身的速率相同。

感谢任何帮助。

最佳答案

我有一个similar problem 。在使用复制的 yuv 缓冲区并使用 OpenCV 进行一些图像处理后,我的应用程序变慢了。我建议您使用tango_support library通过执行以下操作来访问 yuv 图像缓冲区:

在您的配置函数中:

int AugmentedRealityApp::TangoSetupConfig() {
   TangoSupport_createImageBufferManager(TANGO_HAL_PIXEL_FORMAT_YCrCb_420_SP, 1280, 720, &yuv_manager_);
}

在你的回调函数中:

void AugmentedRealityApp::OnFrameAvailable(const TangoImageBuffer* buffer) {
   TangoSupport_updateImageBuffer(yuv_manager_, buffer);
}

在渲染线程中:

void AugmentedRealityApp::Render() {
   TangoImageBuffer* yuv = new TangoImageBuffer();
   TangoSupport_getLatestImageBuffer(yuv_manager_, &yuv);
   cv::Mat yuv_frame, rgb_img, gray_img;
   yuv_frame.create(720*3/2, 1280, CV_8UC1);
   memcpy(yuv_frame.data, yuv->data, 720*3/2*1280);  // yuv image
   cv::cvtColor(yuv_frame, rgb_img, CV_YUV2RGB_NV21); // rgb image
   cvtColor(rgb_img, gray_img, CV_RGB2GRAY); // gray image
}

您可以与其他对象/线程共享 yuv_manger,以便您可以在任何地方访问 yuv 图像缓冲区。

关于android - 使用 OpenCV 图像处理的 Project Tango 渲染问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35563130/

相关文章:

android - 如何以类似于相机为 SurfaceTexture 生成帧的方式生成 YUVI420 帧到 SurfaceTexture?

android - Y'UV420p(和 Y'V12 或 YV12)到 RGB888 转换

android - 为什么在 Android 中使用 HandlerThread

android - 如何在Android中的 float 操作按钮中添加边框

android - dexguard 库无法加密类

javascript - 如何使用 JavaScript 将值从一个 HTML 页面传递到另一个页面?

android - 为什么屏幕旋转 180 度不算作配置更改?

java - 从相机捕获图像并将其显示在android的另一个 Activity 中

java - 1 :1 Aspect Ratio in CameraX

image-processing - 如何在 YUV 颜色空间中调整图像饱和度