如何将原始 YUV 图像转换为 jpg

std*_*err 4 linux camera image yuv type-conversion

v4l2-ctl我有一张在相机设置后拍摄的原始图像,如下所示:

# media-ctl -d /dev/media0 -l "'rzg2l_csi2 10830400.csi2':1 -> 'CRU output':0 [1]"
# media-ctl -d /dev/media0 -V "'rzg2l_csi2 10830400.csi2':1 [fmt:UYVY8_2X8/1280x960 field:none]"
# media-ctl -d /dev/media0 -V "'ov5645 0-003c':0 [fmt:UYVY8_2X8/1280x960 field:none]"
Run Code Online (Sandbox Code Playgroud)

然后这张照片就被拍下来了:

# v4l2-ctl --device /dev/video0 --stream-mmap --stream-to=frame.raw --stream-count=1
Run Code Online (Sandbox Code Playgroud)

现在我尝试了多种方法将其转换为 jpeg 但似乎没有产生预期的输出

原始文件可以在这里下载:https://drive.google.com/file/d/1VqXnrJDYbzdtSsWfTlm2mX9rl1-Rl_7F/view ?usp=sharing

我尝试了以下命令:

convert -verbose -size 1280x960 UYVY:frame.raw frame.bmp
Run Code Online (Sandbox Code Playgroud)

在使用 imagemagick 从 YUV(UYVY) 转换为 RGB 中找到的

但这并不能解决问题

Mar*_*ell 5

您的帧为 2457600 字节,像素尺寸为 1280x960,因此您有:

\n
bits per pixel = 2457600 * 8 / (1280 * 960) = 16\n
Run Code Online (Sandbox Code Playgroud)\n

您可以获得支持使用的像素格式列表ffmpeg

\n
ffmpeg -pix_fmts 2> /dev/null\n
Run Code Online (Sandbox Code Playgroud)\n

样本输出

\n
FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL\n-----\nIO... yuv420p                3            12\nIO... yuyv422                3            16\nIO... rgb24                  3            24\nIO... bgr24                  3            24\nIO... yuv422p                3            16\nIO... yuv444p                3            24\nIO... yuv410p                3             9\n...\n...\n
Run Code Online (Sandbox Code Playgroud)\n

Y这意味着您可以获得包含,U并且每个像素 16 位的像素格式列表,V如下所示:

\n
ffmpeg -pix_fmts 2> /dev/null | awk \'/y/ && /u/ && /16$/ {print}\'  \n\nIO... yuyv422                3            16\nIO... yuv422p                3            16\nIO... yuvj422p               3            16\nIO... uyvy422                3            16\nIO... yuv440p                3            16\nIO... yuvj440p               3            16\nIO... yvyu422                3            16\n
Run Code Online (Sandbox Code Playgroud)\n

现在您可以运行一个循环,迭代所有 16 位每像素 YUV 格式,并查看ffmpeg图像的组成部分 - 以格式命名每个结果,以便您可以识别哪个是哪个:

\n
ffmpeg -pix_fmts 2> /dev/null | \n   awk \'/y/ && /u/ && /16$/ {print $2}\' | \n      while read f; do \n         ffmpeg -y -s:v 1280x960 -pix_fmt $f -i frame.raw $f.jpg\n      done\n
Run Code Online (Sandbox Code Playgroud)\n

这会给你这些文件:

\n
-rw-r--r--  1 mark  staff  304916  3 Feb 09:38 yuv440p.jpg\n-rw-r--r--  1 mark  staff  227123  3 Feb 09:38 yuvj422p.jpg\n-rw-r--r--  1 mark  staff   39543  3 Feb 09:38 yuyv422.jpg\n-rw-r--r--  1 mark  staff   39545  3 Feb 09:38 yvyu422.jpg\n
Run Code Online (Sandbox Code Playgroud)\n

我猜那yuyv422.jpg是你的图像,所以这意味着你可以用以下方法提取它:

\n
ffmpeg -y -s:v 1280x960 -pix_fmt yuyv422 -i frame.raw result.jpg\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n
\n

如果你想用ImageMagick做到这一点,你可以这样做:

