First look at a few
:
Code that can be directly tested:
Header file:
// Saliency. h: interface for the saliency class. <br/> ////////////////////////////// //////////////////////////////////////// <br/> // ======================================== ========================================================== = <br/> // copyright (c) 2009 radhakrishna achanta [EPFL] <br/> // ======================== ========================================================== ========</P> <p> # If! Defined (_ saliency_h_included _) <br/> # DEFINE _ saliency_h_included _ </P> <p> # include <vector> <br/> # include <cfloat> <br/> using namespace STD; </P> <p> class saliency <br/>{< br/> Public: <br/> saliency (); <br/> virtual ~ Saliency (); </P> <p> Public: </P> <p> void getsaliencymap (<br/> const vector <unsigned int> & inputimg, // input: argb buffer in row-Major Order <br/> const Int & width, <br/> const Int & height, <br/> vector <double> & salmap, // output: floating Point buffer in row-Major Order <br/> const bool & normalizeflag = true); // false if normalization is not needed </P> <p> PRIVATE: </P> <p> void rgb2lab (<br/> const vector <unsigned int> & Ubuff, <br/> vector <double> & lvec, <br/> vector <double> & avec, <br/> vector <double> & bvec ); </P> <p> void gaussiansmooth (<br/> const vector <double> & inputimg, <br/> const Int & width, <br/> const Int & height, <br/> const vector <double> & kernel, <br/> vector <double> & smoothimg ); </P> <p> // ================================== ========================================================== ========< br/> /// normalize <br/> //======================== ========== ========================================================== ============< Br/> void normalize (<br/> const vector <double> & input, <br/> const Int & width, <br/> const Int & height, <br/> vector <double> & output, <br/> const Int & normrange = 255) <br/>{< br/> double maxval (0); <br/> double minval (dbl_max); <br/> {int I (0 ); <br/> for (INT y = 0; y <peight; y ++) <br/>{< br/> for (INT x = 0; x <width; X ++) <br/>{< br/> If (maxval <input [I]) maxval = input [I]; <br/> If (minval> input [I]) minval = input [I]; <br/> I ++; <br/>}< br/> double range = maxval-minval; <br/> If (0 = range) range = 1; <br/> int I (0); <br/> output. clear (); <br/> output. resize (width * Height); <br/> for (INT y = 0; y <peight; y ++) <br/> {<br/> for (INT x = 0; x <width; X ++) <br/>{< br/> output [I] = (normrange * (input [I]-minval)/range); <br/> I ++; <br/>}< B R/>}< br/>}</P> <p >}; </P> <p> # endif //! Defined (_ saliency_h_included _) <br/>
CPP:
// Saliency. CPP: Implementation of the saliency class. <br/> ////////////////////////////// //////////////////////////////////////// <br/> // ======================================== ========================================================== = <br/> // copyright (c) 2009 radhakrishna achanta [EPFL] <br/> // ======================== ========================================================== ========</P> <p> # include "saliency. H "<br/> # include <Cmath> </P> <p> ////////////////////////////// //////////////////////////////////////// <br/> // construction/destruction <br/> /////////////////////////// //////////////////////////////////////// /// </P> <p> Saliency:: saliency () <br/>{</P> <p >}</P> <p> Saliency ::~ Saliency () <br/>{</P> <p >}</P> <p> // ==================== ========================================================== ==========================< br/> // rgb2lab <br/> // ========== ========================================================== ========================================< br/> void Saliency:: rgb2lab (<br/> const vector <unsigned int> & ubuff, <br/> vector <double> & lvec, <br/> vector <double> & avec, <br/> vector <double> & bvec) <br/>{< br/> int SZ = int (ubuff. size (); <br/> lvec. resize (sz); <br/> avec. resize (sz); <br/> bvec. resize (sz); </P> <p> for (Int J = 0; j <SZ; j ++) <br/>{< br/> int r = (ubuff [J]> 16) & 0xff; <br/> int G = (ubuff [J]> 8) & 0xff; <br/> int B = (ubuff [J]) & 0xff; </P> <p> double xval = 0.412453 * r + 0.357580 * g + 0.180423 * B; <br/> double yval = 0.212671 * r + 0.715160 * g + 0.072169 * B; <br/> double zval = 0.019334 * r + 0.119193 * g + 0.950227 * B; </P> <p> xval/= (255.0*0.950456); <br/> yval/= 255.0; <br/> zval/= (255.0*1.088754 ); </P> <p> double FX, fy, Fz; <br/> double lval, Aval, bval; </P> <p> If (yval> 0.008856) <br/>{< br/> FY = POW (yval, 1.0/3.0); <br/> lval = 116.0 * FY-16.0; <br/>}< br/> else <br/>{< br/> FY = 7.787 * yval + 16.0/116.0; <br/> lval = 903.3 * yval; <br/>}</P> <p> If (xval> 0.008856) <br/> FX = POW (xval, 1.0/3.0 ); <br/> else <br/> FX = 7.787 * xval + 16.0/116.0; </P> <p> If (zval> 0.008856) <br/> FZ = POW (zval, 1.0/3.0); <br/> else <br/> FZ = 7.787 * zval + 16.0/116.0; </P> <p> Aval = 500.0 * (FX-fy) + 128.0; <br/> bval = 200.0 * (FY-Fz) + 128.0; </P> <p> lvec [J] = lval; <br/> avec [J] = Aval; <br/> bvec [J] = bval; <br/>}</P> <p> // ===================== ========================================================== ========================< br/> // gaussiansmooth <br/> /// <br/> // blur an image with a separable binomial kernel passed in. <br/> // ======================================== ========================================================== ====< br/> void Saliency:: gaussiansmooth (<br/> const vector <double> & inputimg, <br/> const Int & width, <br/> const Int & height, <br/> const vector <double> & kernel, <br/> vector <double> & smoothimg) <br/>{< br/> int center = int (kernel. size ()/2; </P> <p> int SZ = width * height; <br/> smoothimg. clear (); <br/> smoothimg. resize (sz); <br/> vector <double> tempim (sz); <br/> int rows = height; <br/> int Cols = width; <br/> // ---------------------------------------------------------------------------- <br/> // blur in the X ction. <br/> // else <br/> {int index (0); <br/> for (INT r = 0; r <rows; r ++) <br/>{< br/> for (int c = 0; C <Cols; C ++) <br/>{< br/> double kernelsum (0 ); <br/> double sum (0); <br/> for (INT cc = (-center); CC <= center; CC ++) <br/> {<br/> If (C + CC)> = 0) & (C + CC) <Cols )) <br/> {<br/> sum + = inputimg [R * Cols + (C + CC)] * kernel [center + CC]; <br/> kernelsum + = kernel [center + CC]; <br/>}< br/> tempim [Index] = sum/kernelsum; <br/> index ++; <br/>}</P> <p> // ---------------------------------------------------------------------- <br/> // blur in the Y direction. <br/> // else <br/> {int Index = 0; <br/> for (INT r = 0; r <rows; r ++) <br/>{< br/> for (int c = 0; C <Cols; C ++) <br/>{< br/> double kernelsum (0 ); <br/> double sum (0); <br/> for (int rr = (-center); RR <= center; RR ++) <br/> {<br/> If (R + RR)> = 0) & (R + RR) <rows )) <br/> {<br/> sum + = tempim [(R + RR) * Cols + C] * kernel [center + RR]; <br/> kernelsum + = kernel [center + RR]; <br/>}< br/> smoothimg [Index] = sum/kernelsum; <br/> index ++; <br/>}</P> <p> // ================ ========================================================== ================================< br/> // getsaliencymap <br/> /// <br/>/ // outputs a saliency map with a value assigned per pixel. the values are <br/> // normalized in the interval [0,255] If normflag is set true (default value ). <br/> // ======================================== ========================================================== = <br/> void Saliency:: getsaliencymap (<br/> const vector <unsigned int> & inputimg, <br/> const Int & width, <br/> const Int & height, <br/> vector <double> & salmap, <br/> const bool & normflag) <br/>{< br/> int SZ = width * height; <br/> salmap. clear (); <br/> salmap. resize (sz); </P> <p> vector <double> lvec (0), avec (0), bvec (0); <br/> rgb2lab (inputimg, lvec, avec, bvec ); <br/> // ------------------------ <br/> // obtain lab average values <br/> // ------------------------ <br/> double avgl (0), avga (0 ), avgb (0); <br/> {for (INT I = 0; I <SZ; I ++) <br/>{< br/> avgl + = lvec [I]; <br/> avga + = avec [I]; <br/> avgb + = bvec [I]; <br/>}< br/> avgl/= SZ; <br/> avga/= SZ; <br/> avgb/= SZ; </P> <p> vector <double> slvec (0), savec (0), sbvec (0 ); </P> <p> // ---------------------------------------------------- <br/> // The kernel can be [1 2 1] or [1 4 6 4 1] as needed. <br/> // The code below show usage of [1 2 1] kernel. <br/> // ---------------------------------------------------- <br/> vector <double> kernel (0); <br/> kernel. push_back (1.0); <br/> kernel. push_back (2.0); <br/> kernel. push_back (1.0); </P> <p> gaussiansmooth (lvec, width, height, kernel, slvec); <br/> gaussiansmooth (AVEC, width, height, kernel, savec); <br/> gaussiansmooth (bvec, width, height, kernel, sbvec); </P> <p> {for (INT I = 0; I <SZ; I ++) <br/>{< br/> salmap [I] = (slvec [I]-avgl) * (slvec [I]-avgl) + <br/> (savec [I]-avga) * (savec [I]-avga) + <br/> (sbvec [I]-avgb) * (sbvec [I]-avgb); <br/>}}</P> <p> If (true = normflag) <br/>{< br/> vector <double> normalized (0); <br/> normalize (salmap, width, height, normalized ); <br/> swap (salmap, normalized); <br/>}< br/>}
Code instructions:
This file explains the usage of saliency. H and saliency. CPP files. the former contains the declaration of the saliency class and its member functions and the later contains the respective definitions. </P> <p> sample usage: </P> <p> # include "saliency. H "</P> <p> void main () <br/> {<br/> // assume we already have an unsigned integer buffer inputimg of <br/> // inputwidth and inputheight (in row-major order ). <br/> // each unsigned integer has 32 bits and contains pixel data in argb <br/> // format. i. e. from left to right, the first 8 bits contain Alpha <br/> // channel value and are not used in our case. the next 8 bits <br/> // contain R channel value; the next 8 bits contain g channel value; <br/> // the last 8 bits contain the B channel value. <br/> // now create a saliency object and call the getsaliencymap function on it. </P> <p> saliency Sal; <br/> vector <double> salmap (0); <br/> Sal. getsaliencymap (inputimg, inputwidth, inputheight, salmap); </P> <p> // salmap is a floating point output (in row Major Order) <br/>}
My own main test program:
You can specify a folder to save the processing results of all JPG files in this folder.
# Include "saliency. H "</P> <p> # include <cv. h> <br/> # include <cxcore. h> <br/> # include <pighgui. h> </P> <p> # include "windows. H "</P> <p> # include <iostream> <br/> # include <cassert> <br/> using namespace STD; </P> <p> int main (INT argc, char ** argv) <br/>{< br/> win32_find_dataa filedata; <br/> handle hfind; </P> <p> hfind = findfirstfilea (lpcstr) "IMGs /*. jpg ", & filedata); <br/> If (hfind = invalid_handle_value) {<br/> Printf ("invalid file handle. getlasterror reports % d/N ", <br/> getlasterror (); <br/> return (0 ); <br/>}</P> <p> saliency Sal; <br/> vector <double> salmap (0); <br/> while (findnextfilea (hfind, & filedata) {<br/> cout <filedata. cfilename <Endl; <br/> string name ("IMGs/"); <br/> name. append (filedata. cfilename); <br/> iplimage * IMG = cvloadimage (name. c_str (); <br/> If (! IMG) {<br/> cout <"failed to load image" <Endl; <br/> break; <br/>}< br/> assert (IMG-> nchannels = 3); </P> <p> vector <unsigned int> imginput; <br/> vector <double> imgsal; <br/> // iplimage to vector <br/> for (INT h = 0; H height; h ++) {<br/> unsigned char * P = (unsigned char *) IMG-> imagedata + H * IMG-> widthstep; <br/> for (int w = 0; W width; W ++) {<br/> unsigned int T = 0; <br/> T + = * P ++; <br/> T <= 8; <br/> T + = * P ++; <br/> T <= 8; <br/> T + = * P ++; <br/> imginput. push_back (t); <br/>}< br/> Sal. getsaliencymap (imginput, IMG-> width, IMG-> height, imgsal); <br/> // vector to iplimage <br/> int Index = 0; <br/> iplimage * imgout = cvcreateimage (cvgetsize (IMG), ipl_depth_64f, 1); <br/> for (INT h = 0; H height; h ++) {<br/> double * P = (double *) (imgout-> imagedata + H * imgout-> widthstep ); <br/> for (int w = 0; W width; W ++) {<br/> * P ++ = imgsal [index ++]; <br/>}</P> <p> name. append (".saliency.jpg"); </P> <p> cvsaveimage (name. c_str (), imgout); <br/> cvreleaseimage (& IMG); <br/> cvreleaseimage (& imgout ); <br/>}</P> <p> findclose (& hfind); <br/> return 0; <br/>}
Home page of the Code: http://ivrg.epfl.ch/supplementary_material/RK_ICIP2010/index.html
Tsinghua's latest research: http://cg.cs.tsinghua.edu.cn/people /~ CMM/saliency/