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

PHP结合FFmpeg处理图像嵌入视频后颜色值偏移问题求助

问题:视频帧提取后颜色偏移的原因与解决方案

我用PHP给图像写入特定颜色,保存为无损PNG/BMP后,用FFmpeg转成带音频的MP4。但从视频提取帧读取颜色时,出现明显偏移——嵌入的颜色值为44743072,提取后变成4539914、4474121、4408072等(x从0到23,y=0)。无论使用PNG还是BMP格式,都会出现像素颜色丢失的情况。

生成视频的代码

$canvas = imagecreatefromjpeg('translate/first_frame.jpg');
// create a random color
$rand = str_pad(dechex(rand(0x000000, 0xFFFFFF)), 6, 0, STR_PAD_LEFT);
$dec_color= hexdec($rand);

// add the new color to image
for ($i=0; $i < 24; $i++) { 
   imagesetpixel($canvas,$i,0,$dec_color);
}

// store the image and close the file opened
// $filename = 'translate/test/output.png'; 
$filename = 'translate/test/output.bmp'; 

// imagepng($canvas, $filename);
imagebmp($canvas, $filename);

imagedestroy($canvas);

$frame      = $filename; // an image(png,gif,etc)
$audio      = 'translate/output/audio/abcdefghijklmnopqrstuvwxya.mp3';
$output     = 'translate/output/video/'.time().'.mp4';   

$cmd = 'ffmpeg -loop 1 -y -i '.$frame.' -i '.$audio.' -c:v libx264 -tune stillimage -c:a copy -shortest '.$output;
shell_exec($cmd);

提取帧并读取颜色的代码

if($request->hasFile('video')){
    $file = $request->file('video');
    $filename = $file->getClientOriginalName();
    $path = public_path('translate/test/');
}else{
    return 'No file uploaded';
}


if ($file->move($path, $filename)) {
    $video = 'translate/test/'.$filename;
}else{
    return 'error file upload';
}

// $output = 'translate/output/image/'.time().'.png';
$output = 'translate/output/image/'.time().'.bmp';
// $output = 'translate/output/image/'.time().'.jpg';

$cmd = 'ffmpeg -i '.$video.' -vframes 1 '.$output;
shell_exec($cmd);

// $dimg = imagecreatefrompng($output);
$dimg = imageCreateFromBmp($output);
// $dimg = imagecreatefromjpeg($output);

$extracted_color = array();

for ($x=0; $x < 24 ; $x++) { 
  $extracted_color[]= imagecolorat($dimg, $x, 0);
}

echo "<br>Retrived colors:<pre>".print_r($extracted_color,1)."</pre>";

imagedestroy($dimg);

原因分析与解决方案

核心原因

  1. libx264默认是有损编码:即使添加了-tune stillimage,默认的CRF值(质量参数)会进行有损压缩,导致像素颜色精度丢失。
  2. YUV颜色空间转换损失:H.264默认使用YUV420采样格式,这种格式会对色度通道进行下采样,导致颜色细节丢失。
  3. JPEG画布的颜色空间误差:原代码从JPEG读取画布,JPEG本身是有损压缩且基于YUV空间,转RGB时可能引入精度偏差。

具体修复步骤

  • 修改FFmpeg编码参数,强制无损:
    生成视频的命令添加-crf 0(开启H.264无损模式)和-pix_fmt yuv444p(全采样YUV,避免色度下采样):

    $cmd = 'ffmpeg -loop 1 -y -i '.$frame.' -i '.$audio.' -c:v libx264 -crf 0 -pix_fmt yuv444p -tune stillimage -c:a copy -shortest '.$output;
    

    -crf 0会让视频文件变大,但能完全保留原始图像的像素信息;-pix_fmt yuv444p确保每个像素的色度信息都被完整存储。

  • 改用RGB画布创建图像:
    避免从JPEG读取带来的颜色空间转换误差,直接创建真彩色RGB画布并复制原JPEG内容:

    // 替换原imagecreatefromjpeg的初始化代码
    $src_img = imagecreatefromjpeg('translate/first_frame.jpg');
    $width = imagesx($src_img);
    $height = imagesy($src_img);
    $canvas = imagecreatetruecolor($width, $height);
    // 复制原图像到RGB画布
    imagecopy($canvas, $src_img, 0, 0, 0, 0, $width, $height);
    imagedestroy($src_img);
    
  • 优化提取帧的FFmpeg命令:
    提取帧时指定RGB像素格式,避免FFmpeg自动转换带来的损失:

    $cmd = 'ffmpeg -i '.$video.' -vframes 1 -pix_fmt rgb24 '.$output;
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:40:26