多種格式圖像打開與顯示

由於圖像格式的差異,爲了解決圖像格式的問題,結合opencv、hdr庫寫一個能打開、保存多種圖像的類。功能如下:
1.打開、保存raw數據
2.打開、保存bmp、jpg、png圖像
3.打開、保存tif格式圖像
4.打開、保存hdr格式圖像

頭文件

//#pragma once
#ifndef _CIMAGEFILEOPEN_H
#define _CIMAGEFILEOPEN_H
#include<vector>
#include<string>
#include<RGBE.h>
#include<opencv2\opencv.hpp>
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<float>(i);
			for (int j = 0; j < cols; j++)
			{
				psrc[j] = static_cast<float>((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<float>(i);
			float* psrc1 = ncS[1].ptr<float>(i);
			float* psrc2 = ncS[2].ptr<float>(i);
			for (int j = 0; j < cols; j++)
			{
				psrc[j] = static_cast<float>((psrc[j] - dMin) / ddevi);
				psrc1[j] = static_cast<float>((psrc1[j] - dMin) / ddevi1);
				psrc2[j] = static_cast<float>((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<float>(i);
			for (int j = 0; j < cols; j++)
			{
				psrc[j] = static_cast<float>((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<float>(i);
			float* psrc1 = ncS[1].ptr<float>(i);
			float* psrc2 = ncS[2].ptr<float>(i);
			for (int j = 0; j < cols; j++)
			{
				psrc[j] = static_cast<float>((psrc[j] - dMin) / ddevi);
				psrc1[j] = static_cast<float>((psrc1[j] - dMin) / ddevi1);
				psrc2[j] = static_cast<float>((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<float>(i);
			for (int j = 0; j < cols; j++)
			{
				psrc[j] = static_cast<float>((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<float>(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<iostream>
#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;
}

不當之處,歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章