linux打开摄像头命令:关于自动白平衡的算法问题

来源:百度文库 编辑:中财网 时间:2024/05/12 18:15:46
白平衡

白平衡并不是数码摄影特有的东西,胶片也有白平衡,只不过胶片的白平衡是预设的,如钨丝灯型胶卷在钨丝灯光源的照射下拍出的照片就可以有正确的白平衡。换句话说,在胶片时代,摄影师根据光源的不同而选择不同的胶片就是在“调节”白平衡了。但数码技术允许我们后期几乎不受限制地的白平衡,无疑它要灵活得多,给摄影师提供了更多的创作手段。

白平衡的本质是让白色的物体在任何颜色的光源下都显示为白色。这一点对人眼来说很容易办到,因为人眼有自适应的能力,只要光源的色彩不超出一定的限度,就可以自动还原白色。但相机就不同了,无论是图像传感器还是胶卷都会记录光源的颜色,白色的物体就会带上光源的颜色,白平衡所要做的就是把这个偏色去掉。

自动白平衡是一个很复杂的问题,目前还没有一个万能的方法可以解决所有场景的白平衡问题。有些统计数据表明大部分场景的颜色平均值是中性的,即没有颜色【见注一】。一种自动白平衡算法就是依据这个统计数据设计的,它计算出图像颜色的均值,再算出均值和同等亮度的中性灰的差别,这个差别就是偏色值,对每个像素的颜色值用这个偏色值校正就得到正确的自动白平衡了。网上有一个开源的RAW处理软件——dcraw——就是用这种方法自动校正白平衡的(要知道dcraw有多牛,你只要知道早期很多商业软件、包括Adobe Camera Raw都是基于它的源代码的就够了)。

自动白平衡的问题是有时会给出同拍摄者希望相反的结果,比如拍摄一个金色阳光的早晨的场景,自动白平衡可能会算出光线偏红黄而减少照片中的红黄,结果我们美丽的朝阳变成了苍白的阴天。同样,如果一个场景中某种颜色占了很大的比重,如大面积的緑树,相机的自动白平衡算法也有可能被糊弄从而产生不可预知的结果。

问题的根本是我们有时候想保留光源的色彩(如日落、日出),有时候则想去掉光源的色彩,再牛的软件也不知道拍摄者的意图是什么,因此所有的数码单反都允许用户预设白平衡光源,如晴天、多云、日光灯等,拍摄者只要根据不同的光源预设不同的白平衡值就可以得到很好的色彩还原了。对于户外的风光摄影,很多人都喜欢偏暖的色调。胶片时代的摄影师通常用一些暖色的滤镜(如红、黄滤镜等)来解决这个问题,在数码时代有些摄影师则建议把白平衡一直设置在多云上,实际上我的很多风光片都是这么设置的。

预设白平衡可以较好地还原色彩,可以满足我们的大多数要求。我们有时候希望更准确的色彩还原,不同厂商的预设白平衡也可能并不相同,,这时候就需要手动调整白平衡了。手动调整白平衡的原理很简单,我们只要告诉相机或图像处理软件图片中的某个物体是中性的就可以了,软件会根据实际拍摄的物体的颜色值自动地计算出光源的颜色,进而调整整个画面的色彩。一种常见的手动调整白平衡方法是在拍摄的场景中放置一块白卡或灰卡,后期告诉软件它是中性的。

有人可能会问,我们应该用白卡还是灰卡?理论上两者都可以,只要白卡是真正的中性色,灰卡是真正的中性灰。实际使用时,很多市面上的灰卡(如柯达灰卡)并不是中性灰的,这是因为这些灰卡是给测光用的,只要保证它们反射18%的入射光就行了,而不用考虑它们是否是真正的中性灰。目前市面上有售专门为数码白平衡设计的白卡,它们是真正的中性的,如果需要的话,是个不错的选择。我推荐使用白卡手动调整白平衡的另外一个理由是白色的曝光值高(假设拍摄者能正确地曝光),曝光值高的像素有更好的信号和噪声的比例,因而得到的感光数据能更好地用来测试白平衡。

说到这里,是不是我们解决了所有的白平衡问题? Not so fast!最后我要提一下的是白板法仅适用于光照均匀的情形。设想一下,一位拍摄者站在阴影底下拍摄一座阳光照射的大山,这时白板法显然不行,因为拍摄者和拍摄物所处的光源不一样。在这种情况下,没有什么好的机械的手动白平衡调整方法,只有靠记忆后期调整光源的色温了。

【注一】在色彩科学里,中性色是指没有其它颜色,而只有灰色、白色或黑色的颜色。在计算机里面,红(R)、绿(G)、蓝(B)三个值相等就是中性色,白色的(R,G,B)是(255,255,255),是一种中性色;黑色是(0,0,0),也是一种中性色。 不幸的是,我们常常看到中性灰的提法,似乎白和黑不是中性色,这是不对的。

