参考:
图像采集的过程为:光照在成像物体被反射 -> 镜头汇聚 -> Sensor光电转换-> ADC转换为rawRGB。
因为sensor上每个像素只采集特定颜色的光的强度,因此sensor每个像素只能为R或G或B,形成的数据就成为了rawRGB数据。
rawRGB数据是sensor的经过光电转换后通过ADC采样后直接输出数据,是未经处理过的数据,表示sensor接受到的各种光的强度。
Raw数据在输出的时候是有一定的顺序的,一般为以下四种: 00:GR/BG 01: RG/GB 10: BG/GR 11: GB/RG
为什么每种情况里有两个G分量呢?这时因为人的眼睛对绿色比较敏感,所以增加了对绿色的采样。其中每个分量代表一个piexl。所以GR/BG就代表四个piexl,在物理sensor上就表示4个晶体管,用一个晶体管只采样一个颜色分量,然后通过插值计算得到每个piexl,这样做的主要目的是降低功耗。
假设一个sensor的像素是88(分辨率为88),那么这个sensor就有8*8个感光点,每个感光点就是一个晶体管。那么对于上表中四种排列格式的rawRGB数据如下图所示:
由上图可以看出,每一种格式的rawRGB数据的G分量都是B、R分量的两倍,是因为人眼对于绿色的更加敏感,所以加重了其在感光点的权重,增加了对绿色信息的采样。
那么,这里还有一个问题:在rawRGB数据中,每个像素只有R、G、B颜色三分量中一个分量,那么这一个分量用多少bit来表示呢?答案如下表:
之所以有个rawRGB这种格式的数据,这样做的目的一般是为了降低感光器件的物理工艺难度,然后通过ISP处理还原出更真实的图像信息。
sensor输出的数据一般要送到ISP中处理才会得到一个好的效果,这就需要ISP知道sensor输出的raw数据的顺序与大小,其中顺序一般通过配置ISP的pattern寄存器来实现,大小一般配置在ISP的输入格式控制寄存器中。
raw数据几种常用的格式:
RAW8: Raw8即是用8bits表示G/R/B/G中的一个分量,而不是使用8bits表示RG/GB四个分量。在sensor中,为了降低功耗,使用一个晶体来表示一种颜色,然后利用差值计算出相邻像素的值。
Raw10: Raw10就是使用10bit表示上述的一个G/R/B/G,但是数据中是16bit的,高6位没用。
Raw12: Raw12: 就是使用12bit表示上述的一个G/R/B/G,但是数据中是16bit的,高4位没用
看raw数据的工具:picasa、irfanview、photoshop
在数字化的时代,需要一种标准来量化自然界的各种颜色。RGB就是一种在数字化领域表示颜色的标准,也称作一种色彩空间,通过用三原色R、G、B的不同的亮度值组合来表示某一种具体的颜色。注意,RGB里面存的是颜色的亮度值,而不是色度值。
在实际应用中,RGB存在着许多的格式,之所以存在着这些格式,是因为随着技术的进步,系统的更迭,不同的应用场景和设备环境,对颜色表达的需求是不同的。
常用的RGB格式如下表所示:
格式 | 描述 |
---|---|
RGB565 | 每个像素用16位表示,RGB分量分别使用5位、6位、5位。 内存中排列(高字节->低字节):R R R R R G G G G G G B B B B B |
RGB555 | 每个像素用16位表示,RGB分量都使用5位(剩下1位不用) 内存中排列(高字节->低字节):X R R R R G G G G G B B B B B(X表示不用,可以忽略) |
RGB24(RGB888) | 每个像素用24位表示,RGB分量各使用8位。 内存中排列(高字节->低字节):B B B B B B B B G G G G G G G G R R R R R R R R |
RGB32 | 每个像素用32位表示,RGB分量各使用8位(剩下8位不用) 内存中排列(高字节->低字节):B B B B B B B B G G G G G G G G R R R R R R R R X X X X X X X X (X表示不用,可以忽略) |
ARGB32 | 每个像素用32位表示,RGB分量各使用8位(剩下的8位用于表示Alpha通道值) 内存中排列(高字节->低字节):B B B B B B B B G G G G G G G G R R R R R R R R A A A A A A A A |
YUV是一种色彩编码方法,Y表示亮度,U和V表示色度。只有Y就是黑白图像,再加上UV就是彩色图像了。YUV的一个好处就是让彩色系统和传统黑白系统很好的兼容,同时利用了人类视觉系统对亮度的敏感度比对色度高。
在一般应用中,人们所说的YUV就是YCbCr,这我认为是从狭义的角度理解(毕竟现在是数字信号的天下,YCbCr恰好是描述数字信号的)。广义上说,YUV是一种色彩空间分类,一种颜色模型,具体的类型有Y’UV, YUV, YCbCr,YPbPr等,目前市场上常用数字的视频信号和视频/图片文件中的编码格式,用YCbCr来描述,于是人们口中的YUV就代指的是YCbCr,常见应用如H.264/H.265码流、MPEG、JPEG等。
YCbCr中的Cb指蓝色色度分量,而Cr指红色色度分量。
YUV和RGB的相同点:都是用来表达颜色的数学方法;
YUV和RGB的相同点:对颜色的描述思路和方法不同。RGB将一个颜色拆解为3个纯色的亮度组合,YUV将一个颜色分解为一个亮度和2个色度的组合。
那引入YUV这种色彩空间的好处具体有啥呢?
(1)YUV提取Y亮度信号,可以直接给黑白电视使用,兼容黑白电视
(2)人眼对UV的敏感性小于亮度,这样我们适当减少uv的量,而不影响人的感官。所以才会有多种格式的 YUV描述,如420、422、444。
(3)伴随显示设备分辨率的提升,bt组织也针对yuv2rgb设定了不同的系数,来最好的从YUV转换到RGB。
(4)YUV格式可以比RGB格式储存空间小。
那RGB存在的作用是什么呢?
目前人类发明的所有彩色的输入输出设备,本质上都只支持RGB数据。哪怕设备允许YUV的输入输出,那也是经过内部的数据转换而间接支持。
(1)YUV 4:4:4 采样
全采样,对每个像素点的的YUV分量都进行采样,这样的三个分量信息量完整。
(2)YUV 4:2:2 采样
部分采样,可节省1/3存储空间和1/3的数据传输量。UV分量是Y分量采样的一半,Y分量和UV 分量按照2 : 1的比例采样。如果水平方向有10个像素点,那么采样了10个Y分量,而只采样了5个UV分量。其中,每采样过一个像素点,都会采样其Y分量,而U、V分量就会间隔一个采集一个。
(3)YUV 4:2:0 采样
部分采样,可节省1/2存储空间和1/2的数据传输量。YUV 420采样,并不是指只采样U分量而不采样V分量。而是指,在每一行扫描时,只扫描一种色度分量(U或者V),和Y分量按照2 : 1的方式采样。比如,第一行扫描时,YU 按照 2 : 1的方式采样,那么第二行扫描时,YV分量按照 2:1的方式采样。对于每个色度分量来说,它的水平方向和竖直方向的采样和Y分量相比都是2:1 。
YUV存储格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开放 YUV 三个分量,就像是一个三维平面一样。
(1) YUV422 Planar (YUV422P,也称为I422格式)
这里,Y\U\V数据是分开存放的,每两个水平Y采样点,有一个U和一个V采样点,如下图:
也就是说,U0V0由Y0、Y1共用,这样整幅图像较RGB就减少了1/3的存储空间。
YUV 422P 格式,又叫做 I422格式,采用的是平面格式进行存储,先存储所有的 Y 分量,再存储所有的 U 分量,再存储所有的 V 分量。
假如一个8*2像素的图像的该格式的存储分布如下图:
(2) YUV422 packed
此格式有两种情况:分为YUYV格式和UYVY格式。
YUYV格式:
YUYV 格式是采用打包格式进行存储的,指每个像素点都采用 Y 分量,但是每隔一个像素采样它的UV分量。
假如一个8*2像素的图像的该格式的存储分布如下图:
UYVY格式:
UYVY 格式也是采用打包格式进行存储,它的顺序和YUYV相反,先采用U分量再采样Y分量。
假如一个8*2像素的图像的该格式的存储分布如下图:
(3) YUV420 Planar (YUV420P)
这个格式跟YUV422 Planar 类似,但对于U和V的采样在水平和垂直方向都减少为2:1,根据采样规则如下图:
也就是说,U0V0由Y0、Y1、YW、YW+1共用,这样整幅图像较RGB就减少了1/2的存储空间。
YU12和YV12格式都属于YUV 420P类型,即先存储Y分量,再存储U、V 分量,区别在于:YU12是先Y再U后V,而YV12是先Y再V后U 。
YU12格式(也称为I420格式)
YU12是先Y再U后V。
假如一个8*2像素的图像的该格式的存储分布如下图:
YV12格式
YV12是先Y再V后U
假如一个8*2像素的图像的该格式的存储分布如下图:
(4) YUV422 Semi-Planar (YUV422SP)
Semi 是“半”的意思,个人理解这个是半平面模式,这个格式的数据量跟YUV422 Planar的一样,但是U、V是交叉存放的。
假如一个8*2像素的图像的该格式的存储分布如下图:
(5) YUV420 Semi-Planar (YUV420SP)
这个格式的数据量跟YUV420 Planar的一样,但是U、V是交叉存放的。
NV12和NV21格式都属于 YUV420SP 类型。它也是先存储了Y分量,但接下来并不是再存储所有的U或者V分量,而是把UV分量交替连续存储。
NV12
NV12是IOS中有的模式,它的存储顺序是先存Y分量,再UV进行交替存储。
假如一个8*2像素的图像的该格式的存储分布如下图:
NV21
NV21是安卓中有的模式,它的存储顺序是先存Y分量,在VU交替存储。
假如一个8*2像素的图像的该格式的存储分布如下图:
由于YUV有这数字信号和模拟信号的YUV类型,于是RGB与YUV转换方式多种多样,大致分为模拟和数字两种。每种方式下,不同的清晰度视频信号的转换公式也是有所不同。
这里仅仅列出数字YUV(YCbCr)与数字RGB相互转换的BT601(标清国际定义)的转换公式:
“汽车芯片”(FuSa,Security)与“人身安全”密切相关
汽车芯片,有明显的领域应用特色,有门槛要求。
像手机、消费品芯片强行进入该行业,要持有谨慎态度。
从“参数内卷(Parametric In-Roll)”(智能驾驶——高精度地图、激光雷达、高算力芯片)向“落地/注重体验”转变
从“感知(Perception)”到“认知(Cognition)”,感知足够,认知还不成。
终究,美梦还是会屈从于现实。
从“简单”(卡车、巴士、物流)向“复杂”(自动驾驶)的发展路线,不会被颠覆
总想背离基本的逻辑,却被时间教训的服服帖帖。
目前看,发展趋势
功能合并-》域控-》自动驾驶,趋势不可避免。
汽车应用——
座舱 —— Renesas-Gen3、Gen3e
智驾 —— Renesas-V4H
网联 —— Renesas-S4
在/sys/devices/platform/6b030000.esdhc/mmc_host/mmc0/mmc0:0001/目录下可以读取到cid、csd、dsr、ocr、寄存器的值.
# mount -t debugfs none /sys/kernel/debug/
@xxx:/sys/kernel/debug/mmc0 # cat ios
@xxx:/sys/kernel/debug/mmc0/mmc0:0001 # cat ext_csd
00000000000000000000000000000000390300c0470700c04707000000000000000101000000000000000000000000000000000000000000000000000a000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000900e00070100000000151f20000000000000000000000000000000010100090000000008000200571f0a0aeeee8888001e0f460f78140100c0470710140a0a090201320808400007fdfb550100640aeeeeee99011e0200000000320a00100000ee01000000000000000000012020010100000000000000000000000000000000000000000000000000000000000000000000000000001f0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ffffffff00000103007f0003013f3f01010100000000000000
当然这样看很难看,无法很快的确认寄存器中某些位的值。因此,网上就有个小哥写了个python脚本来解析这512字节的数据,以常人可以理解的格式进行解析。详见:https://blog.kylemanna.com/linux/parse-emmc-extended-csd-ecsd-registers-with-python/ 输出的格式如下:
victor @victor-HP:~/ work2/cal_time$ python analysis_ext_csd.py
0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0016: 39 03 00 c0 47 07 00 c0 47 07 00 00 00 00 00 00
0032: 00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00
0048: 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 01
0064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0096: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0112: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0128: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
0144: 00 00 00 00 00 00 00 00 00 00 00 00 00 90 0e 00
0160: 07 01 00 00 00 00 15 1f 20 00 00 00 00 00 00 00
0176: 00 00 00 00 00 00 00 00 01 01 00 09 00 00 00 00
0192: 08 00 02 00 57 1f 0a 0a ee ee 88 88 00 1e 0f 46
0208: 0f 78 14 01 00 c0 47 07 10 14 0a 0a 09 02 01 32
0224: 08 08 40 00 07 fd fb 55 01 00 64 0a ee ee ee 99
0240: 01 1e 02 00 00 00 00 32 0a 00 10 00 00 ee 01 00
0256: 00 00 00 00 00 00 00 00 01 20 20 01 01 00 00 00
0272: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0304: 00 00 00 1f 01 00 00 00 00 00 00 00 00 00 00 00
0320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0352: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0368: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0416: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0432: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0464: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0480: 00 00 00 00 00 00 01 ff ff ff ff 00 00 01 03 00
0496: 7f 00 03 01 3f 3f 01 01 01 00 00 00 00 00 00 00
BOOT_SIZE_MULTI[226] = 0x20
Python内容如下:
#!/usr/bin/env python
"""
Author: Kyle Manna <kyle@kylemanna.com>
Blog: https://blog.kylemanna.com
"""
import binascii
import re
import sys
def str2bytearray(s):
if len(s) % 2:
s = '0' + s
reorder = True
if reorder:
r = []
i = 1
while i <= len(s):
r.append(s[len(s) - i - 1])
r.append(s[len(s) - i])
i += 2
s = ''.join(r)
out = binascii.unhexlify(s)
return out
if __name__ == '__main__':
ecsd_str = '00000000000000000000000000000000390300c0470700c04707000000000000000101000000000000000000000000000000000000000000000000000a000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000900e00070100000000151f20000000000000000000000000000000010100090000000008000200571f0a0aeeee8888001e0f460f78140100c0470710140a0a090201320808400007fdfb550100640aeeeeee99011e0200000000320a00100000ee01000000000000000000012020010100000000000000000000000000000000000000000000000000000000000000000000000000001f0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ffffffff00000103007f0003013f3f01010100000000000000'
#ecsd_str = '320100'
ecsd = str2bytearray(ecsd_str)
csd_len = len(ecsd)
line_len = 16
i = 0
while i < len(ecsd):
sys.stdout.write("{0:04d}:\t".format(i))
for j in range(line_len):
if (i < csd_len):
sys.stdout.write("{0:=02x}".format(ord(ecsd[csd_len-i-1])))
i = i + 1
else:
break
if (j == (line_len - 1)): pass
elif (i % 4): sys.stdout.write(" ")
else: sys.stdout.write(" ")
sys.stdout.write("\n")
print "BOOT_SIZE_MULTI[226] = 0x{:x}".format(ord(ecsd[csd_len-168-1]))
让cp显示进度的工具,拷贝文件夹也是可以的
$ wget http://ftp.gnu.org/gnu/coreutils/coreutils-9.1.tar.xz
$ tar -xf coreutils-9.1.tar.xz
$ cd coreutils-9.1/
$ curl -JLO https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-0.9-9.1.patch
$ patch -p1 -i advcpmv-0.9-9.1.patch
$ export FORCE_UNSAFE_CONFIGURE=1
$ ./configure
$ make
$ sudo cp src/cp /usr/bin/cp
$ sudo cp src/mv /usr/bin/mv
# 用的时候要切换到root模式才行
# cp -r -g /root /home/
#(显示总大小、速度、剩余时间、不显示已拷贝大小,一般速度200kb/s)
$ rsync -av --progress /mnt /home
# (显示拷贝速度、剩余时间、已拷贝大小、进度%,不显示总大小,一般速度为300kb/s)
$ cp -rv 1113 1113_cr7_2
只适用于远程两节点间拷贝
$ scp -r /mnt root@127.0.0.1:/home (拷贝文件夹要加参数 -r,拷贝文件不需要)
#(显示拷贝速度、剩余时间、已拷贝大小、进度%,不显示总大小,一般速度为10M/s)
# (显示速度、进度、不显示总大小、剩余时间、已拷贝大小,一般速度300kb-1M/s不等)
# vi cp.sh
#!/bin/bash
trap 'exit_fun' 2
usage(){
echo "Usage: `basename $0` \"src file\" \"dst file\""
exit 1
}
exit_fun(){
echo -e "\033[?25h"
kill -9 $(ps -ef|awk '/ [c]p /{print $2}') &>/dev/null
exit 1
}
[ "$#" -ne "2" ] && usage
[ -d "$2" ] && k=${2%%/}/`basename $1` || k=$2
fromsize=`ls -s $1|cut -d" " -f1`
cp $1 $k &
start=`date +%s`
sleep 0.2
echo -ne "\033[?25l"
while :;do
tosize=`ls -s $k|cut -d" " -f1`
x=`echo "$tosize $fromsize"|awk '{print int($1*100/$2)}'`
[ $x -eq 99 ] && x=100
echo -n "["
for((i=0;i<x;i=$i+2));do echo -n "=";done
echo -n ">"
for((j=i;j<=99;j=$j+2));do echo -n " ";done
now=$[`date +%s` - $start]
[ $now -eq 0 ] && now=1
avg=$[$tosize/$now]
printf "] %4s%% %4sKb/s" $i $avg
[ $x -ge 100 ] && break
sleep 0.1
echo -ne "\r"
done
echo -e "\033[?25h"
:wq
# chmod +x cp.sh
# 示例:
# ./cp.sh /mnt/a.tar.gz /home
注: 不能拷贝文件夹,只能拷贝单个文件
转自
串行器 | 解串器 | ||
---|---|---|---|
GMSL1 | MAX96701/MAX96715 | MAX9286 | |
12bit DVP IN 1 SIO OUT@1.76Gbps | 4IN 1OUT@MIPI 1.5Gbps | ||
GMSL1/2 兼容 | MAX9295A | MAX9296 | MAX96722 |
4-MIPI IN 1 SIO OUT@6Gbps | 2IN 2OUT@MIPI 2.5Gbps | 4IN 1OUT@MIPI 2.5Gbps | |
GMSL2 | MAX96717/MAX96717F | MAX96712 | |
4-MIPI IN 1 SIO OUT@6Gbps/3Gbps | 4IN 1OUT@MIPI 2.5Gbps |
** GMSL的通信机理 **
(以下信息可以参考Serializer的手册,比如,MAX96705)
图像传感器Image Sensor将捕获的光信号转为数字信号,经CSI2协议传输给串行器(MAX9295A), 传输内容包括:图像数据信息,像素时钟,行同步信号,帧同步信号,其中raw12表示摄像头的传输数据格式为原始数据raw格式,每个像素点有12bit数据,30fps表示每秒发送30张图像
串行器接收到数据信息后,对信息进行串行化处理,将数据整理成包的形式,然后通过同轴电缆,将包以串行的形式发送出去,我们注意到在通过同轴电缆时,有两个方向的数据流传输,其中一个是前向通道,用于发送摄像头捕捉的图像数据,其带宽为6Gbps,还有一个为回馈通道,用以接收应答信息,带宽为187Mbps,这两个通道的传输速率是不一样的,可以根据实际需要进行设定,这也是GMSL的一大特色
之后解串器会接收到串行器串行化的数据,对数据再进行解串,使数据回复至原来模样,然后将原始数据传给FPGA,这个一个定制电路板,一般图像处理器ISP模块会集成到里面,原始数据其实就是发送给了FPGA里面的ISP模块,在它里面对数据进行一些算法处理,最终输出RGB或者YUV格式
图中是将处理好的数据发送给了LCD(液晶显示器),但在自动驾驶中,这个地方就会有些差异,ISP会将处理好的图像数据发送给FPGA里的AI芯片,通过卷积神经网络(CNN)对图像进行分类,检测,跟踪等等,然后根据实际情况,指挥FPGA中的MCU对底盘进行控制,以达到自动驾驶的目的