提取图像特征描述子(HOG,LBP)并利用余弦相似度的计算——C++实现

余弦相似度的计算(C++代码实现)

一.余弦计算

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

二.余弦计算(c++代码实现)

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

二.利用余弦距离计算图像特征之间的相似度(c++代码实现)

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;
		}
	}
}

你可能感兴趣的:(提取图像特征描述子(HOG,LBP)并利用余弦相似度的计算——C++实现)