come from : https://www.cnblogs.com/whw19818/archive/2016/08.html

ISP(Image Singal Process)算法广泛应用于安防监控,汽车电子等等一系列产品中。

ISP主要算法包括:3A---[AWB(自动白平衡),AE(自动曝光),AF(自动对焦)],CFA插值,暗角补偿,坏点检测,2D/3D去噪,锐化,VDE,Color Matrix,图片缩放,数字宽动态,伽马矫正等等一系列图像处理算法.

所有这些算法的最终目的都是使图像看上去更清晰,更好,使人们看上去有一个更好的感受。那么学习ISP算法需要哪些知识呢?其实也就是一些最基本的图像处理方面的知识,如:图像色彩空间:RGB,YUV,LAB,XYZ,HSV空间等等。在研究算法的时候,只要多动脑多查资料,相信都会有一个好的收获。

自动白平衡(auto white balance )

自动白平衡:主要解决图像偏色的问题,如果图像偏色,我们就可以用自动白平衡算法给矫正过来。

有以下几个问题要考虑:

1,我们看到的图像是否存在偏色,如果不偏色就不需要矫正,只有偏色的图片才需要矫正。

注:实际中,图像都存在偏色,只是情况不一样,有的看起来失真严重,有的看起来也还很自然。

2,对于偏色的情况我们采用什么方法来对图片进行矫正。

首先,检测偏色。这一算法,主要用到图像的一些空间变换的知识。RGB—XYZ-—Lab,对图像偏色的检测,主要在Lab空间进行。

其次,矫正。矫正最主要的就是对图像进行找白点,就是白色参考点的确认。这一过程主要用图像YCbCR空间。

如果图片不存在偏色,则对每个像素点必须满足:Cb=0,Cr=0;   但实际情况中,Cb和Cr的值是不可 能全部为零的。我们可以用一下判断条件:

(1) Y>T1(T1事先预设),|Cb|<X,|Cr|<Y;

(2)|Y-|cb|-|Cr||>T1

(3) 对图片进行分块,然后利用(1)或者(2)进行判断白点

具体算法就不一一列出了,呵呵

ISP图像处理算法之一黑电平校正

本文主要介绍ISP pipeline里边算法之一黑电平校正:

众所周知,CMOS传感器采集的信息经过一系列转换,最后生成原始RAW格式数据,RAW数据每个像素点只有一种颜色信息,只是RGB的一个,但是由于sensor对绿色光的频率基本可以全部通过,故RAW data数据里边,有两个G一个R,一个B。我们要想得到RGB数据就必须利用已有的信息来得到缺失的信息,这个处理后面专门介绍。这里接着黑电平校正说。

我们知道图像数据一般为0--255,但sensor在出厂的时候,厂家一般会设置图像数据输出范围如5-250等,反正最低电平不为零。因此我们就需要对图像数据范围进行调整,使其最小值为零,这就是黑电平校正。

黑电平校正有两种方法:一种是直接在RAW data数据上减去一个值,可以RGB减的值一样,也可以不一样,目前大多数厂家如,安霸,海思等基本都是采用这一做法。一种是利用一次函数,这个比较麻烦,就不介绍了。

PS:这个是ISP里面最简单做法,以后会详细介绍一些其他复杂的算法。

ISP图像处理算法之---Demosaic

目前市场上主流传感器为Coms传感器,sensor出来的的数据格式为bayer数据格式,这种格式,每个像素点只有三个颜色通道中的一个,如图1所示 :图1  bayer数据格式

Demosaic的目的就是有bayer数据恢复出完整的RGB数据。

方法:色差和色比,一般用色差的理论

常见算法:双线性,基于梯度,自适应,及其他一些方法,具体原理网上都能查的到,此处不一一介绍,最后贴几张自己做的一个Demosaic和常见算法的一个对比

原图

双线性插值

基于梯度插值

自适应插值

基于差值的插值方法

自己方法

ISP模块之RAW DATA去噪(一)

ISP(Image Signal Processor),图像信号处理器,主要用来对前端图像传感器输出信号处理的单元,主要用于手机,监控摄像头等设备上。

RAW DATA,可以理解为:RAW图像就是CMOS或者CCD图像感应器将捕捉到的光源信号转化为数字信号的原始数据,是无损的,包含了物体原始的颜色信息等。RAW数据格式一般采用的是Bayer排列方式,通过滤波光片,产生彩色滤波阵列(CFA),鉴于人眼对绿色波段的色彩比较敏感,Bayer数据格式中包含了50%的绿色信息,以及各25%的红色和蓝色信息。

Bayer排列格式有以下4种:

1.| R | G |   2.| B | G |    3.| G | R |    4.| G | B |

| G | B |      | G | R |       | B | G |       | R | G |

在ISP处理模块的第一部分,就是需要对CFA DATA进行去噪操作。普通的去噪方式针对Bayer数据格式是不合适的,需要进行变换后才能进行处理。

一、中值滤波CFA(Color Filter Array)Data去噪方法 

首先,让我们一起来回顾一下中值滤波的算法原理以及优缺点,然后给出示意的算法效果图。

中值滤波,顾名思义就是将滤波器里面所有像素值进行排序,然后用中间值替代当前像素点值。常用的中值滤波器有3X3,5X5等。

中值滤波的有点在于,实现简单,能够有效的消除椒盐噪声以及其他脉冲型噪声。缺点也是所有去噪算法所共有的,就是平滑模糊了图像的内容,有些角点以及边缘的信息损失。

对CFA DATA进行去噪时,需要将不同的颜色通道分开进行处理,这样是为了防止在平滑过程中将有用的颜色信息丢掉,比如说,由绿色信息包围的蓝色像素值与其相差很大时,此时就会被认为是噪声被处理掉,然而真实情况是,该区域的蓝色信息都是很大的。所以各通道单独处理的话是有利于保护颜色信息的。在我的处理过程中,是将原CFA DATA分成4块-R,G1,G2,B,分块去噪完成后再重新恢复到原来的位置,这样整个过程就完成了。

下面给出参考的中值滤波和主程序的C++(MFC)代码:

主函数:

  1. void main()
  2. {
  3. /*******开始编写中值滤波去噪模块--2015.07.27***********/
  4. //针对R分量块进行去噪
  5. pNewDoc->m_RBlock  = new unsigned short [m_Height*m_Width/4];
  6. pNewDoc->m_G1Block = new unsigned short [m_Height*m_Width/4];
  7. pNewDoc->m_G2Block = new unsigned short [m_Height*m_Width/4];
  8. pNewDoc->m_BBlock  = new unsigned short [m_Height*m_Width/4];
  9. unsigned short* smoothR  = new unsigned short[m_Height*m_Width/4];
  10. unsigned short* smoothG1 = new unsigned short[m_Height*m_Width/4];
  11. unsigned short* smoothG2 = new unsigned short[m_Height*m_Width/4];
  12. unsigned short* smoothB  = new unsigned short[m_Height*m_Width/4];
  13. for (int i = 0; i < m_Height/2 ;i ++ )
  14. {
  15. for(int j = 0; j < m_Width/2 ; j ++ )
  16. {
  17. pNewDoc->m_RBlock [i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + j*2];
  18. pNewDoc->m_G1Block[i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + j*2 + 1];
  19. pNewDoc->m_G2Block[i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + m_Width + j*2];
  20. pNewDoc->m_BBlock [i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + m_Width + j*2 + 1];
  21. }
  22. }
  23. medianFilter(pNewDoc->m_RBlock,smoothR,m_Width/2,m_Height/2);   //针对R分量块进行去噪
  24. medianFilter(pNewDoc->m_G1Block,smoothG1,m_Width/2,m_Height/2); //针对G1分量块进行去噪
  25. medianFilter(pNewDoc->m_G2Block,smoothG2,m_Width/2,m_Height/2); //针对G2分量块进行去噪
  26. medianFilter(pNewDoc->m_BBlock,smoothB,m_Width/2,m_Height/2);   //针对B分量块进行去噪
  27. //反过来构造去噪去噪后的raw data
  28. for (int i = 0; i < m_Height/2 - 1;i ++ )
  29. {
  30. for(int j = 0; j < m_Width/2-1; j ++ )
  31. {
  32. pNewDoc->m_ImageNR[i*m_Width*2 + j*2] = smoothR[i*m_Width/2 + j];
  33. pNewDoc->m_ImageNR[i*m_Width*2 + j*2 + 1] = smoothG1[i*m_Width/2 + j];
  34. pNewDoc->m_ImageNR[i*m_Width*2 + m_Width + j*2] = smoothG2[i*m_Width/2 + j];
  35. pNewDoc->m_ImageNR[i*m_Width*2 + m_Width + j*2 + 1] = smoothB[i*m_Width/2 + j];
  36. }
  37. }
  38. /***********中值滤波模块完成--2015.07.27********************/
  39. //SaveImageData(pNewDoc->m_ImageNR, m_Height ,m_Width,"E:\\m_ImageNR.bmp");
  40. SetDisplayRawImage( pNewDoc->m_ImageNR, m_Height ,m_Width, m_RawBitType,pNewDoc->m_Image);
  41. }
