源码解析: Imread函数
来源:互联网 发布:淘宝阿里旺旺买家版 编辑:程序博客网 时间:2024/06/05 11:34
源码解析: Imread函数
i mread()函数
声明:
- Mat imread(const string& filename, int flags);
这很标准的写法,传入一个string类型的常量引用。
定义:
- Mat imread(const string& filename, int flags)
- {
- Mat img; //创建一个变量
- imread_(filename,flags,LOAD_MAT,&img);
- return img;
- }
其中imread_()中&img用的是地址符号,为什么呢?当然是为了改变其里面的数据了。imread( )函数是就这么几行么?这么几行能干什么呢?其实它把所有的事情交给了imread_()函数。所以,我们进一步分析imread_()函数。
imread_()函数
声明:
- static void* imread_(const string& filename, int flags, int hdrtype, Mat* mat=0 );
其中这个函数返回的是一个空指针,其实在上面,这个返回值时没有用到的。 filename:文件地址 flags:标志,读取什么样(灰度,彩色)图像hdrtype:传入的为载入什么类型(enum {LOAD_CVMAT=0,LOAD_IMAGE=1, LOAD_MAT=2 };这三个中的一个。) Mat :保存图像的Mat对象了。
定义:
- static void* imread_(const string& filename, int flags, int hdrtype, Mat* mat=0)
- {
- IplImage* image = 0;
- CvMat *matrix = 0;
- Mat temp, *data = &temp;
- ImageDecoder decoder = findDecoder(filename);//这个是解析图像的后缀名的,用来决定读取特定图像的数据,所有的事情都是它干了。
- if( decoder.empty() )
- return 0;
- decoder->setSource(filename);
- if( !decoder->readHeader() )//读取图像的头部信息
- return 0;
- CvSize size; //读取图像的大小
- size.width = decoder->width();
- size.height = decoder->height();
- int type = decoder->type();//读取类型?
- if( flags != -1 )
- { //决定什么样的类型
- if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 )
- type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
- if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||
- ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
- type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);//彩色
- else
- type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);//灰度
- }
- if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT )
- {
- if( hdrtype == LOAD_CVMAT )
- {
- matrix = cvCreateMat( size.height, size.width, type );
- temp = cvarrToMat(matrix); //创建一个空的,即还没有图像数据的对象。
- }
- else
- {
- mat->create( size.height, size.width, type );
- data = mat;
- }
- }
- else//就是传入的类型都为IplImage*类型的
- {
- image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) );
- temp = cvarrToMat(image);
- }
- if(!decoder->readData(*data))//读取数据,这里应该是复制数据,想一想这个是要懂硬盘上去读取数据的。
- {//失败
- cvReleaseImage(&image);
- cvReleaseMat(&matrix);//c风格的释放
- if( mat )
- mat->release();//c++风格的释放
- return 0;
- }
- return hdrtype == LOAD_CVMAT ? (void*)matrix :
- hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;//最后返回c类型的图像指针,这个是为了考虑c风格的
- }
这个看了半天,是不是没有什么实质性的东西?一个到底怎么读图还没完全了解吧。全都封装了起来(decoder),你看不到所有的细节,而只是一个大概的流程。这个流程不是自己都知道了么?
不管怎么样,我不想关注这个图是怎么解析的,只看这函数怎么把数据给读进了Mat中,先保持这个目标不变:
首先:传入了一个Mat类型的变量,这个变量是传了地址的,也就是会改变这个mat类型变量。Mat在构造函数中开始会构造什么呢?尤其是默认构造函数?其实他什么也没有构造,因为什么都不知道。
其次:Mat类型需要记录图像的哪些数据呢?一个是头:图像是灰度或彩色(这里姑且只考虑这两种),一个图像数据的大小(图像的宽与高);一个数据体:二维数组或是一维数组。
最后:从decoder中读入data数据。当然这里会牵涉到图像解码过程的(这个如果特别感兴趣就看看了,否则不用了)。
在第一篇处,我们只是在最表层的上面操作函数,当别人问我们时,我们其实什么也不知道的。就知道,imread是读取函数了,然后掉用其它的函数的乐乐。当然,上面我们可以好好学习人家为什么要这样做了!这里,看一个函数finddecoder()。这个函数主要是获取decoder对象,从而决定读取什么样后缀名的图像(jpg,bmp等等)
findDecoder()函数
声明:
- ImageDecoder findDecoder( const string& filename );//在highgui/loadsave.cpp中
- ImageDecoder findDecoder( const Mat& buf );
定义:
- ImageDecoder findDecoder( const string& filename )
- {
- size_t i, maxlen = 0;
- for( i = 0; i < decoders.size(); i++ )//这里第一个decoders是什么呢?在文件中有这样的一个定义:static vector<ImageDecoder> decoders;好家伙,原来是一个向量,这里第一问,为什么要是一个向量,而且还是全局静态变量,就是说整个程序运行期间它都存在。其只初始化一遍。
- {
- size_t len = decoders[i]->signatureLength();//这一个循环是寻找第一个数据点保存的数据:signature。从这里可以看出,其实后缀名在这里没有什么用处,文件本身是保存了这个类型值的。
- maxlen = std::max(maxlen, len);//读取数据长度为一个最大的。
- }
- FILE* f= fopen( filename.c_str(), "rb" );//熟悉的c函数,读取文件。哈哈,从这个可以看到,所有的文件都可以有FILE来读取的。
- if( !f )
- return ImageDecoder();//没有读取成功,返回一个空的decoder。处理错误的能力。
- string signature(maxlen, ' ');
- maxlen = fread( &signature[0], 1, maxlen, f );//从文件中读取signature数据,这里是用了string,且是按字节读取。string底层用了什么结构呢?string[0]返回的是一个什么值呢?这有待查询。
- /*这里是一个试验:
- int maxlen = 10 ;
- string sig(maxlen,' ');
- cout<<&sig<<endl;
- cout<<((int*)&sig[0])<<endl;
- cout<<((int*)&sig[1])<<endl;
- 从其中可以看出两个量的值是不同的:
- 0x22ff40
- 0x3e3cbc //这里和后面的数据相差一个字节,代表这是一个char类型的
- 0x3e3cbd
- */
- fclose(f);
- signature = signature.substr(0, maxlen);
- for( i = 0; i < decoders.size(); i++ )
- {
- if( decoders[i]->checkSignature(signature) )//检测读取出来的数据是否与保存的数据signature一样,一样就代表是这个类型了。
- return decoders[i]->newDecoder();//创建这个类型的decoder变量。
- }
- return ImageDecoder();
- }
下面是decoders数据内容的来源:
- struct ImageCodecInitializer
- {
- ImageCodecInitializer( )
- {
- decoders.push_back(new BmpDecoder);
- encoders.push_back(new BmpEncoder);
- #ifdef HAVE_JPEG
- decoders.push_back(new JpegDecoder);
- encoders.push_back(new JpegEncoder);
- #endif
- decoders.push_back(new SunRasterDecoder);
- encoders.push_back(new SunRasterEncoder);
- decoders.push_back(new PxMDecoder);
- encoders.push_back(new PxMEncoder);
- #ifdef HAVE_TIFF
- decoders.push_back(new TiffDecoder);
- #endif
- encoders.push_back(new TiffEncoder);
- #ifdef HAVE_PNG
- decoders.push_back(new PngDecoder);
- encoders.push_back(new PngEncoder);
- #endif
- #ifdef HAVE_JASPER
- decoders.push_back(new Jpeg2KDecoder);
- encoders.push_back(new Jpeg2KEncoder);
- #endif
- #ifdef HAVE_OPENEXR
- decoders.push_back(new ExrDecoder);
- encoders.push_back(new ExrEncoder);
- #endif
- // because it is a generic image I/O API, supporting many formats,
- // it should be last in the list.
- #ifdef HAVE_IMAGEIO
- decoders.push_back(new ImageIODecoder);
- encoders.push_back(new ImageIOEncoder);
- #endif
- }
- };
static ImageCodecInitializer initialize_codecs; //这里直接的给定了decoders的内容。
这样读取图像数据又清晰了一步,首先是我们会首先保存好要解析的图像格式,即支持什么类型的图像。然后第一步是取读取保存在第一个数据点上的signature数据,然后再去读取下面的数据。所以,要很清楚的了解图像的头。
ImageDecoder类
ImageDecoder这个类,这个类其实就是一个图像数据的解析类。且看下面的
源代码:
- class BaseImageDecoder //这就是我们要找的ImageDecoder类
- {
- public:
- BaseImageDecoder();
- virtual ~BaseImageDecoder() {};
- int width() const { return m_width; };
- int height() const { return m_height; };
- int type() const { return m_type; };
- virtual bool setSource( const string& filename );
- virtual bool setSource( const Mat& buf );
- virtual bool readHeader() = 0;
- virtual bool readData( Mat& img ) = 0;
- virtual size_t signatureLength() const;//(1)
- virtual bool checkSignature( const string& signature ) const;
- virtual ImageDecoder newDecoder() const;
- protected:
- int m_width; // width of the image ( filled by readHeader )
- int m_height; // height of the image ( filled by readHeader )
- int m_type;
- string m_filename;
- string m_signature;//(2)
- Mat m_buf;
- bool m_buf_supported;
- };
- typedef Ptr<BaseImageDecoder> ImageDecoder; //
且在代码中有:decoders[i]->signatureLength();的调用,且可以看到(1)处就有这个函数。
- size_t BaseImageDecoder::signatureLength() const
- {
- return m_signature.size();
- }
- bool BaseImageDecoder::checkSignature(const string& signature) const
- {
- size_t len = signatureLength();
- return signature.size()>= len&&memcmp(signature.c_str(),m_signature.c_str(),len)==0;
- }
- ImageDecoder BaseImageDecoder::newDecoder() const
- {
- return ImageDecoder();//这里其实就是一个直接的调用了一个构造函数
- }
- BaseImageDecoder::BaseImageDecoder()
- {
- m_width = m_height = 0;
- m_type = -1;
- m_buf_supported = false;
- }
这里不看别的,就看一个bmp类型的吧:
- class BmpDecoder : public BaseImageDecoder
- {
- public:
- BmpDecoder();
- ~BmpDecoder();
- bool readData( Mat& img );//很明显这是读取数据
- bool readHeader();
- void close();
- ImageDecoder newDecoder() const;//这里重新的给了一个声明,表明在调用的时候调用的是子类的东西。
- protected:
- RLByteStream m_strm;
- PaletteEntry m_palette[256];//调试版(palette)
- int m_origin;
- int m_bpp;
- int m_offset;
- BmpCompression m_rle_code;
- /*压缩的格式
- enum BmpCompression
- {
- BMP_RGB = 0,
- BMP_RLE8 = 1,
- BMP_RLE4 = 2,
- BMP_BITFIELDS = 3
- };
- */
- };
- bmpDecoder类里面的东西很多,这里简要的给看看:
- ImageDecoder BmpDecoder::newDecoder() const
- {
- return new BmpDecoder;
- }
- BmpDecoder::BmpDecoder()
- {
- m_signature = fmtSignBmp;//static const char* fmtSignBmp = "BM"; 设定了自己标签名
- m_offset = -1;
- m_buf_supported = true;//buf设定为true,表示可以读取数据
- }
- ImageDecoder BmpDecoder::newDecoder() const
- {
- return new BmpDecoder;
- }
- BmpDecoder::BmpDecoder()
- {
- m_signature = fmtSignBmp;//static const char* fmtSignBmp = "BM"; 设定了自己标签名
- m_offset = -1;
- m_buf_supported = true;//buf设定为true,表示可以读取数据
- }
- bool BmpDecoder::readData(Mat& img){
- uchar* data = img.data;
- int step = (int)img.step;
- bool color = img.channels() > 1;
- uchar gray_palette[256];
- bool result = false;
- int src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
- int nch = color ? 3 : 1;
- int y, width3 = m_width*nch;
- if( m_offset < 0 || !m_strm.isOpened())
- return false;
- if( m_origin == IPL_ORIGIN_BL ){
- data += (m_height - 1)*step;
- step = -step;
- }
- AutoBuffer<uchar> _src, _bgr;
- _src.allocate(src_pitch + 32);
- if(!color){
- if(m_bpp <= 8){
- CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
- }
- _bgr.allocate(m_width*3 + 32);
- }
- uchar *src = _src, *bgr = _bgr;
- try{
- m_strm.setPos(m_offset);
- switch(m_bpp){
- /************************* 1 BPP ************************/
- case 1:
- for( y = 0; y < m_height; y++, data += step){
- m_strm.getBytes( src, src_pitch );
- FillColorRow1( color ? data : bgr, src, m_width, m_palette );
- if( !color )
- icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1));
- }
- result = true;
- break;
- /************************* 4 BPP ************************/
- case 4:
- if( m_rle_code == BMP_RGB){
- for( y = 0; y < m_height; y++, data += step )
- {
- m_strm.getBytes( src, src_pitch );
- if( color )
- FillColorRow4( data, src, m_width, m_palette );
- else
- FillGrayRow4( data, src, m_width, gray_palette );
- }
- result = true;
- }
- else if( m_rle_code == BMP_RLE4 ) // rle4 compression
- {
- uchar* line_end = data + width3;
- y = 0;
- for(;;)
- {
- int code = m_strm.getWord();
- int len = code & 255;
- code >>= 8;
- if( len != 0 ) // encoded mode
- {
- PaletteEntry clr[2];
- uchar gray_clr[2];
- int t = 0;
- clr[0] = m_palette[code >> 4];
- clr[1] = m_palette[code & 15];
- gray_clr[0] = gray_palette[code >> 4];
- gray_clr[1] = gray_palette[code & 15];
- uchar* end = data + len*nch;
- if( end > line_end ) goto decode_rle4_bad;
- do
- {
- if( color )
- WRITE_PIX( data, clr[t] );
- else
- *data = gray_clr[t];
- t ^= 1;
- }
- while( (data += nch) < end );
- }
- else if( code > 2 ) // absolute mode
- {
- if( data + code*nch > line_end ) goto decode_rle4_bad;
- m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
- if( color )
- data = FillColorRow4( data, src, code, m_palette );
- else
- data = FillGrayRow4( data, src, code, gray_palette );
- }
- else
- {
- int x_shift3 = (int)(line_end - data);
- int y_shift = m_height - y;
- if( code == 2 )
- {
- x_shift3 = m_strm.getByte()*nch;
- y_shift = m_strm.getByte();
- }
- len = x_shift3 + ((y_shift * width3) & ((code == 0) - 1));
- if( color )
- data = FillUniColor( data, line_end, step, width3,
- y, m_height, x_shift3,
- m_palette[0] );
- else
- data = FillUniGray( data, line_end, step, width3,
- y, m_height, x_shift3,
- gray_palette[0] );
- if( y >= m_height )
- break;
- }
- }
- result = true;
- decode_rle4_bad: ;
- }
- break;
- /************************* 8 BPP ************************/
- case 8:
- if( m_rle_code == BMP_RGB )
- {
- for( y = 0; y < m_height; y++, data += step )
- {
- m_strm.getBytes( src, src_pitch );
- if( color )
- FillColorRow8( data, src, m_width, m_palette );
- else
- FillGrayRow8( data, src, m_width, gray_palette );
- }
- result = true;
- }
- else if( m_rle_code == BMP_RLE8 ) // rle8 compression
- {
- uchar* line_end = data + width3;
- int line_end_flag = 0;
- y = 0;
- for(;;)
- {
- int code = m_strm.getWord();
- int len = code & 255;
- code >>= 8;
- if( len != 0 ) // encoded mode
- {
- int prev_y = y;
- len *= nch;
- if( data + len > line_end )
- goto decode_rle8_bad;
- if( color )
- data = FillUniColor( data, line_end, step, width3,
- y, m_height, len,
- m_palette[code] );
- else
- data = FillUniGray( data, line_end, step, width3,
- y, m_height, len,
- gray_palette[code] );
- line_end_flag = y - prev_y;
- }
- else if( code > 2 ) // absolute mode
- {
- int prev_y = y;
- int code3 = code*nch;
- if( data + code3 > line_end )
- goto decode_rle8_bad;
- m_strm.getBytes( src, (code + 1) & -2 );
- if( color )
- data = FillColorRow8( data, src, code, m_palette );
- else
- data = FillGrayRow8( data, src, code, gray_palette );
- line_end_flag = y - prev_y;
- }
- else
- {
- int x_shift3 = (int)(line_end - data);
- int y_shift = m_height - y;
- if( code || !line_end_flag || x_shift3 < width3 )
- {
- if( code == 2 )
- {
- x_shift3 = m_strm.getByte()*nch;
- y_shift = m_strm.getByte();
- }
- x_shift3 += (y_shift * width3) & ((code == 0) - 1);
- if( y >= m_height )
- break;
- if( color )
- data = FillUniColor( data, line_end, step, width3,
- y, m_height, x_shift3,
- m_palette[0] );
- else
- data = FillUniGray( data, line_end, step, width3,
- y, m_height, x_shift3,
- gray_palette[0] );
- if( y >= m_height )
- break;
- }
- line_end_flag = 0;
- }
- }
- result = true;
- decode_rle8_bad: ;
- }
- break;
- /************************* 15 BPP ************************/
- case 15:
- for( y = 0; y < m_height; y++, data += step )
- {
- m_strm.getBytes( src, src_pitch );
- if( !color )
- icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
- else
- icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
- }
- result = true;
- break;
- /************************* 16 BPP ************************/
- case 16:
- for( y = 0; y < m_height; y++, data += step )
- {
- m_strm.getBytes( src, src_pitch );
- if( !color )
- icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
- else
- icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
- }
- result = true;
- break;
- /************************* 24 BPP ************************/
- case 24:
- for( y = 0; y < m_height; y++, data += step )
- {
- m_strm.getBytes( src, src_pitch );
- if(!color)
- icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) );
- else
- memcpy( data, src, m_width*3 );
- }
- result = true;
- break;
- /************************* 32 BPP ************************/
- case 32:
- for( y = 0; y < m_height; y++, data += step )
- {
- m_strm.getBytes( src, src_pitch );
- if( !color )
- icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) );
- else
- icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) );
- }
- result = true;
- break;
- default:
- assert(0);
- }
- }
- catch(...)
- {
- }
- return result;
- }
- 源码解析: Imread函数
- 源码解析: Imread函数
- imread函数
- OpenCV之imread解析
- OpenCV中imread函数
- 【opencv】opencv源码分析(一):imread、cvLoadImage、waitKey、imshow函数
- matlab imread函数全说明
- Qt5 OpenCV函数 imread()
- opencv imread函数一点心得
- imread
- imread
- sort()函数源码解析
- cvCanny函数源码解析
- bind函数源码解析
- openCV基础函数imread第二个参数
- opencv imread函数无法调用问题
- opencv的imread函数无法读取图像
- 关于opencv中的imread()函数声明
- 自定义开关控件
- css3控制背景渐变
- uva 10615 - Rooks(完美匹配)
- 2014年各世代iPhone 屏幕尺寸与分辨率表格
- 【iOS】KVC 和 KVO 的使用场景
- 源码解析: Imread函数
- javascript学习笔记(1)初识
- ACM学习资源
- java面试题集锦(二)
- git使用笔记
- Android屏幕适配全攻略(最权威的官方适配指导)
- Android开发环境的离线安装方式(超易搭建秘籍)
- VS2008将原有的tab空格设置为空格符号
- c语言编译过程!!!