先看几张效果图吧
效果图:
可以直接测试的代码:
头文件:
// Saliency.h:interface for the Saliency class.
//
//////////////////////////////////////////////////////////////////////
//===========================================================================
// Copyright (c) 2009 Radhakrishna Achanta[EPFL]
//===========================================================================
#if!defined(_SALIENCY_H_INCLUDED_)
#define _SALIENCY_H_INCLUDED_
#include<vector>
#include <cfloat>
using namespace std;
class Saliency
{
public:
Saliency();
virtual ~Saliency();
public:
voidGetSaliencyMap(
constvector<unsignedint>& inputimg,//INPUT:ARGB buffer in row-major order
constint& width,
constint& height,
vector<double>& salmap,//OUTPUT:Floating point buffer in row-major order
constbool& normalizeflag= true);//false if normalization is not needed
private:
void RGB2LAB(
constvector<unsignedint>& ubuff,
vector<double>& lvec,
vector<double>& avec,
vector<double>& bvec);
voidGaussianSmooth(
constvector<double>& inputImg,
constint& width,
constint& height,
constvector<double>& kernel,
vector<double>& smoothImg);
//==============================================================================
/// Normalize
//==============================================================================
void Normalize(
constvector<double>& input,
constint& width,
constint& height,
vector<double>& output,
constint& normrange= 255)
{
double maxval(0);
double minval(DBL_MAX);
{int i(0);
for( int y = 0; y< height; y++ )
{
for( int x =0; x < width; x++ )
{
if(maxval < input[i] ) maxval = input[i];
if(minval > input[i] ) minval = input[i];
i++;
}
}}
double range =maxval-minval;
if( 0 == range ) range =1;
int i(0);
output.clear();
output.resize(width*height);
for( int y = 0; y< height; y++ )
{
for( int x =0; x < width; x++ )
{
output[i]= ((normrange*(input[i]-minval))/range);
i++;
}
}
}
};
#endif //!defined(_SALIENCY_H_INCLUDED_)
cpp:
// Saliency.cpp: implementation of theSaliency class.
//
//////////////////////////////////////////////////////////////////////
//===========================================================================
// Copyright (c) 2009 Radhakrishna Achanta[EPFL]
//===========================================================================
#include "Saliency.h"
#include <cmath>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Saliency::Saliency()
{
}
Saliency::~Saliency()
{
}
//===========================================================================
/// RGB2LAB
//===========================================================================
void Saliency::RGB2LAB(
const vector<unsignedint>& ubuff,
vector<double>& lvec,
vector<double>& avec,
vector<double>& bvec)
{
int sz = int(ubuff.size());
lvec.resize(sz);
avec.resize(sz);
bvec.resize(sz);
for( int j = 0; j< sz; j++ )
{
int r = (ubuff[j]>> 16) & 0xFF;
int g = (ubuff[j]>> 8)& 0xFF;
int b =(ubuff[j] ) & 0xFF;
double xval = 0.412453 * r +0.357580 * g + 0.180423 * b;
double yval = 0.212671 * r +0.715160 * g + 0.072169 * b;
double zVal = 0.019334 * r +0.119193 * g + 0.950227 * b;
xval /= (255.0 *0.950456);
yval /= 255.0;
zVal /= (255.0 * 1.088754);
double fX, fY, fZ;
double lval, aval, bval;
if(yval > 0.008856)
{
fY =pow(yval, 1.0 / 3.0);
lval = 116.0* fY - 16.0;
}
else
{
fY = 7.787 *yval + 16.0 / 116.0;
lval = 903.3* yval;
}
if(xval > 0.008856)
fX =pow(xval, 1.0 / 3.0);
else
fX = 7.787 *xval + 16.0 / 116.0;
if(zVal > 0.008856)
fZ =pow(zVal, 1.0 / 3.0);
else
fZ = 7.787 *zVal + 16.0 / 116.0;
aval = 500.0 * (fX -fY)+128.0;
bval = 200.0 * (fY -fZ)+128.0;
lvec[j] = lval;
avec[j] = aval;
bvec[j] = bval;
}
}
//==============================================================================
/// GaussianSmooth
///
/// Blur an image with a separable binomial kernelpassed in.
//==============================================================================
void Saliency::GaussianSmooth(
constvector<double>& inputImg,
constint& width,
constint& height,
constvector<double>& kernel,
vector<double>& smoothImg)
{
int center = int(kernel.size())/2;
int sz =width*height;
smoothImg.clear();
smoothImg.resize(sz);
vector<double>tempim(sz);
int rows = height;
int cols = width;
//--------------------------------------------------------------------------
// Blur in the xdirection.
//---------------------------------------------------------------------------
{int index(0);
for( int r = 0; r < rows; r++)
{
for( int c = 0; c< cols; c++ )
{
doublekernelsum(0);
doublesum(0);
for( int cc =(-center); cc <= center; cc++ )
{
if(((c+cc)>= 0) && ((c+cc)< cols))
{
sum+= inputImg[r*cols+(c+cc)] * kernel[center+cc];
kernelsum+= kernel[center+cc];
}
}
tempim[index]= sum/kernelsum;
index++;
}
}}
//--------------------------------------------------------------------------
// Blur in the y direction.
//---------------------------------------------------------------------------
{int index = 0;
for( int r = 0; r < rows; r++)
{
for( int c = 0; c< cols; c++ )
{
doublekernelsum(0);
doublesum(0);
for( int rr =(-center); rr <= center; rr++ )
{
if(((r+rr)>= 0) && ((r+rr)< rows))
{
sum += tempim[(r+rr)*cols+c] * kernel[center+rr];
kernelsum += kernel[center+rr];
}
}
smoothImg[index]= sum/kernelsum;
index++;
}
}}
}
//===========================================================================
/// GetSaliencyMap
///
/// Outputs a saliency map with a value assigned per pixel. Thevalues are
/// normalized in the interval [0,255] if normflag is set true(default value).
//===========================================================================
void Saliency::GetSaliencyMap(
const vector<unsignedint>& inputimg,
constint& width,
constint& height,
vector<double>& salmap,
constbool& normflag)
{
int sz = width*height;
salmap.clear();
salmap.resize(sz);
vector<double>lvec(0), avec(0), bvec(0);
RGB2LAB(inputimg, lvec, avec, bvec);
//--------------------------
// Obtain Lab average values
//--------------------------
double avgl(0), avga(0), avgb(0);
{for( int i = 0; i < sz; i++)
{
avgl += lvec[i];
avga += avec[i];
avgb += bvec[i];
}}
avgl /= sz;
avga /= sz;
avgb /= sz;
vector<double>slvec(0), savec(0), sbvec(0);
//----------------------------------------------------
// The kernel can be [1 2 1] or [1 4 6 4 1] asneeded.
// The code below show usage of [1 2 1]kernel.
//----------------------------------------------------
vector<double>kernel(0);
kernel.push_back(1.0);
kernel.push_back(2.0);
kernel.push_back(1.0);
GaussianSmooth(lvec,width, height, kernel, slvec);
GaussianSmooth(avec, width, height, kernel,savec);
GaussianSmooth(bvec, width, height, kernel,sbvec);
{for( int i = 0; i< sz; i++ )
{
salmap[i] =(slvec[i]-avgl)*(slvec[i]-avgl) +
(savec[i]-avga)*(savec[i]-avga)+
(sbvec[i]-avgb)*(sbvec[i]-avgb);
}}
if( true == normflag)
{
vector<double>normalized(0);
Normalize(salmap, width,height, normalized);
swap(salmap, normalized);
}
}
关于代码的使用说明:
This file explains the usage ofSaliency.h and Saliency.cpp files. The former contains thedeclaration of the Saliency class and its member functions and thelater contains the respective definitions.
Sample usage:
#include "Saliency.h"
void main()
{
// Assume we already have an unsigned integerbuffer inputImg of
// inputWidth and inputHeight (in row-majororder).
// Each unsigned integer has 32 bits and containspixel data in ARGB
// format. I.e. From left to right, the first 8bits contain alpha
// channel value and are not used in our case.The next 8 bits
// contain R channel value; the next 8 bitscontain G channel value;
// the last 8 bits contain the B channelvalue.
//
// Now create a Saliency object and call theGetSaliencyMap function on it.
Saliency sal;
vector<double>salmap(0);
sal.GetSaliencyMap(inputImg, inputWidth,inputHeight, salmap);
// salmap is afloating point output (in row major order)
}
我自己写的测试主程序:
可以指定一个文件夹,程序保存该文件夹下所有jpg文件的处理结果
#include "Saliency.h"
#include<cv.h>
#include <cxcore.h>
#include <highgui.h>
#include "windows.h"
#include<iostream>
#include <cassert>
using namespace std;
int main(int argc,char** argv)
{
WIN32_FIND_DATAA FileData;
HANDLE hFind;
hFind =FindFirstFileA((LPCSTR)"Imgs/*.jpg",&FileData);
if (hFind == INVALID_HANDLE_VALUE) {
printf ("Invalid File Handle.GetLastError reports %d/n",
GetLastError());
return (0);
}
Saliency sal;
vector<double>salmap(0);
while (FindNextFileA(hFind,&FileData)) {
cout<<FileData.cFileName<<endl;
string name("Imgs/");
name.append(FileData.cFileName);
IplImage*img=cvLoadImage(name.c_str());
if (!img) {
cout<<"failedto load image"<<endl;
break;
}
assert(img->nChannels==3);
vector<unsignedint >imgInput;
vector<double>imgSal;
//IplImage to vector
for (inth=0;h<img->height;h++) {
unsignedchar*p=(unsignedchar*)img->imageData+h*img->widthStep;
for (intw=0;w<img->width;w++) {
unsignedint t=0;
t+=*p++;
t<<=8;
t+=*p++;
t<<=8;
t+=*p++;
imgInput.push_back(t);
}
}
sal.GetSaliencyMap(imgInput,img->width, img->height,imgSal);
//vector to IplImage
int index=0;
IplImage*imgout=cvCreateImage(cvGetSize(img),IPL_DEPTH_64F ,1);
for (inth=0;h<imgout->height;h++) {
double*p=(double*)(imgout->imageData+h*imgout->widthStep);
for (intw=0;w<imgout->width;w++) {
*p++=imgSal[index++];
}
}
name.append(".saliency.jpg");
cvSaveImage(name.c_str(),imgout);
cvReleaseImage(&img);
cvReleaseImage(&imgout);
}
FindClose(&hFind);
return 0;
}
该代码的主页:http://ivrg.epfl.ch/supplementary_material/RK_ICIP2010/index.html
清华的最新研究:http://cg.cs.tsinghua.edu.cn/people/~cmm/saliency/