mirror of
https://github.com/opencv/opencv.git
synced 2024-11-30 06:10:02 +08:00
788 lines
19 KiB
C++
788 lines
19 KiB
C++
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
|
|
// Digital Ltd. LLC
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Industrial Light & Magic nor the names of
|
|
// its contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Miscellaneous helper functions for OpenEXR image file I/O
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <ImfMisc.h>
|
|
#include <ImfHeader.h>
|
|
#include <ImfCompressor.h>
|
|
#include <ImfChannelList.h>
|
|
#include <ImfXdr.h>
|
|
#include <ImathFun.h>
|
|
#include <Iex.h>
|
|
#include <ImfStdIO.h>
|
|
#include <ImfConvert.h>
|
|
|
|
namespace Imf {
|
|
|
|
using Imath::Box2i;
|
|
using Imath::divp;
|
|
using Imath::modp;
|
|
using std::vector;
|
|
|
|
int
|
|
pixelTypeSize (PixelType type)
|
|
{
|
|
int size;
|
|
|
|
switch (type)
|
|
{
|
|
case UINT:
|
|
|
|
size = Xdr::size <unsigned int> ();
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
size = Xdr::size <half> ();
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
size = Xdr::size <float> ();
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel type.");
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
int
|
|
numSamples (int s, int a, int b)
|
|
{
|
|
int a1 = divp (a, s);
|
|
int b1 = divp (b, s);
|
|
return b1 - a1 + ((a1 * s < a)? 0: 1);
|
|
}
|
|
|
|
|
|
size_t
|
|
bytesPerLineTable (const Header &header,
|
|
vector<size_t> &bytesPerLine)
|
|
{
|
|
const Box2i &dataWindow = header.dataWindow();
|
|
const ChannelList &channels = header.channels();
|
|
|
|
bytesPerLine.resize (dataWindow.max.y - dataWindow.min.y + 1);
|
|
|
|
for (ChannelList::ConstIterator c = channels.begin();
|
|
c != channels.end();
|
|
++c)
|
|
{
|
|
int nBytes = pixelTypeSize (c.channel().type) *
|
|
(dataWindow.max.x - dataWindow.min.x + 1) /
|
|
c.channel().xSampling;
|
|
|
|
for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
|
|
if (modp (y, c.channel().ySampling) == 0)
|
|
bytesPerLine[i] += nBytes;
|
|
}
|
|
|
|
size_t maxBytesPerLine = 0;
|
|
|
|
for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
|
|
if (maxBytesPerLine < bytesPerLine[i])
|
|
maxBytesPerLine = bytesPerLine[i];
|
|
|
|
return maxBytesPerLine;
|
|
}
|
|
|
|
|
|
void
|
|
offsetInLineBufferTable (const vector<size_t> &bytesPerLine,
|
|
int linesInLineBuffer,
|
|
vector<size_t> &offsetInLineBuffer)
|
|
{
|
|
offsetInLineBuffer.resize (bytesPerLine.size());
|
|
|
|
size_t offset = 0;
|
|
|
|
for (int i = 0; i < bytesPerLine.size(); ++i)
|
|
{
|
|
if (i % linesInLineBuffer == 0)
|
|
offset = 0;
|
|
|
|
offsetInLineBuffer[i] = offset;
|
|
offset += bytesPerLine[i];
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
lineBufferMinY (int y, int minY, int linesInLineBuffer)
|
|
{
|
|
return ((y - minY) / linesInLineBuffer) * linesInLineBuffer + minY;
|
|
}
|
|
|
|
|
|
int
|
|
lineBufferMaxY (int y, int minY, int linesInLineBuffer)
|
|
{
|
|
return lineBufferMinY (y, minY, linesInLineBuffer) + linesInLineBuffer - 1;
|
|
}
|
|
|
|
|
|
Compressor::Format
|
|
defaultFormat (Compressor * compressor)
|
|
{
|
|
return compressor? compressor->format(): Compressor::XDR;
|
|
}
|
|
|
|
|
|
int
|
|
numLinesInBuffer (Compressor * compressor)
|
|
{
|
|
return compressor? compressor->numScanLines(): 1;
|
|
}
|
|
|
|
|
|
void
|
|
copyIntoFrameBuffer (const char *& readPtr,
|
|
char * writePtr,
|
|
char * endPtr,
|
|
size_t xStride,
|
|
bool fill,
|
|
double fillValue,
|
|
Compressor::Format format,
|
|
PixelType typeInFrameBuffer,
|
|
PixelType typeInFile)
|
|
{
|
|
//
|
|
// Copy a horizontal row of pixels from an input
|
|
// file's line or tile buffer to a frame buffer.
|
|
//
|
|
|
|
if (fill)
|
|
{
|
|
//
|
|
// The file contains no data for this channel.
|
|
// Store a default value in the frame buffer.
|
|
//
|
|
|
|
switch (typeInFrameBuffer)
|
|
{
|
|
case UINT:
|
|
|
|
{
|
|
unsigned int fillVal = (unsigned int) (fillValue);
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
*(unsigned int *) writePtr = fillVal;
|
|
writePtr += xStride;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
{
|
|
half fillVal = half (fillValue);
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
*(half *) writePtr = fillVal;
|
|
writePtr += xStride;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
{
|
|
float fillVal = float (fillValue);
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
*(float *) writePtr = fillVal;
|
|
writePtr += xStride;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
else if (format == Compressor::XDR)
|
|
{
|
|
//
|
|
// The the line or tile buffer is in XDR format.
|
|
//
|
|
// Convert the pixels from the file's machine-
|
|
// independent representation, and store the
|
|
// results in the frame buffer.
|
|
//
|
|
|
|
switch (typeInFrameBuffer)
|
|
{
|
|
case UINT:
|
|
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
Xdr::read <CharPtrIO> (readPtr, *(unsigned int *) writePtr);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
half h;
|
|
Xdr::read <CharPtrIO> (readPtr, h);
|
|
*(unsigned int *) writePtr = halfToUint (h);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
float f;
|
|
Xdr::read <CharPtrIO> (readPtr, f);
|
|
*(unsigned int *)writePtr = floatToUint (f);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
unsigned int ui;
|
|
Xdr::read <CharPtrIO> (readPtr, ui);
|
|
*(half *) writePtr = uintToHalf (ui);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
Xdr::read <CharPtrIO> (readPtr, *(half *) writePtr);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
float f;
|
|
Xdr::read <CharPtrIO> (readPtr, f);
|
|
*(half *) writePtr = floatToHalf (f);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
unsigned int ui;
|
|
Xdr::read <CharPtrIO> (readPtr, ui);
|
|
*(float *) writePtr = float (ui);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
half h;
|
|
Xdr::read <CharPtrIO> (readPtr, h);
|
|
*(float *) writePtr = float (h);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
Xdr::read <CharPtrIO> (readPtr, *(float *) writePtr);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The the line or tile buffer is in NATIVE format.
|
|
// Copy the results into the frame buffer.
|
|
//
|
|
|
|
switch (typeInFrameBuffer)
|
|
{
|
|
case UINT:
|
|
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
for (size_t i = 0; i < sizeof (unsigned int); ++i)
|
|
writePtr[i] = readPtr[i];
|
|
|
|
readPtr += sizeof (unsigned int);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
half h = *(half *) readPtr;
|
|
*(unsigned int *) writePtr = halfToUint (h);
|
|
readPtr += sizeof (half);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
float f;
|
|
|
|
for (size_t i = 0; i < sizeof (float); ++i)
|
|
((char *)&f)[i] = readPtr[i];
|
|
|
|
*(unsigned int *)writePtr = floatToUint (f);
|
|
readPtr += sizeof (float);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
unsigned int ui;
|
|
|
|
for (size_t i = 0; i < sizeof (unsigned int); ++i)
|
|
((char *)&ui)[i] = readPtr[i];
|
|
|
|
*(half *) writePtr = uintToHalf (ui);
|
|
readPtr += sizeof (unsigned int);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
*(half *) writePtr = *(half *)readPtr;
|
|
readPtr += sizeof (half);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
float f;
|
|
|
|
for (size_t i = 0; i < sizeof (float); ++i)
|
|
((char *)&f)[i] = readPtr[i];
|
|
|
|
*(half *) writePtr = floatToHalf (f);
|
|
readPtr += sizeof (float);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
unsigned int ui;
|
|
|
|
for (size_t i = 0; i < sizeof (unsigned int); ++i)
|
|
((char *)&ui)[i] = readPtr[i];
|
|
|
|
*(float *) writePtr = float (ui);
|
|
readPtr += sizeof (unsigned int);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
half h = *(half *) readPtr;
|
|
*(float *) writePtr = float (h);
|
|
readPtr += sizeof (half);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (writePtr <= endPtr)
|
|
{
|
|
for (size_t i = 0; i < sizeof (float); ++i)
|
|
writePtr[i] = readPtr[i];
|
|
|
|
readPtr += sizeof (float);
|
|
writePtr += xStride;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
skipChannel (const char *& readPtr,
|
|
PixelType typeInFile,
|
|
size_t xSize)
|
|
{
|
|
switch (typeInFile)
|
|
{
|
|
case UINT:
|
|
|
|
Xdr::skip <CharPtrIO> (readPtr, Xdr::size <unsigned int> () * xSize);
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
Xdr::skip <CharPtrIO> (readPtr, Xdr::size <half> () * xSize);
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
Xdr::skip <CharPtrIO> (readPtr, Xdr::size <float> () * xSize);
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
convertInPlace (char *& writePtr,
|
|
const char *& readPtr,
|
|
PixelType type,
|
|
size_t numPixels)
|
|
{
|
|
switch (type)
|
|
{
|
|
case UINT:
|
|
|
|
for (int j = 0; j < numPixels; ++j)
|
|
{
|
|
Xdr::write <CharPtrIO> (writePtr, *(const unsigned int *) readPtr);
|
|
readPtr += sizeof(unsigned int);
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
for (int j = 0; j < numPixels; ++j)
|
|
{
|
|
Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr);
|
|
readPtr += sizeof(half);
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
for (int j = 0; j < numPixels; ++j)
|
|
{
|
|
Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr);
|
|
readPtr += sizeof(float);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
copyFromFrameBuffer (char *& writePtr,
|
|
const char *& readPtr,
|
|
const char * endPtr,
|
|
size_t xStride,
|
|
Compressor::Format format,
|
|
PixelType type)
|
|
{
|
|
//
|
|
// Copy a horizontal row of pixels from a frame
|
|
// buffer to an output file's line or tile buffer.
|
|
//
|
|
|
|
if (format == Compressor::XDR)
|
|
{
|
|
//
|
|
// The the line or tile buffer is in XDR format.
|
|
//
|
|
|
|
switch (type)
|
|
{
|
|
case UINT:
|
|
|
|
while (readPtr <= endPtr)
|
|
{
|
|
Xdr::write <CharPtrIO> (writePtr,
|
|
*(const unsigned int *) readPtr);
|
|
readPtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (readPtr <= endPtr)
|
|
{
|
|
Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr);
|
|
readPtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (readPtr <= endPtr)
|
|
{
|
|
Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr);
|
|
readPtr += xStride;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The the line or tile buffer is in NATIVE format.
|
|
//
|
|
|
|
switch (type)
|
|
{
|
|
case UINT:
|
|
|
|
while (readPtr <= endPtr)
|
|
{
|
|
for (size_t i = 0; i < sizeof (unsigned int); ++i)
|
|
*writePtr++ = readPtr[i];
|
|
|
|
readPtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
while (readPtr <= endPtr)
|
|
{
|
|
*(half *) writePtr = *(const half *) readPtr;
|
|
writePtr += sizeof (half);
|
|
readPtr += xStride;
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
while (readPtr <= endPtr)
|
|
{
|
|
for (size_t i = 0; i < sizeof (float); ++i)
|
|
*writePtr++ = readPtr[i];
|
|
|
|
readPtr += xStride;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
fillChannelWithZeroes (char *& writePtr,
|
|
Compressor::Format format,
|
|
PixelType type,
|
|
size_t xSize)
|
|
{
|
|
if (format == Compressor::XDR)
|
|
{
|
|
//
|
|
// Fill with data in XDR format.
|
|
//
|
|
|
|
switch (type)
|
|
{
|
|
case UINT:
|
|
|
|
for (int j = 0; j < xSize; ++j)
|
|
Xdr::write <CharPtrIO> (writePtr, (unsigned int) 0);
|
|
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
for (int j = 0; j < xSize; ++j)
|
|
Xdr::write <CharPtrIO> (writePtr, (half) 0);
|
|
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
for (int j = 0; j < xSize; ++j)
|
|
Xdr::write <CharPtrIO> (writePtr, (float) 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Fill with data in NATIVE format.
|
|
//
|
|
|
|
switch (type)
|
|
{
|
|
case UINT:
|
|
|
|
for (int j = 0; j < xSize; ++j)
|
|
{
|
|
static const unsigned int ui = 0;
|
|
|
|
for (size_t i = 0; i < sizeof (ui); ++i)
|
|
*writePtr++ = ((char *) &ui)[i];
|
|
}
|
|
break;
|
|
|
|
case HALF:
|
|
|
|
for (int j = 0; j < xSize; ++j)
|
|
{
|
|
*(half *) writePtr = half (0);
|
|
writePtr += sizeof (half);
|
|
}
|
|
break;
|
|
|
|
case FLOAT:
|
|
|
|
for (int j = 0; j < xSize; ++j)
|
|
{
|
|
static const float f = 0;
|
|
|
|
for (size_t i = 0; i < sizeof (f); ++i)
|
|
*writePtr++ = ((char *) &f)[i];
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
throw Iex::ArgExc ("Unknown pixel data type.");
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Imf
|