#include "HC.h"
using namespace std;
template<typename T> inline T sqr(T x) { return x * x; }
typedef vector<string> vecS;
typedef vector<int> vecI;
typedef vector<float> vecF;
typedef vector<double> vecD;
typedef pair<double, int> CostIdx;
typedef pair<float, int> CostfIdx;
template<class T> inline T vecDist3(const Vec<T, 3> &v1, const Vec<T, 3> &v2) { return sqrt(sqr(v1[0] - v2[0]) + sqr(v1[1] - v2[1]) + sqr(v1[2] - v2[2])); }
template<class T> inline T vecSqrDist3(const Vec<T, 3> &v1, const Vec<T, 3> &v2) { return sqr(v1[0] - v2[0]) + sqr(v1[1] - v2[1]) + sqr(v1[2] - v2[2]); }
/*********************************
函数声明:计算显著性图函数
参数:NONE
注释:NONE
测试:
Mat srcImage, dstImage;
srcImage = imread("0.jpg");//读取灰度图
imshow("原图",srcImage);
HC hc;
hc.calculateSaliencyMap(&srcImage, &dstImage);
imshow("HC算法显著图", dstImage);
waitKey();
return 0;
**********************************/
void HC::calculateSaliencyMap(Mat *src, Mat * dst)
{
Mat img3f;
(*src).convertTo(img3f, CV_32FC3, 1.0 / 255); //将原图像素值缩放1/255
Mat idx1i, binColor3f, colorNums1i, weight1f, _colorSal;
Quantize(img3f, idx1i, binColor3f, colorNums1i);//颜色量化
cvtColor(binColor3f, binColor3f, COLOR_BGR2Lab);
normalize(colorNums1i, weight1f, 1, 0, NORM_L1, CV_32F);
GetHC(binColor3f, weight1f, _colorSal);
float* colorSal = (float*)(_colorSal.data);
Mat salHC1f(img3f.size(), CV_32F);
for (int r = 0; r < img3f.rows; r++)
{
float* salV = salHC1f.ptr<float>(r);
int* _idx = idx1i.ptr<int>(r);
for (int c = 0; c < img3f.cols; c++)
salV[c] = colorSal[_idx[c]];
}
GaussianBlur(salHC1f, salHC1f, Size(3, 3), 0);
normalize(salHC1f, *dst, 0, 1, NORM_MINMAX);
}
/*********************************
函数声明:量化颜色数量函数
参数:
Mat& img3f:
double ratio:找出像素数目覆盖图像不小于95%的高频颜色,以及其他的不高于5%的颜色种类
注释:NONE
测试:NONE
**********************************/
int HC::Quantize(const Mat& img3f, Mat &idx1i, Mat &_color3f, Mat &_colorNum, double ratio )
{
static const int clrNums[3] = { 12, 12, 12 };
static const float clrTmp[3] = { clrNums[0] - 0.0001f, clrNums[1] - 0.0001f, clrNums[2] - 0.0001f };
static const int w[3] = { clrNums[1] * clrNums[2], clrNums[2], 1 };
CV_Assert(img3f.data != NULL);
idx1i = Mat::zeros(img3f.size(), CV_32S);
int rows = img3f.rows, cols = img3f.cols;
if (img3f.isContinuous() && idx1i.isContinuous())
//这里的continue的意思是在内存上continue,正常情况下,头一行的末尾在内存里和下一行的开头是相连的,
//但是有时候我们做了一些操作,选取了Mat 的一部分,例如选了一个ROI 这时候就不满足上面说的相连了。那么这时候continuous就被判定为假。
{
cols *= rows;
rows = 1;
}
// 建立调色板
std::map<int, int> pallet; //map键值对
for (int y = 0; y < rows; y++)//遍历整个图像
{
const float* imgData = img3f.ptr<float>(y);
int* idx = idx1i.ptr<int>(y);
for (int x = 0; x < cols; x++, imgData += 3)
{
idx[x] = (int)(imgData[0] * clrTmp[0])*w[0] + (int)(imgData[1] * clrTmp[1])*w[1] + (int)(imgData[2] * clrTmp[2]);//三个通道像素
pallet[idx[x]] ++;
}
}
// Fine significant colors
int maxNum = 0;//找出像素数目覆盖图像不小于95%的高频颜色,以及其他的不高于5%的颜色种类,假设高频颜色共有maxnum种
{
int count = 0;
vector<pair<int, int>> num; // (num, color) pairs in num
num.reserve(pallet.size());
for (map<int, int>::iterator it = pallet.begin(); it != pallet.end(); it++)
num.push_back(pair<int, int>(it->second, it->first)); // (color, num) pairs in pallet
sort(num.begin(), num.end(), std::greater< pair<int, int> >());
maxNum = (int)num.size();
int maxDropNum = cvRound(rows * cols * (1 - ratio));
for (int crnt = num[maxNum - 1].first; crnt < maxDropNum && maxNum > 1; maxNum--)
crnt += num[maxNum - 2].first;
maxNum = min(maxNum, 256); // To avoid very rarely case
if (maxNum < 10)
maxNum = min((int)pallet.size(), 100);
pallet.clear();
for (int i = 0; i < maxNum; i++)
pallet[num[i].second] = i;
vector<Vec3i> color3i(num.size());
for (unsigned int i = 0; i < num.size(); i++)
{
color3i[i][0] = num[i].second / w[0];
color3i[i][1] = num[i].second % w[0] / w[1];
color3i[i][2] = num[i].second % w[1];
}
for (unsigned int i = maxNum; i < num.size(); i++)
{
int simIdx = 0, simVal = INT_MAX;
for (int j = 0; j < maxNum; j++)
{
int d_ij = vecSqrDist3(color3i[i], color3i[j]);
if (d_ij < simVal)
simVal = d_ij, simIdx = j;
}
pallet[num[i].second] = pallet[num[simIdx].second];
}
}
_color3f = Mat::zeros(1, maxNum, CV_32FC3);
_colorNum = Mat::zeros(_color3f.size(), CV_32S);
Vec3f* color = (Vec3f*)(_color3f.data);
int* colorNum = (int*)(_colorNum.data);
for (int y = 0; y < rows; y++)
{
const Vec3f* imgData = img3f.ptr<Vec3f>(y);
int* idx = idx1i.ptr<int>(y);
for (int x = 0; x < cols; x++)
{
idx[x] = pallet[idx[x]];
color[idx[x]] += imgData[x];
colorNum[idx[x]] ++;
}
}
for (int i = 0; i < _color3f.cols; i++)
color[i] = color[i] / colorNum[i];
return _color3f.cols;
}
/*********************************
函数声明:计算显著图
参数:NONE
注释:NONE
测试:NONE
**********************************/
void HC::GetHC(const Mat &binColor3f, const Mat &weight1f, Mat &_colorSal)
{
int binN = binColor3f.cols;
_colorSal = Mat::zeros(1, binN, CV_32F);
float* colorSal = (float*)(_colorSal.data);
vector<vector< pair<double, int>>> similar(binN); // Similar color: how similar and their index
Vec3f* color = (Vec3f*)(binColor3f.data);
float *w = (float*)(weight1f.data);
for (int i = 0; i < binN; i++)
{
vector< pair<double, int>> &similari = similar[i];
similari.push_back(make_pair(0.f, i));
for (int j = 0; j < binN; j++)
{
if (i == j)
continue;
float dij = vecDist3<float>(color[i], color[j]);
similari.push_back(make_pair(dij, j));
colorSal[i] += w[j] * dij;
}
sort(similari.begin(), similari.end());
}
SmoothSaliency(binColor3f, _colorSal, 4.0f, similar);
}
/*********************************
函数声明:平滑处理函数
参数:NONE
注释:NONE
测试:NONE
**********************************/
void HC::SmoothSaliency(const Mat &binColor3f, Mat &sal1d, float delta, const vector<vector< pair<double, int>>> &similar)
{
if (sal1d.cols < 2)
return;
CV_Assert(binColor3f.size() == sal1d.size() && sal1d.rows == 1);
int binN = binColor3f.cols;
Vec3f* color = (Vec3f*)(binColor3f.data);
Mat tmpSal;
sal1d.copyTo(tmpSal);
float *sal = (float*)(tmpSal.data);
float *nSal = (float*)(sal1d.data);
//* Distance based smooth
int n = max(cvRound(binN / delta), 2);
vecF dist(n, 0), val(n);
for (int i = 0; i < binN; i++)
{
const vector< pair<double, int>> &similari = similar[i];
float totalDist = 0;
val[0] = sal[i];
for (int j = 1; j < n; j++)
{
int ithIdx = similari[j].second;
dist[j] = similari[j].first;
val[j] = sal[ithIdx];
totalDist += dist[j];
}
float valCrnt = 0;
for (int j = 0; j < n; j++)
valCrnt += val[j] * (totalDist - dist[j]);
nSal[i] = valCrnt / ((n - 1) * totalDist);
}
}
- 1
- 2
- 3
前往页