接上一篇imencode 源码解读,简单写一下代码注释
static bool
imdecode_( const Mat& buf, int flags, Mat& mat )
{
// 图片是否为空
CV_Assert(!buf.empty());
// 传入图片是否连续,这里有一个概念,图像的连续性
/*
isContinue可以检查图片在内存中是否是连续的,
比如通过rect裁剪,返回的图片虽然从形式上好像已经被裁剪了,
但就像深拷贝,浅拷贝的的问题,上述方式进行的裁剪只是浅拷贝,在内存上并不连续
*/
CV_Assert(buf.isContinuous());
/*
检查这个Mat是否为Vector,用来确认传入的数据格式是否正确。
*/
CV_Assert(buf.checkVector(1, CV_8U) > 0);
/*
转换为单行,reshape 在逻辑上改变矩阵的通道数及行数,
但实际上并没有任何数据复制,和数据增减
*/
Mat buf_row = buf.reshape(1, 1); // decoders expects single row, avoid issues with vector columns
String filename;
// 也是一个工厂模式,查找解码器
ImageDecoder decoder = findDecoder(buf_row);
if( !decoder )
// 没有合适的解码器,
return 0;
// 检查解码器是否支持内存中解码
// 如果不支持,就需要创建一个临时文件在存放解码文件
if( !decoder->setSource(buf_row) )
{
// 不支持内存中解码
// 创建临时文件
filename = tempfile();
// 写二进制文件
FILE* f = fopen( filename.c_str(), "wb" );
// 文件是否成功打开
if( !f )
return 0;
// 返回矩阵的元素总个数 * 矩阵中每一个元素的数据大小
size_t bufSize = buf_row.total()*buf.elemSize();
// 写入图片缓存
if (fwrite(buf_row.ptr(), 1, bufSize, f) != bufSize)
{
// 写入失败,关闭文件
fclose( f );
CV_Error( Error::StsError, "failed to write image data to temporary file" );
}
// 写入完成后,关闭文件
if( fclose(f) != 0 )
{
// 关闭文件失败
CV_Error( Error::StsError, "failed to write image data to temporary file" );
}
// 设置解码源文件
decoder->setSource(filename);
}
// 解码是否成功标志位
bool success = false;
try
{
// 读取文件头
if (decoder->readHeader())
success = true;
}
catch (const cv::Exception& e)
{
std::cerr << "imdecode_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
}
catch (...)
{
std::cerr << "imdecode_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
}
// 解码失败,
if (!success)
{
// 释放解码器
decoder.release();
// 检查文件是否为空
if (!filename.empty())
{
// 删除文件
if (0 != remove(filename.c_str()))
{
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
}
}
return 0;
}
// established the required input image size
// 检查是否是有效的图片大小
Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
// 获取图片类型
int type = decoder->type();
if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
{
if( (flags & IMREAD_ANYDEPTH) == 0 )
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
if( (flags & IMREAD_COLOR) != 0 ||
((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
else
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
}
// 创建空图片
mat.create( size.height, size.width, type );
success = false;
try
{
// 将解码后的文件写入空白图片中
if (decoder->readData(mat))
success = true;
}
catch (const cv::Exception& e)
{
std::cerr << "imdecode_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
}
catch (...)
{
std::cerr << "imdecode_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
}
// 释放解码器
decoder.release();
// 文件是否存在
if (!filename.empty())
{
// 删除文件
if (0 != remove(filename.c_str()))
{
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
}
}
if (!success)
{
// 解码失败,释放图片
mat.release();
return false;
}
return true;
}