You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV warpAffine旋转YUV420视频帧画面扭曲问题求解

问题描述

尝试使用OpenCV的warpAffine()接口,对libcamera-apps组件中libcamera-vid工具采集的视频帧执行任意角度旋转操作,经确认采集到的视频帧为YUV420 planar格式。
核心实现逻辑如下:

#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>

cv::Point2f Ycenter = cv::Point2f(width / 2.0f, height / 2.0f);
cv::Point2f UVcenter = cv::Point2f(width / 4.0f, height / 4.0f);
double rotation = 0;
cv::Mat Ytransform = cv::getRotationMatrix2D(Ycenter, rotation, 1.0);
cv::Mat UVtransform = cv::getRotationMatrix2D(UVcenter, rotation, 1.0);

int Uoffset = height*width;
int Voffset = 5*info.height*info.width/4;

cv::Size Ysize(info.height, info.width);
cv::Size UVsize(info.height / 2, info.width / 2);

for (unsigned int count = 0; ; count++)
{
    // ...
    // 等待帧到达
    // ...    
    
    // 获取存储帧的缓冲区
    uint8_t* buffer = getFrameBuffer(); 
    
    double rot = floor(count / 10);
        
    if (10*rot != rotation)
    {
        rotation = 10*rot;
        Ytransform = cv::getRotationMatrix2D(Ycenter, rotation, 1.0);
        UVtransform = cv::getRotationMatrix2D(UVcenter, rotation, 1.0);
    }

        
    cv::Mat Y(Ysize.height, Ysize.width, CV_8UC1, buffer);
    cv::Mat U(UVsize.height, UVsize.width, CV_8UC1, buffer + Uoffset);
    cv::Mat V(UVsize.height, UVsize.width, CV_8UC1, buffer + Voffset);
        

    cv::warpAffine(Y, Y, Ytransform, Ysize);
    cv::warpAffine(U, U, UVtransform, UVsize);
    cv::warpAffine(V, V, UVtransform, UVsize);

    sendFrameToEncoder(buffer); 
}

上述代码中height、width参数分别对应视频帧的原始高度与宽度。
程序运行后输出画面存在异常扭曲,仅能观察到部分内容发生旋转,整体显示效果完全不符合预期,不同旋转角度的效果如下:

  • rotation = 0时的输出效果:
    未旋转图像
  • rotation = 10时的输出效果:
    旋转10度效果
  • rotation = 20时的输出效果:
    旋转20度效果
  • rotation = 30时的输出效果:
    旋转30度效果
    运行环境:树莓派Zero W,搭载Raspberry Pi OS Bullseye系统,使用OpenCV 4.5.1版本。
故障原因

代码存在两处核心错误,直接导致画面异常:

  1. cv::Size参数顺序传反
    OpenCV中cv::Size构造函数的参数顺序为(宽度, 高度),代码中定义Ysize时传入(info.height, info.width)、定义UVsize时传入(info.height/2, info.width/2),完全颠倒了宽高值。这直接导致Y、U、V三个平面的Mat对象内存步长计算错误,像素地址映射完全错位,哪怕旋转角度为0,画面也会出现扭曲。
  2. warpAffine非法原地操作
    cv::warpAffine不支持输入、输出指向同一块内存的原地运算。仿射变换过程中需要读取原始帧的完整像素数据计算目标像素位置,直接把输出写回原始Mat,会提前覆盖还未参与采样计算的原始像素,最终导致变换结果错乱,旋转角度越大,扭曲现象越明显。
修复方案
  • 修正尺寸定义,保证宽高参数顺序正确:
    cv::Size Ysize(info.width, info.height);
    cv::Size UVsize(info.width / 2, info.height / 2);
    // 中心坐标直接对应平面尺寸计算,避免硬编码出错
    cv::Point2f Ycenter = cv::Point2f(Ysize.width / 2.0f, Ysize.height / 2.0f);
    cv::Point2f UVcenter = cv::Point2f(UVsize.width / 2.0f, UVsize.height / 2.0f);
    
  • 为warpAffine准备独立的输出内存,不要直接在原始帧缓冲区上写入变换结果,变换完成后再将结果拷贝到待编码的缓冲区,保证运算过程中原始像素不会被提前覆盖。

内容的提问来源于stack exchange,提问作者mandeala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 17:25:04