void main()
{/*******开始编写中值滤波去噪模块--2015.07.27***********///针对R分量块进行去噪pNewDoc->m_RBlock  = new unsigned short [m_Height*m_Width/4];pNewDoc->m_G1Block = new unsigned short [m_Height*m_Width/4];pNewDoc->m_G2Block = new unsigned short [m_Height*m_Width/4];pNewDoc->m_BBlock  = new unsigned short [m_Height*m_Width/4];unsigned short* smoothR  = new unsigned short[m_Height*m_Width/4];unsigned short* smoothG1 = new unsigned short[m_Height*m_Width/4];unsigned short* smoothG2 = new unsigned short[m_Height*m_Width/4];unsigned short* smoothB  = new unsigned short[m_Height*m_Width/4];for (int i = 0; i < m_Height/2 ;i ++ ){for(int j = 0; j < m_Width/2 ; j ++ ){pNewDoc->m_RBlock [i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + j*2];pNewDoc->m_G1Block[i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + j*2 + 1];pNewDoc->m_G2Block[i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + m_Width + j*2];pNewDoc->m_BBlock [i*m_Width/2 + j] = m_RawImage[i*m_Width*2 + m_Width + j*2 + 1];}}medianFilter(pNewDoc->m_RBlock,smoothR,m_Width/2,m_Height/2);   //针对R分量块进行去噪medianFilter(pNewDoc->m_G1Block,smoothG1,m_Width/2,m_Height/2); //针对G1分量块进行去噪medianFilter(pNewDoc->m_G2Block,smoothG2,m_Width/2,m_Height/2); //针对G2分量块进行去噪medianFilter(pNewDoc->m_BBlock,smoothB,m_Width/2,m_Height/2);   //针对B分量块进行去噪//反过来构造去噪去噪后的raw datafor (int i = 0; i < m_Height/2 - 1;i ++ ){for(int j = 0; j < m_Width/2-1; j ++ ){pNewDoc->m_ImageNR[i*m_Width*2 + j*2] = smoothR[i*m_Width/2 + j];pNewDoc->m_ImageNR[i*m_Width*2 + j*2 + 1] = smoothG1[i*m_Width/2 + j]; pNewDoc->m_ImageNR[i*m_Width*2 + m_Width + j*2] = smoothG2[i*m_Width/2 + j];pNewDoc->m_ImageNR[i*m_Width*2 + m_Width + j*2 + 1] = smoothB[i*m_Width/2 + j];}}/***********中值滤波模块完成--2015.07.27********************///SaveImageData(pNewDoc->m_ImageNR, m_Height ,m_Width,"E:\\m_ImageNR.bmp");SetDisplayRawImage( pNewDoc->m_ImageNR, m_Height ,m_Width, m_RawBitType,pNewDoc->m_Image);
}
  1. void medianFilter (unsigned short* corrupted, unsigned short* smooth, int width, int height)
  2. {
  3. memcpy ( smooth, corrupted, width*height*sizeof(unsigned short) );
  4. for (int j=1;j<height-1;j++)
  5. {
  6. for (int i=1;i<width-1;i++)
  7. {
  8. int k = 0;
  9. unsigned short window[9];
  10. for (int jj = j - 1; jj < j + 2; ++jj)
  11. for (int ii = i - 1; ii < i + 2; ++ii)
  12. window[k++] = corrupted[jj * width + ii];
  13. //   Order elements (only half of them)
  14. for (int m = 0; m < 5; ++m)
  15. {
  16. int min = m;
  17. for (int n = m + 1; n < 9; ++n)
  18. if (window[n] < window[min])
  19. min = n;
  20. //   Put found minimum element in its place
  21. unsigned short temp = window[m];
  22. window[m] = window[min];
  23. window[min] = temp;
  24. }
  25. smooth[ j*width+i ] = window[4];
  26. }
  27. }
  28. }
void medianFilter (unsigned short* corrupted, unsigned short* smooth, int width, int height)
{  memcpy ( smooth, corrupted, width*height*sizeof(unsigned short) );  for (int j=1;j<height-1;j++)  {  for (int i=1;i<width-1;i++)  {  int k = 0;  unsigned short window[9];  for (int jj = j - 1; jj < j + 2; ++jj)  for (int ii = i - 1; ii < i + 2; ++ii)  window[k++] = corrupted[jj * width + ii];  //   Order elements (only half of them)  for (int m = 0; m < 5; ++m)  {  int min = m;  for (int n = m + 1; n < 9; ++n)  if (window[n] < window[min])  min = n;  //   Put found minimum element in its place  unsigned short temp = window[m];  window[m] = window[min];  window[min] = temp;  }smooth[ j*width+i ] = window[4];  }  }
} <span style="font-family: Arial, Helvetica, sans-serif;"> </span>

中值滤波函数是在网上找的代码,由于比较基础,就直接拿过来用了,侵删去噪前后效果图:

下一篇文章,我将主要给大家展示一下BM3D算法RAW DATA去噪效果,谢谢。

ISP模块之RAW DATA去噪(二)--BM3D算法

在正式开始本篇文章之前,让我们一起回顾一下CFA图像去噪的一些基本思路与方法。接着我会详细地和大家分享自己学习理解的BM3D算法,操作过程,它的优缺点,最后会给出算法效果图供参考。

在ISP模块里,研究者们会讨论去噪模块(Noise Reduction)到底是在去马赛克模块(Demosaic)之前还是之后进行。如果在之前处理的话,随着去噪过程的进行,噪声点消除的同时,伴随着彩色信息的损失;如果在之后,复杂的插值过程将会改变噪声的统计模型,使其变得很复杂并且难以计算。所以,更多的情况是选择在Demosaic之前进行去噪操作。

CFA(Color Filter Array) Data不能采用传统的灰度图像去噪算法,因为CFA图像中相邻的像素点具有不同的颜色信息度量,CFA图像的块状结构与没有传统意义上的平滑性以及分段恒常性,以至于一般的去噪算法对CFA图像并不适用。CFA Data也不能够采用彩色图像去噪算法因为每个像素点只含有一个颜色通道的信息。

①一种方法是,将原来的CFA图像阵列分成四小块(R,G1,G2,B),分别对这四块采用灰度图像去噪的方法。这种方法往往表现差,因为重要的色彩相关性信息被忽视掉了。CFA去噪算法可以通过利用CFA Data的空间以及色彩相关性来改善其效果。

②另外一种方法是利用CFA图像里面各颜色块的信息构造一幅低分辨率的RGB图像,这种方式很好的利用了其颜色相关信息,但是不能够较好的保护空间域上的高频信息。

③BM3D(Block Matching 3-D filtering algorithm)算法的提出,通过限制图像块具有相同的颜色配置结构来达到处理CFA图像的目的。

下面是BM3D算法的详细介绍:

1.基础估计

1).逐块估计(Block-wise estimates)

分组(Grouping),找到所有与目前处理图像块相似的块,把它们堆在一起形成一个3维的数组(分组)。

联合硬阈值(Collaborative Hard-Thresholding).对已经组织好的分组进行3D变换,通过硬阈值3D变换系数达到减弱噪声的目的,然后通过3D反变换回去得到分组内图像块的去噪后估计,并返回到它们之前所在的位置。

2).聚集(Aggregation) 对所估计图像块重复遮盖的像素点进行加权平均,得到最终的像素值,也就是最后的基础估计结果。

2.最终估计

1).逐块估计(Block-wise estimates)

分组(Grouping),使用图像块匹配的方法,找到原噪声图像以及基础估计图像里面与目前处理图像块相似的所有块,形成两个3维数组(分组)。

联合维纳滤波(Collaborative wiener-filtering).对已经组织好的两个分组进行3D变换,将基础估计图像的能量频谱作为真实的能量频谱对噪声图像分组进行维纳滤波,然后通过3D反变换回去得到所有分组的图像块估计,并返回到它们之前所在的位置。

2).聚集(Aggregation)

对所有得到的估计图像块重复遮盖的像素点进行加权平均,得到最终的像素值,也就是最后的最终估计结果。

BM3D如何找到相似图像块组织3D分组:如下图所示,正方形所示为各个图像块,左上的分组所选取的图像块都具有角点(尖点)特征,其他分组类似。

BM3D如何在CFA中进行处理:如下图所示,左边的分组里面的图像块具有不同的彩色配置,即R,G,B的排列方式不是一致的,而右边具有相同的彩色配置,所以其对于处理CFA图像是非常合理的。

上面将BM3D的算法原理以及细节操作都跟大家介绍清楚了,下面就来看一下BM3D对于CFA图像的算法效果:

原噪声图像

中值滤波图像

BM3D去噪图像

算法效果(PSNR)明显优于中值滤波,去噪模块就此结束,下一篇开始给大家介绍两种色彩增强的算法。

BM3D网上有现成的Matlab代码,算法链接网址:http://www.cs.tut.fi/~foi/GCF-BM3D/

参考文献:

1).A case for denoising before demosaicking color fiter array data,Sung Hee Park etc.

2).A Framework for wavelet-based analysis and processing of color filter array images with applications to denoising and demosaicing,Hirakawa etc.Havard University.

3).Cross-color BM3D Filtering of Noise Raw Data,Aram Danielyan etc.

ISP模块之彩色图像增强--ACE算法 .

  ACE(Automatic Color Enhancement),自动色彩增强算法,是一种对于彩色图像增强十分行之有效的方法。它的改进算法以及快速实现在文章Automatic Color Enhancement (ACE) and its Fast Implementation,2012中提出。