\n
#!/bin/bash\n\npython3 <<EOF\nimport numpy as np\nh, w = 960, 1280\n\n#\xc2\xa0Load raw file into Numpy array\nraw = np.fromfile(\'frame.raw\', np.uint8)\nraw[0::2].tofile(\'Y\')     # Starting at the 1st byte, write every 2nd byte to file "Y"\nraw[1::4].tofile(\'U\')     # Starting at the 2nd byte, write every 4th byte to file "U"\nraw[3::4].tofile(\'V\')     # Starting at the 3rd byte, write every 4th byte to file "V"\nEOF\n\n# Load the Y channel, then the U and V channels forcibly resizing them, then combine and go to sRGB\nmagick -depth 8 -size 1280x960 gray:Y \\\n  \\( -size 640x960 gray:U gray:V -resize 1280x960\\! \\) \\\n  -set colorspace YUV -combine -colorspace sRGB result.jpg\n
Run Code Online (Sandbox Code Playgroud)\n
\n

如果您不喜欢/不使用 Python,则该部分可以用一些基本的 C 替换,如下所示:

\n
#include <stdint.h>\n#include <stdio.h>\n\n// Split YUYV file called "frame.raw" into separate channels with filenames "Y", "U" and "V"\n// Compile with: clang -O3 splitter.c -o splitter\n\nint main(){\n\n   FILE    *in, *Y, *U, *V;\n   uint8_t buffer[4];\n   size_t  bytesRead;\n\n   // Open input file and 1 output file per channel\n   in = fopen("frame.raw", "rb");   \n   Y  = fopen("Y", "wb");   \n   U  = fopen("U", "wb");   \n   V  = fopen("V", "wb");   \n\n   // read up to sizeof(buffer) bytes\n   while ((bytesRead = fread(buffer, 1, sizeof(buffer), in)) > 0)\n   {\n      fputc(buffer[0], Y);\n      fputc(buffer[1], U);\n      fputc(buffer[2], Y);\n      fputc(buffer[3], V);\n   }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

ffmpeg在做、Python和版本方面有很多乐趣之后C,我想我应该尝试在 shell 中进行操作 - 将字节转换为行,这样我就可以选择替代行而不是替代字节。这与上面的工作原理相同:

\n
#!/bin/bash\n\n# Build JPEG image from YUYV image with packed bytes in order YUYVYUYV...\n# Use "xxd" to convert bytes into lines, then extract alternate lines - which is easier than extracting bytes\n\nH=960\nW=1280\nINPUT="frame.raw"\n\n# Take top byte of every uint16 and put into "Y.pgm"\nxxd -c1 -p "$INPUT" | sed -n \'p;n\' | xxd -r -p | magick -size ${W}x${H} -depth 8 gray:- Y.pgm\n\n# Take bottom byte of every 2nd uint16, starting at the 1st, resize up to full width and put into "U.pgm"\nxxd -c1 -p "$INPUT" | sed -n \'n;p\' | sed -n \'p;n\' | xxd -r -p | magick -size $((W/2))x${H} -depth 8 gray:- -resize ${W}x${H}\\! U.pgm\n\n# Take bottom byte of every 2nd uint16, starting at the 2nd, resize up to full width and put into "V.pgm"\nxxd -c1 -p "$INPUT" | sed -n \'n;p\' | sed -n \'n;p\' | xxd -r -p | magick -size $((W/2))x${H} -depth 8 gray:- -resize ${W}x${H}\\! V.pgm\n\n# Load the 3 channels, combine and convert to JPEG\nmagick {Y,U,V}.pgm -set colorspace YUV -combine -colorspace sRGB result.jpg\n\n#\xc2\xa0Remove litter\nrm {Y,U,V}.pgm\n
Run Code Online (Sandbox Code Playgroud)\n
\n

至于色偏消除,正如我在评论中所说,“正常”方式,据我所知,是获取图像的平均颜色并反转其色调,然后将“否定色偏”与原始图像混合回以抵消原始图像偏色。这是一个粗略的尝试 - 如果有人知道更好,请告诉我!

\n

第 1 步:获取平均色偏

\n
magick result.jpg -resize 1x1\\! cast.png\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

第 2 步:反转演员表

\n
magick cast.png -modulate 100,100,0 correction.png\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

第 3 步:将原始图像与修正图像混合并可能提亮

\n
magick result.jpg correction.png -define compose:args=50,50 -compose blend -composite -auto-level result.jpg\n
Run Code Online (Sandbox Code Playgroud)\n

以下是原始版本和更正版本:

\n

在此输入图像描述

\n

显然,您可以更改不同程度的“校正”的百分比。

\n