如何查看Opencv中函数的源代码--imread()的源代码
为了查看opencv中的源代码,可以安装cmake,编译一个.sln工程,如下图所示。这样可以很方便的查看函数的源代码。
关于配置cmake的方法可以直接百度,有很多相关教程
2. imread()的源代码
下面是转载自hujingshuang的博客(http://blog.****.net/hujingshuang/article/details/47184717),对imread()的源代码添加了注释,方便阅读理解。
imread函数原型如下,filename是文件名,flags默认为1,其含义同上iscolor枚举。
- CV_EXPORTS_W Mat imread( const string& filename, int flags=1 );
- Mat imread( const string& filename, int flags )
- {
- Mat img;//定义一个Mat类,用于装载图片
- imread_( filename, flags, LOAD_MAT, &img );//读图像
- return img;
- }
显然,不论是cvLoadImage还是imread,都是调用的imread_函数。那么我们就由此及彼,由表及里,去粗取精,去伪存真的去剖析其源码。
imread_函数源码(在源文件loadsave.cpp中):- static void*
- imread_( const string& filename, int flags, int hdrtype, Mat* mat=0 )
- {
- IplImage* image = 0;//定义一个IplImage结构体
- CvMat *matrix = 0;//定义一个CvMat结构体
- Mat temp, *data = &temp;//data中保存的是temp的地址,temp是一个Mat类容器
- 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);//temp与matrix同址
- }
- else
- {
- mat->create( size.height, size.width, type );
- data = mat;//data与mat同址
- }
- }
- else
- {
- image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) );
- temp = cvarrToMat(image);//temp与image同址
- }
- if( !decoder->readData( *data ))//⑤
- {
- cvReleaseImage( &image );
- cvReleaseMat( &matrix );
- if( mat )
- mat->release();
- return 0;
- }
- //根据指针及同址关系,可知matrix、image、mat数据(若存在)与data数据一致
- return hdrtype == LOAD_CVMAT ? (void*)matrix :
- hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;
- }
在imread_中,有几个地方值得注意①②③④⑤,下面一一分析:
①findDecoder(),这是一个很重要的重载函数,它的目的是:解析图片信息,并确定应该使用的译码器(.jpg格式使用Jpeg译码器),其内部源码如下:
- static ImageCodecInitializer codecs;
- static ImageDecoder findDecoder( const string& filename )
- {
- size_t i, maxlen = 0;
- for( i = 0; i < codecs.decoders.size(); i++ )
- {
- size_t len = codecs.decoders[i]->signatureLength();
- maxlen = std::max(maxlen, len);
- }
- FILE* f= fopen( filename.c_str(), "rb" );//读取二进制文件
- if( !f )
- return ImageDecoder();
- string signature(maxlen, ' ');
- maxlen = fread( &signature[0], 1, maxlen, f );
- fclose(f);
- signature = signature.substr(0, maxlen);
- for( i = 0; i < codecs.decoders.size(); i++ )
- {
- if( codecs.decoders[i]->checkSignature(signature) )
- return codecs.decoders[i]->newDecoder();
- }
- return ImageDecoder();
- }
译码器的定义如下:
- struct ImageCodecInitializer
- {
- ImageCodecInitializer()
- {
- decoders.push_back( new BmpDecoder );//Bmp译码器
- encoders.push_back( new BmpEncoder );//Bmp编码器
- #ifdef HAVE_JPEG
- decoders.push_back( new JpegDecoder );//Jpeg
- encoders.push_back( new JpegEncoder );
- #endif
- decoders.push_back( new SunRasterDecoder );
- encoders.push_back( new SunRasterEncoder );
- decoders.push_back( new PxMDecoder );PxM
- encoders.push_back( new PxMEncoder );
- #ifdef HAVE_TIFF
- decoders.push_back( new TiffDecoder );//Tiff
- #endif
- encoders.push_back( new TiffEncoder );
- #ifdef HAVE_PNG
- decoders.push_back( new PngDecoder );//Png
- 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
- }
- vector<ImageDecoder> decoders;
- vector<ImageEncoder> encoders;
- };
②decoder->readHeader(),它是属于decoder类方法,它的作用是:根据上述译码器类型(即Jpeg译码器),对图片进行解压,并读取图片信息头。其源码如下:
- bool JpegDecoder::readHeader()//Jpeg格式译码器
- {
- bool result = false;
- close();
- JpegState* state = new JpegState;
- m_state = state;
- state->cinfo.err = jpeg_std_error(&state->jerr.pub);
- state->jerr.pub.error_exit = error_exit;
- if( setjmp( state->jerr.setjmp_buffer ) == 0 )
- {
- jpeg_create_decompress( &state->cinfo );
- if( !m_buf.empty() )
- {
- jpeg_buffer_src(&state->cinfo, &state->source);
- state->source.pub.next_input_byte = m_buf.data;
- state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();
- }
- else
- {
- m_f = fopen( m_filename.c_str(), "rb" );
- if( m_f )
- jpeg_stdio_src( &state->cinfo, m_f );
- }
- if (state->cinfo.src != 0)
- {
- jpeg_read_header( &state->cinfo, TRUE );
- m_width = state->cinfo.image_width;//宽
- m_height = state->cinfo.image_height;//高
- m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;
- result = true;
- }
- }
- if( !result )
- close();
- return result;
- }
④hdrtype的值不是LOAD_CVMAT就是LOAD_MAT或者LOAD_IMAGE,因为IplImage、cvMat都是由cvArr派生出来的,所以hdrtype不论是LOAD_CVMAT还是LOAD_IMAGE,最终都会cvarrToMat()转换成为Mat类型。
⑤decoder->readData(),它属于decoder类方法,是用来解析图片数据的,它将解析出的数据存放于传入的参数中,其源码如下。在源码的一些函数中,用到Jpeg解压并涉及到了DCT变换的代码,到了底层是汇编代码,在memcpy.asm中(此处我们只看目的,不究过程):
- bool JpegDecoder::readData( Mat& img )
- {
- bool result = false;
- int step = (int)img.step;
- bool color = img.channels() > 1;
- if( m_state && m_width && m_height )
- {
- jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;
- JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;
- JSAMPARRAY buffer = 0;
- if( setjmp( jerr->setjmp_buffer ) == 0 )
- {
- /* check if this is a mjpeg image format */
- if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
- cinfo->ac_huff_tbl_ptrs[1] == NULL &&
- cinfo->dc_huff_tbl_ptrs[0] == NULL &&
- cinfo->dc_huff_tbl_ptrs[1] == NULL )
- {
- /* yes, this is a mjpeg image format, so load the correct
- huffman table */
- my_jpeg_load_dht( cinfo,
- my_jpeg_odml_dht,
- cinfo->ac_huff_tbl_ptrs,
- cinfo->dc_huff_tbl_ptrs );
- }
- if( color )
- {
- if( cinfo->num_components != 4 )
- {
- cinfo->out_color_space = JCS_RGB;
- cinfo->out_color_components = 3;
- }
- else
- {
- cinfo->out_color_space = JCS_CMYK;
- cinfo->out_color_components = 4;
- }
- }
- else
- {
- if( cinfo->num_components != 4 )
- {
- cinfo->out_color_space = JCS_GRAYSCALE;
- cinfo->out_color_components = 1;
- }
- else
- {
- cinfo->out_color_space = JCS_CMYK;
- cinfo->out_color_components = 4;
- }
- }
- jpeg_start_decompress( cinfo );
- buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
- JPOOL_IMAGE, m_width*4, 1 );
- uchar* data = img.data;
- for( ; m_height--; data += step )
- {
- jpeg_read_scanlines( cinfo, buffer, 1 );
- if( color )
- {
- if( cinfo->out_color_components == 3 )
- icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
- else
- icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
- }
- else
- {
- if( cinfo->out_color_components == 1 )
- memcpy( data, buffer[0], m_width );
- else
- icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
- }
- }
- result = true;
- jpeg_finish_decompress( cinfo );
- }
- }
- close();
- return result;
- }
总结下来,方法①②,读取图像的过程都是:输入filename—>解析图片—>确定译码器—>译码函数进行信息、数据的读取—>存放于Mat容器—>返回。
相关推荐
- 如何获取Linux中某个命令的源代码
- 如何获取Linux中某个命令的源代码
- oracle PACKAGE中的函数如何查看函数体(两种方法)
- 手把手图文说明如何在Eclipse中查看JDK类库的源代码(JDK1.8,Eclipse Oxygen)
- 关于Eclipse中“ctrl+鼠标左击类”快捷键不能查看该类API源代码的解决方法
- 14,matlab中如何查看程序中所调用的函数
- 在Myeclipse中查看Spring.Jar的源代码
- 选择用于在Internet Explorer中查看源代码的文本编辑器
- 如何查看Opencv中自带内部函数的源代码
- 查找OpenCV里的函数源代码
- 第2章需求分析④【笔记】
- vs2008调用opencv2.4.9的imread()函数失败解决办法