在NxN的图像上,ACE算法的算法复杂度为O(N^4),文章提出的新的ACE算法采取了两种近似的方法,一是采用多项式函数逼近坡度函数(Slope function)降低卷积计算量,二是采用不同程度的插值来降低卷积的计算量。

ACE算法具体步骤:

第一步:分别对彩色图像的R,G,B通道进行单独处理,计算每个像素点的R(x)值,其中Sa(t)为坡度函数,表示如下,第一步适应局部图像对比,Sa(t)能够放大较小的差异,并且丰富大的差异,能够根据局部内容来扩展或者压缩动态范围:

第二步:利用下面的公式将R(x)展到[0,1]之间,得到增强后的通道,第二步获得全局白平衡。

第三步:求解最优化问题,ACE算法可以看做是对规范的直方图均衡化方法的一种平滑和局部修正的方法。

改进方法所考虑的一些因素:

1)其他的坡度函数Sa(t),多项式函数逼近

2)除了1/||x-y||外的权重函数的选择

3)在求和的过程中,y可以限制在x周围的一个小窗口中

4)L(x)的一些其他的标准化方法

实验效果:在官网上下载源代码,安装FFTW3库之后方能正常运行得到结果。该方法对于对比度低,或者有雾的图像处理后效果明显。

源代码链接网址:http://www.ipol.im/pub/art/2012/g-ace/

FFTW3库下载以及配置链接:http://bbs.csdn.net/topics/390815673

 命令行:AutoColorEnhancement -a 5 -w 1/r -m interp:12 input.bmp output.bmp

原图

ACE处理后

原图

ACE处理后

ISP模块之色彩增强算法--HSV空间Saturation通道调整 .

色彩增强不同于彩色图像增强,图像增强的一般处理方式为直方图均衡化等,目的是为了增强图像局部以及整体对比度。而色彩增强的目的是为了使的原有的不饱和的色彩信息变得饱和、丰富起来。对应于Photoshop里面的“色相/饱和度”调节选项里面对饱和度的操作。色彩增强的过程,并不改变原有彩色图像的颜色以及亮度信息。

在我的色彩增强算法模块里面,始终只针对色彩饱和度(Saturation)信息做研究,调整。这样的话,那就不得不介绍HSV颜色空间了,H代表Hue(色彩),S代表Saturation(饱和度),V代表Value,也可用B表示(Brightness,明度),HSV空间也可称作HSB空间。

HSV空间在wikipedia上的介绍,https://en.wikipedia.org/wiki/HSL_and_HSV

下面根据自己的理解介绍一下HSV空间,以及其各通道在Matlab和OpenCV中的不同。

HSV的圆柱模型

HSV的圆锥模型

从上图可以看出,在HSV空间中,Hue通道的取值从0-360°变化时,颜色从红->黄->绿->青->蓝逐步变化。Saturation从0->1变化时,色彩逐渐加深变成纯色(pure)。Value值从0->1变化时,图像整体亮度增加,V值为0时,图像为全黑,V值为1时,图像为全白

Matlab RGB色彩空间向HSV转换,采用函数rgb2hsv,转换后的hsv各通道的元素取值范围为[0,1];OpenCV中彩色图像向HSV空间中转换,cvtColor(src,srcHsv,CV_BGR2HSV),转换后H的取值范围为[0,180],S,V的取值范围为[0,255].

下面介绍自己的算法处理思路,后面会给出完整的Matlab代码:

步骤一、给出一张原图src,用PS进行饱和度(Saturation)+40处理后另存为src_40;

步骤二、将以上两张图像分别转换到hsv空间,提取出饱和度信息,分别为S,S_40;

步骤三、统计饱和度增加40后,原色彩饱和度与饱和度增量之间的对应关系,即S -- (S_40-S);

步骤四、对关系S -- (S_40-S)进行二次多项式曲线拟合,得到二次曲线f(x) = p1*x^2 + p2*x + p3;

为什么是二次?1.对应关系呈现出抛物线形状;2.更高次曲线并没有明显改善拟合性能,且计算消耗会变高。

步骤五、任意给定输出图像input,根据其色彩饱和度信息,即可进行色彩增强40处理,新的饱和度信息可以表示为S'(x) = S(x) + f(x),得到增强后的色彩信息后返回RGB图像输出;

步骤六、分别对原图+20,+40,+60后进行饱和度信息统计,并得到相应拟合参数,设置为色彩增强的低、中、高三挡,在实际处理过程中,根据输入图像input自身色彩饱和度信息(均值)自适应选取相应参数进行色彩增强;

步骤七、按需对某一单独颜色通道进行色彩增强处理,例如绿色范围为105°-135°,在对该范围进行增强的同时,还需对75°-105°,135°-165°进行一半强度的增强,这样才会保证色彩的连续性,不会出现色斑;

步骤八、按需对色彩(Hue)进行转换;

代码部分:第一部分用作估计拟合参数,在Curve fitting tool里面对X,Y进行拟合,得到曲线参数。

  1. % Color Enhancement
  2. clc,clear,close all
  3. src1 = imread('src.bmp');
  4. src2 = imread('src_40.bmp');
  5. src1_hsv = rgb2hsv(src1);
  6. src2_hsv = rgb2hsv(src2);
  7. h1 = src1_hsv(:,:,1);
  8. s1 = src1_hsv(:,:,2);
  9. v1 = src1_hsv(:,:,3);
  10. h2 = src2_hsv(:,:,1);
  11. s2 = src2_hsv(:,:,2);
  12. v2 = src2_hsv(:,:,3);
  13. %
  14. meanS1 = mean(s1(:));
  15. varS1  = std2(s1);
  16. %
  17. meanS2 = mean(s2(:));
  18. varS2  = std2(s2);
  19. %
  20. deltaS = s2 - s1;
  21. deltaV = v2 - v1;
  22. %% test1 : 观测“原饱和度-饱和度调整增量”的关系 saturation and delta saturation
  23. figure;
  24. oriS = zeros(101,2);
  25. s3 = s1;
  26. j = 1;
  27. for i = 0: 0.01 : 1
  28. oriS(j,1) = i + 0.01;
  29. oriS(j,2) =  mean(deltaS(find(s1 > i & s1< i + 0.01)));
  30. j = j + 1;
  31. end
  32. X  = oriS(:,1);
  33. Y  = oriS(:,2);
  34. XX = oriS(:,1) * 255;
  35. YY = oriS(:,2) * 255;
  36. plot(XX,YY)
% Color Enhancement
clc,clear,close all
src1 = imread('src.bmp');
src2 = imread('src_40.bmp');src1_hsv = rgb2hsv(src1);
src2_hsv = rgb2hsv(src2);h1 = src1_hsv(:,:,1);
s1 = src1_hsv(:,:,2);
v1 = src1_hsv(:,:,3);h2 = src2_hsv(:,:,1);
s2 = src2_hsv(:,:,2);
v2 = src2_hsv(:,:,3);
%
meanS1 = mean(s1(:));
varS1  = std2(s1);
%
meanS2 = mean(s2(:));
varS2  = std2(s2);
%
deltaS = s2 - s1;
deltaV = v2 - v1;%% test1 : 观测“原饱和度-饱和度调整增量”的关系 saturation and delta saturation
figure;
oriS = zeros(101,2);
s3 = s1;
j = 1;
for i = 0: 0.01 : 1oriS(j,1) = i + 0.01;oriS(j,2) =  mean(deltaS(find(s1 > i & s1< i + 0.01)));j = j + 1;
end
X  = oriS(:,1);
Y  = oriS(:,2);
XX = oriS(:,1) * 255;
YY = oriS(:,2) * 255;
plot(XX,YY)

