一、源码位置
opencv-3.4/modules/imgcodecs/src/loadsave.cpp
imread()函数从loadsave.cpp文件的第634行起。
imread_()函数从loadsave.cpp文件的第384行起。
二、源码及解析如下
imread()函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * Read an image * * This function merely calls the actual implementation above and returns itself. * * @param[in] filename File to load * @param[in] flags Flags you wish to set. */ Mat imread( const String& filename, int flags ) { CV_TRACE_FUNCTION(); /// create the basic container Mat img; /// load the data imread_( filename, flags, LOAD_MAT, &img ); // 可见imread调用imread_实现功能 /// optionally rotate the data if EXIF' orientation flag says so if( !img.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED ) { ApplyExifOrientation(filename, img); } /// return a reference to the data return img; } |
imread_()函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
/** * Read an image into memory and return the information * * @param[in] filename File to load * @param[in] flags Flags * @param[in] hdrtype { LOAD_CVMAT=0, * LOAD_IMAGE=1, * LOAD_MAT=2 * } * @param[in] mat Reference to C++ Mat object (If LOAD_MAT) * @param[in] scale_denom Scale value * */ static void* imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 ) { CV_Assert(mat || hdrtype != LOAD_MAT); // mat is required in LOAD_MAT case IplImage* image = 0; CvMat *matrix = 0; Mat temp, *data = &temp; // data初值是temp的地址,之后用来存放解析后的图片数据 /// Search for the relevant decoder to handle the imagery ImageDecoder decoder; #ifdef HAVE_GDAL if(flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL ){ decoder = GdalDecoder().newDecoder(); // 使用GDAL驱动读取文件 /*GDAL(Geospatial Data Abstraction Library) 是一个在X/MIT许可协议下的开源栅格空间数据转换库。 */ }else{ #endif // 使用findDecoder()解析图片信息,确定应使用的译码器 decoder = findDecoder( filename ); #ifdef HAVE_GDAL } #endif /// if no decoder was found, return nothing. if( !decoder ){ return 0; } /* 在文件/opencv-3.4/modules/imgcodecs/include/opencv2/imgcodecs.hpp 的第64行起,找到如下定义: //! Imread flags enum ImreadModes { IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion). IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image. IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit. IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format. IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image. IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2. IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2. IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4. IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4. IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8. IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8. IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag. }; */ int scale_denom = 1; if( flags > IMREAD_LOAD_GDAL ) // 如果flags > 8 { if( flags & IMREAD_REDUCED_GRAYSCALE_2 ) // & 16 scale_denom = 2; else if( flags & IMREAD_REDUCED_GRAYSCALE_4 ) // & 32 scale_denom = 4; else if( flags & IMREAD_REDUCED_GRAYSCALE_8 ) // &64 scale_denom = 8; } // 以上可见flag值影响驱动解码的等级,该等级会影响图片大小 /// set the scale_denom in the driver decoder->setScale( scale_denom ); /// set the filename in the driver decoder->setSource( filename ); try { // read the header to make sure it succeeds if( !decoder->readHeader() ) return 0; } catch (const cv::Exception& e) { std::cerr << "imread_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush; return 0; } catch (...) { std::cerr << "imread_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush; return 0; } // established the required input image size Size size = validateInputImageSize(Size(decoder->width(), decoder->height())); /*在文件opencv-3.4/modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs_c.h 第55行起,找到定义如下: enum { // 8bit, color or not CV_LOAD_IMAGE_UNCHANGED =-1, // 8bit, gray CV_LOAD_IMAGE_GRAYSCALE =0, // ?, color CV_LOAD_IMAGE_COLOR =1, // any depth, ? CV_LOAD_IMAGE_ANYDEPTH =2, // ?, any color CV_LOAD_IMAGE_ANYCOLOR =4, // ?, no rotate CV_LOAD_IMAGE_IGNORE_ORIENTATION =128 }; */ // grab the decoded type int type = decoder->type(); if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED ) { // flag值用于判断解码类型 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 { image = cvCreateImage(cvSize(size), cvIplDepth(type), CV_MAT_CN(type)); temp = cvarrToMat( image ); } // read the image data bool success = false; try { // readData()用来解析图片数据,将解析出的数据存入容器 if (decoder->readData(*data)) success = true; } catch (const cv::Exception& e) { std::cerr << "imread_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush; } catch (...) { std::cerr << "imread_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush; } if (!success) // 读取图像数据失败 { cvReleaseImage( &image ); cvReleaseMat( &matrix ); if( mat ) mat->release(); return 0; } if( decoder->setScale( scale_denom ) > 1 ) // if decoder is JpegDecoder then decoder->setScale always returns 1 { resize( *mat, *mat, Size( size.width / scale_denom, size.height / scale_denom ), 0, 0, INTER_LINEAR_EXACT); } return hdrtype == LOAD_CVMAT ? (void*)matrix : hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat; } |
三、imread()过程总结
确定译码器---->根据flag值确定驱动解码的等级(flag>8便会影响图片大小)---->建立输入图片所需的size---->确定解码类型(影响所加载图像的颜色类型)---->解析图片数据存入容器---->返回图像
文章评论