|
|
|
@ -43,50 +43,58 @@ |
|
|
|
|
#include "precomp.hpp" |
|
|
|
|
#include "utils.hpp" |
|
|
|
|
#include "grfmt_pxm.hpp" |
|
|
|
|
#include <iostream> |
|
|
|
|
|
|
|
|
|
namespace cv |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
///////////////////////// P?M reader //////////////////////////////
|
|
|
|
|
|
|
|
|
|
static int ReadNumber( RLByteStream& strm, int maxdigits ) |
|
|
|
|
static int ReadNumber(RLByteStream& strm, int maxdigits = 0) |
|
|
|
|
{ |
|
|
|
|
int code; |
|
|
|
|
int val = 0; |
|
|
|
|
int64 val = 0; |
|
|
|
|
int digits = 0; |
|
|
|
|
|
|
|
|
|
code = strm.getByte(); |
|
|
|
|
|
|
|
|
|
if( !isdigit(code)) |
|
|
|
|
while (!isdigit(code)) |
|
|
|
|
{ |
|
|
|
|
do |
|
|
|
|
if (code == '#' ) |
|
|
|
|
{ |
|
|
|
|
if( code == '#' ) |
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
code = strm.getByte(); |
|
|
|
|
} |
|
|
|
|
while( code != '\n' && code != '\r' ); |
|
|
|
|
code = strm.getByte(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (code != '\n' && code != '\r'); |
|
|
|
|
code = strm.getByte(); |
|
|
|
|
|
|
|
|
|
while( isspace(code)) |
|
|
|
|
} |
|
|
|
|
else if (isspace(code)) |
|
|
|
|
{ |
|
|
|
|
while (isspace(code)) |
|
|
|
|
code = strm.getByte(); |
|
|
|
|
} |
|
|
|
|
while( !isdigit( code )); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
#if 1 |
|
|
|
|
CV_Error_(CV_StsError, ("PXM: Unexpected code in ReadNumber(): 0x%x (%d)", code, code)); |
|
|
|
|
#else |
|
|
|
|
code = strm.getByte(); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
val = val*10 + code - '0'; |
|
|
|
|
if( ++digits >= maxdigits ) break; |
|
|
|
|
val = val*10 + (code - '0'); |
|
|
|
|
CV_Assert(val <= INT_MAX && "PXM: ReadNumber(): result is too large"); |
|
|
|
|
digits++; |
|
|
|
|
if (maxdigits != 0 && digits >= maxdigits) break; |
|
|
|
|
code = strm.getByte(); |
|
|
|
|
} |
|
|
|
|
while( isdigit(code)); |
|
|
|
|
while (isdigit(code)); |
|
|
|
|
|
|
|
|
|
return val; |
|
|
|
|
return (int)val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -119,13 +127,13 @@ ImageDecoder PxMDecoder::newDecoder() const |
|
|
|
|
return new PxMDecoder; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void PxMDecoder::close() |
|
|
|
|
void PxMDecoder::close() |
|
|
|
|
{ |
|
|
|
|
m_strm.close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool PxMDecoder::readHeader() |
|
|
|
|
bool PxMDecoder::readHeader() |
|
|
|
|
{ |
|
|
|
|
bool result = false; |
|
|
|
|
|
|
|
|
@ -155,10 +163,10 @@ bool PxMDecoder::readHeader() |
|
|
|
|
m_binary = code >= '4'; |
|
|
|
|
m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1; |
|
|
|
|
|
|
|
|
|
m_width = ReadNumber( m_strm, INT_MAX ); |
|
|
|
|
m_height = ReadNumber( m_strm, INT_MAX ); |
|
|
|
|
m_width = ReadNumber(m_strm); |
|
|
|
|
m_height = ReadNumber(m_strm); |
|
|
|
|
|
|
|
|
|
m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX ); |
|
|
|
|
m_maxval = m_bpp == 1 ? 1 : ReadNumber(m_strm); |
|
|
|
|
if( m_maxval > 65535 ) |
|
|
|
|
throw RBS_BAD_HEADER; |
|
|
|
|
|
|
|
|
@ -172,8 +180,14 @@ bool PxMDecoder::readHeader() |
|
|
|
|
result = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
catch(...) |
|
|
|
|
catch (const cv::Exception&) |
|
|
|
|
{ |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
catch (...) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush; |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if( !result ) |
|
|
|
@ -193,27 +207,23 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
int step = (int)img.step; |
|
|
|
|
PaletteEntry palette[256]; |
|
|
|
|
bool result = false; |
|
|
|
|
int bit_depth = CV_ELEM_SIZE1(m_type)*8; |
|
|
|
|
int src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8; |
|
|
|
|
const int bit_depth = CV_ELEM_SIZE1(m_type)*8; |
|
|
|
|
const int src_pitch = (m_width*m_bpp*(bit_depth/8) + 7) / 8; |
|
|
|
|
|
|
|
|
|
int nch = CV_MAT_CN(m_type); |
|
|
|
|
int width3 = m_width*nch; |
|
|
|
|
int i, x, y; |
|
|
|
|
|
|
|
|
|
if( m_offset < 0 || !m_strm.isOpened()) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
AutoBuffer<uchar,1024> _src(src_pitch + 32); |
|
|
|
|
uchar* src = _src; |
|
|
|
|
AutoBuffer<uchar,1024> _gray_palette; |
|
|
|
|
uchar* gray_palette = _gray_palette; |
|
|
|
|
uchar gray_palette[256] = {0}; |
|
|
|
|
|
|
|
|
|
// create LUT for converting colors
|
|
|
|
|
if( bit_depth == 8 ) |
|
|
|
|
{ |
|
|
|
|
_gray_palette.allocate(m_maxval + 1); |
|
|
|
|
gray_palette = _gray_palette; |
|
|
|
|
CV_Assert(m_maxval < 256); |
|
|
|
|
|
|
|
|
|
for( i = 0; i <= m_maxval; i++ ) |
|
|
|
|
for (int i = 0; i <= m_maxval; i++) |
|
|
|
|
gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0)); |
|
|
|
|
|
|
|
|
|
FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 ); |
|
|
|
@ -227,12 +237,16 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
{ |
|
|
|
|
////////////////////////// 1 BPP /////////////////////////
|
|
|
|
|
case 1: |
|
|
|
|
CV_Assert(CV_MAT_DEPTH(m_type) == CV_8U); |
|
|
|
|
if( !m_binary ) |
|
|
|
|
{ |
|
|
|
|
for( y = 0; y < m_height; y++, data += step ) |
|
|
|
|
AutoBuffer<uchar> _src(m_width); |
|
|
|
|
uchar* src = _src; |
|
|
|
|
|
|
|
|
|
for (int y = 0; y < m_height; y++, data += step) |
|
|
|
|
{ |
|
|
|
|
for( x = 0; x < m_width; x++ ) |
|
|
|
|
src[x] = ReadNumber( m_strm, 1 ) != 0; |
|
|
|
|
for (int x = 0; x < m_width; x++) |
|
|
|
|
src[x] = ReadNumber(m_strm, 1) != 0; |
|
|
|
|
|
|
|
|
|
if( color ) |
|
|
|
|
FillColorRow8( data, src, m_width, palette ); |
|
|
|
@ -242,7 +256,10 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
for( y = 0; y < m_height; y++, data += step ) |
|
|
|
|
AutoBuffer<uchar> _src(src_pitch); |
|
|
|
|
uchar* src = _src; |
|
|
|
|
|
|
|
|
|
for (int y = 0; y < m_height; y++, data += step) |
|
|
|
|
{ |
|
|
|
|
m_strm.getBytes( src, src_pitch ); |
|
|
|
|
|
|
|
|
@ -258,11 +275,15 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
////////////////////////// 8 BPP /////////////////////////
|
|
|
|
|
case 8: |
|
|
|
|
case 24: |
|
|
|
|
for( y = 0; y < m_height; y++, data += step ) |
|
|
|
|
{ |
|
|
|
|
AutoBuffer<uchar> _src(std::max<size_t>(width3*2, src_pitch)); |
|
|
|
|
uchar* src = _src; |
|
|
|
|
|
|
|
|
|
for (int y = 0; y < m_height; y++, data += step) |
|
|
|
|
{ |
|
|
|
|
if( !m_binary ) |
|
|
|
|
{ |
|
|
|
|
for( x = 0; x < width3; x++ ) |
|
|
|
|
for (int x = 0; x < width3; x++) |
|
|
|
|
{ |
|
|
|
|
int code = ReadNumber( m_strm, INT_MAX ); |
|
|
|
|
if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval; |
|
|
|
@ -277,7 +298,7 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
m_strm.getBytes( src, src_pitch ); |
|
|
|
|
if( bit_depth == 16 && !isBigEndian() ) |
|
|
|
|
{ |
|
|
|
|
for( x = 0; x < width3; x++ ) |
|
|
|
|
for (int x = 0; x < width3; x++) |
|
|
|
|
{ |
|
|
|
|
uchar v = src[x * 2]; |
|
|
|
|
src[x * 2] = src[x * 2 + 1]; |
|
|
|
@ -288,7 +309,7 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
|
|
|
|
|
if( img.depth() == CV_8U && bit_depth == 16 ) |
|
|
|
|
{ |
|
|
|
|
for( x = 0; x < width3; x++ ) |
|
|
|
|
for (int x = 0; x < width3; x++) |
|
|
|
|
{ |
|
|
|
|
int v = ((ushort *)src)[x]; |
|
|
|
|
src[x] = (uchar)(v >> 8); |
|
|
|
@ -329,12 +350,19 @@ bool PxMDecoder::readData( Mat& img ) |
|
|
|
|
} |
|
|
|
|
result = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
assert(0); |
|
|
|
|
CV_Error(CV_StsError, "m_bpp is not supported"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
catch(...) |
|
|
|
|
catch (const cv::Exception&) |
|
|
|
|
{ |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
catch (...) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush; |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
@ -410,8 +438,9 @@ bool PxMEncoder::write( const Mat& img, const vector<int>& params ) |
|
|
|
|
char* buffer = _buffer; |
|
|
|
|
|
|
|
|
|
// write header;
|
|
|
|
|
sprintf( buffer, "P%c\n%d %d\n%d\n", |
|
|
|
|
sprintf( buffer, "P%c\n# Generated by OpenCV %s\n%d %d\n%d\n", |
|
|
|
|
'2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0), |
|
|
|
|
CV_VERSION, |
|
|
|
|
width, height, (1 << depth) - 1 ); |
|
|
|
|
|
|
|
|
|
strm.putBytes( buffer, (int)strlen(buffer) ); |
|
|
|
|