第二部分,对输入图像进行高、中、低三级自适应增强处理

  1. %% Color Enhancement Module -- Authored by HuangDao,08/17/2015
  2. % functions: input a image of type BMP or PNG, the program will decide to
  3. % do the Color Enhancement choice for you.There are four types of Enhanced
  4. % intensity - 20,40,60,80.The larger number stands for stronger
  5. % enhancement.
  6. % And we can also choose the simple color channel(eg.R,G,B) to do the
  7. % enhancement.There are also four different types of enhanced intensity.
  8. %
  9. % parameters table
  10. %  ------------------------------------------------------------------------
  11. % | Enhanced  |     MATLAB params             |      OpenCV params         |
  12. % | intensity |p1        p2        p3         | p1        p2        p3     |
  13. % | 20        |-0.1661   0.2639    -0.003626  |-0.0006512 0.2639    -0.9246|
  14. % | 40        |-0.4025   0.6238    -0.0005937 |0.001578   0.6238    -0.1514|
  15. % | 60        |1.332     1.473     -0.01155   |-0.005222  1.473     -2.946 |
  16. % | 80        |-4.813    3.459     -0.004568  |-0.01887   3.459     -1.165 |
  17. %  ------------------------------------------------------------------------
  18. clc; clear ;close all
  19. % 载入文件夹
  20. pathName = '.\';
  21. fileType = '*.bmp';
  22. files    = dir([pathName fileType]);
  23. len      = length(files);
  24. for pic = 5%1:1:len
  25. srcName = files(pic).name;
  26. srcImg  = imread(srcName);
  27. srcHSV  = rgb2hsv(srcImg);
  28. srcH    = srcHSV(:,:,1);
  29. srcS    = srcHSV(:,:,2);
  30. srcV    = srcHSV(:,:,3);
  31. meanS   = mean(srcS(:));
  32. varS    = std2(srcS);
  33. %图像整体进行色彩增强处理
  34. if (meanS >= 0.5)
  35. p1 = 0;p2 = 0;p3 = 0;
  36. else if (meanS >= 0.35 && meanS < 0.5)
  37. p1 = -0.1661;p2 = 0.2639;p3 = -0.003626;
  38. else if (meanS >=0.2 && meanS <0.35)
  39. p1 = -0.4025;p2 = 0.6238;p3 = -0.0005937;
  40. else
  41. p1 = 1.332;p2 = 1.473;p3 = -0.01155;
  42. end
  43. end
  44. end
  45. dstS = srcS + p1*srcS.*srcS + p2*srcS + p3 ;
  46. dstHSV = srcHSV;
  47. dstHSV(:,:,2) = dstS;
  48. dstImg = hsv2rgb(dstHSV);
  49. figure;imshow(srcImg);
  50. figure;imshow(dstImg);
  51. %指定R,G,B通道进行色彩增强处理,红色范围([225-255]),绿色范围(75-[105-135]-165),蓝色范围([-15-15])
  52. p11 = -0.4025;p21 = 0.6238;p31 = -0.0005937;%周边杂色调整系数,40
  53. p12 = 1.332;  p22 = 1.473; p32 = -0.01155;  %纯色区域调整系数,60
  54. compHue = srcH;
  55. GcompS  = dstS;
  56. RcompS  = dstS;
  57. BcompS  = dstS;
  58. channel = 'B';
  59. switch channel
  60. case 'G'
  61. I1 = find(compHue > 0.2083 & compHue <0.2917);
  62. GcompS(I1) = dstS(I1) + dstS(I1).*dstS(I1)*p11 + dstS(I1)*p21 + p31;
  63. I2 = find(compHue >= 0.2917 & compHue <= 0.3750);
  64. GcompS(I2) = dstS(I2) + dstS(I2).*dstS(I2)*p12 + dstS(I2)*p22 + p32;
  65. I3 = find(compHue > 0.3750 & compHue <0.4583);
  66. GcompS(I3) = dstS(I3) + dstS(I3).*dstS(I3)*p11 + dstS(I3)*p21 + p31;
  67. compHSV = dstHSV;
  68. compHSV(:,:,2) = GcompS;
  69. dstImgG = hsv2rgb(compHSV);
  70. figure;imshow(dstImgG);
  71. case 'R'
  72. I1 = find(compHue > 0.875 & compHue <0.9583);
  73. RcompS(I1) = dstS(I1) + dstS(I1).*dstS(I1)*p11 + dstS(I1)*p21 + p31;
  74. I2 = find(compHue >= 0.9583 | compHue <= 0.0417);
  75. RcompS(I2) = dstS(I2) + dstS(I2).*dstS(I2)*p12 + dstS(I2)*p22 + p32;
  76. I3 = find(compHue > 0.0417 & compHue <0.125);
  77. RcompS(I3) = dstS(I3) + dstS(I3).*dstS(I3)*p11 + dstS(I3)*p21 + p31;
  78. compHSV = dstHSV;
  79. compHSV(:,:,2) = RcompS;
  80. dstImgR = hsv2rgb(compHSV);
  81. figure;imshow(dstImgR);
  82. case 'B'
  83. I1 = find(compHue > 0.5417 & compHue <0.625);
  84. BcompS(I1) = dstS(I1) + dstS(I1).*dstS(I1)*p11 + dstS(I1)*p21 + p31;
  85. I2 = find(compHue >= 0.625 & compHue <= 0.7083);
  86. BcompS(I2) = dstS(I2) + dstS(I2).*dstS(I2)*p12 + dstS(I2)*p22 + p32;
  87. I3 = find(compHue > 0.7083 & compHue <0.7917);
  88. BcompS(I3) = dstS(I3) + dstS(I3).*dstS(I3)*p11 + dstS(I3)*p21 + p31;
  89. compHSV = dstHSV;
  90. compHSV(:,:,2) = BcompS;
  91. dstImgB = hsv2rgb(compHSV);
  92. figure;imshow(dstImgB);
  93. end
  94. %进行R,G,B通道之间的互换
  95. convH = zeros(size(srcH,1),size(srcH,2)); %convert
  96. deltaHue = 240;
  97. switch deltaHue
  98. case 120
  99. disp('R -> G')
  100. convH = srcH + 1/3;
  101. convH(find(convH >= 1)) = convH(find(convH >= 1)) - 1;
  102. case 240
  103. disp('R -> B')
  104. convH = srcH + 2/3;
  105. convH(find(convH >= 1)) = convH(find(convH >= 1)) - 1;
  106. end
  107. convHSV = dstHSV;
  108. convHSV(:,:,1) = convH;
  109. convImg = hsv2rgb(convHSV);
  110. figure;imshow(convImg)
  111. pause();
  112. end
%% Color Enhancement Module -- Authored by HuangDao,08/17/2015
% functions: input a image of type BMP or PNG, the program will decide to
% do the Color Enhancement choice for you.There are four types of Enhanced
% intensity - 20,40,60,80.The larger number stands for stronger
% enhancement.
% And we can also choose the simple color channel(eg.R,G,B) to do the
% enhancement.There are also four different types of enhanced intensity.
%
% parameters table
%  ------------------------------------------------------------------------
% | Enhanced  |     MATLAB params             |      OpenCV params         |
% | intensity |p1        p2        p3         | p1        p2        p3     |
% | 20        |-0.1661   0.2639    -0.003626  |-0.0006512 0.2639    -0.9246|
% | 40        |-0.4025   0.6238    -0.0005937 |0.001578   0.6238    -0.1514|
% | 60        |1.332     1.473     -0.01155   |-0.005222  1.473     -2.946 |
% | 80        |-4.813    3.459     -0.004568  |-0.01887   3.459     -1.165 |
%  ------------------------------------------------------------------------clc; clear ;close all
% 载入文件夹
pathName = '.\';
fileType = '*.bmp';
files    = dir([pathName fileType]);
len      = length(files);for pic = 5%1:1:lensrcName = files(pic).name;srcImg  = imread(srcName);srcHSV  = rgb2hsv(srcImg);srcH    = srcHSV(:,:,1);srcS    = srcHSV(:,:,2);srcV    = srcHSV(:,:,3);meanS   = mean(srcS(:));varS    = std2(srcS);%图像整体进行色彩增强处理if (meanS >= 0.5)p1 = 0;p2 = 0;p3 = 0;else if (meanS >= 0.35 && meanS < 0.5)p1 = -0.1661;p2 = 0.2639;p3 = -0.003626;else if (meanS >=0.2 && meanS <0.35)p1 = -0.4025;p2 = 0.6238;p3 = -0.0005937;elsep1 = 1.332;p2 = 1.473;p3 = -0.01155;endendenddstS = srcS + p1*srcS.*srcS + p2*srcS + p3 ;dstHSV = srcHSV;dstHSV(:,:,2) = dstS;dstImg = hsv2rgb(dstHSV);figure;imshow(srcImg);figure;imshow(dstImg);%指定R,G,B通道进行色彩增强处理,红色范围([225-255]),绿色范围(75-[105-135]-165),蓝色范围([-15-15])p11 = -0.4025;p21 = 0.6238;p31 = -0.0005937;%周边杂色调整系数,40p12 = 1.332;  p22 = 1.473; p32 = -0.01155;  %纯色区域调整系数,60compHue = srcH;GcompS  = dstS;RcompS  = dstS;BcompS  = dstS;channel = 'B';switch channelcase 'G'I1 = find(compHue > 0.2083 & compHue <0.2917);GcompS(I1) = dstS(I1) + dstS(I1).*dstS(I1)*p11 + dstS(I1)*p21 + p31;I2 = find(compHue >= 0.2917 & compHue <= 0.3750);GcompS(I2) = dstS(I2) + dstS(I2).*dstS(I2)*p12 + dstS(I2)*p22 + p32;I3 = find(compHue > 0.3750 & compHue <0.4583);GcompS(I3) = dstS(I3) + dstS(I3).*dstS(I3)*p11 + dstS(I3)*p21 + p31;compHSV = dstHSV;compHSV(:,:,2) = GcompS;dstImgG = hsv2rgb(compHSV);figure;imshow(dstImgG);case 'R'I1 = find(compHue > 0.875 & compHue <0.9583);RcompS(I1) = dstS(I1) + dstS(I1).*dstS(I1)*p11 + dstS(I1)*p21 + p31;I2 = find(compHue >= 0.9583 | compHue <= 0.0417);RcompS(I2) = dstS(I2) + dstS(I2).*dstS(I2)*p12 + dstS(I2)*p22 + p32;I3 = find(compHue > 0.0417 & compHue <0.125);RcompS(I3) = dstS(I3) + dstS(I3).*dstS(I3)*p11 + dstS(I3)*p21 + p31;compHSV = dstHSV;compHSV(:,:,2) = RcompS;dstImgR = hsv2rgb(compHSV);figure;imshow(dstImgR);case 'B'I1 = find(compHue > 0.5417 & compHue <0.625);BcompS(I1) = dstS(I1) + dstS(I1).*dstS(I1)*p11 + dstS(I1)*p21 + p31;I2 = find(compHue >= 0.625 & compHue <= 0.7083);BcompS(I2) = dstS(I2) + dstS(I2).*dstS(I2)*p12 + dstS(I2)*p22 + p32;I3 = find(compHue > 0.7083 & compHue <0.7917);BcompS(I3) = dstS(I3) + dstS(I3).*dstS(I3)*p11 + dstS(I3)*p21 + p31;compHSV = dstHSV;compHSV(:,:,2) = BcompS;dstImgB = hsv2rgb(compHSV);figure;imshow(dstImgB);end%进行R,G,B通道之间的互换convH = zeros(size(srcH,1),size(srcH,2)); %convertdeltaHue = 240;switch deltaHuecase 120disp('R -> G')convH = srcH + 1/3;convH(find(convH >= 1)) = convH(find(convH >= 1)) - 1;case 240disp('R -> B')convH = srcH + 2/3;convH(find(convH >= 1)) = convH(find(convH >= 1)) - 1;endconvHSV = dstHSV;convHSV(:,:,1) = convH;convImg = hsv2rgb(convHSV);figure;imshow(convImg)pause();
end

