赞
踩
在opencv中,imencode 经常用,但一直不知道它到底干了什么,于是今天来看一下,顺便写点注释,如果有理解错误还请指出
下一篇imdecode 源码解读
/* Parameters - ext File extension that defines the output format. - img Image to be written. - buf Output buffer resized to fit the compressed image. - params Format-specific parameters. See cv::imwrite and cv::ImwriteFlags. */ bool imencode( const String& ext, InputArray _image, std::vector<uchar>& buf, const std::vector<int>& params ) { // 跟踪图片在读取过程中的问题 CV_TRACE_FUNCTION(); // 获取输入的图像 Mat image = _image.getMat(); // 判断是否为空 CV_Assert(!image.empty()); // 获取图片通道数 int channels = image.channels(); // 只支持 通道为1 ,3, 4 的情况 CV_Assert( channels == 1 || channels == 3 || channels == 4 ); // 根据传入的字符串,获取对应的编码器,这里用到了一个工厂模式 ImageEncoder encoder = findEncoder( ext ); // 无法找到编码器 if( !encoder ) CV_Error( Error::StsError, "could not find encoder for the specified extension" ); // 检查编码器是否支持当前图像位数 (bytes per pixel) if( !encoder->isFormatSupported(image.depth()) ) { // 检查编码器是否支持 8位,如果支持就进行转换 // 这里是为了增加一点函数的鲁棒性,能够处理一些情况 CV_Assert( encoder->isFormatSupported(CV_8U) ); Mat temp; image.convertTo(temp, CV_8U); image = temp; } // 检查操作是否成功标志 bool code; // 检查是否设置编码目标为--编码到内存 // 因为encoder 是用工厂模式的方法,返回基类编码器指针, // 但并不是所有的派生的编码器都支持在直接在内存上进行编码 // 所以这里分成了两种情况 if( encoder->setDestination(buf) ) { // 说明是支持在内存上编码 // 按参数要求,编码写入 code = encoder->write(image, params); // 检查编码是否成功 encoder->throwOnEror(); CV_Assert( code ); } else { // 因为不支持在内存中编码,所以创建一个临时文件,设置编码到文件 String filename = tempfile(); // 设置目标文件 code = encoder->setDestination(filename); CV_Assert( code ); // 按参数要求,编码写入 code = encoder->write(image, params); // 检查编码是否成功 encoder->throwOnEror(); CV_Assert( code ); // 读写打开二进制文件 FILE* f = fopen( filename.c_str(), "rb" ); // 检查是否开启成功 CV_Assert(f != 0); // 设置文件流的位置为文件尾部SEEK_END fseek( f, 0, SEEK_END ); // 返回当前文件位置 long pos = ftell(f); // 设置缓存大小,前面的操作其实就就是为了获得编码后文件的大小, // 先初始化一个内存中的空间 buf.resize((size_t)pos); // 设置文件流到开头 fseek( f, 0, SEEK_SET ); // 将文件内容写入内存 buf.resize(fread( &buf[0], 1, buf.size(), f )); // 关闭文件 fclose(f); // 删除文件 remove(filename.c_str()); } return code; }
在注释中写过,encoder 是返回的基类指针,而findEncoder 就是一个编码器工厂
typedef Ptr<BaseImageEncoder> ImageEncoder;
ImageEncoder encoder = findEncoder( ext );
static ImageEncoder findEncoder( const String& _ext ) { if( _ext.size() <= 1 ) return ImageEncoder(); const char* ext = strrchr( _ext.c_str(), '.' ); if( !ext ) return ImageEncoder(); int len = 0; for( ext++; len < 128 && isalnum(ext[len]); len++ ) ; for( size_t i = 0; i < codecs.encoders.size(); i++ ) { String description = codecs.encoders[i]->getDescription(); const char* descr = strchr( description.c_str(), '(' ); while( descr ) { descr = strchr( descr + 1, '.' ); if( !descr ) break; int j = 0; for( descr++; j < len && isalnum(descr[j]) ; j++ ) { int c1 = tolower(ext[j]); int c2 = tolower(descr[j]); if( c1 != c2 ) break; } if( j == len && !isalnum(descr[j])) return codecs.encoders[i]->newEncoder(); descr += j; } } return ImageEncoder(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。