Bayer图像说明
1、Bayer图像格式介绍
bayer格式图片是伊士曼·柯达公司科学家Bryce Bayer发明的,Bryce Bayer所发明的拜耳阵列被广泛运用数字图像。
对于彩色图像,需要采集多种最基本的颜色,如rgb三种颜色,最简单的方法就是用滤镜的方法,红色的滤镜透过红色的波长,绿色的滤镜透过绿色的波长,蓝色的滤镜透过蓝色的波长。如果要采集rgb三个基本色,则需要三块滤镜,这样价格昂贵,且不好制造,因为三块滤镜都必须保证每一个像素点都对齐。当用bayer格式的时候,很好的解决了这个问题。bayer 格式图片在一块滤镜上设置的不同的颜色,通过分析人眼对颜色的感知发现,人眼对绿色比较敏感,所以一般bayer格式的图片绿色格式的像素是是r和g像素的和。
另外,Bayer格式是相机内部的原始图片, 一般后缀名为.raw。很多软件都可以查看, 比如PS。我们相机拍照下来存储在存储卡上的.jpeg或其它格式的图片, 都是从.raw格式转化过来的。如下图,为bayer色彩滤波阵列,由一半的G,1/4的R,1/4的B组成。
2、Bayer图像传感原理
图像传感器的结构如下所示,每一个感光像素之间都有金属隔离层,光纤通过显微镜头,在色彩滤波器过滤之后,投射到相应的漏洞式硅的感光元件上。
当Image Sensor往外逐行输出数据时,像素的序列为GRGRGR…/BGBGBG…(顺序RGB)。这样阵列的Sensor设计,使得RGB传感器减少到了全色传感器的1/3,如下所示。
3、bayer格式插值红蓝算法实现
每一个像素仅仅包括了光谱的一部分,必须通过插值来实现每个像素的RGB值。为了从Bayer格式得到每个像素的RGB格式,我们需要通过插值填补缺失的2个色彩。插值的方法有很多(包括领域、线性、3*3等),速度与质量权衡,最好的线性插值补偿算法。其中算法如下:
R和B通过线性领域插值,但这有四种不同的分布,如下图所示:
A B
C D
在(a)与(b)中,R和B分别取邻域的平均值。
在(c)与(d)中,取领域的4个B或R的均值作为中间像素的B值。
4、bayer格式插值绿算法实现
E F
由于人眼对绿光反应最敏感,对紫光和红光则反应较弱,因此为了达到更好的画质,需要对G特殊照顾。在上述(c)与(d)中,扩展开来就是上图的(e)与(f)中间像素G的取值,者也有一定的算法要求,不同的算法效果上会有差异。经过相关的研究,
(e)中间像素G值的算法如下:
(f)中间像素G值的算法如下:
CMOS摄像头这部分转换是在内部用ADC或者ISP完成的,生产商为了降低成本必然会使得图像失真。当然用外部处理器来实现转换,如果处理器的速度足够NB,能够胜任像素的操作,用上面的算法来进行转换,皆大欢喜。不过上述算法将直接成倍提高了算法的复杂度,速度上将会有所限制。因此为了速度的提成,可以直接通过来4领域G取均值来中间像素的G值,将会降低一倍的速率,而在性能上差之甚微,算法如下:
如果能够通过损失图像的额质量,来达到更快的速度,还可以取G1、G2的均值来实现,但是这样的做法会导致边沿以及跳变部分的失真。
将Bayer格式转换为tif格式
//全部.h文件
#include <iostream>
#include <vector>
#include <fstream>
#include <gdal_priv.h>
#include <gdalwarper.h>
#include <gdal.h>
#include <stdio.h>
#include <stdlib.h>
#include "j2k_mem_advance.h"
#include "format_defs.h"
#include "j2k_mem.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/io.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <memory>
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <time.h>
#include <thread>
#include <stdio.h>
#include <string.h>
#include "TinyXML.h"
using namespace std;
//此头文件应该是必须的部分
#include <iostream>
#include <fstream>
#include <gdal_priv.h>
#include <gdalwarper.h>
#include <gdal.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
//核心代码部分
//将.dat文件读取后进行gbbr转换,最后转码为TIF文件
bool Anal_pixel(string strFilePath, string strSavePath, long nWidth, long nHeight, int nType)
{
// TODO: 在此添加控件通知处理程序代码
GDALAllRegister();
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //支持中文路径
if (strFilePath == "")
{
return false;
}
const char* pszFormat = "GTIFF";
GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
if (!poDriver) {
return false;
}
//long width = 7920;
//long height = 6004;
long long width = nWidth;
long long height = nHeight;
GDALDataType gdal_data_type = GDT_UInt16;
unsigned short* pData = new unsigned short[width * height];
fstream sf;
sf.open(strFilePath, ios::in | ios::binary);//打开文件,供读
sf.seekg(0, ios::beg);
//byte *bTemp = new byte[2];
unsigned char* bTemp = new unsigned char[2];
for (int i = 0; i < height * width; i++)
{
sf.read((char*)&bTemp[0], sizeof(unsigned char));
sf.read((char*)&bTemp[1], sizeof(unsigned char));
pData[i] = bTemp[0] * 256 + bTemp[1];
//char pBuff[8];
//sprintf(pBuff, "%04x", pData[i]);
//int isdsd = 0;
}
sf.close();
delete[] bTemp;
//----------------------解析
#pragma region 解析
PointInfo** cArryAllPoint; // 二维数组
cArryAllPoint = (PointInfo**)malloc(height * sizeof(PointInfo*));//height 行
for (int i = 0; i < height; i++) {
cArryAllPoint[i] = (PointInfo*)malloc(width * sizeof(PointInfo));//width 列
}
//读取文件,将文件中的数值填充
for (long long y = 0; y < height; y++)
{
for (long long x = 0; x < width / 2; x++)
{
cArryAllPoint[y][2 * x].Point_X = 2 * x;
cArryAllPoint[y][2 * x].Point_Y = y;
cArryAllPoint[y][2 * x + 1].Point_X = 2 * x + 1;
cArryAllPoint[y][2 * x + 1].Point_Y = y;
if (y % 2 == 0)
{
cArryAllPoint[y][2 * x].Point_B = pData[y * width / 4 + x + height * width * 1 / 2];//B
cArryAllPoint[y][2 * x + 1].Point_G = pData[y * width / 2 + x];//G
}
else
{
cArryAllPoint[y][2 * x].Point_G = pData[y * width / 2 + x];//G
cArryAllPoint[y][2 * x + 1].Point_R = pData[(y - 1) * width / 4 + x + height * width * 3 / 4];//R
}
}
}
delete[] pData;//释放内存
//计算RGB值
unsigned short R1, R2, R3, R4, B1, B2, B3, B4, G1, G2, G3, G4;
for (long long y = 0; y < height; y++)//初始化数据
{
for (long long x = 0; x < width; x++)
{
if (y % 2 == 0)
{
if (x % 2 == 0)
{
if (x == 0)
{
if (y == 0)
{
R1 = 0;
R2 = 0;
R3 = 0;
R4 = cArryAllPoint[y + 1][x + 1].Point_R;
G1 = 0;
G2 = 0;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
else if (y == height - 1)
{
R1 = 0;
R2 = 0;
R3 = cArryAllPoint[y - 1][x + 1].Point_R;
R4 = 0;
G1 = 0;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = 0;
}
else
{
R1 = 0;
R2 = 0;
R3 = cArryAllPoint[y - 1][x + 1].Point_R;
R4 = cArryAllPoint[y + 1][x + 1].Point_R;
G1 = 0;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
}
else if (x == width - 1)
{
if (y == 0)
{
R1 = cArryAllPoint[y + 1][x - 1].Point_R;
R2 = 0;
R3 = 0;
R4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = 0;
G3 = 0;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
else if (y == height - 1)
{
R1 = 0;
R2 = cArryAllPoint[y - 1][x - 1].Point_R;
R3 = 0;
R4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = 0;
G4 = 0;
}
else
{
R1 = cArryAllPoint[y + 1][x - 1].Point_R;
R2 = cArryAllPoint[y - 1][x - 1].Point_R;
R3 = 0;
R4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = 0;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
}
else
{
if (y == 0)
{
R1 = cArryAllPoint[y + 1][x - 1].Point_R;
R2 = 0;
R3 = 0;
R4 = cArryAllPoint[y + 1][x + 1].Point_R;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = 0;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
else if (y == height - 1)
{
R1 = 0;
R2 = cArryAllPoint[y - 1][x - 1].Point_R;
R3 = cArryAllPoint[y - 1][x + 1].Point_R;
R4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = 0;
}
else
{
R1 = cArryAllPoint[y + 1][x - 1].Point_R;
R2 = cArryAllPoint[y - 1][x - 1].Point_R;
R3 = cArryAllPoint[y - 1][x + 1].Point_R;
R4 = cArryAllPoint[y + 1][x + 1].Point_R;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
}
cArryAllPoint[y][x].Point_R = (R1 + R2 + R3 + R4) / 4;
cArryAllPoint[y][x].Point_G = (G1 + G2 + G3 + G4) / 4;
}
else
{
//unsigned short R1, R2, B1, B2;
//G
//G1,R2,G4
//B1,G ,B2
//G2,R1,G3
//R1 = cArryAllPoint.GetAt(y - 1)->GetAt(x).Point_R;
//R2 = cArryAllPoint.GetAt(y + 1)->GetAt(x).Point_R;
//B1 = cArryAllPoint.GetAt(y)->GetAt(x - 1).Point_B;
//B2 = cArryAllPoint.GetAt(y)->GetAt(x + 1).Point_B;
if (x == 0)
{
if (y == 0)
{
R1 = 0;
R2 = cArryAllPoint[y + 1][x].Point_R;
B1 = 0;
B2 = cArryAllPoint[y][x + 1].Point_B;
}
else if (y == height - 1)
{
R1 = cArryAllPoint[y - 1][x].Point_R;
R2 = 0;
B1 = 0;
B2 = cArryAllPoint[y][x + 1].Point_B;
}
else
{
R1 = cArryAllPoint[y - 1][x].Point_R;
R2 = cArryAllPoint[y + 1][x].Point_R;
B1 = 0;
B2 = cArryAllPoint[y][x + 1].Point_B;
}
}
else if (x == width - 1)
{
if (y == 0)
{
R1 = 0;
R2 = cArryAllPoint[y + 1][x].Point_R;
B1 = cArryAllPoint[y][x - 1].Point_B;
B2 = 0;
}
else if (y == height - 1)
{
R1 = cArryAllPoint[y - 1][x].Point_R;
R2 = 0;
B1 = cArryAllPoint[y][x - 1].Point_B;
B2 = 0;
}
else
{
R1 = cArryAllPoint[y - 1][x].Point_R;
R2 = cArryAllPoint[y + 1][x].Point_R;
B1 = cArryAllPoint[y][x - 1].Point_B;
B2 = 0;
}
}
else
{
if (y == 0)
{
R1 = 0;
R2 = cArryAllPoint[y + 1][x].Point_R;
B1 = cArryAllPoint[y][x - 1].Point_B;
B2 = cArryAllPoint[y][x + 1].Point_B;
}
else if (y == height - 1)
{
R1 = cArryAllPoint[y - 1][x].Point_R;
R2 = 0;
B1 = cArryAllPoint[y][x - 1].Point_B;
B2 = cArryAllPoint[y][x + 1].Point_B;
}
else
{
R1 = cArryAllPoint[y - 1][x].Point_R;
R2 = cArryAllPoint[y + 1][x].Point_R;
B1 = cArryAllPoint[y][x - 1].Point_B;
B2 = cArryAllPoint[y][x + 1].Point_B;
}
}
cArryAllPoint[y][x].Point_R = (R1 + R2) / 2;
cArryAllPoint[y][x].Point_B = (B1 + B2) / 2;
}
}
else
{
if (x % 2 == 0)
{
//unsigned short R1, R2, B1, B2;
//G
//G1,B2,G4
//R1,G ,R2
//G2,B1,G3
//R1 = cArryAllPoint.GetAt(y)->GetAt(x - 1).Point_R;
//R2 = cArryAllPoint.GetAt(y)->GetAt(x + 1).Point_R;
//B1 = cArryAllPoint.GetAt(y - 1)->GetAt(x).Point_B;
//B2 = cArryAllPoint.GetAt(y + 1)->GetAt(x).Point_B;
if (x == 0)
{
if (y == 0)
{
R1 = 0;
R2 = cArryAllPoint[y][x + 1].Point_R;
B1 = 0;
B2 = cArryAllPoint[y + 1][x].Point_B;
}
else if (y == height - 1)
{
R1 = 0;
R2 = cArryAllPoint[y][x + 1].Point_R;
B1 = cArryAllPoint[y - 1][x].Point_B;
B2 = 0;
}
else
{
R1 = 0;
R2 = cArryAllPoint[y][x + 1].Point_R;
B1 = cArryAllPoint[y - 1][x].Point_B;
B2 = cArryAllPoint[y + 1][x].Point_B;
}
}
else if (x == width - 1)
{
if (y == 0)
{
R1 = cArryAllPoint[y][x - 1].Point_R;
R2 = 0;
B1 = 0;
B2 = cArryAllPoint[y + 1][x].Point_B;
}
else if (y == height - 1)
{
R1 = cArryAllPoint[y][x - 1].Point_R;
R2 = 0;
B1 = cArryAllPoint[y - 1][x].Point_B;
B2 = 0;
}
else
{
R1 = cArryAllPoint[y][x - 1].Point_R;
R2 = 0;
B1 = cArryAllPoint[y - 1][x].Point_B;
B2 = cArryAllPoint[y + 1][x].Point_B;
}
}
else
{
if (y == 0)
{
R1 = cArryAllPoint[y][x - 1].Point_R;
R2 = cArryAllPoint[y][x + 1].Point_R;
B1 = 0;
B2 = cArryAllPoint[y + 1][x].Point_B;
}
else if (y == height - 1)
{
R1 = cArryAllPoint[y][x - 1].Point_R;
R2 = cArryAllPoint[y][x + 1].Point_R;
B1 = cArryAllPoint[y - 1][x].Point_B;
B2 = 0;
}
else
{
R1 = cArryAllPoint[y][x - 1].Point_R;
R2 = cArryAllPoint[y][x + 1].Point_R;
B1 = cArryAllPoint[y - 1][x].Point_B;
B2 = cArryAllPoint[y + 1][x].Point_B;
}
}
cArryAllPoint[y][x].Point_R = (R1 + R2) / 2;
cArryAllPoint[y][x].Point_B = (B1 + B2) / 2;
}
else
{
//unsigned short B1, B2, B3, B4, G1, G2, G3, G4;
//R
//B1,G4,B4
//G1,R ,G3
//B2,G2,B3
//B1 = cArryAllPoint.GetAt(y + 1)->GetAt(x - 1).Point_B;
//B2 = cArryAllPoint.GetAt(y - 1)->GetAt(x - 1).Point_B;
//B3 = cArryAllPoint.GetAt(y - 1)->GetAt(x + 1).Point_B;
//B4 = cArryAllPoint.GetAt(y + 1)->GetAt(x + 1).Point_B;
//G1 = cArryAllPoint.GetAt(y)->GetAt(x - 1).Point_G;
//G2 = cArryAllPoint.GetAt(y - 1)->GetAt(x).Point_G;
//G3 = cArryAllPoint.GetAt(y)->GetAt(x + 1).Point_G;
//G4 = cArryAllPoint.GetAt(y + 1)->GetAt(x).Point_G;
if (x == 0)
{
//不存在 X=0
}
else if (x == width - 1)
{
if (y == 0)
{
//不存在 Y=0
}
else if (y == height - 1)
{
B1 = 0;
B2 = cArryAllPoint[y - 1][x - 1].Point_B;
B3 = 0;
B4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = 0;
G4 = 0;
}
else
{
B1 = cArryAllPoint[y + 1][x - 1].Point_B;
B2 = cArryAllPoint[y - 1][x - 1].Point_B;
B3 = 0;
B4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = 0;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
}
else
{
if (y == 0)
{
//不存在 Y=0
}
else if (y == height - 1)
{
B1 = 0;
B2 = cArryAllPoint[y - 1][x - 1].Point_B;
B3 = cArryAllPoint[y - 1][x + 1].Point_B;
B4 = 0;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = 0;
}
else
{
B1 = cArryAllPoint[y + 1][x - 1].Point_B;
B2 = cArryAllPoint[y - 1][x - 1].Point_B;
B3 = cArryAllPoint[y - 1][x + 1].Point_B;
B4 = cArryAllPoint[y + 1][x + 1].Point_B;
G1 = cArryAllPoint[y][x - 1].Point_G;
G2 = cArryAllPoint[y - 1][x].Point_G;
G3 = cArryAllPoint[y][x + 1].Point_G;
G4 = cArryAllPoint[y + 1][x].Point_G;
}
}
cArryAllPoint[y][x].Point_B = (B1 + B2 + B3 + B4) / 4;
cArryAllPoint[y][x].Point_G = (G1 + G2 + G3 + G4) / 4;
}
}
}
}
//整合到pDataRGB中
//unsigned char * pDataRGB = new unsigned char[width * height * 3];
unsigned short** newbuffs = new unsigned short* [3]; // 1, 2, 3 : r g b
newbuffs[0] = new unsigned short[width * height];
newbuffs[1] = new unsigned short[width * height];
newbuffs[2] = new unsigned short[width * height];
double dTemp;
for (long long y = 0; y < height; y++)//初始化数据
{
for (long long x = 0; x < width; x++)
{
dTemp = (double)cArryAllPoint[y][x].Point_R;
newbuffs[0][y * width + x] = (unsigned short)dTemp;
dTemp = (double)cArryAllPoint[y][x].Point_G;
newbuffs[1][y * width + x] = (unsigned short)dTemp;
dTemp = (double)cArryAllPoint[y][x].Point_B;
newbuffs[2][y * width + x] = (unsigned short)dTemp;
}
}
double minDN[3] = { 0 };//统计最小的DN值
double maxDN[3] = { 0 };//统计最大的DN值
//释放内存 cArryAllPoint
for (int i = 0; i < height; i++)
{
delete[] cArryAllPoint[i];
}
free(cArryAllPoint);
//将原数据进行拉伸放大
for (long long m = 0; m < height; m++)
{
for (long long n = 0; n < width; n++)
{
for (long long i = 0; i < 3; i++)
{
if (newbuffs[i][m * width + n] < minDN[i])
minDN[i] = newbuffs[i][m * width + n];
if (newbuffs[i][m * width + n] > maxDN[i])
maxDN[i] = newbuffs[i][m * width + n];
}
}
}
for (long long i = 0; i < 3; i++)
{
for (long long m = 0; m < height*width; m++)
{
newbuffs[i][m] = (newbuffs[i][m] - minDN[i]) * 1.0 / (maxDN[i] - minDN[i]) * 65535;
}
}
#pragma endregion
if (nType == 0)//拉伸后的图像
{
char** papszOptions = nullptr;
papszOptions = CSLSetNameValue(papszOptions, "INTERLEAVE", "BAND");
papszOptions = CSLSetNameValue(papszOptions, "BIGTIFF", "IF_NEEDED");
const char* pszDstFilename = strSavePath.c_str();
GDALDataset* poDstDS = poDriver->Create(pszDstFilename, width, height, 3, GDT_UInt16, papszOptions);
if (!poDstDS) {
for (int i = 0; i < 3; i++)
{
delete[] newbuffs[i];
}
free(newbuffs);
return false;
}
int bandMap[3] = { 1, 2, 3 };
for (int i = 0; i < 3; i++)
{
poDstDS->GetRasterBand(i + 1)->RasterIO(GF_Write, 0, 0, width, height, newbuffs[i], width, height, GDT_UInt16, 0, 0, 0);
delete[] newbuffs[i];
}
free(newbuffs);
GDALClose((GDALDatasetH)poDstDS);
}
else
{
//针对原图16位的值进行高8位、低8位、中8位的转换。
unsigned char** newbuffs1 = new unsigned char* [3]; // 1, 2, 3 : r g b
newbuffs1[0] = new unsigned char[width * height];
newbuffs1[1] = new unsigned char[width * height];
newbuffs1[2] = new unsigned char[width * height];
for (long long i = 0; i < 3; i++)
{
for (long long m = 0; m < height; m++)
{
for (long long n = 0; n < width; n++)
{
char pBuff[4], pBuff2[8];
if (nType == 1)//高8
{
newbuffs1[i][m * width + n] = newbuffs[i][m * width + n] / 4;//------G8
}
else if (nType == 2)//中8
{
newbuffs1[i][m * width + n] = newbuffs[i][m * width + n] / 2;//-------M8
}
else if (nType == 3)//低8
{
newbuffs1[i][m * width + n] = newbuffs[i][m * width + n];//------D8
}
}
}
}
char** papszOptions = nullptr;
papszOptions = CSLSetNameValue(papszOptions, "INTERLEAVE", "BAND");
papszOptions = CSLSetNameValue(papszOptions, "BIGTIFF", "IF_NEEDED");
const char* pszDstFilename = strSavePath.c_str();
GDALDataset* poDstDS = poDriver->Create(pszDstFilename, width, height, 3, GDT_Byte, papszOptions);
if (!poDstDS) {
for (int i = 0; i < 3; i++)
{
delete[] newbuffs[i];
delete[] newbuffs1[i];
}
return false;
}
int bandMap[3] = { 1, 2, 3 };
for (int i = 0; i < 3; i++)
{
poDstDS->GetRasterBand(i + 1)->RasterIO(GF_Write, 0, 0, width, height, newbuffs1[i], width, height, GDT_Byte, 0, 0, 0);
delete[] newbuffs[i];
delete[] newbuffs1[i];
}
GDALClose((GDALDatasetH)poDstDS);
}
return true;
}
第一次书写博客会有些许乱,有需求的可以私我或者留言询问具体问题。
参考文件:
感谢作者:
淇淇宝贝 https://www.cnblogs.com/qiqibaby/p/5267566.html