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 中找到的
但这并不能解决问题
您的帧为 2457600 字节,像素尺寸为 1280x960,因此您有:
\nbits per pixel = 2457600 * 8 / (1280 * 960) = 16\n
Run Code Online (Sandbox Code Playgroud)\n您可以获得支持使用的像素格式列表ffmpeg
:
ffmpeg -pix_fmts 2> /dev/null\n
Run Code Online (Sandbox Code Playgroud)\n样本输出
\nFLAGS 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)\nY
这意味着您可以获得包含,U
并且每个像素 16 位的像素格式列表,V
如下所示:
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
图像的组成部分 - 以格式命名每个结果,以便您可以识别哪个是哪个:
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
是你的图像,所以这意味着你可以用以下方法提取它:
ffmpeg -y -s:v 1280x960 -pix_fmt yuyv422 -i frame.raw result.jpg\n
Run Code Online (Sandbox Code Playgroud)\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如果您不喜欢/不使用 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)\nffmpeg
在做、Python和版本方面有很多乐趣之后C
,我想我应该尝试在 shell 中进行操作 - 将字节转换为行,这样我就可以选择替代行而不是替代字节。这与上面的工作原理相同:
#!/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第 1 步:获取平均色偏
\nmagick result.jpg -resize 1x1\\! cast.png\n
Run Code Online (Sandbox Code Playgroud)\n\n第 2 步:反转演员表
\nmagick cast.png -modulate 100,100,0 correction.png\n
Run Code Online (Sandbox Code Playgroud)\n\n第 3 步:将原始图像与修正图像混合并可能提亮
\nmagick 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