添加OpenCV代码段:

  1. Mat srcHSV,sat,satAdj,dstMerge,dst;     //sat - saturation饱和度分量
  2. Mat imageAwb = imread("m_ImageAwb.bmp");
  3. vector<Mat> channels,channels1;
  4. double p1,p2,p3;
  5. cvtColor(imageAwb,srcHSV,CV_BGR2HSV);
  6. split(srcHSV,channels);
  7. split(srcHSV,channels1);
  8. sat = channels.at(1);
  9. Scalar m = mean(sat);
  10. if (m(0) <= 51.5)
  11. {p1 = -0.002714 , p2 = 0.9498, p3 = -0.5073;  AfxMessageBox("High Color Enhancement!"); }//高
  12. else if (m(0) > 38.5 && m(0) <= 89.5)
  13. {p1 = -0.001578  , p2 = 0.6238, p3 = -0.1514;AfxMessageBox("Middle Color Enhancement!"); }//中
  14. else if (m(0) > 89.5 && m(0) <=127.5)
  15. {p1 = -0.0006512, p2 = 0.2639, p3 = -0.9246;AfxMessageBox("Low Color Enhancement!");}//低
  16. else
  17. {p1 = 0,p2 = 0,p3 =0;AfxMessageBox("No Color Enhancement!");}
  18. satAdj = sat;
  19. for (int i = 0 ; i < sat.rows;i ++)
  20. {
  21. for (int j = 0;j < sat.cols;j ++)
  22. {
  23. uchar val = sat.at<uchar>(i,j);
  24. satAdj.at<uchar>(i,j) = (val + p1 * val * val + p2 * val + p3) ;
  25. }
  26. }
  27. channels1.at(1) = satAdj;
  28. merge(channels1,dstMerge);
  29. cvtColor(dstMerge,dst,CV_HSV2BGR);
  30. imwrite("m_ImageCE.bmp",dst);
   Mat srcHSV,sat,satAdj,dstMerge,dst;     //sat - saturation饱和度分量Mat imageAwb = imread("m_ImageAwb.bmp");vector<Mat> channels,channels1;double p1,p2,p3;cvtColor(imageAwb,srcHSV,CV_BGR2HSV);split(srcHSV,channels);split(srcHSV,channels1);sat = channels.at(1);Scalar m = mean(sat);if (m(0) <= 51.5)                       {p1 = -0.002714 , p2 = 0.9498, p3 = -0.5073;  AfxMessageBox("High Color Enhancement!"); }//高else if (m(0) > 38.5 && m(0) <= 89.5)  {p1 = -0.001578  , p2 = 0.6238, p3 = -0.1514;AfxMessageBox("Middle Color Enhancement!"); }//中else if (m(0) > 89.5 && m(0) <=127.5)  {p1 = -0.0006512, p2 = 0.2639, p3 = -0.9246;AfxMessageBox("Low Color Enhancement!");}//低else                                   {p1 = 0,p2 = 0,p3 =0;AfxMessageBox("No Color Enhancement!");}satAdj = sat;for (int i = 0 ; i < sat.rows;i ++){for (int j = 0;j < sat.cols;j ++){uchar val = sat.at<uchar>(i,j);satAdj.at<uchar>(i,j) = (val + p1 * val * val + p2 * val + p3) ;}}channels1.at(1) = satAdj;merge(channels1,dstMerge);cvtColor(dstMerge,dst,CV_HSV2BGR);imwrite("m_ImageCE.bmp",dst);

最后给出算法效果图:

Group1.原图->增强后

Group2.原图->R通道增强->颜色通道改变R2B

Group3.原图->增强后->颜色通道改变R2B

完!下篇讲Local Tone Mapping。

直方图均衡(HE)与局部色调映射(LTM) .

直方图均衡(Histogram Equalization)是图像处理中一个十分基础的概念,具有调整图像灰度,增强对比度的作用。

   限制对比度自适应直方图均衡(Contrast Limited Adaptive Histogram Equalization,CLAHE),关于该算法的中文原理性描述可以参考网址:http://www.cnblogs.com/Imageshop/archive/2013/04/07/3006334.html

下面我按照自己的理解来介绍一下CLAHE算法:

自适应直方图均衡(AHE)算法,对于图像中存在明显比其他区域亮或者暗的地方时,普通的直方图均衡算法就不能将该处的细节信息描述出来。AHE算法通过在当前处理像素周边的一个矩形区域内进行直方图均衡,来达到扩大局部对比度,显示平滑区域细节的作用。

AHE算法的2个属性:1、AHE算法处理的局部领域,矩形领域小,局部对比度强,矩形领域大,局部对比度弱。2、如果矩形区域内的图像块信息比较平坦,灰度接近,其灰度直方图呈尖状,在直方图均衡的过程中就可能会出现过度放大噪声的情况。

CLAHE,对比度受限的自适应直方图均衡算法就能够有效的限制噪声放大的情形。下图表示的就是局部矩形领域内的灰度直方图,由于对比度放大的程度与像素点的概率分布直方图的曲线斜度成比例,所以为了限制对比度,将大于一定阈值的部分平均分配到直方图的其他地方,如右图所示,这样的话,通过限制CDF(累积分布函数)的斜率来一定程度限制对比度。

插值过程,得到了CDF函数,也就获得了对应的亮度变换函数,在计算变换函数的时候可以通过插值过程来降低计算量。其中红色块(图像角点处)的变换函数是完全按照定义获得的,绿色块(图像边缘)的变换函数是通过旁边两个图像块的变换函数线性插值得到的,蓝色部分图像块的变换函数则是通过双线性插值得到。

目前,Matlab和OpenCV中都已经集成了CLAHE函数,在Matlab中,就是函数J = adapthisteq(I);

在OpenCV中,按照如下代码段处理:

  1. Ptr<CLAHE> clahe = createCLAHE();
  2. clahe ->apply(src,dst);
Ptr<CLAHE> clahe = createCLAHE();
clahe ->apply(src,dst);

   局部色调映射(Local Tone Mapping)

重建视觉外观是色调映射的终极目标。色调映射算法在降低高动态图像(HDR)范围的同时着力保护捕捉到的原始图像的外观。色调映射算子分两种策略,一种是全局的,另一种是局部的。

全局映射算子

每一个像素点将会根据它的全图特征和亮度信息进行映射,不管其空间位置几何。全局算子一个比较典型的例子就是色调曲线。全局色调映射在处理12位(12-bit)深度的图像的时候是完全OK的,当图像的动态范围特别高的时候,那就不行了。这是因为所有的像素点都采取同一种方式进行处理,根本就没有管它是在较亮区域还是较暗区域。这样的话,就是导致图像色调映射过后看起来很平坦,失去了其局部的细节信息。

局部映射算子    像素点所在的空间位置会被考虑,在进行尺度变换的时候,所以,具有相同亮度值的两个像素点会被映射成不同的值,因为它们的空间位置周边的亮度信息可能不一样。局部色调映射需要考虑到每个像素点周围的亮度信息,这样这会使得计算量和内存的使用会更大,但是会有更好的结果。如果处理得当,局部色调映射会很好的保护高亮和阴影部分的局部对比度和细节信息。

目前的一些色调映射算法:

1、伽马压缩算法

2、基于直方图均衡的压缩算法

3、基于Retinex的算法

4、基于梯度的压缩算法,等等

下面给出2组基于CLAHE的LTP算法效果图:(测试图像在网上找的)

Matlab代码如下:

  1. %% local tone mapping
  2. clc,clear ,close all
  3. % src = imread('m_ImageDemosaic.bmp');
  4. src = imread('C:\Users\Administrator\Desktop\LTP5.png');
  5. figure;imshow(src);
  6. srcHDR = double(src) * 256;
  7. hsv = rgb2hsv(srcHDR);
  8. figure;imshow(uint16(srcHDR))
  9. J = adapthisteq(uint16(hsv(:,:,3)));
  10. hsv(:,:,3) = double(J);
  11. dstHDR = hsv2rgb(hsv);
  12. figure;imshow(uint16(dstHDR))
  13. imwrite(uint16(dstHDR),'C:\Users\Administrator\Desktop\LTP5_1.png')
