如何查看Opencv中函数的源代码--imread()的源代码

1. 查看opencv中函数的源代码
为了查看opencv中的源代码,可以安装cmake,编译一个.sln工程,如下图所示。这样可以很方便的查看函数的源代码。
关于配置cmake的方法可以直接百度,有很多相关教程




2. imread()的源代码

下面是转载自hujingshuang的博客(http://blog.csdn.net/hujingshuang/article/details/47184717),对imread()的源代码添加了注释,方便阅读理解。

imread函数原型如下,filename是文件名,flags默认为1,其含义同上iscolor枚举。

[cpp]  view plain  copy
  1. CV_EXPORTS_W Mat imread( const string& filename, int flags=1 );  
进一步查看imread源码,发现实际上调用的还是imread_函数,现在这里的参数就是LOAD_MAT了。
[cpp]  view plain  copy
  1. Mat imread( const string& filename, int flags )  
  2. {  
  3.     Mat img;//定义一个Mat类,用于装载图片  
  4.     imread_( filename, flags, LOAD_MAT, &img );//读图像  
  5.     return img;  
  6. }  

显然,不论是cvLoadImage还是imread,都是调用的imread_函数。那么我们就由此及彼,由表及里,去粗取精,去伪存真的去剖析其源码。

imread_函数源码(在源文件loadsave.cpp中):
[cpp]  view plain  copy
  1. static void*  
  2. imread_( const string& filename, int flags, int hdrtype, Mat* mat=0 )  
  3. {  
  4.     IplImage* image = 0;//定义一个IplImage结构体  
  5.     CvMat *matrix = 0;//定义一个CvMat结构体  
  6.     Mat temp, *data = &temp;//data中保存的是temp的地址,temp是一个Mat类容器  
  7.   
  8.     ImageDecoder decoder = findDecoder(filename);//①译码器  
  9.     if( decoder.empty() )  
  10.         return 0;  
  11.     decoder->setSource(filename);  
  12.     if( !decoder->readHeader() )//②读取信息头  
  13.         return 0;  
  14.   
  15.     CvSize size;  
  16.     size.width = decoder->width();  
  17.     size.height = decoder->height();  
  18.   
  19.     int type = decoder->type();  
  20.     if( flags != -1 )//③  
  21.     {  
  22.         if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 )  
  23.             type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));  
  24.   
  25.         if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||  
  26.            ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )  
  27.             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);//彩色  
  28.         else  
  29.             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);//灰度  
  30.     }  
  31.   
  32.     if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT )//④  
  33.     {  
  34.         if( hdrtype == LOAD_CVMAT )  
  35.         {  
  36.             matrix = cvCreateMat( size.height, size.width, type );  
  37.             temp = cvarrToMat(matrix);//temp与matrix同址  
  38.         }  
  39.         else  
  40.         {  
  41.             mat->create( size.height, size.width, type );  
  42.             data = mat;//data与mat同址  
  43.         }  
  44.     }  
  45.     else  
  46.     {  
  47.         image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) );  
  48.         temp = cvarrToMat(image);//temp与image同址  
  49.     }  
  50.   
  51.     if( !decoder->readData( *data ))//⑤  
  52.     {  
  53.         cvReleaseImage( &image );  
  54.         cvReleaseMat( &matrix );  
  55.         if( mat )  
  56.             mat->release();  
  57.         return 0;  
  58.     }  
  59.     //根据指针及同址关系,可知matrix、image、mat数据(若存在)与data数据一致  
  60.     return hdrtype == LOAD_CVMAT ? (void*)matrix :  
  61.         hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;  
  62. }  

imread_中,有几个地方值得注意①②③④⑤,下面一一分析:

findDecoder(),这是一个很重要的重载函数,它的目的是:解析图片信息,并确定应该使用的译码器(.jpg格式使用Jpeg译码器),其内部源码如下:

[cpp]  view plain  copy
  1. static ImageCodecInitializer codecs;  
  2.   
  3. static ImageDecoder findDecoder( const string& filename )  
  4. {  
  5.     size_t i, maxlen = 0;  
  6.     for( i = 0; i < codecs.decoders.size(); i++ )  
  7.     {  
  8.         size_t len = codecs.decoders[i]->signatureLength();  
  9.         maxlen = std::max(maxlen, len);  
  10.     }  
  11.   
  12.     FILE* f= fopen( filename.c_str(), "rb" );//读取二进制文件  
  13.     if( !f )  
  14.         return ImageDecoder();  
  15.     string signature(maxlen, ' ');  
  16.     maxlen = fread( &signature[0], 1, maxlen, f );  
  17.     fclose(f);  
  18.     signature = signature.substr(0, maxlen);  
  19.   
  20.     for( i = 0; i < codecs.decoders.size(); i++ )  
  21.     {  
  22.         if( codecs.decoders[i]->checkSignature(signature) )  
  23.             return codecs.decoders[i]->newDecoder();  
  24.     }  
  25.   
  26.     return ImageDecoder();  
  27. }  

