c++实现对图像数据的读写
近日,由于对图像的读取底层封装特别的好奇,想试试自己的想法是否正确,结果出乎我的意料了,仅以此篇博客记录自己的拓展心得吧!!!
一般情况下,对于图像数据的读取操作跟文件读取操作基本一致,区别在于一个使用文本模式读取,另一个使用二进制模式读取,按照这个思路开始coding,发现每次读取的图像数据都和自己计算的数据总是对不上,开始迷惑了。。。。。。
先放个图说下自己的想法
此图为宽高数据为(350, 499),位深度为真彩色24位。
按照正常思路,整张图的像素点为(350x499),而对于真彩色24位图像来说,每个像素是占用24位,也就是24/8=3个字节,8byte=1bit,1024bit=1kb,最后计算出的结果就是350x499x24/8/1024=511.6KB
然而
查看图像的属性却发现实际大小只有76.4KB,一头雾水中。。。。。
愤然跑去google查找资料,最后发现,其实图像是经过JPEG进行标准压缩后的数据大小,而且还不会让图像失真,看起来效果都很好,真的是不查不知道,一查吓一跳呀!
其实想想也对,如果对于一张分辨率为1920*1080的24位图像,那他的存储数据量就达到了5.9MB啊,而且网络上那么多的高清图,那需要的存储量可想而知!
对于压缩原理可以查看[JPEG压缩原理]
最后还进行了程序demo测试的过程,通过C++编写,读取图像中的所有数据字节数
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
ifstream f; // 读取图像
f.open("D:/Images/test3.jpg", ios::in | ios::binary);
f.seekg(0, ios::end); // 将文件指针移动到文件末尾
int length = f.tellg(); // 返回文件指针的位置
cout << "图像数据总字节数:" << length << endl;
f.seekg(0, ios::beg);
//根据图像数据长度分配内存buffer
uchar* ImgBuffer = new uchar[length];
f.read((char *)ImgBuffer, length * sizeof(char));
f.close();
ofstream out; // 读取图像
out.open("C:/Users/cheng/Desktop/test.jpg", ios::out | ios::binary);
//从buffer中写数据到out指向的文件中
out.write((const char*)ImgBuffer, length * sizeof(char));
//关闭文件指针,释放buffer内存
out.close();
delete[]ImgBuffer;
return 0;
}
最后的结果反而对上了图像属性字节数
而如果对于需要对图像做处理,那就需要考虑的每个像素值得处理,而对于jpg图像被压缩是有RGB形式转到CMYK的形式,主要是减少数据量的目的,而最后还有一个压缩数据比,就可能需要涉及自己coding解压缩的代码,这部分就需要理解底层的压缩原理了,后续会再去研究,目前还是用OpenCV中的Mat形式读写数据,OpenCV是将图像数据封装成了一个Mat数组的形式,对于图像底层的解压缩已经封装成了类,直接调用就行了,又是个站在巨人的肩膀上前进的过程,嘻嘻!
如果有童鞋真的很喜欢研究底层图像知识的话,可以骚扰我哈,给我点见解,哈哈!
用到的知识链接:http://www.360doc.com/content/17/0901/18/41193811_683881904.shtml