%% local tone mapping
clc,clear ,close all
% src = imread('m_ImageDemosaic.bmp');
src = imread('C:\Users\Administrator\Desktop\LTP5.png');
figure;imshow(src);
srcHDR = double(src) * 256;
hsv = rgb2hsv(srcHDR);
figure;imshow(uint16(srcHDR))
J = adapthisteq(uint16(hsv(:,:,3)));
hsv(:,:,3) = double(J);
dstHDR = hsv2rgb(hsv);
figure;imshow(uint16(dstHDR))
imwrite(uint16(dstHDR),'C:\Users\Administrator\Desktop\LTP5_1.png')

由于获取不到源HDR,所以自己先将8-bit图像映射到16-bit之后再进行试验

测试图像来源链接:http://www.vista123.com/vista/9226.html;http://www.nipic.com/show/7139458.html

什么是ISP,他的工作原理是怎样的?

ISP是Image Signal Processor的缩写,全称是影像处理器。在相机成像的整个环节中,它负责接收感光元件(Sensor)的原始信号数据,可以理解为整个相机拍照、录像的第一步处理流程,对图像质量起着非常重要的作用。

高通8974 拍照显示流程,可以清晰的看出ISP在整个流程中的位置

  ISP的功能比较杂,基本上跟图像效果有关的它都有份。它内部包含多个图像算法处理模块,其中比较有代表性的是:

扣暗电流(去掉底电流噪声),线性化(解决数据非线性问题),shading(解决镜头带来的亮度衰减与颜色变化),去坏点(去掉sensor中坏点数据),去噪(去除噪声),demosaic(raw数据转为RGB数据),3A(自动白平衡,自动对焦,自动曝光),gamma(亮度映射曲线,优化局部与整体对比度),旋转(角度变化),锐化(调整锐度),缩放(放大缩小),色彩空间转换(转换到不同色彩空间进处理),颜色增强(可选,调整颜色),肤色增强(可选,优化肤色表现)等

  实际情况下,不同芯片的ISP,其处理流程和模块可能会稍有不同,但是其原理、实现功能都是一样的。

ISP基础一

1、专业术语

【ColorTemp】 色温

所谓色温,简而言之,就是定量地以开尔文温度(K)来表示色彩。英国著名物理学家开尔文认为,假定某一黑体物质,能够将落在其上的所有热量吸收,而没有损失,同时又能够将热量生成的能量全部以“光”的形式释放出来的话,它便会因受到热力的高低而变成不同的颜色。例如,当黑体受到的热力相当于500—550℃时,就会变成暗红色,达到1050-1150℃时,就变成黄色,温度继续升高会呈现蓝色。光源的颜色成分与该黑体所受的热力温度是相对应的,任何光线的色温是相当于上述黑体散发出同样颜色时所受到的“温度”,这个温度就用来表示某种色光的特性以区别其它,这就是色温。打铁过程中,黑色的铁在炉温中逐渐变成红色,这便是黑体理论的最好例子。色温现象在日常生活中非常普遍,相信人们对它并不陌生。钨丝灯所发出的光由于色温较低表现为黄色调,不同的路灯也会发出不同颜色的光,天然气的火焰是蓝色的,原因是色温较高。正午阳光直射下的色温约为5600 K,阴天更接近室内色温3200K。日出或日落时的色温约为2000K,烛光的色温约为1000K。

【备注】

黑体的定义:

⑴在任何温度下,完全吸收任何波长的外来辐射而无任何反射的物体。

⑵吸收比为1的物体。

⑶在任何温度下,对入射的任何波长的辐射全部吸收的物体。

黑体,是一个理想化了的物体,它能够吸收外来的全部电磁辐射,并且不会有任何的反射与透射。换句话说,黑体对于任何波长的电磁波的吸收系数为1,透射系数为0。但黑体不见得就是黑色的,即使它没办法反射任何的电磁波,它也可以放出电磁波来,而这些电磁波的波长和能量则全取决于黑体的温度,不因其他因素而改变。当然,黑体在700K以下时看起来是黑色的,但那也只是因为在700K之下的黑体所放出来的辐射能量很小且辐射波长在可见光范围之外。若黑体的温度高过上述的温度的话,黑体则不会再是黑色的了,它会开始变成红色,并且随着温度的升高,而分别有橘色、黄色、白色等颜色出现,即黑体吸收和放出电磁波的过程遵循了光谱,其轨迹为普朗克轨迹(或称为黑体轨迹)。黑体辐射实际上是黑体的热辐射。在黑体的光谱中,由于高温引起高频率即短波长,因此较高温度的黑体靠近光谱结尾的蓝色区域而较低温度的黑体靠近红色区域。

在室温下,黑体辐射的能量集中在长波电磁辐射和远红外波段;当黑体温度到几百摄氏度之后,黑体开始发出可见光。以钢材为例根据温度的升高过程,分别变为红色,橙色,黄色,当温度超过1300摄氏度时开始发白色和蓝色。当黑体变为白色的时候,它同时会放出大量的紫外线。

色温规律:

色温越高,光色越偏蓝;色温越低则偏红。

某一种色光比其它色光的色温高时,说明该色光比其它色光偏蓝,反之则偏红;

同样,当一种色光比其它色光偏蓝时说明该色光的色温偏高,反之偏低。

由于人眼具有独特的适应性,使我们有的时候不能发现色温的变化。比如在钨丝灯下呆久了,并不会觉得钨丝灯下的白纸偏红,如果突然把日光灯改为钨丝灯照明,就会觉查到白纸的颜色偏红了,但这种感觉也只能够持续一会儿。

摄像机的CCD并不能像人眼那样具有适应性,所以如果摄像机的色彩调整同景物照明的色温不一致就会发生偏色。白平衡就是为了避免偏色的出现。从而引出白平衡概念。

【AWB】Auto White Balance

概念

白平衡就是针对不同色温条件下,通过调整摄像机内部的色彩电路使拍摄出来的影像抵消偏色,更接近人眼的视觉习惯。白平衡可以简单地理解为在任意色温条件下,摄像机镜头所拍摄的标准白色经过电路的调整,使之成像后仍然为白色。这是一种经常出现的情况,但不是全部,白平衡其实是通过摄像机内部的电路调整(改变蓝、绿、红三个CCD电平的平衡关系)使反射到镜头里的光线都呈现为消色。如果以偏红的色光来调整白平衡,那么该色光的影像就为消色,而其他色彩的景物就会偏蓝(补色关系)。

【备注】消色就是指黑白灰三种颜色。黑白灰的物体对光源的光谱成分不是有选择地吸收和反射而是等量吸收和等量反射各种光谱成分。这时物体看上去没有了色彩。对各种光谱成分全部吸收的表面,看上去是黑色,等量吸收一部分等量反射一部分的表面是灰色,反射绝大部分而吸收极小部分是白色。消色和任何色彩搭配在一起,都显得和谐协调。

白平衡是一个很抽象的概念,最通俗的理解就是让白色所成的像依然为白色,如果白是白,那其他景物的影像就会接近人眼的色彩视觉习惯。调整白平衡的过程叫做白平衡调整,白平衡调整在前期设备上一般有三种方式:预置白平衡、手动白平衡调整和自动跟踪白平衡调整。通常按照白平衡调整的程序,推动白平衡的调整开关,白平衡调整电路开始工作,自动完成调校工作,并记录调校结果。如果掌握了白平衡的工作原理,那么使用起来会更加有的放矢,得心应手。

工作原理

摄像机内部有三个CCD电子耦合元件,他们分别感受蓝色、绿色、红色的光线,在预置情况下这三个感光电路电子放大比例是相同的,为1:1:1的关系,白平衡的调整就是根据被调校的景物改变了这种比例关系。比如被调校景物的蓝、绿、红色光的比例关系是2:1:1(蓝光比例多,色温偏高),那么白平衡调整后的比例关系为1:2:2,调整后的电路放大比例中明显蓝的比例减少,增加了绿和红的比例,这样被调校景物通过白平衡调整电路到所拍摄的影像,蓝、绿、红的比例才会相同。也就是说如果被调校的白色偏一点蓝,那么白平衡调整就改变正常的比例关系减弱蓝电路的放大,同时增加绿和红的比例,使所成影像依然为白色

换一个思路来考虑白平衡调整的问题,摄像机在白平衡调整容度之内不会“拒绝”放在镜头前面的被调校景物,就是说镜头可以对着任何景物来调整白平衡。大多情况下使用白色的调白板(卡)来调整白平衡,是因为白色调白板(卡)可最有效地反映环境的色温,其实很多时候某种环境下白板(卡)并不是白色,多多少少会偏一点蓝或其它的颜色,经验丰富的摄像也会利用蓝天来调白平衡,从而得到偏红黄色调的画面。搞清楚白平衡的工作原理之后,再使用的时候就会大胆地尝试不同的效果,丰富了摄像创作。

数码相机白平衡的调整通常有三种模式;自动白平衡,分档设定白平衡,精确设定白平衡(手动设定模式)。不同的相机设有不同调节白平衡的方式。一般的普及型的数码相机大都采用自动白平衡。准专业数码相机大都设有分档设定白平衡。专业的数码相机设有精确白平衡(手动设定模式)。专业数码相机这三种模式的白平衡都拥有,准专业数码相机拥有自动和分档设定白平衡。可根据使用者的不同需要而选用。

自动白平衡,是依赖数码相机里的测色温系统,测出红光和蓝光的相对比例。再依据次数据调整曝光,产生红、绿、蓝电信号的增益。自动白平衡最大的优势是;简单、快洁。但有时按它的调整拍摄离准确的色彩还原还相距甚远。有时它还会帮倒忙。

