1.几何中,夹角余弦可用来衡量两个向量方向的差异;机器学习中,借用这一概念来衡量样本向量之间的差异。
2.二维空间中向量A(x1,y1)与向量B(x2,y2)的夹角余弦公式:
3.两个n维样本点a(x11,x12,…,x1n)和b(x21,x22,…,x2n)的夹角余弦为:
即:
夹角余弦取值范围为[-1,1]。余弦越大表示两个向量的夹角越小,余弦越小表示两向量的夹角越大。当两个向量的方向重合时余弦取最大值1,当两个向量的方向完全相反余弦取最小值-1。
参考博客:https://blog.csdn.net/weixin_33743248/article/details/91946456
1,opencv中封装了矩阵运算,可以直接调用
float getSimilarity(const cv::Mat& first,const cv::Mat& second)
{
double dotSum=first.dot(second);//内积
double normFirst=cv::norm(first);//取模
double normSecond=cv::norm(second);
if(normFirst!=0 && normSecond!=0)
{
return dotSum/(normFirst*normSecond);
}
}
2,如果特征向量不是Mat类型,是vector类型
float getMold(const vector<float>& vec)
{ //求向量的模长
int n = vec.size();
float sum = 0.0;
for (int i = 0; i<n; ++i)
sum += vec[i] * vec[i];
return sqrt(sum);
}
float getSimilarity(const vector<float>& lhs, const vector<float>& rhs)
{
int n = lhs.size();
assert(n == rhs.size());
float tmp = 0.0; //内积
for (int i = 0; i<n; ++i)
{
tmp += lhs[i] * rhs[i];
}
return tmp / (getMold(lhs)*getMold(rhs));
}
参考博客:https://blog.csdn.net/qq_17278169/article/details/77093303
3.Matlab计算夹角余弦(Matlab中的pdist(X, ‘cosine’)得到的是1减夹角余弦的值):
X=[1 1;1 2;2 5;1 -4];
d=1-pdist(X,'cosine')
d=
0.9487 0.9191 -0.5145 0.9965 -0.7593 -0.8107
1.利用opencv提取hog特征,然后使用hog特征的特征描述子进行两张图像之间的相似度计算
float* get_hog_feature(cv::Mat img)
{
cv::HOGDescriptor hog = cv::HOGDescriptor(cvSize(20, 20), cvSize(10, 10), cvSize(5, 5), cvSize(5, 5), 9);
cv::resize(img, img, cv::Size(30, 30), (0, 0), (0, 0), cv::INTER_LINEAR);
std::vector<float> descriptors;
// float *descriptors;
hog.compute(img, descriptors, cv::Size(20, 20), cv::Size(0, 0));
float *feature_float = (float*)malloc(descriptors.size() * sizeof(float));
assert(feature_float);
for (int i = 0; i < 128; i++)
{
feature_float[i] = descriptors[i * 2];
}
return feature_float;
}
bool getRectsHogFeature(const cv::Mat& img, DETECTIONS& d)
{
std::vector<cv::Mat> mats;
int feature_dim = 128;
for (DETECTION_ROW& dbox : d)
{
cv::Rect rc = cv::Rect(int(dbox.tlwh(0)), int(dbox.tlwh(1)), int(dbox.tlwh(2)), int(dbox.tlwh(3)));
rc.x = (rc.x >= 0 ? rc.x : 0);
rc.y = (rc.y >= 0 ? rc.y : 0);
rc.width = (rc.x + rc.width <= img.cols ? rc.width : (img.cols - rc.x));
rc.height = (rc.y + rc.height <= img.rows ? rc.height : (img.rows - rc.y));
cv::Mat mattmp = img(rc).clone();
//cv::resize(mattmp, mattmp, cv::Size(64, 128));
float *feature_float = get_hog_feature(mattmp);
for (int i=0;i<feature_dim;i++)
{
dbox.feature[i] = feature_float[i];
}
}
return true;
}
2.提取图像LBP特征描述子进行两张图像之间的相似度计算
bool getRectsLBPFeature(const cv::Mat& img, DETECTIONS& d)
{
std::vector<cv::Mat> mats;
int feature_dim = 128;
for (DETECTION_ROW& dbox : d)
{
cv::Rect rc = cv::Rect(int(dbox.tlwh(0)), int(dbox.tlwh(1)), int(dbox.tlwh(2)), int(dbox.tlwh(3)));
rc.x = (rc.x >= 0 ? rc.x : 0);
rc.y = (rc.y >= 0 ? rc.y : 0);
rc.width = (rc.x + rc.width <= img.cols ? rc.width : (img.cols - rc.x));
rc.height = (rc.y + rc.height <= img.rows ? rc.height : (img.rows - rc.y));
cv::Mat mattmp = img(rc).clone();
//cv::resize(mattmp, mattmp, cv::Size(64, 128));
vector<float> LBPFrature= get_LBP_feature(mattmp);
for (int i = 0; i < feature_dim; i++)
{
dbox.feature[i] = LBPFrature[i];
}
}
return true;
}
vector<float> get_LBP_feature(cv::Mat img)
{
cv::resize(img, img, cv::Size(55, 55));
Mat LBPFeatureImg, GrayImg;
cv::cvtColor(img, GrayImg, CV_BGR2GRAY);
LBPFeatureExtract LBPFeature;
//等价灰度不变LBP(58)特征
LBPFeature.NormalLBPFeature(GrayImg, Size(50, 50), LBPFeatureImg);
float *dataOfFeatureVector = (float *)LBPFeatureImg.data;
vector<float>feature_float;
feature_float.reserve(128);
for (int i = 0; i < 128; i++)
{
feature_float.push_back(dataOfFeatureVector[i * 2]);
}
return feature_float;
}
void LBPFeatureExtract::NormalLBPFeature(const Mat &srcImage, Size cellSize, Mat &featureVector)
{
// 参数检查,内存分配
CV_Assert(srcImage.depth() == CV_8U && srcImage.channels() == 1);
Mat LBPImage;
NormalLBPImage(srcImage, LBPImage);
// 计算cell个数
int widthOfCell = cellSize.width;
int heightOfCell = cellSize.height;
int numberOfCell_X = srcImage.cols / widthOfCell;// X方向cell的个数
int numberOfCell_Y = srcImage.rows / heightOfCell;
// 特征向量的个数
int numberOfDimension = 256 * numberOfCell_X*numberOfCell_Y;
featureVector.create(1, numberOfDimension, CV_32FC1);
featureVector.setTo(Scalar(0));
// 计算LBP特征向量
int stepOfCell = srcImage.cols;
int pixelCount = cellSize.width*cellSize.height;
float *dataOfFeatureVector = (float *)featureVector.data;
vector<float>LBPFeature;
// cell的特征向量在最终特征向量中的起始位置
int index = -256;
for (int y = 0; y <= numberOfCell_Y - 1; ++y)
{
for (int x = 0; x <= numberOfCell_X - 1; ++x)
{
index += 256;
// 计算每个cell的LBP直方图
Mat cell = LBPImage(Rect(x * widthOfCell, y * heightOfCell, widthOfCell, heightOfCell));
uchar *rowOfCell = cell.data;
for (int y_Cell = 0; y_Cell <= cell.rows - 1; ++y_Cell, rowOfCell += stepOfCell)
{
uchar *colOfCell = rowOfCell;
for (int x_Cell = 0; x_Cell <= cell.cols - 1; ++x_Cell, ++colOfCell)
{
++dataOfFeatureVector[index + colOfCell[0]];
}
}
// 一定要归一化!否则分类器计算误差很大
for (int i = 0; i <= 255; ++i)
{
dataOfFeatureVector[index + i] /= pixelCount;
LBPFeature.push_back(dataOfFeatureVector[index + i]);
}
}
}
}
//灰度不变常规LBP(256)
void LBPFeatureExtract::NormalLBPImage(const Mat &srcImage, Mat &LBPImage)
{
CV_Assert(srcImage.depth() == CV_8U && srcImage.channels() == 1);
LBPImage.create(srcImage.size(), srcImage.type());
Mat extendedImage;
copyMakeBorder(srcImage, extendedImage, 1, 1, 1, 1, BORDER_DEFAULT);
// 计算LBP特征图
int heightOfExtendedImage = extendedImage.rows;
int widthOfExtendedImage = extendedImage.cols;
int widthOfLBP = LBPImage.cols;
uchar *rowOfExtendedImage = extendedImage.data + widthOfExtendedImage + 1;
uchar *rowOfLBPImage = LBPImage.data;
for (int y = 1; y <= heightOfExtendedImage - 2; ++y, rowOfExtendedImage += widthOfExtendedImage, rowOfLBPImage += widthOfLBP)
{
// 列
uchar *colOfExtendedImage = rowOfExtendedImage;
uchar *colOfLBPImage = rowOfLBPImage;
for (int x = 1; x <= widthOfExtendedImage - 2; ++x, ++colOfExtendedImage, ++colOfLBPImage)
{
// 计算LBP值
int LBPValue = 0;
if (colOfExtendedImage[0 - widthOfExtendedImage - 1] >= colOfExtendedImage[0])
LBPValue += 128;
if (colOfExtendedImage[0 - widthOfExtendedImage] >= colOfExtendedImage[0])
LBPValue += 64;
if (colOfExtendedImage[0 - widthOfExtendedImage + 1] >= colOfExtendedImage[0])
LBPValue += 32;
if (colOfExtendedImage[0 + 1] >= colOfExtendedImage[0])
LBPValue += 16;
if (colOfExtendedImage[0 + widthOfExtendedImage + 1] >= colOfExtendedImage[0])
LBPValue += 8;
if (colOfExtendedImage[0 + widthOfExtendedImage] >= colOfExtendedImage[0])
LBPValue += 4;
if (colOfExtendedImage[0 + widthOfExtendedImage - 1] >= colOfExtendedImage[0])
LBPValue += 2;
if (colOfExtendedImage[0 - 1] >= colOfExtendedImage[0])
LBPValue += 1;
colOfLBPImage[0] = LBPValue;
}
}
}