译码器的定义如下:

[cpp]  view plain  copy
  1. struct ImageCodecInitializer  
  2. {  
  3.     ImageCodecInitializer()  
  4.     {  
  5.         decoders.push_back( new BmpDecoder );//Bmp译码器  
  6.         encoders.push_back( new BmpEncoder );//Bmp编码器  
  7.     #ifdef HAVE_JPEG  
  8.         decoders.push_back( new JpegDecoder );//Jpeg  
  9.         encoders.push_back( new JpegEncoder );  
  10.     #endif  
  11.         decoders.push_back( new SunRasterDecoder );  
  12.         encoders.push_back( new SunRasterEncoder );  
  13.         decoders.push_back( new PxMDecoder );PxM  
  14.         encoders.push_back( new PxMEncoder );  
  15.     #ifdef HAVE_TIFF  
  16.         decoders.push_back( new TiffDecoder );//Tiff  
  17.     #endif  
  18.         encoders.push_back( new TiffEncoder );  
  19.     #ifdef HAVE_PNG  
  20.         decoders.push_back( new PngDecoder );//Png  
  21.         encoders.push_back( new PngEncoder );  
  22.     #endif  
  23.     #ifdef HAVE_JASPER  
  24.         decoders.push_back( new Jpeg2KDecoder );  
  25.         encoders.push_back( new Jpeg2KEncoder );  
  26.     #endif  
  27.     #ifdef HAVE_OPENEXR  
  28.         decoders.push_back( new ExrDecoder );  
  29.         encoders.push_back( new ExrEncoder );  
  30.     #endif  
  31.     // because it is a generic image I/O API, supporting many formats,  
  32.     // it should be last in the list.  
  33.     #ifdef HAVE_IMAGEIO  
  34.         decoders.push_back( new ImageIODecoder );  
  35.         encoders.push_back( new ImageIOEncoder );  
  36.     #endif  
  37.     }  
  38.   
  39.     vector<ImageDecoder> decoders;  
  40.     vector<ImageEncoder> encoders;  
  41. };  

decoder->readHeader(),它是属于decoder类方法,它的作用是:根据上述译码器类型(即Jpeg译码器),对图片进行解压,并读取图片信息头。其源码如下:

[cpp]  view plain  copy
  1. bool  JpegDecoder::readHeader()//Jpeg格式译码器  
  2. {  
  3.     bool result = false;  
  4.     close();  
  5.   
  6.     JpegState* state = new JpegState;  
  7.     m_state = state;  
  8.     state->cinfo.err = jpeg_std_error(&state->jerr.pub);  
  9.     state->jerr.pub.error_exit = error_exit;  
  10.   
  11.     if( setjmp( state->jerr.setjmp_buffer ) == 0 )  
  12.     {  
  13.         jpeg_create_decompress( &state->cinfo );  
  14.   
  15.         if( !m_buf.empty() )  
  16.         {  
  17.             jpeg_buffer_src(&state->cinfo, &state->source);  
  18.             state->source.pub.next_input_byte = m_buf.data;  
  19.             state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();  
  20.         }  
  21.         else  
  22.         {  
  23.             m_f = fopen( m_filename.c_str(), "rb" );  
  24.             if( m_f )  
  25.                 jpeg_stdio_src( &state->cinfo, m_f );  
  26.         }  
  27.   
  28.         if (state->cinfo.src != 0)  
  29.         {  
  30.             jpeg_read_header( &state->cinfo, TRUE );  
  31.   
  32.             m_width = state->cinfo.image_width;//宽  
  33.             m_height = state->cinfo.image_height;//高  
  34.             m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;  
  35.             result = true;  
  36.         }  
  37.     }  
  38.   
  39.     if( !result )  
  40.         close();  
  41.   
  42.     return result;  
  43. }  
flags是用于判断读取图片的方式。

hdrtype的值不是LOAD_CVMAT就是LOAD_MAT或者LOAD_IMAGE,因为IplImagecvMat都是由cvArr派生出来的,所以hdrtype不论是LOAD_CVMAT还是LOAD_IMAGE,最终都会cvarrToMat()转换成为Mat类型。

decoder->readData(),它属于decoder类方法,是用来解析图片数据的,它将解析出的数据存放于传入的参数中,其源码如下。在源码的一些函数中,用到Jpeg解压并涉及到了DCT变换的代码,到了底层是汇编代码,在memcpy.asm中(此处我们只看目的,不究过程):

