libcvd-members
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libcvd-members] libcvd cvd/image_convert.h cvd/internal/load_an...


From: Olaf Kähler
Subject: [libcvd-members] libcvd cvd/image_convert.h cvd/internal/load_an...
Date: Thu, 18 Feb 2010 13:30:11 +0000

CVSROOT:        /sources/libcvd
Module name:    libcvd
Changes by:     Olaf Kähler <ok245>     10/02/18 13:30:10

Modified files:
        cvd            : image_convert.h 
        cvd/internal   : load_and_save.h 
        cvd/internal/io: cvdimage.h 
        pnm_src        : cvdimage.cxx 
        test           : test_images.cxx 

Log message:
        - more accurate separation of IsConvertible and PixelByPixelConvertible
        - revised automatic color conversion upon loading an image
        - added I/O support for Bayer images in CVD image format
        - improved prediction methods in CVD image format
        - added test cases for the CVD image format

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd/image_convert.h?cvsroot=libcvd&r1=1.15&r2=1.16
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd/internal/load_and_save.h?cvsroot=libcvd&r1=1.16&r2=1.17
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd/internal/io/cvdimage.h?cvsroot=libcvd&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/libcvd/pnm_src/cvdimage.cxx?cvsroot=libcvd&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/libcvd/test/test_images.cxx?cvsroot=libcvd&r1=1.16&r2=1.17

Patches:
Index: cvd/image_convert.h
===================================================================
RCS file: /sources/libcvd/libcvd/cvd/image_convert.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -b -r1.15 -r1.16
--- cvd/image_convert.h 26 Oct 2009 15:44:58 -0000      1.15
+++ cvd/image_convert.h 18 Feb 2010 13:30:10 -0000      1.16
@@ -180,13 +180,27 @@
        template<class D> Image<D> convert_image(const BasicImage<C>& from);
 
   #endif
-    /// Can teo types be converted with CVD::convert_image?
+    /// Can two types be converted with CVD::convert_image?
     /// @ingroup gImageIO
        template<class In, class Out> struct IsConvertible
        { 
                static const bool is=Pixel::DefaultConvertible<In>::is && 
Pixel::DefaultConvertible<Out>::is;
        };
 
+    /// Can individual pixels of two types be converted with 
ConvertPixels::convert()?
+    /// E.g. Bayer patterns or YUV411 can usually not.
+    /// @ingroup gImageIO
+       template<class In, class Out> struct PixelByPixelConvertible
+       { 
+               static const bool is=Pixel::DefaultConvertible<In>::is && 
Pixel::DefaultConvertible<Out>::is;
+       };
+
+       /// Identity conversion by memcpy is always supported
+       template<class InOut> struct PixelByPixelConvertible<InOut, InOut>
+       { 
+               static const bool is=1;
+       };
+
 }
 
 #endif

Index: cvd/internal/load_and_save.h
===================================================================
RCS file: /sources/libcvd/libcvd/cvd/internal/load_and_save.h,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -b -r1.16 -r1.17
--- cvd/internal/load_and_save.h        19 Aug 2008 22:33:28 -0000      1.16
+++ cvd/internal/load_and_save.h        18 Feb 2010 13:30:10 -0000      1.17
@@ -21,8 +21,10 @@
 #ifndef CVD_LOAD_AND_SAVE_H
 #define CVD_LOAD_AND_SAVE_H
 
+#include <iostream>
 #include <cvd/exceptions.h>
 #include <cvd/image_convert.h>
+#include <cvd/colourspace_convert.h>
 #include <cvd/internal/convert_pixel_types.h>
 #include <cvd/internal/name_CVD_rgb_types.h>
 
@@ -197,6 +199,21 @@
                        }
                };
 
+               template<class PixelType, class DiskPixelType, class 
ImageLoader> struct read_and_then_process
+               {
+                       static void exec(BasicImage<PixelType>& im, 
ImageLoader& r)
+                       {
+                               Image<DiskPixelType> imgbuf(r.size());
+
+                               for(int row = 0; row < r.size().y; row++)
+                               {
+                                       r.get_raw_pixel_line(imgbuf[row]);
+                               }
+
+                               convert_image(imgbuf, im);
+                       }
+               };
+
 
                
////////////////////////////////////////////////////////////////////////////////
        
                //
@@ -204,11 +221,17 @@
                //
                template<class PixelType, class ImageLoader, class List > 
struct Reader
                {       
-                       static void read(SubImage<PixelType>& im, ImageLoader& 
r)
+                       static void read(BasicImage<PixelType>& im, 
ImageLoader& r)
                        {
                                if(r.datatype() == PNM::type_name<typename 
List::Type>::name())
                                {
+                                       //std::cout << "converting " << 
r.datatype() << " -> " << PNM::type_name<PixelType>::name() << " PixelByPixel: 
" << PixelByPixelConvertible<typename List::Type, PixelType>::is << " 
Convertible: " << IsConvertible<typename List::Type, PixelType>::is << 
std::endl;
+                                       if (PixelByPixelConvertible<typename 
List::Type, PixelType>::is)
                                        read_and_maybe_process<PixelType, 
typename List::Type, ImageLoader>::exec(im, r);
+                                       else if (IsConvertible<typename 
List::Type, PixelType>::is)
+                                               
read_and_then_process<PixelType, typename List::Type, ImageLoader>::exec(im, r);
+                                       else
+                                               throw 
CVD::Exceptions::Image_IO::ReadTypeMismatch(r.datatype(), 
PNM::type_name<PixelType>::name());
                                }
                                else
                                        Reader<PixelType, ImageLoader, typename 
List::Next>::read(im, r);
@@ -217,7 +240,7 @@
 
                template<class PixelType, class ImageLoader> struct 
Reader<PixelType, ImageLoader, Head>
                {
-                       static void read(SubImage<PixelType>&, ImageLoader& r)
+                       static void read(BasicImage<PixelType>&, ImageLoader& r)
                        {       
                                throw 
Exceptions::Image_IO::UnsupportedImageSubType(r.name(), r.datatype() + " not 
yet supported");
                        }
@@ -229,12 +252,12 @@
                // Driver functions for loading images.
                //
 
-               template<class T, class ImageLoader> void 
readImage(SubImage<T>& im, ImageLoader& r)
+               template<class T, class ImageLoader> void 
readImage(BasicImage<T>& im, ImageLoader& r)
                {
                        Reader<T, ImageLoader, typename 
ImageLoader::Types>::read(im, r);
                }
 
-               template <class T, class ImageLoader> void 
readImage(SubImage<T>& im, std::istream& in)
+               template <class T, class ImageLoader> void 
readImage(BasicImage<T>& im, std::istream& in)
                {
                        ImageLoader loader(in);
                        ImageRef size = loader.size();

Index: cvd/internal/io/cvdimage.h
===================================================================
RCS file: /sources/libcvd/libcvd/cvd/internal/io/cvdimage.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- cvd/internal/io/cvdimage.h  15 Feb 2010 10:40:48 -0000      1.1
+++ cvd/internal/io/cvdimage.h  18 Feb 2010 13:30:10 -0000      1.2
@@ -28,6 +28,7 @@
 
 #include <cvd/image.h>
 #include <cvd/byte.h>
+#include <cvd/colourspaces.h>
 #include <cvd/internal/convert_pixel_types.h>
 #include <cvd/internal/load_and_save.h>
 
@@ -50,6 +51,10 @@
                        ImageRef size();
 
                        void get_raw_pixel_line(unsigned char*);
+                       void get_raw_pixel_line(bayer_bggr*);
+                       void get_raw_pixel_line(bayer_rggb*);
+                       void get_raw_pixel_line(bayer_grbg*);
+                       void get_raw_pixel_line(bayer_gbrg*);
                        void get_raw_pixel_line(Rgb<unsigned char>*);
                        void get_raw_pixel_line(Rgba<unsigned char>*);
 
@@ -58,9 +63,13 @@
 
 
                        typedef TypeList<byte,
+                                       TypeList<bayer_bggr, 
+                                       TypeList<bayer_rggb, 
+                                       TypeList<bayer_grbg, 
+                                       TypeList<bayer_gbrg, 
                                        TypeList<Rgb<byte>, 
                                        TypeList<Rgba<byte>, 
-                                       Head> > > Types;
+                                       Head> > > > > > > Types;
                
                private:
                        std::auto_ptr<ReadPimpl> t; 
@@ -76,6 +85,10 @@
                        ~writer();
 
                        void write_raw_pixel_line(const byte*);
+                       void write_raw_pixel_line(const bayer_bggr*);
+                       void write_raw_pixel_line(const bayer_rggb*);
+                       void write_raw_pixel_line(const bayer_grbg*);
+                       void write_raw_pixel_line(const bayer_gbrg*);
                        void write_raw_pixel_line(const Rgb<byte>*);
                        void write_raw_pixel_line(const Rgba<byte>*);
 
@@ -88,12 +101,31 @@
                        std::auto_ptr<WritePimpl> t; 
        };
 
+       template <> struct writer::Outgoing<bayer_bggr> 
+       {
+               typedef bayer_bggr type;
+       };
+
+       template <> struct writer::Outgoing<bayer_rggb> 
+       {
+               typedef bayer_rggb type;
+       };
+
+       template <> struct writer::Outgoing<bayer_grbg> 
+       {
+               typedef bayer_grbg type;
+       };
+
+       template <> struct writer::Outgoing<bayer_gbrg> 
+       {
+               typedef bayer_gbrg type;
+       };
+
        template<class C> struct writer::Outgoing<Rgb<C> > 
        {
                typedef Rgb<byte> type;
        };
 
-
        template<class C> struct writer::Outgoing<Rgba<C> > 
        {
                typedef Rgba<byte> type;

Index: pnm_src/cvdimage.cxx
===================================================================
RCS file: /sources/libcvd/libcvd/pnm_src/cvdimage.cxx,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- pnm_src/cvdimage.cxx        16 Feb 2010 22:52:11 -0000      1.2
+++ pnm_src/cvdimage.cxx        18 Feb 2010 13:30:10 -0000      1.3
@@ -20,6 +20,8 @@
 */
 
 #include <stdio.h>
+#include <stdint.h>
+#include <string.h>
 #include <arpa/inet.h> // used for byte reordering
 #include "cvd/internal/io/cvdimage.h"
 
@@ -44,24 +46,170 @@
 // helper functions for prediction
 
 // Use a simple linewise predictor and compute the residual differences for a
-// single line. The predictor uses the value stored @p predictionlen bytes in
+// single line. The predictor uses the value stored @p pred_len bytes in
 // the past to predict the current value.
-void line_diff(const byte* in, int width, byte* out, int predictionlen = 1)
+void pred_horizontal_diff(const byte* in, int width, byte* out, int pred_len = 
1)
 {
-       for (int i = 0; i < predictionlen; i++)
+       for (int i = 0; i < pred_len; i++)
                out[i] = in[i];
 
-       for (int i = predictionlen; i < width; i++)
-               out[i] = (256 + in[i] - in[i-predictionlen])&255;
+       for (int i = pred_len; i < width; i++)
+               out[i] = (256 + in[i] - in[i-pred_len])&255;
 }
 
-void line_undiff(const byte* in, int width, byte* out, int predictionlen = 1)
+void pred_horizontal_undiff(const byte* in, int width, byte* out, int pred_len 
= 1)
 {
-       for (int i = 0; i < predictionlen; i++)
+       for (int i = 0; i < pred_len; i++)
                out[i] = in[i];
 
-       for (int i = predictionlen; i < width; i++)
-               out[i] = (in[i] + out[i-predictionlen])&255;
+       for (int i = pred_len; i < width; i++)
+               out[i] = (in[i] + out[i-pred_len])&255;
+}
+
+// Use a better 2d predictor where Gonzalez & Woods refer to a proof, stating
+// that it is in some sense the best 2d predictor you can get. Again compute
+// the residual differences for a single line of pixels. The predictor uses
+// the three values stored @p pred_len bytes to the left and one line above
+// the current pixel to predict the value. 
+void pred_2doptimal_diff(const byte* in, int width, byte* buffer, byte* out, 
int pred_len = 1)
+{
+       // simple vertical prediction for first column(s)
+       for (int i = 0; i < pred_len; i++) {
+               out[i] = (256 + in[i] - buffer[i]) & 255;
+       }
+
+       // 0.75 i[x-1][y] + 0.75 i[x][y-1] - 0.5 i[x-1][y-1]
+       // buffer is used to store the previous row
+       for (int i = pred_len; i < width; i++) {
+               int pred = (3*in[i-pred_len] - 2*buffer[i-pred_len] + 
3*buffer[i]) / 4;
+               out[i] = (256 + in[i] - pred)&255;
+               buffer[i-pred_len] = in[i-pred_len];
+       }
+
+       // fix remaining values in the buffer
+       for (int i = width-pred_len; i < width; i++) {
+               buffer[i] = in[i];
+       }
+}
+
+void pred_2doptimal_undiff(const byte* in, int width, byte* buffer, byte* out, 
int pred_len = 1)
+{
+       // vertical prediction for first column(s)
+       for (int i = 0; i < pred_len; i++) {
+               out[i] = (in[i] + buffer[i]) & 255;
+       }
+
+       // see above
+       for (int i = pred_len; i < width; i++) {
+               int pred = (3*out[i-pred_len] - 2*buffer[i-pred_len] + 
3*buffer[i]) / 4;
+               out[i] = (in[i] + pred)&255;
+               buffer[i-pred_len] = out[i-pred_len];
+       }
+
+       // fix remaining values in the buffer
+       for (int i = width-pred_len; i < width; i++) {
+               buffer[i] = out[i];
+       }
+}
+
+// Use a 2d predictor for Bayer lines of pixels. In case @p greenfirst is set,
+// the row is assumed to be of the form gxgx, otherwise it is xgxg. The
+// predictor uses two rows above the current pixel and two columns to the
+// left.
+
+// see King-Hong Chung and Yuk-Hee Chan. A Lossless Compression Scheme for
+// Bayer Color Filter Array Images. IEEE Transactions on Image Processing, 
2007.
+// (i don't trust that paper!)
+//static const int pred_coeff_green[]={5, 2, 1}; => 24.5549
+
+//static const int pred_coeff_green[]={3, 5, 0}; => 24.4918
+//static const int pred_coeff_green[]={6, -4, 6}; => 24.9409
+//static const int pred_coeff_green[]={1, 6, 1}; //=> 24.4494
+static const int pred_coeff_green[]={2, 4, 2}; //=> 24.3723
+//static const int pred_coeff_bluered[]={8, 0, 0}; //=> 24.6116
+//static const int pred_coeff_bluered[]={6, -4, 6}; //=> 24.3723
+//static const int pred_coeff_bluered[]={3, 2, 3}; //=> 24.3034
+//static const int pred_coeff_bluered[]={5, -2, 5}; //=> 24.2141
+static const int pred_coeff_bluered[]={4, 0, 4}; //=> 24.1666
+
+// Ideally one would learn the best coefficients from the autocorrelation
+// matrix as done in: S Andriani, G Calvagno, D Menon. Lossless Compression of
+// Bayer Mask Images using an Optimal Vector Prediction Technique. EUSIPCO 
2006.
+// Unfortunaly they don't give their final coefficients.
+
+void pred_2dbayer_diff(const byte* in, int width, byte* buffer1, byte* 
buffer2, byte* out, bool greenfirst)
+{
+       // simple vertical prediction for first two columns
+       out[0] = (256 + in[0] - buffer1[0]) & 255;
+       out[1] = (256 + in[1] - buffer1[1]) & 255;
+
+       // for red and blue: 0.75 i[x-2][y] + 0.75 i[x][y-2] - 0.5 i[x-2][y-2]
+       // for green: 0.25 i[x-2][y] + 0.5 i[x-1][y-1] - 0.25 i[x+1][y-1]
+       // buffer1 is used to store the pre-previous row
+       // buffer2 is used to store the previous row
+       int i=2;
+       if (greenfirst) {
+               int pred = (pred_coeff_green[0]*in[i-2] +
+                       pred_coeff_green[1]*buffer2[i-1] +
+                       pred_coeff_green[2]*buffer1[i]) / 8;
+               out[i] = (256 + in[i] - pred)&255;
+               buffer1[i-2] = in[i-2];
+               i++;
+       }
+
+       for (; i < width; i++) {
+               int pred = (pred_coeff_bluered[0]*in[i-2] +
+                       pred_coeff_bluered[1]*buffer1[i-2] +
+                       pred_coeff_bluered[2]*buffer1[i]) / 8;
+               out[i] = (256 + in[i] - pred)&255;
+               buffer1[i-2] = in[i-2];
+               i++;
+               if (!(i<width)) break;
+               pred = (pred_coeff_green[0]*in[i-2] +
+                       pred_coeff_green[1]*buffer2[i-1] +
+                       pred_coeff_green[2]*buffer1[i]) / 8;
+               out[i] = (256 + in[i] - pred)&255;
+               buffer1[i-2] = in[i-2];
+       }
+
+       buffer1[width-2] = in[width-2];
+       buffer1[width-1] = in[width-1];
+}
+
+void pred_2dbayer_undiff(const byte* in, int width, byte* buffer1, byte* 
buffer2, byte* out, bool greenfirst)
+{
+       // simple vertical prediction for first two columns
+       out[0] = (in[0] + buffer1[0]) & 255;
+       out[1] = (in[1] + buffer1[1]) & 255;
+
+       // see above
+       int i=2;
+       if (greenfirst) {
+               int pred = (pred_coeff_green[0]*out[i-2] +
+                       pred_coeff_green[1]*buffer2[i-1] +
+                       pred_coeff_green[2]*buffer1[i]) / 8;
+               out[i] = (in[i] + pred)&255;
+               buffer1[i-2] = out[i-2];
+               i++;
+       }
+
+       for (; i < width; i++) {
+               int pred = (pred_coeff_bluered[0]*out[i-2] +
+                       pred_coeff_bluered[1]*buffer1[i-2] +
+                       pred_coeff_bluered[2]*buffer1[i]) / 8;
+               out[i] = (in[i] + pred)&255;
+               buffer1[i-2] = out[i-2];
+               i++;
+               if (!(i<width)) break;
+               pred = (pred_coeff_green[0]*out[i-2] +
+                       pred_coeff_green[1]*buffer2[i-1] +
+                       pred_coeff_green[2]*buffer1[i]) / 8;
+               out[i] = (in[i] + pred)&255;
+               buffer1[i-2] = out[i-2];
+       }
+
+       buffer1[width-2] = out[width-2];
+       buffer1[width-1] = out[width-1];
 }
 
 // helper functions for huffman coding
@@ -150,6 +298,13 @@
 static const int Bits_48 = 48 / PackBits == 0 ? 1 : 48/PackBits;
 static const int Bits_96 = 96 / PackBits == 0 ? 1 : 96/PackBits;
 
+enum cvd_predictors {
+       PRED_HORIZONTAL = 0,
+       PRED_2D_OPTIMAL = 2,
+       PRED_2D_BAYER_1 = 3,
+       PRED_2D_BAYER_2 = 4,
+};
+
 struct SortIndex
 {
        const array<int, 256>& d;
@@ -165,7 +320,7 @@
        
 };
 
-// given a image (or "some data") and histogram of the contained symbols,
+// given a image (or "some data") and a histogram of the contained symbols,
 // create a Huffman tree, encode the data and return the new code
 vector<PackType> huff_compress(const Image<byte>& im, const array<int,256>& h)
 {
@@ -295,10 +450,8 @@
 {
        public:
                ReadPimpl(std::istream&);
-               int channels(){return m_channels;}
                long  x_size() const {return xs;}
                long  y_size() const {return ys;}
-               long  elements_per_line() const {return xs * m_channels;}
                void get_raw_pixel_lines(unsigned char*, unsigned long nlines);
                ~ReadPimpl();
                string datatype()
@@ -318,12 +471,17 @@
                void read_header(std::istream& is);
                array<int, 256> read_hist(std::istream& is);
                vector<PackType> read_data(std::istream& is);
+               void bayer_swap_rows(void);
+
                long    xs, ys;
-               int     m_channels;
+               int bypp; // bytes per pixel
+               int pred_len;
+               enum cvd_predictors pred_mode;
                std::istream&   i;
                string type;
                Image<byte> diff;
                int row;
+               byte *buffer, *buffer2; //size unknown at compile time
 };
 
 ImageRef reader::size()
@@ -336,6 +494,26 @@
        t->get_raw_pixel_line(d);
 }
 
+void reader::get_raw_pixel_line(bayer_bggr* d)
+{
+       t->get_raw_pixel_line(d);
+}
+
+void reader::get_raw_pixel_line(bayer_rggb* d)
+{
+       t->get_raw_pixel_line(d);
+}
+
+void reader::get_raw_pixel_line(bayer_grbg* d)
+{
+       t->get_raw_pixel_line(d);
+}
+
+void reader::get_raw_pixel_line(bayer_gbrg* d)
+{
+       t->get_raw_pixel_line(d);
+}
+
 void reader::get_raw_pixel_line(Rgb<byte>* d)
 {
        t->get_raw_pixel_line(d);
@@ -366,13 +544,19 @@
 ReadPimpl::ReadPimpl(istream& in)
 :i(in)
 {
+       pred_mode = PRED_HORIZONTAL;
        row = 0;
        read_header(in);
        array<int,256> h = read_hist(in);
 
-       diff.resize(ImageRef(xs*m_channels,ys));
-       vector<PackType> d = read_data(in);
+       diff.resize(ImageRef(xs*bypp,ys));
+       buffer = new byte[xs*bypp];
+       if ((pred_mode==PRED_2D_BAYER_1)||(pred_mode==PRED_2D_BAYER_2))
+               buffer2 = new byte[xs*bypp];
+       else
+               buffer2 = NULL;
 
+       vector<PackType> d = read_data(in);
        huff_decompress(d, h, diff);
 }
 
@@ -380,21 +564,42 @@
 {
        string tmp;
        getline(in, tmp);
-       //cout << "header-id: '" << tmp << "'" << endl;
+       //cout << "loading: header-id: '" << tmp << "'" << endl;
        if (tmp != "CVD") throw 
CVD::Exceptions::Image_IO::MalformedImage(string("Error in CVD image: incorrect 
header ID"));
 
+       // get data type
        getline(in, type);
-       //cout << "type: '" << type << "'" << endl;
-       if (type== "unsigned char") m_channels=1;
-       else if (type== "CVD::Rgb<unsigned char>") m_channels=3;
-       else if (type== "CVD::Rgba<unsigned char>") m_channels=4;
-       else throw CVD::Exceptions::Image_IO::MalformedImage(string("Error in 
CVD image: unknown data type"));
+       //cout << "loading: type: '" << type << "'" << endl;
 
+       // get image dimensions
        in >> xs >> ys;
-       //cout << "size: " << xs << "x" << ys << endl;
+       //cout << "loading: size: " << xs << "x" << ys << endl;
 
+       // get extra information, comments, compression options
        getline(in, tmp);
-       //cout << "extras: '" << tmp << "'";
+       //cout << "loading: extras: '" << tmp << "'" << endl;
+       size_t pos = tmp.find("pred=");
+       if (pos!=tmp.npos) {
+               istringstream sstr(tmp.substr(pos+5));
+               sstr >> (int&)pred_mode;
+       }
+
+       //cout << "type: '" << type << "'" << endl;
+       if (type== "unsigned char")
+               bypp = pred_len = 1;
+       else if (type== "CVD::Rgb<unsigned char>")
+               bypp = pred_len = 3;
+       else if (type== "CVD::Rgba<unsigned char>")
+               bypp = pred_len = 4;
+       else if ((type== "bayer_bggr")||(type== "bayer_rggb")) {
+               bypp = 1; pred_len = 2;
+               if ((pred_mode==PRED_2D_OPTIMAL)||(pred_mode==PRED_2D_BAYER_1))
+                       pred_mode = PRED_2D_BAYER_2;
+       } else if ((type== "bayer_grbg")||(type== "bayer_gbrg")) {
+               bypp = 1; pred_len = 2;
+               if ((pred_mode==PRED_2D_OPTIMAL)||(pred_mode==PRED_2D_BAYER_2))
+                       pred_mode = PRED_2D_BAYER_1;
+       } else throw CVD::Exceptions::Image_IO::MalformedImage(string("Error in 
CVD image: unknown data type"));
 }
 
 array<int, 256> ReadPimpl::read_hist(std::istream& is)
@@ -424,16 +629,65 @@
 
 void ReadPimpl::get_raw_pixel_lines(unsigned char*data, unsigned long nlines)
 {
-       for(unsigned int i=0; i < nlines; i++)  
-       {
-               line_undiff(diff[row], xs*m_channels, data, m_channels);
-               data += xs;
+       switch (pred_mode) {
+       case PRED_HORIZONTAL:
+               for(unsigned int i=0; i < nlines; i++)  {
+                       pred_horizontal_undiff(diff[row], xs*bypp, data, 
pred_len);
+                       data += xs*bypp;
                row++;
        }
+               break;
+       case PRED_2D_OPTIMAL:
+               if (row==0) {           
+                       pred_horizontal_undiff(diff[row], xs*bypp, data, 
pred_len);
+                       memcpy(buffer, data, xs*bypp);
+                       data += xs*bypp;
+                       row++;
+                       nlines--;
+               }
+               for(unsigned int i=0; i < nlines; i++)  {
+                       pred_2doptimal_undiff(diff[row], xs*bypp, buffer, data, 
pred_len);
+                       data += xs*bypp;
+                       row++;
+               }
+               break;
+       case PRED_2D_BAYER_1:
+       case PRED_2D_BAYER_2:
+               //first two rows use horizontal prediction
+               while (row<=1) {
+                       pred_horizontal_undiff(diff[row], xs*bypp, data, 
pred_len);
+                       memcpy(buffer, data, xs*bypp);
+                       bayer_swap_rows();
+                        data += xs*bypp;
+                        row++;
+                       nlines--;
+                       if (nlines==0) break;
+               }
+
+               // regular lines
+               while (nlines>0) {
+                       pred_2dbayer_undiff(diff[row], xs*bypp, buffer, 
buffer2, data, (pred_mode==PRED_2D_BAYER_1));
+                       bayer_swap_rows();
+                       data += xs*bypp;
+                       row++;
+                       nlines--;
+               }
+       }
+}
+
+void ReadPimpl::bayer_swap_rows(void)
+{
+       byte *tmp = buffer;
+       buffer = buffer2;
+       buffer2 = tmp;
+       if (pred_mode==PRED_2D_BAYER_1) pred_mode=PRED_2D_BAYER_2;
+       else if (pred_mode==PRED_2D_BAYER_2) pred_mode=PRED_2D_BAYER_1;
 }
 
 ReadPimpl::~ReadPimpl()
 {
+       delete[] buffer;
+       if (buffer2!=NULL) delete[] buffer2;
 }
 
 
////////////////////////////////////////////////////////////////////////////////
@@ -449,8 +703,7 @@
 class WritePimpl
 {
        public:
-               WritePimpl(std::ostream&, int  xsize, int ysize, const string& 
type, const std::string& comm="");
-               int channels(){return m_channels;}
+               WritePimpl(std::ostream&, int  xsize, int ysize, const string& 
type);
                long  x_size() const {return xs;}
                long  y_size() const {return ys;}
                void    write_raw_pixel_lines(const unsigned char*, unsigned 
long);
@@ -461,47 +714,104 @@
                void write_header(std::ostream& os);
                void write_hist(std::ostream& os, const array<int, 256>& h);
                void write_data(std::ostream& os, vector<PackType>& data);
+               void bayer_swap_rows(void);
 
                long    xs, ys, row;
-               int     m_channels;
+               int     bypp; // bytes per pixel :)
+               int     pred_len;
+               enum cvd_predictors pred_mode;
                std::ostream&   o;
                string type;
                Image<byte> diff;
+               byte *buffer, *buffer2; //size unknown at compile time
 };
 
 
 
-WritePimpl::WritePimpl(std::ostream& out, int xsize, int ysize, const string& 
t, const string& comm)
+WritePimpl::WritePimpl(std::ostream& out, int xsize, int ysize, const string& 
t)
 :o(out)
 {
        xs = xsize;
        ys = ysize;
        type = t;
        row=0;
+       pred_mode = PRED_2D_OPTIMAL;
+//     pred_mode = PRED_HORIZONTAL;
        
        if(type == "unsigned char")
-               m_channels = 1;
+               bypp = pred_len = 1;
        else if(type == "CVD::Rgb<unsigned char>")
-               m_channels = 3;
+               bypp = pred_len = 3;
        else if(type == "CVD::Rgba<unsigned char>")
-               m_channels = 4;
-       else
+               bypp = pred_len = 4;
+       else if((type == "bayer_bggr")||(type == "bayer_rggb"))  {
+               bypp = 1; pred_len = 2;
+               if (pred_mode==PRED_2D_OPTIMAL) pred_mode = PRED_2D_BAYER_2;
+       } else if((type == "bayer_grbg")||(type == "bayer_gbrg"))  {
+               bypp = 1; pred_len = 2;
+               if (pred_mode==PRED_2D_OPTIMAL) pred_mode = PRED_2D_BAYER_1;
+       } else
                throw Exceptions::Image_IO::UnsupportedImageSubType("CVDimage", 
type);
 
-       diff.resize(ImageRef(xs*m_channels,ys));
+       diff.resize(ImageRef(xs*bypp,ys));
+       buffer = new byte[xs*bypp];
+       if ((pred_mode==PRED_2D_BAYER_1)||(pred_mode==PRED_2D_BAYER_2))
+               buffer2 = new byte[xs*bypp];
+       else
+               buffer2 = NULL;
 }
 
 void WritePimpl::write_raw_pixel_lines(const unsigned char* data, unsigned 
long nlines)
 {
        if(nlines + row > (unsigned long) ys)
                throw CVD::Exceptions::Image_IO::InternalLibraryError("CVD", 
"Write past end of image.");
+       if (nlines==0) return;
        
-       for(unsigned int i=0; i < nlines; i++)  
-       {
-               line_diff(data, xs*m_channels, diff[row], m_channels);
-               data += xs;
+       switch (pred_mode) {
+       case PRED_HORIZONTAL:
+               for (unsigned int i=0; i < nlines; i++) {
+                       pred_horizontal_diff(data, xs*bypp, diff[row], 
pred_len);
+                       data += xs*bypp;
+                       row++;
+               }
+               break;
+       case PRED_2D_OPTIMAL:
+               if (row==0) {
+                       pred_horizontal_diff(data, xs*bypp, diff[row], 
pred_len);
+                       memcpy(buffer, data, xs*bypp);
+                        data += xs*bypp;
+                        row++;
+                       nlines--;
+               }
+               for (unsigned int i=0; i < nlines; i++) {
+                       pred_2doptimal_diff(data, xs*bypp, buffer, diff[row], 
pred_len);
+                       data += xs*bypp;
                row++;
        }
+               break;
+       case PRED_2D_BAYER_1:
+       case PRED_2D_BAYER_2:
+               //first two rows use horizontal prediction
+               while (row<=1) {
+                       pred_horizontal_diff(data, xs*bypp, diff[row], 
pred_len);
+                       memcpy(buffer, data, xs*bypp);
+                       bayer_swap_rows();
+                        data += xs*bypp;
+                        row++;
+                       nlines--;
+                       if (nlines==0) break;
+               }
+
+               // regular lines
+               while (nlines>0) {
+                       pred_2dbayer_diff(data, xs*bypp, buffer, buffer2, 
diff[row], (pred_mode==PRED_2D_BAYER_1));
+                       bayer_swap_rows();
+                       data += xs*bypp;
+                       row++;
+                       nlines--;
+               }
+       }
+       
 }
 
 template<class C>      void WritePimpl::write_raw_pixel_line(const C*d)
@@ -512,9 +822,21 @@
        write_raw_pixel_lines((const unsigned char*)d, 1); 
 }
 
+void WritePimpl::bayer_swap_rows(void)
+{
+       byte *tmp = buffer;
+       buffer = buffer2;
+       buffer2 = tmp;
+       if (pred_mode==PRED_2D_BAYER_1) pred_mode=PRED_2D_BAYER_2;
+       else if (pred_mode==PRED_2D_BAYER_2) pred_mode=PRED_2D_BAYER_1;
+}
+
 void WritePimpl::write_header(std::ostream& os)
 {
-       os << "CVD\n" << type << "\n" << xs << " " << ys << "\n";
+       os << "CVD\n" << type << "\n" << xs << " " << ys;
+       if (pred_mode==PRED_2D_BAYER_2) pred_mode = PRED_2D_BAYER_1;
+       if (pred_mode!=PRED_HORIZONTAL) os << " pred=" << (int)pred_mode;
+       os << "\n";
 }
 
 void WritePimpl::write_hist(std::ostream& os, const array<int, 256>& h)
@@ -547,6 +869,8 @@
 
 WritePimpl::~WritePimpl()
 {
+       delete[] buffer;
+       if (buffer2!=NULL) delete[] buffer2;
        write_header(o);
 
        array<int, 256> h;
@@ -575,6 +899,26 @@
        t->write_raw_pixel_line(data);
 }
 
+void writer::write_raw_pixel_line(const bayer_bggr* data)
+{
+       t->write_raw_pixel_line(data);
+}
+
+void writer::write_raw_pixel_line(const bayer_rggb* data)
+{
+       t->write_raw_pixel_line(data);
+}
+
+void writer::write_raw_pixel_line(const bayer_grbg* data)
+{
+       t->write_raw_pixel_line(data);
+}
+
+void writer::write_raw_pixel_line(const bayer_gbrg* data)
+{
+       t->write_raw_pixel_line(data);
+}
+
 void writer::write_raw_pixel_line(const Rgb<byte>* data)
 {
        t->write_raw_pixel_line(data);

Index: test/test_images.cxx
===================================================================
RCS file: /sources/libcvd/libcvd/test/test_images.cxx,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -b -r1.16 -r1.17
--- test/test_images.cxx        4 Jun 2009 17:07:50 -0000       1.16
+++ test/test_images.cxx        18 Feb 2010 13:30:10 -0000      1.17
@@ -58,6 +58,40 @@
        }
 };
 
+template<> struct randpix<bayer_bggr>
+{
+       static double r()
+       {
+               return rand() % 256;
+       }
+};
+template<> struct randpix<bayer_rggb>
+{
+       static double r()
+       {
+               return rand() % 256;
+       }
+};
+
+template<> struct randpix<bayer_grbg>
+{
+       static double r()
+       {
+               return rand() % 256;
+       }
+};
+
+template<> struct randpix<bayer_gbrg>
+{
+       static double r()
+       {
+               return rand() % 256;
+       }
+};
+
+
+
+
 
 template<> struct randpix<double>
 {
@@ -364,6 +398,17 @@
 
                                       Head> > > > > > > > > > > > > 
>::exec(ImageType::TIFF);
        #endif
+       cerr << "Testing CVD (type " << ImageType::CVD << ")\n";
+       randtest<
+                       TypeList<byte,
+                       TypeList<bayer_bggr,
+                       TypeList<bayer_rggb,
+                       TypeList<bayer_grbg,
+                       TypeList<bayer_gbrg,
+                       TypeList<Rgb<byte>,
+                       TypeList<Rgba<byte>,
+                       Head> > > > > > > >::exec(ImageType::CVD);
+
 
        exit(0);
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]