imagediff.cpp

00001
00002 /***************************************************************************
00003  *  imagediff.cpp - check images if they are different
00004  *
00005  *  Generated: Tue Jun 06 10:22:49 2006
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <fvutils/statistical/imagediff.h>
00025 #include <fvutils/color/yuv.h>
00026
00027 #include <cstdlib>
00028 
00029 /** @class ImageDiff <fvutils/statistical/imagediff.h>
00030  * Image difference checker.
00031  * @author Tim Niemueller
00032  */
00033 
00034 /** Constructor.
00035  * @param scanline_model scanlinemodel to use, if null all pixels
00036  * are compared.
00037  */
00038 ImageDiff::ImageDiff(ScanlineModel *scanline_model)
00039 {
00040   this->scanline_model = scanline_model;
00041 }
00042
00043 
00044 /** Constructor.
00045  * Use this constructor to compare all pixels.
00046  */
00047 ImageDiff::ImageDiff()
00048 {
00049   scanline_model = NULL;
00050 }
00051
00052 
00053 /** Destructor. */
00054 ImageDiff::~ImageDiff()
00055 {
00056 }
00057
00058 
00059 /** Set first buffer.
00060  * @param yuv422planar_buffer buffer
00061  * @param width image width in pixels
00062  * @param height image height in pixels
00063  */
00064 void
00065 ImageDiff::setBufferA(unsigned char *yuv422planar_buffer,
00066                       unsigned int width, unsigned int height)
00067 {
00068   buffer_a = yuv422planar_buffer;
00069   width_a  = width;
00070   height_a = height;
00071 }
00072
00073 
00074 /** Set second buffer.
00075  * @param yuv422planar_buffer buffer
00076  * @param width image width in pixels
00077  * @param height image height in pixels
00078  */
00079 void
00080 ImageDiff::setBufferB(unsigned char *yuv422planar_buffer,
00081                       unsigned int width, unsigned int height)
00082 {
00083   buffer_b = yuv422planar_buffer;
00084   width_b  = width;
00085   height_b = height;
00086 }
00087
00088 
00089 /** Check if images are different.
00090  * This method will compare the two images. If any pixel marked by
00091  * the scanline or any pixel at all if no scanline model is given
00092  * differ the images are considered to be different. The same applies
00093  * if any buffer is unset or the widths or heights are not the same.
00094  * @return true if images are different, false otherwise
00095  */
00096 bool
00097 ImageDiff::different()
00098 {
00099   if ( (buffer_a == NULL) && (buffer_b == NULL) ) return false;
00100   if ( (buffer_a == NULL) && (buffer_b != NULL) ) return true;
00101   if ( (buffer_a != NULL) && (buffer_b == NULL) ) return true;
00102   if ( (width_a != width_b) || (height_a != height_b) ) return true;
00103
00104   if ( scanline_model != NULL ) {
00105     // use the supplied scanline model
00106
00107     unsigned int x, y;
00108     unsigned char y_a, u_a, v_a, y_b, u_b, v_b;
00109
00110     scanline_model->reset();
00111     while (! scanline_model->finished() ) {
00112       x = (*scanline_model)->x;
00113       y = (*scanline_model)->y;
00114
00115       YUV422_PLANAR_YUV(buffer_a, width_a, height_a, x, y, y_a, u_a, v_a);
00116       YUV422_PLANAR_YUV(buffer_b, width_b, height_b, x, y, y_b, u_b, v_b);
00117
00118       if ( (y_a != y_b) || (u_a != u_b) || (v_a != v_b) ) {
00119         return true;
00120       }
00121     }
00122   } else {
00123     // no scanline model, check every single pixel
00124
00125     unsigned char *ypa = buffer_a;
00126     unsigned char *ypb = buffer_b;
00127
00128     for ( unsigned int i = 0; i < (width_a * height_a); ++i) {
00129       if ( *ypa != *ypb ) {
00130         return true;
00131       }
00132       ++ypa;
00133       ++ypb;
00134     }
00135   }
00136
00137   return false;
00138 }
00139
00140 
00141 /** Number of differing pixels.
00142  * Executes the same routine as different(). But instead of just saying that
00143  * the images are different will tell how many pixels differ.
00144  * @return number of different pixels
00145  */
00146 unsigned int
00147 ImageDiff::numDifferingPixels()
00148 {
00149   if ( (buffer_a == NULL) && (buffer_b == NULL) ) return 0;
00150   if ( (buffer_a == NULL) && (buffer_b != NULL) ) return (width_b * height_b);
00151   if ( (buffer_a != NULL) && (buffer_b == NULL) ) return (width_a * height_a);
00152   if ( (width_a != width_b) || (height_a != height_b) ) {
00153     return abs(width_a - width_b) * abs(height_a - height_b);
00154   }
00155
00156   unsigned int num = 0;
00157   if ( scanline_model != NULL ) {
00158     // use the supplied scanline model
00159
00160     unsigned int x, y;
00161     unsigned char y_a, u_a, v_a, y_b, u_b, v_b;
00162
00163     scanline_model->reset();
00164     while (! scanline_model->finished() ) {
00165       x = (*scanline_model)->x;
00166       y = (*scanline_model)->y;
00167
00168       YUV422_PLANAR_YUV(buffer_a, width_a, height_a, x, y, y_a, u_a, v_a);
00169       YUV422_PLANAR_YUV(buffer_b, width_b, height_b, x, y, y_b, u_b, v_b);
00170
00171       if ( (y_a != y_b) || (u_a != u_b) || (v_a != v_b) ) {
00172         ++num;
00173       }
00174     }
00175   } else {
00176     // no scanline model, check every single pixel
00177
00178     unsigned char *ypa = buffer_a;
00179     unsigned char *ypb = buffer_b;
00180
00181     for ( unsigned int i = 0; i < (width_a * height_a); ++i) {
00182       if ( *ypa++ != *ypb++ ) ++num;
00183     }
00184   }
00185   return num;
00186 }