首先来介绍一下关于相机的基础知识:
1.CCD/CMOS相机的感光元件对波长(即颜色)不敏感,如果拿一个裸体的CCD/CMOS传感器去拍摄图像,只能得到灰度图;
2.因为上述这条,人们必须找到能够将波长区分开的方法,其中一种是使用三个滤光片(通常是RGB三色),在这三个滤光片之后放置三个CCD,这就是3CCD相机;
-
3.显然上一种方法的成本太高了,聪明的人类又想到了另一个方法:那就是在CCD/CMOS传感器矩阵之前放置一个滤色片矩阵,每个像素对应一个滤色片,将RGB三种颜色的滤色片均匀分布在这个矩阵中,拍摄到图像后将对应颜色的像素的值取出来并进行插值,就得到了三个通道的数据。
-
RAW文件存储的就是第三种方法拍摄的原始数据,可以使用photoshop打开,放大后能够很明显的观察到类似棋盘格一样的像素值。虽然没有白平衡设置,但最大的好处是真实的数据也没有被改变,基于这些数据操作者可以设置自己的通道权值,能够任意的调整色温和白平衡。
-
将图像放大:
- 局部放大
继续放大:
下面来介绍如何用OpenCV打开raw文件。思路如下:
1.以二进制方式打开文件;
2.将每个像素对应的16bit的数据分成两个8bit,分别放入两个矩阵中;
3.对这两个矩阵进行色彩空间变换,转换为两个8bit三通道的图像;
4.将这两个图像合成为一个16bit三通道的图像。
废话少说,代码如下:
-
void CMy20120510readrawfileDlg::OnBnClickedButton2()
-
{
-
const
int WIDTH =
1360;
-
const
int HEIGHT =
1024;
-
-
CFile file;
-
file.Open(_T(
"aaa.raw"), CFile::modeRead | CFile::typeBinary);
-
file.SeekToBegin();
-
-
BYTE * pfilebuf =
new BYTE[HEIGHT*WIDTH*
2];
-
-
if (HEIGHT*WIDTH*
2 != file.Read(pfilebuf, HEIGHT*WIDTH*
2))
-
{
-
//提示文件读取错误
-
file.Close();
-
return;
-
}
-
-
file.Close();
-
-
//////////////////////////////////////////////////////////////////////////
-
-
CvMat* mat_a = cvCreateMat(
1, HEIGHT*WIDTH, CV_8U);
//单行矩阵便于赋值操作
-
CvMat* mat_b = cvCreateMat(
1, HEIGHT*WIDTH, CV_8U);
//同上
-
-
int i=
0;
-
-
do {
-
CV_MAT_ELEM(*mat_a,
unsigned
char,
0, i) = pfilebuf[i*
2];
//低8位信息
-
CV_MAT_ELEM(*mat_b,
unsigned
char,
0, i) = pfilebuf[i*
2+
1];
//高8位信息
-
-
i++;
-
}
while(i<HEIGHT*WIDTH);
-
-
delete[] pfilebuf;
-
-
cvReshape(mat_a, mat_a,
0, HEIGHT);
//把单行矩阵整形为二维矩阵
-
cvReshape(mat_b, mat_b,
0, HEIGHT);
-
-
IplImage* img_a = cvCreateImage(cvSize(WIDTH,HEIGHT), IPL_DEPTH_8U,
3);
-
IplImage* img_b = cvCreateImage(cvSize(WIDTH,HEIGHT), IPL_DEPTH_8U,
3);
-
-
cvCvtColor(mat_a, img_a, CV_BayerBG2RGB);
//色彩空间转换,即Bayer模式转为RGB
-
cvCvtColor(mat_b, img_b, CV_BayerBG2RGB);
-
-
cvReleaseMat(&mat_a);
-
cvReleaseMat(&mat_b);
-
-
cvNamedWindow(
"img_a");
-
cvNamedWindow(
"img_b");
-
cvShowImage(
"img_a", img_a);
-
cvShowImage(
"img_b", img_b);
-
-
//////////////////////////////////////////////////////////////////////////
-
-
//因为cvAddWeighted需要参数矩阵都具有相同类型、相同大小
-
IplImage* img_a_16 = cvCreateImage(cvSize(WIDTH,HEIGHT), IPL_DEPTH_16U,
3);
-
IplImage* img_b_16 = cvCreateImage(cvSize(WIDTH,HEIGHT), IPL_DEPTH_16U,
3);
-
-
cvConvert(img_a, img_a_16);
-
cvConvert(img_b, img_b_16);
-
-
IplImage* img = cvCreateImage(cvSize(WIDTH,HEIGHT), IPL_DEPTH_16U,
3);
-
-
//高8位左移8位加上低8位合成一个16位图像
-
cvAddWeighted(img_a_16,
1, img_b_16,
256,
0, img);
-
-
cvNamedWindow(
"img");
-
cvShowImage(
"img", img);
-
-
cvWaitKey();
-
cvDestroyAllWindows();
-
-
cvReleaseImage(&img_a);
-
cvReleaseImage(&img_b);
-
cvReleaseImage(&img);
-
}
得到的图像如下:
可以看出img_a的结果是原16bit图像的低8位,直接显示的话是没什么意义的。
最后合成的16bit肉眼几乎观察不出有什么区别,但是对OpenCV来说已经是可以直接处理的16bit图像数据了!
接下来,要怎么处理就可以自由发挥啦。
顺便给出OpenCV帮助文档里cvCvtColor对Bayer模式转换的说明,请认真阅读哦: