2020-10-21 17:24:01 +02:00

196 lines
6.5 KiB
C++

/****************************************************************************
* MeshLab o o *
* An extendible mesh processor o o *
* _ O _ *
* Copyright(C) 2005, 2009 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include <Qt>
#include <QPixmap>
#include <bzlib.h>
#include <vector>
#include "scalar_image.h"
using namespace std;
/*
Images with bit-depths greater than 8bpp and up to 31bpp are supported by the JJ2000 codec if they are stored in PGX files
(one file per component). PGX is a custom monochrome file format invented specifically to simplify the use of JPEG 2000
with images of different bit-depths in the range of 1 to 31 bits per pixel.
The file consists of a one line text header followed by the (raw) data.
Header: "PG"+ ws +<endianess>+ ws +[sign]+ws + <bit-depth>+" "+<width>+" "+<height>+[compressed_size]'\n'
where:
* ws (white-spaces) is any combination of characters ' ' and '\t'.
* endianess equals "LM" or "ML"(resp. little-endian or big-endian)
* sign equals "+" or "-" (resp. unsigned or signed). If omited, values are supposed to be unsigned.
* bit-depth that can be any number between 1 and 31. This number must take into account the eventual sign bit.
* width and height are the image dimensions (in pixels).
Data: The image binary values appear one after the other (in raster order) immediately after the last header character ('\n')
and are byte-aligned (they are packed into 1,2 or 4 bytes per sample, depending upon the bit-depth value).
*/
template <>
bool ScalarImage<float>::Open(const char *filename)
{
FILE *fp=fopen(filename,"rb");
if(!fp) return false;
char buf[256];
fgets(buf,255,fp);
qDebug("Header of %s is '%s'",filename,buf);
float ll,lh;
int depth;
char mode;
int compressed_size=0;
sscanf(buf,"PG LM %i %i %i %c %f %f %i",&depth,&w,&h,&mode,&ll,&lh,&compressed_size);
qDebug("image should be of %i x %i %i depth and with range in %f -- %f in mode %c",w,h,depth,ll,lh,mode);
if(depth!=16)
{
qDebug("Wrong depth of image 16 bit expected");
return false;
}
if (mode != 'l' && mode != 'L')
{
qDebug("Wrong mode, expected l or L");
return false;
}
if (mode == 'l')
{
vector<unsigned short> bb(w*h);
fread(&*bb.begin(),w*h,sizeof(short),fp);
v.resize(w*h);
for(int i =0; i<w*h;++i)
v[i]=ll+(lh-ll)*(float(bb[i])/65536.0f);
}
else
{
char* compressed_buffer = new char[compressed_size];
fread(compressed_buffer,compressed_size,1,fp);
// decompress!
size_t size = w*h*sizeof(short);
unsigned char * uncompressed_buffer = new unsigned char[size];
unsigned int mysize = size;
BZ2_bzBuffToBuffDecompress((char*)uncompressed_buffer, &mysize, compressed_buffer, compressed_size, 0, 0);
if (mysize != size)
{
qDebug("This is very wrong. The uncompressed size is not the expected size");
return false;
}
int imagesize = w*h;
unsigned char *correct_buffer = new unsigned char[size];
for (int i=0; i<imagesize; ++i)
{
for (size_t j=0; j<sizeof(short); ++j)
{
correct_buffer[sizeof(short)*i +j] = uncompressed_buffer[imagesize*j + i];
}
}
v.resize(w*h);
for (int i=0; i<imagesize; ++i)
{
float a = *((unsigned short*)&correct_buffer[i*sizeof(short)]);
v[i] = ll+(lh-ll)*(a/65536.0f);
}
delete [] uncompressed_buffer;
delete [] compressed_buffer;
delete [] correct_buffer;
}
fclose(fp);
return true;
}
template <>
bool ScalarImage<unsigned char>::Open(const char *filename)
{
FILE *fp=fopen(filename,"rb");
if(!fp) return false;
char buf[256];
fgets(buf,255,fp);
qDebug("Header of %s is '%s'",filename,buf);
int depth;
char mode = ' ';
int compressed_size=0;
int nrscan = sscanf(buf,"PG LM %i %i %i %c %i",&depth,&w,&h,&mode,&compressed_size);
if (nrscan == 3)
qDebug("image should be of %i x %i %i depth ",w,h,depth);
else
qDebug("compressed image of %i x %i %i depth ",w,h,depth);
if(depth!=8)
{
qDebug("Wrong depth of image: 8 bit expected");
return false;
}
if (mode != 'C')
{
v.resize(w*h);
fread(&*v.begin(),w*h,sizeof(unsigned char),fp);
}
else
{
char* compressed_buffer = new char[compressed_size];
fread(compressed_buffer,compressed_size,1,fp);
// decompress!
unsigned int mysize = w*h;
v.resize(w*h);
BZ2_bzBuffToBuffDecompress((char*)&*v.begin(), &mysize, compressed_buffer, compressed_size, 0, 0);
if (mysize != (unsigned int)(w*h))
{
qDebug("This is very wrong. The uncompressed size is not the expected size");
return false;
}
}
fclose(fp);
return true;
}
template <>
ScalarImage<unsigned char>::ScalarImage(QImage img)
{
resize(img.width(),img.height());
for(int y=0;y<h;++y)
for(int x=0;x<w;++x)
Val(x,y)=qGray(img.pixel(x,y));
}
template <class ScalarType>
bool ScalarImage<ScalarType>::Subsample(const int factor, ScalarImage<ScalarType> &fli)
{
resize(fli.w/factor,fli.h/factor);
for(int i=0;i<h;++i)
for(int j=0;j<w;++j)
Val(i,j)=fli.Val(i*factor,j*factor);
return true;
};