C++实现binary文件读取(可对’bil’,‘bsq’ float32,double,unchar,unit16,unit8等格式进行读取)
#pragma once
#include<windows.h>
#include<iostream>
#include<string>
#include<sstream>
#include<fstream>
#include <vector>
#include"image.h"
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class Binary
{
int binaryWidth;//图像的宽
int binaryHeight;//图像的高
int bands;//波段
string interleave;//数据存储格式(bil,bsq)
string datatype;//数据类型(int,double,float)
int Datatype;//头文件中data type表数据类型的数字(1,2,3)
int headeroffset;//文件头所占字节
typedef struct tagBINARYINFO//文件头中的信息
{
WORD Width;//图像的宽
WORD Height;//图像的高
WORD Bands;//图像波段
WORD Year;//年
WORD Month;//月
WORD Day;//日
}tagBINARYINFO;
typedef struct tagBINARYHEAD
{
char sensor[6];//传感器类型
}tagBINARYHEAD;
//读取binary文件头,获取相关参数
bool readbinaryhead(char* binaryname);
template<typename T>
bool readbinary(T* pbinaryBuf, char* readpath, T** band);//读取文件
/*vector<string> strsplit(const string& s, const string& seperator);*/
public:
Binary()
{
binaryWidth = 0;
binaryHeight = 0;
bands = 0;
Datatype = 0;
headeroffset = 0;
}
int read(char*);//测试程序
template<typename T>
T* readBand(T* imgBuf, const char* data_type, int);//分波段读取数据
};
//读取头文件
bool Binary::readbinaryhead(char* Binaryname)
{
char* binaryname;
binaryname = new char[strlen(Binaryname)];
strcpy(binaryname, Binaryname);//创建副本,保留原指针
int t = strlen(binaryname);
if (binaryname[strlen(binaryname) - 4] == '.')//查找文件头文件
{
binaryname[strlen(binaryname) - 3] = 'h';
binaryname[strlen(binaryname) - 2] = 'd';
binaryname[strlen(binaryname) - 1] = 'r';
}
ifstream inf;
inf.open(binaryname);
if (!inf.is_open())
{
cout << "头文件打开失败!" << endl;
return 0;
}
string sline;//每一行
string out;
string s1, s2, s3, s4;
while (getline(inf, sline))
{
istringstream sin(sline);
sin >> s1 >> s2 >> s3 >> s4;
if (s1 == "samples")
binaryWidth = atoi(s3.c_str());
if (s1 == "lines")
binaryHeight = atoi(s3.c_str());
if (s1 == "bands")
bands = atoi(s3.c_str());
if (s1 == "header" && s2 == "offset")
headeroffset = atoi(s4.c_str());
if (s1 == "data" && s2 == "type")
Datatype = atoi(s4.c_str());
if (s1 == "interleave")
interleave = s3.c_str();
}
switch (Datatype)
{
case 1:
datatype = "uint8";// 灰度范围0 - 255
break;
case 2:
datatype = "int16"; // 16位整数
break;
case 3:
datatype = "int32"; // 32位整数
break;
case 4:
datatype = "float32"; // 32位浮点数
break;
case 5:
datatype = "double"; // 64位浮点数
break;
case 6:
datatype = "uint16";//灰度范围0 - 2 ^ 16
break;
case 7:
datatype = "uint32";// 灰度范围0 - 2 ^ 32
break;
case 8:
datatype = "uint64";// 灰度范围0 - 2 ^ 64
break;
case 12:
datatype = "uint16";// 灰度范围0 - 2 ^ 16
break;
case 13:
datatype = "uint32";// 灰度范围0 - 2 ^ 32
break;
}
return 1;
}
template<typename T>
T* Binary::readBand(T* imgBuf, const char* type, int k)//k指波段数
{
int widthstep = double(binaryWidth) * sizeof(T);
T* image = new T[binaryWidth * binaryHeight];
if (strcmp(type, "bil") == 0)
{
for (int i = 0; i < binaryHeight; i++)
{
for (int j = 0; j < binaryWidth; j++)
{
image[i * binaryWidth + j] = imgBuf[binaryWidth * bands * i + binaryWidth * (k - 1) + j];
}
}
}
if (strcmp(type, "bsq") == 0)
{
for (int i = 0; i < binaryHeight; i++)
{
for (int j = 0; j < binaryWidth; j++)
{
image[i * binaryWidth + j] = imgBuf[(k - 1) * binaryWidth * binaryHeight + i * binaryWidth + j];
}
}
}
return image;
}
template<typename T>
bool Binary::readbinary(T* pbinaryBuf, char* readpath, T** band)//
{
FILE* fp; errno_t err;
err = fopen_s(&fp, readpath, "rb");
if (err != 0)
{
cout << "The file" << readpath << "was not opend" << endl;
return 0;
}
fseek(fp, headeroffset, 0);//跳过头文件所占字节
double widthstep = double(binaryWidth) * sizeof(T);//计算宽度
fread(pbinaryBuf, sizeof(T), widthstep * binaryHeight * bands, fp);//读取文件到指针
fclose(fp);//关闭文件
if (!pbinaryBuf)
{
cout << "输入文件错误!";
return 0;
};
for (int i = 0; i < bands; i++)//为指针申请空间
{
band[i] = new T[double(binaryWidth) * binaryHeight];
}
for (int i = 0; i < bands; i++)//按波段读取数据
{
band[i] = readBand(pbinaryBuf, interleave.c_str(), i + 1);
}
return 1;
}
int Binary::read(char* Path)
{
readbinaryhead(Path);
switch (Datatype)
{
case 1:
{
double widthstep = double(binaryWidth) * sizeof(unsigned char);//计算宽度
unsigned char* pbinaryBuf = new unsigned char[widthstep * binaryHeight * bands];//申请指针所占内存
unsigned char** band = new unsigned char* [bands];
readbinary(pbinaryBuf, Path, band);
Mat myimg(binaryHeight, binaryWidth, CV_8UC3);
for (int row = 0; row < binaryHeight; row++)
{
for (int col = 0; col < binaryWidth; col++)
{
myimg.at<Vec3b>(row, col) = Vec3b(band[0][row * binaryWidth + col], band[1][row * binaryWidth + col], band[2][row * binaryWidth + col]);
}
}
imshow("读取影像", myimg);
cv::waitKey(0);
}break;
case 2:
{
double widthstep = double(binaryWidth) * sizeof(short int);//计算宽度
short int* pbinaryBuf = new short int[widthstep * binaryHeight * bands];//申请指针所占内存
short int** band = new short int* [bands];
readbinary(pbinaryBuf, Path, band);
Mat myimg(binaryHeight, binaryWidth, CV_16UC3);
for (int row = 0; row < binaryHeight; row++)
{
for (int col = 0; col < binaryWidth; col++)
{
myimg.at<Vec3s>(row, col) = Vec3s(band[0][row * binaryWidth + col], band[1][row * binaryWidth + col], band[2][row * binaryWidth + col]);
}
}
imshow("读取影像", myimg * 10);
cv::waitKey(0);
}break;
case 3:
{
double widthstep = double(binaryWidth) * sizeof(int);//计算宽度
int* pbinaryBuf = new int[widthstep * binaryHeight * bands];//申请指针所占内存
int** band = new int* [bands];
readbinary(pbinaryBuf, Path, band);
Mat myimg(binaryHeight, binaryWidth, CV_32SC3);
for (int row = 0; row < binaryHeight; row++)
{
for (int col = 0; col < binaryWidth; col++)
{
myimg.at<Vec3s>(row, col) = Vec3s(band[0][row * binaryWidth + col], band[1][row * binaryWidth + col], band[2][row * binaryWidth + col]);
}
}
imshow("读取影像", myimg * 100);
cv::waitKey(0);
}break;
case 4:
{
double widthstep = double(binaryWidth) * sizeof(float);//计算宽度
float* pbinaryBuf = new float[widthstep * binaryHeight * bands];//申请指针所占内存
float** band = new float* [bands];
readbinary(pbinaryBuf, Path, band);
Mat myimg(binaryHeight, binaryWidth, CV_32FC3);
for (int row = 0; row < binaryHeight; row++)
{
for (int col = 0; col < binaryWidth; col++)
{
myimg.at<Vec3f>(row, col) = Vec3f(band[0][row * binaryWidth + col], band[1][row * binaryWidth + col], band[2][row * binaryWidth + col]);
}
}
imshow("读取影像", myimg / 2047);
cv::waitKey(0);
}break;
case 5:
{
double widthstep = double(binaryWidth) * sizeof(double);//计算宽度
double* pbinaryBuf = new double[widthstep * binaryHeight * bands];//申请指针所占内存
double** band = new double* [bands];
readbinary(pbinaryBuf, Path, band);
Mat myimg(binaryHeight, binaryWidth, CV_64FC3);
for (int row = 0; row < binaryHeight; row++)
{
for (int col = 0; col < binaryWidth; col++)
{
myimg.at<Vec3d>(row, col) = Vec3d(band[0][row * binaryWidth + col], band[1][row * binaryWidth + col], band[2][row * binaryWidth + col]);
}
}
imshow("读取影像", myimg / 2047);
cv::waitKey(0);
}break;
case 12:
{
double widthstep = double(binaryWidth) * sizeof(unsigned int);//计算宽度
unsigned int* pbinaryBuf = new unsigned int[widthstep * binaryHeight * bands];//申请指针所占内存
unsigned int** band = new unsigned int* [bands];
readbinary(pbinaryBuf, Path, band);
Mat myimg;
if (bands >= 3)
myimg.create(binaryHeight, binaryWidth, CV_16UC3);
else
myimg.create(binaryHeight, binaryWidth, CV_16UC1);
for (int row = 0; row < binaryHeight; row++)
{
for (int col = 0; col < binaryWidth; col++)
{
if (bands >= 3)
myimg.at<Vec3s>(row, col) = Vec3s(band[0][row * binaryWidth + col], band[1][row * binaryWidth + col], band[2][row * binaryWidth + col]);
}
}
imshow("读取影像", myimg);
cv::waitKey(0);
}break;
}
cout << "运行结束!" << endl;
return 1;
}
总结:
读取文件成功,但是显示图像的时候出现条状混乱线条可能是:
headoffset出错,读取方式bil或者bsq出错,行列数出错;
调用imshow时乘的数字是为了让图像得以显示,后续可以写拉伸程序实现
多波段可以读取成功,单波段暂时不能读取。