分档设定白平衡,是按光源种类分和色温值分两类。大多数数码相机都是按光源种类分的这类。在相机上分别设有日光、阴天、日光灯、白炽灯、闪光灯的图标档位。拍摄时只需将拍摄时的光源种类和相机上的白平衡档位相吻合就可拍出较为准确的色彩。但由于分设档位少,分设档位的精度不高,在一些特殊光照条件下拍摄就不能准确的记录色彩。按色温分类的白平衡,理论上讲其精度要高于按光源种类分档。但它要求使用者要记住各种光源的色温值,这就给使用者带来极大的麻烦。故用此分档白平衡的相机较少。

精确白平衡(手动设定模式),是在拍摄现场光的条件下,用白纸或白色物体充满镜头视野进行白平衡调节。经过这样的调试再拍摄,记录的色彩将是非常准确的这是目前最准确的白平衡调节方式。白平衡的功能给我们摄影带来了许多的便利和意想不到的效果。如摄影棚摄影对灯光的色温要求就可不必那么高。白炽灯下依然可拍出准确的色彩。也不必为日光灯给我们带来的青色而烦恼。我们可以在较高色温条件下设定白平衡,在较低色温情况下拍摄,使画面带上暖色调。反之,也可在低色温条件下设定,在高色温下拍摄也可产生特别的效果。在分档设定白平衡里,也可有意的将光源档与现场光设定不一致,亦可同样的产生不同的艺术效果

【AE】Auto Exposure

自动曝光是相机根据光线的强弱自动调整曝光量,防止曝光过度或者不足,但是,在场景反差很大的时候会出现误差(比如舞台的场景),光圈优先和快门优先都是自动曝光的范畴,除非很高档的相机,这两种功能不会同时出现在一个相机上,在自动曝光的同时也让你有部分选择的权利,当使用光圈优先的功能时,特别是小光圈时,要注意此时的快门速度会相应的调得很低,端稳相机防止图像不清晰

自动曝光,主要分为三类,全自动程式曝光、光圈先决曝光、快门先决曝光

【CCM】Color Correction Matrix

【IMP】?

【AI】Auto Iris 自动光圈

【AntiFlicker 】 抗闪烁

【ColorTone】冷暖色调

色彩的冷暖分别。色彩学上根据心理感受,把颜色分为暖色调(红、橙、黄)、冷色调(青、蓝)和中性色调(紫、绿、黑、灰、白)。

【RDC】Dynamic Range Compression

即动态范围压缩,目的是调整图像的动态范围,使得图像显示出更多的信息。 DRC 模块是一个基于人眼视觉系统特性的高级局部色阶映射(多空间动态范围压缩)引擎。

【AntiFalseColor】去假彩

真彩色(True Color):真彩色是指在组成一幅彩色图像的每个像素值中,有R、G、B三个基色分量,每个基色分量直接决定显示设备的基色强度产生彩色。

伪彩色(Pseudo Color):每个像素的颜色不是由每个基色分量的数值直接决定,而是把像素值当作颜色查找表(color look-up table,CLUT)的表项入口地址,去查找一个显示图像时使用的R,G,B强度值,用查找出的R,G,B强度值合成产生彩色。

假彩色(False Color):将多波段单色影像合成为假彩色影像,如landsat 7/ETM+有八个波段,用其中三个合成就是假彩色

从实现技术上讲,假彩色与真彩色是一致的,都是R、G、B分量组合显示;伪彩色显示调用的是颜色表。

【AntiFog】去雾

去雾原理很复杂,可以参考链接:

http://blog.csdn.net/baimafujinji/article/details/27206237

http://blog.csdn.net/occupy8/article/details/40322683

【Defect Pixel】坏点

【ShadingAttr】暗角校正属性

【ShadingTable】暗角补偿查找表

【Denoise】噪点抑制

【SharpenAttr】边缘锐化属性

【DemosaicAttr】去马赛克属性

【NoiseProfile】噪声型式表

【CrosstalkAttr】CrossTalk remove Attr

【DIS】?

【FPN】获取内部状态扩展信息QueryInnerStateInfoEx

【LostFrameStrategy】丢帧策略

gamma校正原理

http://blog.csdn.net/u013286409/article/details/50239377

图2中左图为原图,中图为gamma = 1/2.2在校正结果,原图中左半侧的灰度值较高,右半侧的灰度值较低,经过gamma = 1/2.2校正后(中图),左侧的对比度降低(见胡须),右侧在对比度提高(明显可以看清面容),同时图像在的整体灰度值提高。

右图为gamma = 2.2在校正结果,校正后,左侧的对比度提高(见胡须),右侧在对比度降低(面容更不清楚了),同时图像在的整体灰度值降低。

值得一提的是,人眼是按照gamma < 1的曲线对输入图像进行处理的。

  1. #include <opencv2/core/core.hpp>
  2. #include <opencv2/imgproc/imgproc.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. #include <iostream>
  5. using namespace cv;
  6. using namespace std;
  7. // Normalizes a given image into a value range between 0 and 255.
  8. Mat norm_0_255(const Mat& src) {
  9. // Create and return normalized image:
  10. Mat dst;
  11. switch(src.channels()) {
  12. case 1:
  13. cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
  14. break;
  15. case 3:
  16. cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
  17. break;
  18. default:
  19. src.copyTo(dst);
  20. break;
  21. }
  22. return dst;
  23. }
  24. int main(int argc, const char *argv[]) {
  25. // Get filename to the source image:
  26. if (argc != 2) {
  27. cout << "usage: " << argv[0] << " <image.ext>" << endl;
  28. exit(1);
  29. }
  30. // Load image & get skin proportions:
  31. //Mat image = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
  32. Mat image = imread(argv[1], CV_LOAD_IMAGE_COLOR);
  33. // Convert to floating point:
  34. Mat X;
  35. image.convertTo(X, CV_32FC1);
  36. //image.convertTo(X, CV_32F);
  37. // Start preprocessing:
  38. Mat I;
  39. float gamma = 1/2.2;
  40. pow(X, gamma, I);
  41. // Draw it on screen:
  42. imshow("Original Image", image);
  43. imshow("Gamma correction image", norm_0_255(I));
  44. //imwrite("origin.jpg", image);
  45. imwrite("gamma_inv2.2.jpg", norm_0_255(I));
  46. // Show the images:
  47. waitKey(0);
  48. // Success!
  49. return 0;
  50. }
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>#include <iostream>using namespace cv;
using namespace std;// Normalizes a given image into a value range between 0 and 255.
Mat norm_0_255(const Mat& src) {// Create and return normalized image:Mat dst;switch(src.channels()) {case 1:cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);break;case 3:cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);break;default:src.copyTo(dst);break;}return dst;
}int main(int argc, const char *argv[]) {// Get filename to the source image:if (argc != 2) {cout << "usage: " << argv[0] << " <image.ext>" << endl;exit(1);}// Load image & get skin proportions://Mat image = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);Mat image = imread(argv[1], CV_LOAD_IMAGE_COLOR);// Convert to floating point:Mat X;image.convertTo(X, CV_32FC1);//image.convertTo(X, CV_32F);// Start preprocessing:Mat I;float gamma = 1/2.2;pow(X, gamma, I);// Draw it on screen:imshow("Original Image", image);imshow("Gamma correction image", norm_0_255(I));//imwrite("origin.jpg", image);imwrite("gamma_inv2.2.jpg", norm_0_255(I));// Show the images:waitKey(0);// Success!return 0;
}

Gamma 校正

问题:什么是Gamma曲线矫正?Gamma曲线矫正是什么意思?
       Gamma曲线是一种特殊的色调曲线,当Gamma值等于1的时候,曲线为与坐标轴成45°的直线,这个时候表示输入和输出密度相同。高于1的Gamma值将会造成输出亮化,低于1的Gamma值将会造成输出暗化。总之,我们的要求是输入和输出比率尽可能地接近于1。在显示器、扫描仪、打印机等输入、输出设备中这是一个相当常见并且比较重要的概念。在计算机系统中,由于显卡或者显示器的原因会出现实际输出的图像在亮度上有偏差,而Gamma曲线矫正就是通过一定的方法来矫正图像的这种偏差的方法。一般情况下,当用于Gamma矫正的值大于1时,图像的高光部分被压缩而暗调部分被扩展,当Gamma矫正的值小于1时,图像的高光部分被扩展而暗调部分被压缩,Gamma矫正一般用于平滑的扩展暗调的细节。

图1 CRT显示器的亮度响应曲线图

图1显示的是一般CRT显示器的亮度响应曲线,可以看到其输入电压提高一倍,亮度输出并不是提高一倍,而是接近于两倍,显然这样输出的图像同原来的图像相比就发生了输出亮化的现象,也就是说未经过Gamma矫正的CRT显示器其Gamma值是小于1的。

没有经过Gamma矫正的设备会影响最终输出图像的颜色亮度,比如一种颜色由红色和绿色组成,红色的亮度为50%,绿色的亮度为25%,如果一个未经过Gamma矫正的CRT显示器的Gamma值是2.5,那么输出结果的亮度将分别为18%和3%,其亮度大大的降低了。

图2  按图进行曲线补偿

为了补偿这方面的不足,我们需要使用反效果补偿曲线来让显示器尽可能地输出同输入图像相同的图像,所以这个时候显示器的输入信号应该按照图2所示的曲线进行补偿,这样才能在显示器上得到比较理想的输出结果。