[cpp]  view plain  copy
  1. bool  JpegDecoder::readData( Mat& img )  
  2. {  
  3.     bool result = false;  
  4.     int step = (int)img.step;  
  5.     bool color = img.channels() > 1;  
  6.   
  7.     if( m_state && m_width && m_height )  
  8.     {  
  9.         jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;  
  10.         JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;  
  11.         JSAMPARRAY buffer = 0;  
  12.   
  13.         if( setjmp( jerr->setjmp_buffer ) == 0 )  
  14.         {  
  15.             /* check if this is a mjpeg image format */  
  16.             if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&  
  17.                 cinfo->ac_huff_tbl_ptrs[1] == NULL &&  
  18.                 cinfo->dc_huff_tbl_ptrs[0] == NULL &&  
  19.                 cinfo->dc_huff_tbl_ptrs[1] == NULL )  
  20.             {  
  21.                 /* yes, this is a mjpeg image format, so load the correct 
  22.                 huffman table */  
  23.                 my_jpeg_load_dht( cinfo,  
  24.                     my_jpeg_odml_dht,  
  25.                     cinfo->ac_huff_tbl_ptrs,  
  26.                     cinfo->dc_huff_tbl_ptrs );  
  27.             }  
  28.   
  29.             if( color )  
  30.             {  
  31.                 if( cinfo->num_components != 4 )  
  32.                 {  
  33.                     cinfo->out_color_space = JCS_RGB;  
  34.                     cinfo->out_color_components = 3;  
  35.                 }  
  36.                 else  
  37.                 {  
  38.                     cinfo->out_color_space = JCS_CMYK;  
  39.                     cinfo->out_color_components = 4;  
  40.                 }  
  41.             }  
  42.             else  
  43.             {  
  44.                 if( cinfo->num_components != 4 )  
  45.                 {  
  46.                     cinfo->out_color_space = JCS_GRAYSCALE;  
  47.                     cinfo->out_color_components = 1;  
  48.                 }  
  49.                 else  
  50.                 {  
  51.                     cinfo->out_color_space = JCS_CMYK;  
  52.                     cinfo->out_color_components = 4;  
  53.                 }  
  54.             }  
  55.   
  56.             jpeg_start_decompress( cinfo );  
  57.   
  58.             buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,  
  59.                                               JPOOL_IMAGE, m_width*4, 1 );  
  60.   
  61.             uchar* data = img.data;  
  62.             for( ; m_height--; data += step )  
  63.             {  
  64.                 jpeg_read_scanlines( cinfo, buffer, 1 );  
  65.                 if( color )  
  66.                 {  
  67.                     if( cinfo->out_color_components == 3 )  
  68.                         icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );  
  69.                     else  
  70.                         icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );  
  71.                 }  
  72.                 else  
  73.                 {  
  74.                     if( cinfo->out_color_components == 1 )  
  75.                         memcpy( data, buffer[0], m_width );  
  76.                     else  
  77.                         icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );  
  78.                 }  
  79.             }  
  80.             result = true;  
  81.             jpeg_finish_decompress( cinfo );  
  82.         }  
  83.     }  
  84.   
  85.     close();  
  86.     return result;  
  87. }  
imread_经过5个关键步骤,将读取到的图片信息头,以及图片数据以Mat类型返回(若是cvLoadImage则会被强制转换成IplImage类型)。

总结下来,方法①②读取图像的过程都是:输入filename—>解析图片—>确定译码器—>译码函数进行信息、数据的读取—>存放于Mat容器—>返回


  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV是一个开源的计算机视觉库,可以用于实现人脸识别功能。以下是一个示例的人脸识别源代码(用C语言实现): ```c #include <opencv2/opencv.hpp> #include <opencv2/face.hpp> using namespace cv; using namespace cv::face; int main() { // 创建人脸识别器 Ptr<LBPHFaceRecognizer> model = LBPHFaceRecognizer::create(); // 准备训练数据 std::vector<Mat> images; std::vector<int> labels; // 输入样本图片和对应的标签 images.push_back(imread("person1.jpg", 0)); labels.push_back(1); images.push_back(imread("person2.jpg", 0)); labels.push_back(2); // 训练人脸识别模型 model->train(images, labels); // 加载待识别的测试图片 Mat testImage = imread("test.jpg", 0); // 进行人脸识别 int predictedLabel = -1; double predictedConfidence = 0.0; model->predict(testImage, predictedLabel, predictedConfidence); // 输出识别结果 if (predictedLabel != -1) { std::cout << "Predicted label: " << predictedLabel << std::endl; std::cout << "Confidence: " << predictedConfidence << std::endl; } else { std::cout << "No face detected in the test image." << std::endl; } return 0; } ``` 上述代码首先创建了一个LBPHFaceRecognizer的对象,接着加载训练样本图片和对应的标签,并通过train函数对模型进行训练。然后,代码加载待识别的测试图片,调用predict函数进行人脸识别,并输出识别结果。如果成功识别出人脸,代码将打印出预测的标签和置信度。如果无法在测试图片检测到人脸,则输出未检测到人脸的提示信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值