由于图像格式的差异,为了解决图像格式的问题,结合opencv、hdr库写一个能打开、保存多种图像的类。功能如下:
1.打开、保存raw数据
2.打开、保存bmp、jpg、png图像
3.打开、保存tif格式图像
4.打开、保存hdr格式图像
头文件
//#pragma once
#ifndef _CIMAGEFILEOPEN_H
#define _CIMAGEFILEOPEN_H
#include
#include
#include
#include
using namespace cv;
class CImageFileOpen
{
public:
CImageFileOpen();
~CImageFileOpen();
public://function
int MallocData();
int OpenRawFile(const char* filename, int rows, int cols);
int ReadHdrFile(const char* filename);
int ReadBmp(const char* filename);
int ReadJTP(const char* filename);
int ImWriteRaw(const char* filename, Mat src);
int ImWriteBJTP(const char* filename, Mat src);
int ImWriteHDR(const char* filename, Mat src);
public://data
/*
0:表示没有打开图片
1:Raw数据
2:hdr图像
3:bmp
4:jpg、tif、png
*/
size_t m_iFileType;
size_t m_iRows;
size_t m_iCols;
unsigned short* m_pRawData;
Mat m_mImage;
std::string m_sFileName;
};
#endif // !_CIMAGEFILEOPEN_H
.cpp文件
#include "ImageFileOpen.h"
#include "hdrloader.h"
typedef struct tagBITMAPFILEHEADER
{
unsigned short int bfType; //位图文件的类型,必须为BM
unsigned long bfSize; //文件大小,以字节为单位
unsigned short int bfReserverd1; //位图文件保留字,必须为0
unsigned short int bfReserverd2; //位图文件保留字,必须为0
unsigned long bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER
{
long biSize; //该结构大小,字节为单位
long biWidth; //图形宽度以象素为单位
long biHeight; //图形高度以象素为单位
short int biPlanes; //目标设备的级别,必须为1
short int biBitcount; //颜色深度,每个象素所需要的位数
long biCompression; //位图的压缩类型
long biSizeImage; //位图的大小,以字节为单位
long biXPelsPermeter; //位图水平分辨率,每米像素数
long biYPelsPermeter; //位图垂直分辨率,每米像素数
long biClrUsed; //位图实际使用的颜色表中的颜色数
long biClrImportant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER;
CImageFileOpen::CImageFileOpen():
m_iFileType(0)
, m_iRows(1024)
, m_iCols(1024)
, m_pRawData(nullptr)
, m_sFileName("")
{
}
CImageFileOpen::~CImageFileOpen()
{
if (m_pRawData)
{
delete[] m_pRawData;
m_pRawData = NULL;
}
}
int CImageFileOpen::MallocData()
{
if (m_iCols == 0 || m_iRows == 0)
return 0;//内存分配不合理
if (m_pRawData)
{
delete[] m_pRawData;
m_pRawData = nullptr;
}
size_t size = m_iCols*m_iRows;
m_pRawData = new unsigned short[size];
if (m_pRawData)
{
memset(m_pRawData, 0, size << 1);
return 1;
}
return 0;//分配失败
}
int CImageFileOpen::OpenRawFile(const char* filename, int rows, int cols)
{
if (filename == nullptr || rows == 0 || cols == 0)
return -1;//文件参数有错
m_sFileName = filename;
m_iCols = cols;
m_iRows = rows;
int tret = MallocData();
if (!tret)
return -3;//内存分配失败
FILE* tFile;
if (!fopen_s(&tFile, filename, "rb+"))
{//文件打开成功返回 0 离开时请务必保证图像已经关闭
fseek(tFile, 0, SEEK_END); //定位到文件末
int fileLength = ftell(tFile);
size_t nSize = (m_iCols*m_iRows);
if (fileLength < (nSize << 1))
{
fclose(tFile);
return -1;//文件打开成功,但是图像参数设置有误
}
else
{
fseek(tFile, 0, SEEK_SET);
if (m_pRawData == NULL)
{
fclose(tFile);
return -2;//文件打开成功,但是图像保存参数设置有误
}
//fread_s参数解析 https://docs.microsoft.com/zh-cn/previous-versions/hh977173(v=vs.110)
fread_s(m_pRawData, nSize << 1, sizeof(unsigned short), nSize, tFile);//bufferSize 目标缓冲区的大小(以字节为单位)
fclose(tFile);//关闭文件
m_mImage = Mat(rows, cols, CV_16UC1);
memcpy(m_mImage.data, m_pRawData, nSize << 1);
m_iFileType = 1;//raw 数据
return 1;//读取文件成功
}
}
else
return 0;//文件打开失败
}
int CImageFileOpen::ReadHdrFile(const char* filename)
{
HDRLoaderResult result;
bool ret = HDRLoader::load(filename, result);
if (!ret)
return -1;
m_iRows = result.height;
m_iCols = result.width;
m_mImage = Mat(result.height, result.width, CV_32FC3);
memcpy(m_mImage.data, result.cols, sizeof(float) * 3 * m_iRows*m_iCols);
m_sFileName = filename;
m_iFileType = 2;//hdr 文件
return 1;//读取文件成功
}
int CImageFileOpen::ReadBmp(const char* filename)
{
if (filename == nullptr)
return -1;//文件名为空
int flags;
FILE* tFile;
if (!fopen_s(&tFile, filename, "rb+"))
{//文件打开成功 请保证离开时关闭文件
//跳过位图文件头结构BITMAPFILEHEADER
fseek(tFile, sizeof(BITMAPFILEHEADER), 0);
//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中
BITMAPINFOHEADER head;
fread(&head, sizeof(BITMAPINFOHEADER), 1, tFile);
int biBitCount = head.biBitcount;//bmp图像的位数 可分8位与24位
flags = biBitCount == 8 ? 0 : 1;
flags = biBitCount == 24 ? 1 : 0;
fclose(tFile);
}
else
return -1;//文件打开失败
m_mImage = cv::imread(filename, flags);
m_iFileType = 3;
m_sFileName = filename;
return 1;//获取图像成功
}
int CImageFileOpen::ReadJTP(const char* filename)
{
if (filename == nullptr)
return -1;//文件名为空
m_mImage = cv::imread(filename);
m_iFileType = 4;
m_sFileName = filename;
return 1;//获取图像成功
}
int CImageFileOpen::ImWriteRaw(const char* filename, Mat src)
{
if (filename == nullptr || src.empty())
return -1;
Mat tsrc = src.clone();
int rows = tsrc.rows;
int cols = tsrc.cols;
int size = rows*cols;
if (src.channels() != 1)
cvtColor(src, tsrc, CV_BGR2GRAY);
Mat mStore;
if (tsrc.depth() != 2)
{
double dMin, dMax;
minMaxIdx(tsrc, &dMin, &dMax);
Mat fsrc;
tsrc.convertTo(fsrc, CV_32FC1);
double ddevi = dMax - dMin + DBL_EPSILON;
for (int i = 0; i < rows; i++)
{
float* psrc = fsrc.ptr(i);
for (int j = 0; j < cols; j++)
{
psrc[j] = static_cast((psrc[j] - dMin) / ddevi);
}
}
fsrc.convertTo(mStore, CV_16UC1, 65535);
}
FILE* tFile;
unsigned short *tdata = new unsigned short[size];
memcpy(tdata, mStore.data, size << 1);
if (!fopen_s(&tFile, filename, "wb+"))
{
fwrite(tdata, sizeof(unsigned short), size, tFile);
fclose(tFile);
}
if (tdata)
{
delete[] tdata;
tdata = nullptr;
}
return 1;
}
int CImageFileOpen::ImWriteBJTP(const char* filename, Mat src)
{
if (filename == nullptr || src.empty())
return -1;
std::string tfilename = filename;
if (tfilename.find(".tif") != std::string::npos)
imwrite(filename, src);
int nchannel = src.channels();
if(src.depth()==1)
imwrite(filename, src);
if (nchannel & 2)
{
Mat tStore;
src.convertTo(tStore, CV_32FC3);
int rows = tStore.rows;
int cols = tStore.cols;
Mat ncS[3];
split(tStore, ncS);
double dMin, dMax, dMin1, dMax1, dMin2, dMax2;
minMaxIdx(ncS[0], &dMin, &dMax);
minMaxIdx(ncS[1], &dMin1, &dMax1);
minMaxIdx(ncS[2], &dMin2, &dMax2);
double ddevi = dMax - dMin + DBL_EPSILON;
double ddevi1 = dMax1 - dMin1 + DBL_EPSILON;
double ddevi2 = dMax2 - dMin2 + DBL_EPSILON;
for (int i = 0; i < rows; i++)
{
float* psrc = ncS[0].ptr(i);
float* psrc1 = ncS[1].ptr(i);
float* psrc2 = ncS[2].ptr(i);
for (int j = 0; j < cols; j++)
{
psrc[j] = static_cast((psrc[j] - dMin) / ddevi);
psrc1[j] = static_cast((psrc1[j] - dMin) / ddevi1);
psrc2[j] = static_cast((psrc2[j] - dMin) / ddevi2);
}
}
merge(ncS, 3, tStore);
Mat store;
tStore.convertTo(store, CV_8UC3, 255);
imwrite(filename, store);
return 1;
}
else
{
Mat tStore;
src.convertTo(tStore, CV_32FC1);
int rows = tStore.rows;
int cols = tStore.cols;
double dMin, dMax;
minMaxIdx(tStore, &dMin, &dMax);
double ddevi = dMax - dMin + DBL_EPSILON;
for (int i = 0; i < rows; i++)
{
float* psrc = tStore.ptr(i);
for (int j = 0; j < cols; j++)
{
psrc[j] = static_cast((psrc[j] - dMin) / ddevi);
}
}
Mat store;
tStore.convertTo(store, CV_8UC1, 255);
imwrite(filename, store);
return 1;
}
}
int CImageFileOpen::ImWriteHDR(const char* filename, Mat src)
{
if (filename == nullptr || src.empty())
return -1;
int nchannel = src.channels();
Mat tStore;
if (nchannel & 2)
{
src.convertTo(tStore, CV_32FC3);
int rows = tStore.rows;
int cols = tStore.cols;
Mat ncS[3];
split(tStore, ncS);
double dMin, dMax, dMin1, dMax1, dMin2, dMax2;
minMaxIdx(ncS[0], &dMin, &dMax);
minMaxIdx(ncS[1], &dMin1, &dMax1);
minMaxIdx(ncS[2], &dMin2, &dMax2);
double ddevi = dMax - dMin + DBL_EPSILON;
double ddevi1 = dMax1 - dMin1 + DBL_EPSILON;
double ddevi2 = dMax2 - dMin2 + DBL_EPSILON;
for (int i = 0; i < rows; i++)
{
float* psrc = ncS[0].ptr(i);
float* psrc1 = ncS[1].ptr(i);
float* psrc2 = ncS[2].ptr(i);
for (int j = 0; j < cols; j++)
{
psrc[j] = static_cast((psrc[j] - dMin) / ddevi);
psrc1[j] = static_cast((psrc1[j] - dMin) / ddevi1);
psrc2[j] = static_cast((psrc2[j] - dMin) / ddevi2);
}
}
merge(ncS, 3, tStore);
}
else
{
src.convertTo(tStore, CV_32FC1);
int rows = tStore.rows;
int cols = tStore.cols;
double dmin, dmax;
minMaxIdx(tStore, &dmin, &dmax);
double dSub = dmax - dmin + DBL_EPSILON;
for (int i = 0; i < rows; i++)
{
float* psrc = tStore.ptr(i);
for (int j = 0; j < cols; j++)
{
psrc[j] = static_cast((psrc[j] - dmin) / dSub);
}
}
Mat ncS[3];
tStore.copyTo(ncS[0]);
tStore.copyTo(ncS[1]);
tStore.copyTo(ncS[2]);
merge(ncS, 3, tStore);
}
FILE* tStoref;
if (!fopen_s(&tStoref, filename, "wb+"))
{
int width = tStore.cols;
int height = tStore.rows;
int size = width*height;
rgbe_header_info info;
memset(&info, 0, sizeof(rgbe_header_info));
info.valid = 1;
strcpy_s(info.programtype, "RADIANCE");
RGBE_WriteHeader(tStoref, width, height, &info);
float* wdata = new float[size * 3];
if (wdata == NULL)
{
fclose(tStoref);
return -1;
}
memset(wdata, 0, size * 3 * sizeof(float));
size_t position = 0;
int nc = width * tStore.channels();
for (int i = 0; i < height; i++)
{
float* data = tStore.ptr(i);
for (int j = 0; j < nc; j++)
{
wdata[position + j] = data[j];
}
position += nc;
}
RGBE_WritePixels(tStoref, wdata, size);
fclose(tStoref);
if (wdata)
{
delete[] wdata;
wdata = NULL;
}
return 1;
}
else
return 0;
}
测试程序
#include
#include"ImageFileOpen.h"
using namespace std;
int main()
{
CImageFileOpen tem;
// const char* fileName = "D:\\41.raw";
// tem.OpenRawFile(fileName, 1024, 1024);
const char* fileName = "D:\\hdrPic\\belgium.hdr";
tem.ReadHdrFile(fileName);
imshow("src", tem.m_mImage);
waitKey(0);
return 0;
}
不当之处,欢迎指正。