再附上两种处理原代码:先是VC的BYTE RGB[3] = {0}, YCbCr[3] = {0};
DOUBLE dbHSV[3] = {0}, dbStdRGB[3] = {0}, dbStdYCbCr[3] = {0};
PWBRESULTTYPE pResult = &(pResultInfo->WBResult);
DWORD dwBlockSize = pResultInfo->Setting.dwBlockSize;
DWORD dwPicture = pResultInfo->DocInfo.BmpInfo.bmiHeader.biWidth;
DWORD dwDataSize = GETPICTUREWIDTH(dwPicture);
DWORD dwHeight = pResultInfo->DocInfo.BmpInfo.bmiHeader.biHeight;
CRect rect;

rect.top = pResultInfo->Setting.ptArray.x;
rect.left = pResultInfo->Setting.ptArray.x;
rect.bottom = rect.top + dwBlockSize;
rect.right = rect.left + dwBlockSize;

// calcult mean RGB and standard RGB
CalculateRGB(pResultInfo->DocInfo.BmpInfo, pResultInfo->DocInfo.lpFileData, rect, RGB);
pResult->Blue = RGB[2];
pResult->Green = RGB[1];
pResult->Red = RGB[0];

// calculate YCbCr and standard luminance
CalculateYCbCr(pResultInfo->DocInfo.BmpInfo, pResultInfo->DocInfo.lpFileData, rect, YCbCr);
pResult->Luminance = YCbCr[0];

pResult->dbRG = (RGB[0]*1.0)/RGB[1];
pResult->dbGG = 1;
pResult->dbBG = (RGB[2]*1.0)/RGB[1];  再是VB的。Public Function AutoColorPoise(mBitmap As cDIB, AutoInfo As Label) As Boolean
Dim i As Long, j As Long
Dim JumpLines As Long, JumpBits As Long, StepLines As Long, StepBits As Long
Dim MeanColor(0 To 2) As Single, SumColor(0 To 2) As Long, Bits As Long, GreyColor As Long
Dim RedTable(0 To 255) As Long, GreenTable(0 To 255) As Long, BlueTable(0 To 255) As Long
Dim RedValue As Long, GreenValue As Long, BlueValue As Long
Dim dWidth As Long, dHeight As Long, Scanline As Long, SizeImage As Long
Dim dPtr As Long

dWidth = mBitmap.mWidth - 1: dHeight = mBitmap.mHeight - 1
SizeImage = mBitmap.SizeImage
Scanline = mBitmap.Scanline
dPtr = mBitmap.ImagePtr

JumpLines = Int(dHeight / 1500) * Scanline
StepLines = Int(dHeight / 1500) + 1

JumpBits = Int(dWidth / 1500) * 4 + 4
StepBits = Int(dWidth / 1500) + 1

p4Byte0Ptr(0) = dPtr

For i = 0 To dHeight Step StepLines
For j = 0 To dWidth Step StepBits
SumColor(0) = SumColor(0) + p4Byte0(0)
SumColor(1) = SumColor(1) + p4Byte0(1)
SumColor(2) = SumColor(2) + p4Byte0(2)
Bits = Bits + 1
p4Byte0Ptr(0) = p4Byte0Ptr(0) + JumpBits
Next j
p4Byte0Ptr(0) = p4Byte0Ptr(0) + JumpLines
Next i

MeanColor(0) = SumColor(0) \ Bits
MeanColor(1) = SumColor(1) \ Bits
MeanColor(2) = SumColor(2) \ Bits

GreyColor = (MeanColor(0) * 11 + MeanColor(1) * 59 + MeanColor(2) * 30) \ 100

BlueValue = GreyColor - MeanColor(0)
GreenValue = GreyColor - MeanColor(1)
RedValue = GreyColor - MeanColor(2)

AutoInfo.Caption = "红色:" & CStr(RedValue) & " | 绿色:" & CStr(GreenValue) & " | 蓝色:" & CStr(BlueValue)

For i = 0 To 255
RedTable(i) = i + RedValue
If RedTable(i) > &HFF Then RedTable(i) = &HFF
If RedTable(i) < &H0 Then RedTable(i) = &H0
GreenTable(i) = i + GreenValue
If GreenTable(i) > &HFF Then GreenTable(i) = &HFF
If GreenTable(i) < &H0 Then GreenTable(i) = &H0
BlueTable(i) = i + BlueValue
If BlueTable(i) > &HFF Then BlueTable(i) = &HFF
If BlueTable(i) < &H0 Then BlueTable(i) = &H0
Next i

p4Byte0Ptr(0) = dPtr

FrmMain.AutoPBar.Max = dHeight
For i = 0 To dHeight
For j = 0 To dWidth
p4Byte0(0) = BlueTable(p4Byte0(0))
p4Byte0(1) = GreenTable(p4Byte0(1))
p4Byte0(2) = RedTable(p4Byte0(2))
p4Byte0Ptr(0) = p4Byte0Ptr(0) + 4
Next j
FrmMain.AutoPBar.Value = i
Next i

FrmMain.AutoPBar.Max = 100: FrmMain.AutoPBar.Value = 100

AutoColorPoise = True
End Function