mirror of
https://github.com/opencv/opencv.git
synced 2025-06-08 01:53:19 +08:00
parent
9802b4e123
commit
a2445c44cb
@ -56,7 +56,7 @@
|
|||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "grfmt_pam.hpp"
|
#include "grfmt_pam.hpp"
|
||||||
|
|
||||||
using namespace cv;
|
namespace cv {
|
||||||
|
|
||||||
/* the PAM related fields */
|
/* the PAM related fields */
|
||||||
#define MAX_PAM_HEADER_IDENITFIER_LENGTH 8
|
#define MAX_PAM_HEADER_IDENITFIER_LENGTH 8
|
||||||
@ -220,14 +220,14 @@ basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool ReadPAMHeaderLine (cv::RLByteStream& strm,
|
static
|
||||||
PamHeaderFieldType &fieldtype,
|
bool ReadPAMHeaderLine(
|
||||||
char value[MAX_PAM_HEADER_VALUE_LENGTH+1])
|
cv::RLByteStream& strm,
|
||||||
|
CV_OUT PamHeaderFieldType &fieldtype,
|
||||||
|
CV_OUT char value[MAX_PAM_HEADER_VALUE_LENGTH+1])
|
||||||
{
|
{
|
||||||
int code, pos;
|
int code;
|
||||||
bool ident_found = false;
|
char ident[MAX_PAM_HEADER_IDENITFIER_LENGTH+1] = {};
|
||||||
uint i;
|
|
||||||
char ident[MAX_PAM_HEADER_IDENITFIER_LENGTH+1] = { 0 };
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
code = strm.getByte();
|
code = strm.getByte();
|
||||||
@ -246,82 +246,95 @@ static bool ReadPAMHeaderLine (cv::RLByteStream& strm,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nul-ify buffers before writing to them */
|
int ident_sz = 0;
|
||||||
memset (ident, '\0', sizeof(char) * MAX_PAM_HEADER_IDENITFIER_LENGTH);
|
for (; ident_sz < MAX_PAM_HEADER_IDENITFIER_LENGTH; ident_sz++)
|
||||||
for (i=0; i<MAX_PAM_HEADER_IDENITFIER_LENGTH; i++) {
|
{
|
||||||
if (!isspace(code))
|
if (isspace(code))
|
||||||
ident[i] = (char) code;
|
|
||||||
else
|
|
||||||
break;
|
break;
|
||||||
|
ident[ident_sz] = (char)code;
|
||||||
code = strm.getByte();
|
code = strm.getByte();
|
||||||
}
|
}
|
||||||
|
CV_DbgAssert(ident_sz <= MAX_PAM_HEADER_IDENITFIER_LENGTH);
|
||||||
|
ident[ident_sz] = 0;
|
||||||
|
|
||||||
/* we may have filled the buffer and still have data */
|
/* we may have filled the buffer and still have data */
|
||||||
if (!isspace(code))
|
if (!isspace(code))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (i=0; i<PAM_FIELDS_NO; i++) {
|
bool ident_found = false;
|
||||||
if (strncmp(fields[i].identifier, ident, MAX_PAM_HEADER_IDENITFIER_LENGTH+1) == 0) {
|
for (uint i = 0; i < PAM_FIELDS_NO; i++)
|
||||||
|
{
|
||||||
|
if (0 == strncmp(fields[i].identifier, ident, std::min(ident_sz, MAX_PAM_HEADER_IDENITFIER_LENGTH) + 1))
|
||||||
|
{
|
||||||
fieldtype = fields[i].type;
|
fieldtype = fields[i].type;
|
||||||
ident_found = true;
|
ident_found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ident_found)
|
if (!ident_found)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
memset (value, '\0', sizeof(char) * MAX_PAM_HEADER_VALUE_LENGTH);
|
memset(value, 0, sizeof(char) * (MAX_PAM_HEADER_VALUE_LENGTH + 1));
|
||||||
/* we may have an identifier that has no value */
|
/* we may have an identifier that has no value */
|
||||||
if (code == '\n' || code == '\r')
|
if (code == '\n' || code == '\r')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
code = strm.getByte();
|
code = strm.getByte();
|
||||||
} while ( isspace(code) );
|
} while (isspace(code));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* read identifier value */
|
/* read identifier value */
|
||||||
for (i=0; i<MAX_PAM_HEADER_VALUE_LENGTH; i++) {
|
int value_sz = 0;
|
||||||
if (code != '\n' && code != '\r') {
|
for (; value_sz < MAX_PAM_HEADER_VALUE_LENGTH; value_sz++)
|
||||||
value[i] = (char) code;
|
{
|
||||||
} else if (code != '\n' || code != '\r')
|
if (code == '\n' || code == '\r')
|
||||||
break;
|
break;
|
||||||
|
value[value_sz] = (char)code;
|
||||||
code = strm.getByte();
|
code = strm.getByte();
|
||||||
}
|
}
|
||||||
pos = i;
|
CV_DbgAssert(value_sz <= MAX_PAM_HEADER_VALUE_LENGTH);
|
||||||
|
value[value_sz] = 0;
|
||||||
|
|
||||||
|
int pos = value_sz;
|
||||||
|
|
||||||
/* should be terminated */
|
/* should be terminated */
|
||||||
if (code != '\n' && code != '\r')
|
if (code != '\n' && code != '\r')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* remove trailing white spaces */
|
/* remove trailing white spaces */
|
||||||
while (pos >= 0 && isspace(value[pos]))
|
while (--pos >= 0 && isspace(value[pos]))
|
||||||
value[pos--] = '\0';
|
value[pos] = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseNumber (char *str, int *retval)
|
static int ParseInt(const char *str, int len)
|
||||||
{
|
{
|
||||||
char *endptr;
|
CV_Assert(len > 0);
|
||||||
long lval = strtol (str, &endptr, 0);
|
|
||||||
|
|
||||||
if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
|
int pos = 0;
|
||||||
|| (errno != 0 && lval == 0)) {
|
bool is_negative = false;
|
||||||
return false;
|
if (str[0] == '-')
|
||||||
}
|
{
|
||||||
if (endptr == str) {
|
is_negative = true;
|
||||||
return false;
|
pos++;
|
||||||
}
|
CV_Assert(isdigit(str[pos]));
|
||||||
|
}
|
||||||
*retval = (int) lval;
|
uint64_t number = 0;
|
||||||
|
while (pos < len && isdigit(str[pos]))
|
||||||
return true;
|
{
|
||||||
|
char ch = str[pos];
|
||||||
|
number = (number * 10) + (uint64_t)((int)ch - (int)'0');
|
||||||
|
CV_Assert(number < INT_MAX);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
if (pos < len)
|
||||||
|
CV_Assert(str[pos] == 0);
|
||||||
|
return (is_negative) ? -(int)number : (int)number;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace cv
|
|
||||||
{
|
|
||||||
|
|
||||||
PAMDecoder::PAMDecoder()
|
PAMDecoder::PAMDecoder()
|
||||||
{
|
{
|
||||||
@ -357,21 +370,12 @@ ImageDecoder PAMDecoder::newDecoder() const
|
|||||||
return makePtr<PAMDecoder>();
|
return makePtr<PAMDecoder>();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct parsed_fields
|
bool PAMDecoder::readHeader()
|
||||||
{
|
|
||||||
bool endhdr, height, width, depth, maxval;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HEADER_READ_CORRECT(pf) (pf.endhdr && pf.height && pf.width \
|
|
||||||
&& pf.depth && pf.maxval)
|
|
||||||
|
|
||||||
|
|
||||||
bool PAMDecoder::readHeader()
|
|
||||||
{
|
{
|
||||||
PamHeaderFieldType fieldtype = PAM_HEADER_NONE;
|
PamHeaderFieldType fieldtype = PAM_HEADER_NONE;
|
||||||
char value[MAX_PAM_HEADER_VALUE_LENGTH+1];
|
char value[MAX_PAM_HEADER_VALUE_LENGTH+1];
|
||||||
int byte;
|
int byte;
|
||||||
struct parsed_fields flds;
|
|
||||||
if( !m_buf.empty() )
|
if( !m_buf.empty() )
|
||||||
{
|
{
|
||||||
if( !m_strm.open(m_buf) )
|
if( !m_strm.open(m_buf) )
|
||||||
@ -379,6 +383,7 @@ bool PAMDecoder::readHeader()
|
|||||||
}
|
}
|
||||||
else if( !m_strm.open( m_filename ))
|
else if( !m_strm.open( m_filename ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte = m_strm.getByte();
|
byte = m_strm.getByte();
|
||||||
@ -393,70 +398,72 @@ bool PAMDecoder::readHeader()
|
|||||||
if (byte != '\n' && byte != '\r')
|
if (byte != '\n' && byte != '\r')
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
|
|
||||||
uint i;
|
bool flds_endhdr = false, flds_height = false, flds_width = false, flds_depth = false, flds_maxval = false;
|
||||||
memset (&flds, 0x00, sizeof (struct parsed_fields));
|
|
||||||
do {
|
do {
|
||||||
if (!ReadPAMHeaderLine(m_strm, fieldtype, value))
|
if (!ReadPAMHeaderLine(m_strm, fieldtype, value))
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
switch (fieldtype) {
|
switch (fieldtype)
|
||||||
|
{
|
||||||
case PAM_HEADER_NONE:
|
case PAM_HEADER_NONE:
|
||||||
case PAM_HEADER_COMMENT:
|
case PAM_HEADER_COMMENT:
|
||||||
continue;
|
continue;
|
||||||
case PAM_HEADER_ENDHDR:
|
case PAM_HEADER_ENDHDR:
|
||||||
flds.endhdr = true;
|
flds_endhdr = true;
|
||||||
break;
|
break;
|
||||||
case PAM_HEADER_HEIGHT:
|
case PAM_HEADER_HEIGHT:
|
||||||
if (flds.height)
|
if (flds_height)
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
if (!ParseNumber (value, &m_height))
|
m_height = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||||
throw RBS_BAD_HEADER;
|
flds_height = true;
|
||||||
flds.height = true;
|
|
||||||
break;
|
break;
|
||||||
case PAM_HEADER_WIDTH:
|
case PAM_HEADER_WIDTH:
|
||||||
if (flds.width)
|
if (flds_width)
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
if (!ParseNumber (value, &m_width))
|
m_width = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||||
throw RBS_BAD_HEADER;
|
flds_width = true;
|
||||||
flds.width = true;
|
|
||||||
break;
|
break;
|
||||||
case PAM_HEADER_DEPTH:
|
case PAM_HEADER_DEPTH:
|
||||||
if (flds.depth)
|
if (flds_depth)
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
if (!ParseNumber (value, &m_channels))
|
m_channels = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||||
throw RBS_BAD_HEADER;
|
flds_depth = true;
|
||||||
flds.depth = true;
|
|
||||||
break;
|
break;
|
||||||
case PAM_HEADER_MAXVAL:
|
case PAM_HEADER_MAXVAL:
|
||||||
if (flds.maxval)
|
if (flds_maxval)
|
||||||
throw RBS_BAD_HEADER;
|
|
||||||
if (!ParseNumber (value, &m_maxval))
|
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
|
m_maxval = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||||
if ( m_maxval > 65535 )
|
if ( m_maxval > 65535 )
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
if ( m_maxval > 255 ) {
|
m_sampledepth = (m_maxval > 255) ? CV_16U : CV_8U;
|
||||||
m_sampledepth = CV_16U;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_sampledepth = CV_8U;
|
|
||||||
if (m_maxval == 1)
|
if (m_maxval == 1)
|
||||||
bit_mode = true;
|
bit_mode = true;
|
||||||
flds.maxval = true;
|
flds_maxval = true;
|
||||||
break;
|
break;
|
||||||
case PAM_HEADER_TUPLTYPE:
|
case PAM_HEADER_TUPLTYPE:
|
||||||
for (i=0; i<PAM_FORMATS_NO; i++) {
|
{
|
||||||
if (strncmp(formats[i].name,
|
bool format_found = false;
|
||||||
value, MAX_PAM_HEADER_VALUE_LENGTH+1) == 0) {
|
for (uint i=0; i<PAM_FORMATS_NO; i++)
|
||||||
|
{
|
||||||
|
if (0 == strncmp(formats[i].name, value, MAX_PAM_HEADER_VALUE_LENGTH+1))
|
||||||
|
{
|
||||||
selected_fmt = formats[i].fmt;
|
selected_fmt = formats[i].fmt;
|
||||||
|
format_found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CV_Assert(format_found);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw RBS_BAD_HEADER;
|
throw RBS_BAD_HEADER;
|
||||||
}
|
}
|
||||||
} while (fieldtype != PAM_HEADER_ENDHDR);
|
} while (fieldtype != PAM_HEADER_ENDHDR);
|
||||||
|
|
||||||
if (HEADER_READ_CORRECT(flds)) {
|
if (flds_endhdr && flds_height && flds_width && flds_depth && flds_maxval)
|
||||||
if (selected_fmt == CV_IMWRITE_PAM_FORMAT_NULL) {
|
{
|
||||||
|
if (selected_fmt == CV_IMWRITE_PAM_FORMAT_NULL)
|
||||||
|
{
|
||||||
if (m_channels == 1 && m_maxval == 1)
|
if (m_channels == 1 && m_maxval == 1)
|
||||||
selected_fmt = CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE;
|
selected_fmt = CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE;
|
||||||
else if (m_channels == 1 && m_maxval < 256)
|
else if (m_channels == 1 && m_maxval < 256)
|
||||||
@ -469,28 +476,32 @@ bool PAMDecoder::readHeader()
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch(...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
m_offset = -1;
|
// failed
|
||||||
m_width = m_height = -1;
|
m_offset = -1;
|
||||||
m_strm.close();
|
m_width = m_height = -1;
|
||||||
return false;
|
m_strm.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
m_offset = -1;
|
||||||
|
m_width = m_height = -1;
|
||||||
|
m_strm.close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PAMDecoder::readData( Mat& img )
|
bool PAMDecoder::readData(Mat& img)
|
||||||
{
|
{
|
||||||
uchar* data = img.ptr();
|
uchar* data = img.ptr();
|
||||||
int target_channels = img.channels();
|
const int target_channels = img.channels();
|
||||||
size_t imp_stride = img.step;
|
size_t imp_stride = img.step;
|
||||||
int sample_depth = CV_ELEM_SIZE1(m_type);
|
const int sample_depth = CV_ELEM_SIZE1(m_type);
|
||||||
int src_elems_per_row = m_width*m_channels;
|
const int src_elems_per_row = m_width*m_channels;
|
||||||
int src_stride = src_elems_per_row*sample_depth;
|
const int src_stride = src_elems_per_row*sample_depth;
|
||||||
int x, y;
|
PaletteEntry palette[256] = {};
|
||||||
bool res = false, funcout;
|
|
||||||
PaletteEntry palette[256];
|
|
||||||
const struct pam_format *fmt = NULL;
|
const struct pam_format *fmt = NULL;
|
||||||
struct channel_layout layout = { 0, 0, 0, 0 }; // normalized to 1-channel grey format
|
struct channel_layout layout = { 0, 0, 0, 0 }; // normalized to 1-channel grey format
|
||||||
|
|
||||||
@ -512,7 +523,6 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
m_strm.setPos( m_offset );
|
m_strm.setPos( m_offset );
|
||||||
|
|
||||||
@ -521,10 +531,10 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
/* special case for 16bit images with wrong endianness */
|
/* special case for 16bit images with wrong endianness */
|
||||||
if (m_sampledepth == CV_16U && !isBigEndian())
|
if (m_sampledepth == CV_16U && !isBigEndian())
|
||||||
{
|
{
|
||||||
for (y = 0; y < m_height; y++, data += imp_stride )
|
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||||
{
|
{
|
||||||
m_strm.getBytes( src, src_stride );
|
m_strm.getBytes( src, src_stride );
|
||||||
for( x = 0; x < src_elems_per_row; x++ )
|
for (int x = 0; x < src_elems_per_row; x++)
|
||||||
{
|
{
|
||||||
uchar v = src[x * 2];
|
uchar v = src[x * 2];
|
||||||
data[x * 2] = src[x * 2 + 1];
|
data[x * 2] = src[x * 2 + 1];
|
||||||
@ -543,7 +553,7 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
if( target_channels == 1 )
|
if( target_channels == 1 )
|
||||||
{
|
{
|
||||||
uchar gray_palette[2] = {0, 255};
|
uchar gray_palette[2] = {0, 255};
|
||||||
for( y = 0; y < m_height; y++, data += imp_stride )
|
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||||
{
|
{
|
||||||
m_strm.getBytes( src, src_stride );
|
m_strm.getBytes( src, src_stride );
|
||||||
FillGrayRow1( data, src, m_width, gray_palette );
|
FillGrayRow1( data, src, m_width, gray_palette );
|
||||||
@ -551,21 +561,21 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
} else if ( target_channels == 3 )
|
} else if ( target_channels == 3 )
|
||||||
{
|
{
|
||||||
FillGrayPalette( palette, 1 , false );
|
FillGrayPalette( palette, 1 , false );
|
||||||
for( y = 0; y < m_height; y++, data += imp_stride )
|
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||||
{
|
{
|
||||||
m_strm.getBytes( src, src_stride );
|
m_strm.getBytes( src, src_stride );
|
||||||
FillColorRow1( data, src, m_width, palette );
|
FillColorRow1( data, src, m_width, palette );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (y = 0; y < m_height; y++, data += imp_stride )
|
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||||
{
|
{
|
||||||
m_strm.getBytes( src, src_stride );
|
m_strm.getBytes( src, src_stride );
|
||||||
|
|
||||||
/* endianness correction */
|
/* endianness correction */
|
||||||
if( m_sampledepth == CV_16U && !isBigEndian() )
|
if( m_sampledepth == CV_16U && !isBigEndian() )
|
||||||
{
|
{
|
||||||
for( x = 0; x < src_elems_per_row; x++ )
|
for (int x = 0; x < src_elems_per_row; x++)
|
||||||
{
|
{
|
||||||
uchar v = src[x * 2];
|
uchar v = src[x * 2];
|
||||||
src[x * 2] = src[x * 2 + 1];
|
src[x * 2] = src[x * 2 + 1];
|
||||||
@ -576,7 +586,7 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
/* scale down */
|
/* scale down */
|
||||||
if( img.depth() == CV_8U && m_sampledepth == CV_16U )
|
if( img.depth() == CV_8U && m_sampledepth == CV_16U )
|
||||||
{
|
{
|
||||||
for( x = 0; x < src_elems_per_row; x++ )
|
for (int x = 0; x < src_elems_per_row; x++)
|
||||||
{
|
{
|
||||||
int v = ((ushort *)src)[x];
|
int v = ((ushort *)src)[x];
|
||||||
src[x] = (uchar)(v >> 8);
|
src[x] = (uchar)(v >> 8);
|
||||||
@ -589,7 +599,7 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
}
|
}
|
||||||
/* perform correct conversion based on format */
|
/* perform correct conversion based on format */
|
||||||
else if (fmt) {
|
else if (fmt) {
|
||||||
funcout = false;
|
bool funcout = false;
|
||||||
if (fmt->cvt_func)
|
if (fmt->cvt_func)
|
||||||
funcout = fmt->cvt_func (src, data, m_width, target_channels,
|
funcout = fmt->cvt_func (src, data, m_width, target_channels,
|
||||||
img.depth());
|
img.depth());
|
||||||
@ -608,13 +618,8 @@ bool PAMDecoder::readData( Mat& img )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = true;
|
|
||||||
} catch(...)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user