图3  理想状态下的曲线

一般的反效果可以直接被赋予存储在帧缓存中的图像,使之Gamma曲线呈非线性,也可以通过RAMDAC进行这种反效果补偿(或者说是Gamma曲线矫正)。这样我们就可以在显示器上看到同我们输入的图像接近的图像了(如图3)。当然图3所示的曲线只是理想状态下的情况,在实际应用中我们并不可能得到如此完美的曲线,所以不同的厂商之间所竞争的就是谁能做到最接近于这个效果。

显示器的gamma值是用于定义一个显示器的显示特性的数学方法,是决定显示器从黑色到白色的值。简单的说,当显示一个颜色从黑到白时(也就是0到1),显示器的电压也要随之变化,但这个变化不是线性的。因为显示器的物理特性决定了如果电压的变化是线性的,显示出来的亮度就不是线性的,这时,显示的亮度就会很暗。所以,为了保整显示出来的亮度是正常(线性)的,就需要对显示器的电压变化加以校正,这个值就是我们通常所说的gamma值。通常情况只有在调整HDRI图片时和在做动画渲染时会用到。

γ校正(Gamma Correction,伽玛校正):所 谓伽玛校正就是对图像的伽玛曲线进行编辑,以对图像进行非线性色调编辑的方法,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比 度效果。计算机绘图领域惯以此屏幕输出电压与对应亮度的转换关系曲线,称为伽玛曲线(Gamma Curve)。以传统CRT(Cathode Ray Tube)屏幕的特性而言,该曲线通常是一个乘幂函数,Y=(X+e)γ,其中,Y为亮度、X为输出电压、e为补偿系数、乘幂值(γ)为伽玛值,改变乘幂 值(γ)的大小,就能改变CRT的伽玛曲线。典型的Gamma值是0.45,它会使CRT的影像亮度呈现线性。使用CRT的电视机等显示器屏幕,由于对于 输入信号的发光灰度,不是线性函数,而是指数函数,因此必需校正。

在电视和图形监视器中,显像管发生的电子束及其生成的图像亮度并不是随显像管的输入电压线性变化,电子流与输入电压相比是按照指数曲线变化的,输入 电压的指数要大于电子束的指数。这说明暗区的信号要比实际情况更暗,而亮区要比实际情况更高。所以,要重现摄像机拍摄的画面,电视和监视器必须进行伽玛补 偿。这种伽玛校正也可以由摄像机完成。我们对整个电视系统进行伽玛补偿的目的,是使摄像机根据入射光亮度与显像管的亮度对称而产生的输出信号,所以应对图 像信号引入一个相反的非线性失真,即与电视系统的伽玛曲线对应的摄像机伽玛曲线,它的值应为1/γ,我们称为摄像机的伽玛值。电视系统的伽玛值约为  2.2,所以电视系统的摄像机非线性补偿伽玛值为0.45。彩色显像管的伽玛值为2.8,它的图像信号校正指数应为1/2.8=0.35,但由于显像管内 外杂散光的影响,重现图像的对比度和饱和度均有所降低,所以现在的彩色摄像机的伽玛值仍多采用0.45。在实际应用中,我们可以根据实际情况在一定范围内 调整伽玛值,以获得最佳效果。

今天有个朋友问γ校正的用处,这里简单说一下:

伽马校正最初是由于显示器的阴极现象管(也就是物理上所说的示波管的阴极射线版)的成像扭曲引起的,为了不使画面失真所以就用先特殊算法进行校正,此之谓γ校正。

γ校正的原理是修改显示系统的配色方案,本来显示系统输出的r g b电子枪线性的根据显存中的各个颜色值输出对应的控制电压,但是通过伽码校正可以把某个颜色值对应的输出电压调整高或调整低。达到校正显示系统色泽的目的。同时可以用软件的方法校正,就是对一副图片设定某个颜色的颜色值变换成新的颜色值的对照表,然后用新的颜色值取代原来图片中对应的颜色就行了呀。比如你先编写一个控制rgb各个分量对应关系的曲线调节器,在曲线调节器里面调整控制曲线设置原来颜色多少对应目标颜色多少,然后根据设定的关系,修改要调整色泽的图片每一个像素的颜色就可以了。

数学公式可以深刻和精确的把握一个概念,却不能表达概念的物理意义和本质含义,本贴试图摆脱数学公式的陈述和推导,用言语来解释gamma的本质含义。

原文链接:

http://blog.csdn.net/lichengyu/article/details/20840135

http://www.downhot.com/show/dnjc/160420120603552393894.html

ISP算法介绍--------super Good相关推荐

  1. 【高通SDM660平台 Android 10.0】(17) --- ISP算法相关-待学习文章

    <精 高通camera结构(摄像头基础介绍)> <Android : Camera2/HAL3 框架分析> 待学习: <基于IC设计的实用ISP介绍> <IS ...

  2. ISP算法高水平分析(上)

    ISP算法高水平分析(上) 一.ISP基本框架及算法介绍 ISP是Image Signal Processor的缩写,全称是影像处理器.在相机成像的整个环节中,它负责接收感光元件(Sensor)的原始 ...

  3. 深度学习【使用pytorch实现基础模型、优化算法介绍、数据集的加载】

    文章目录 一 Pytorch完成基础模型 1. Pytorch完成模型常用API 1.1 `nn.Module` 1.2 优化器类 1.3 损失函数 1.4 线性回归完整代码 2. 在GPU上运行代码 ...

  4. 海思平台(hi3559/hi3519/hi3516/hi3518)下的ISP功能介绍及问题调试总结(包括黑光成像/逆光成像/降噪/宽动态wdr/偏色等问题)

    海思平台下的ISP功能介绍及问题调试 平台说明 该调试是在海思平台下进行的(我用的是3559,在3519/3516测试也是没有问题的,只是部分参数稍微有差异.其海思他系列处理器的ISP调试大体上也是一 ...

  5. 反汇编算法介绍和应用——递归下降算法分析

    上一篇博文我介绍了Windbg使用的线性扫描(linear sweep)反汇编算法.本文我将介绍IDA使用的递归下降(recursive descent)反汇编算法.(转载请指明来源于breaksof ...

  6. 改进型 clock 页面置换算法实现_ID生成算法雪花算法介绍及实现

    1. SnowFlake 算法介绍 雪花算法是由 Twitter 公司开源的可在分布式系统中产生一个全局唯一 ID 的算法.最初 Twitter 把存储系统从 MySQL 迁移到 Cassandra, ...

  7. 五子棋html游戏代码与算法介绍

    五子棋html游戏代码与算法介绍 运行图片 目录路径 五子棋.html 五子棋算法 进行下一个游戏的开发! 注意事项 我会把html文件.css文件提供下载地址,文件夹路径也展示给大家.但是图片就没法 ...

  8. HTML五子棋游戏代码介绍,五子棋html游戏代码与算法介绍

    五子棋html游戏代码与算法介绍 我会把html文件.css文件提供下载地址,文件夹路径也展示给大家.但是图片就没法一一放在博客里面了. 大家有需要的话,加博主QQ:2864144286,全天在线. ...

  9. 知识图谱学习笔记-风控算法介绍

    一.风控算法的评估 1.搭建风控模型 数据(KG)-特征工程-模型 特征工程: 申请人相关特征:年龄.收入.工作性质等等 从知识图谱提取出的特征: 1)从规则提取出来的特征:申请人是不是第一次借款(0 ...

最新文章

  1. OpenJudge/Poj 2027 No Brainer
  2. 微信小程序注意点及快捷键
  3. 线性代数:第三章 矩阵的初等变换与线性方程组(2)线性方程组的解 初等方阵
  4. MongoDB(6.mongodb的聚合操作以及高级查询3、排序等)
  5. 【linux】kill命令模板
  6. 百度前端学院参考答案:第二十五天到第二十七天 倒数开始 滴答滴 滴答滴(2)...
  7. Spring cloud Gateway(二) 一个Http请求的流程解析
  8. 拉普拉斯变换公式表_复变函数之拉普拉斯变换小结
  9. php最新版本6,PHP实用函数6
  10. java 解析excle
  11. gogs 把用户加入团队
  12. jeDate 日期控件
  13. tkinter教程_Tkinter教程–第2部分
  14. SpreadJS 15.0 隆重登场 SpreadJS
  15. 弹性力学经典解法与有限元法的不同特点
  16. js如何判断字符串是否为空
  17. 控制系统 丢包 matlab 程序,基于MATLAB的网络控制系统仿真.pdf
  18. 行稳致远,进而有为——2020年 XAG发展展望
  19. 细说final的的四种用法-----修饰类,修饰方法,常量,修饰参数 及内部类与final
  20. Semantic UI 之 对话框 modal

热门文章

  1. 【工具】git 入门
  2. XSS-Libs通关详解
  3. 阿里云aliyun 的SLB 对 ECS的健康检查
  4. 朱刘算法 有向图的最小生成树
  5. 虹膜识别论文2:An Experimental Study of Deep Convolutional Features For Iris Recognition 2016年 学习心得
  6. Hadoop —— 漫画图解hdfs读、写、容错、副本机制
  7. 小型计算机房建设标准,依据国家计算机房建设标准.doc
  8. 0、PIC系列参考手册中文版文档汇总
  9. 数据库存储图片解决方案
  10. DeepMind用强化学习探索大脑多巴胺对学习的作用