Path: blob/master/modules/imgcodecs/src/grfmt_pfm.cpp
16337 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.34#include "precomp.hpp"5#include "utils.hpp"6#include "grfmt_pfm.hpp"7#include <iostream>89#ifdef HAVE_IMGCODEC_PFM1011namespace {1213static_assert(sizeof(float) == 4, "float must be 32 bit.");141516bool is_byte_order_swapped(double scale)17{18// ".pfm" format file specifies that:19// positive scale means big endianess;20// negative scale means little endianess.2122#ifdef WORDS_BIGENDIAN23return scale < 0.0;24#else25return scale >= 0.0;26#endif27}2829void swap_endianess(uint32_t& ui)30{31static const uint32_t A(0x000000ffU);32static const uint32_t B(0x0000ff00U);33static const uint32_t C(0x00ff0000U);34static const uint32_t D(0xff000000U);3536ui = ( (ui & A) << 24 )37| ( (ui & B) << 8 )38| ( (ui & C) >> 8 )39| ( (ui & D) >> 24 );40}4142template<typename T> T atoT(const std::string& s);43template<> int atoT<int>(const std::string& s) { return std::atoi(s.c_str()); }44template<> double atoT<double>(const std::string& s) { return std::atof(s.c_str()); }4546template<typename T>47T read_number(cv::RLByteStream& strm)48{49// should be enogh to take string representation of any number50const size_t buffer_size = 2048;5152std::vector<char> buffer(buffer_size, 0);53for (size_t i = 0; i < buffer_size; ++i) {54const int intc = strm.getByte();55CV_Assert(intc >= -128 && intc < 128);56char c = static_cast<char>(intc);57if (std::isspace(c)) {58break;59}60buffer[i] = c;61}62const std::string str(buffer.begin(), buffer.end());63return atoT<T>(str);64}6566template<typename T> void write_anything(cv::WLByteStream& strm, const T& t)67{68std::ostringstream ss;69ss << t;70strm.putBytes(ss.str().c_str(), static_cast<int>(ss.str().size()));71}7273}7475namespace cv {7677PFMDecoder::~PFMDecoder()78{79}8081PFMDecoder::PFMDecoder() : m_scale_factor(0), m_swap_byte_order(false)82{83m_strm.close();84}8586bool PFMDecoder::readHeader()87{88if (m_buf.empty()) {89if (!m_strm.open(m_filename)) {90return false;91}92} else {93if (!m_strm.open(m_buf)) {94return false;95}96}9798if (m_strm.getByte() != 'P') {99CV_Error(Error::StsError, "Unexpected file type (expected P)");100}101102switch (m_strm.getByte()) {103case 'f':104m_type = CV_32FC1;105break;106case 'F':107m_type = CV_32FC3;108break;109default:110CV_Error(Error::StsError, "Unexpected file type (expected `f` or `F`)");111}112113if ('\n' != m_strm.getByte()) {114CV_Error(Error::StsError, "Unexpected header format (expected line break)");115}116117118m_width = read_number<int>(m_strm);119m_height = read_number<int>(m_strm);120m_scale_factor = read_number<double>(m_strm);121m_swap_byte_order = is_byte_order_swapped(m_scale_factor);122123return true;124}125126bool PFMDecoder::readData(Mat& mat)127{128if (!m_strm.isOpened()) {129CV_Error(Error::StsError, "Unexpected status in data stream");130}131132Mat buffer(mat.size(), m_type);133for (int y = m_height - 1; y >= 0; --y) {134m_strm.getBytes(buffer.ptr(y), static_cast<int>(m_width * buffer.elemSize()));135if (is_byte_order_swapped(m_scale_factor)) {136for (int i = 0; i < m_width * buffer.channels(); ++i) {137static_assert( sizeof(uint32_t) == sizeof(float),138"uint32_t and float must have same size." );139swap_endianess(buffer.ptr<uint32_t>(y)[i]);140}141}142}143144if (buffer.channels() == 3) {145cv::cvtColor(buffer, buffer, cv::COLOR_BGR2RGB);146}147148CV_Assert(fabs(m_scale_factor) > 0.0f);149buffer *= 1.f / fabs(m_scale_factor);150151buffer.convertTo(mat, mat.type());152153return true;154}155156size_t PFMDecoder::signatureLength() const157{158return 3;159}160161bool PFMDecoder::checkSignature( const String& signature ) const162{163return signature.size() >= 3164&& signature[0] == 'P'165&& ( signature[1] == 'f' || signature[1] == 'F' )166&& isspace(signature[2]);167}168169void PFMDecoder::close()170{171// noop172}173174//////////////////////////////////////////////////////////////////////////////////////////175176PFMEncoder::PFMEncoder()177{178m_description = "Portable image format - float (*.pfm)";179}180181PFMEncoder::~PFMEncoder()182{183}184185bool PFMEncoder::isFormatSupported(int depth) const186{187// any depth will be converted into 32-bit float.188CV_UNUSED(depth);189return true;190}191192bool PFMEncoder::write(const Mat& img, const std::vector<int>& params)193{194CV_UNUSED(params);195196WLByteStream strm;197if (m_buf) {198if (!strm.open(*m_buf)) {199return false;200} else {201m_buf->reserve(alignSize(256 + sizeof(float) * img.channels() * img.total(), 256));202}203} else if (!strm.open(m_filename)) {204return false;205}206207Mat float_img;208strm.putByte('P');209switch (img.channels()) {210case 1:211strm.putByte('f');212img.convertTo(float_img, CV_32FC1);213break;214case 3:215strm.putByte('F');216img.convertTo(float_img, CV_32FC3);217break;218default:219CV_Error(Error::StsBadArg, "Expected 1 or 3 channel image.");220}221strm.putByte('\n');222223224write_anything(strm, float_img.cols);225strm.putByte(' ');226write_anything(strm, float_img.rows);227strm.putByte('\n');228#ifdef WORDS_BIGENDIAN229write_anything(strm, 1.0);230#else231write_anything(strm, -1.0);232#endif233234strm.putByte('\n');235236// Comments are not officially supported in this file format.237// write_anything(strm, "# Generated by OpenCV " CV_VERSION "\n");238239for (int y = float_img.rows - 1; y >= 0; --y)240{241if (float_img.channels() == 3) {242const float* bgr_row = float_img.ptr<float>(y);243size_t row_size = float_img.cols * float_img.channels();244std::vector<float> rgb_row(row_size);245for (int x = 0; x < float_img.cols; ++x) {246rgb_row[x*3+0] = bgr_row[x*3+2];247rgb_row[x*3+1] = bgr_row[x*3+1];248rgb_row[x*3+2] = bgr_row[x*3+0];249}250strm.putBytes( reinterpret_cast<const uchar*>(rgb_row.data()),251static_cast<int>(sizeof(float) * row_size) );252} else if (float_img.channels() == 1) {253strm.putBytes(float_img.ptr(y), sizeof(float) * float_img.cols);254}255}256return true;257}258259260}261262263#endif // HAVE_IMGCODEC_PFM264265266