张洋 4 days ago
parent
commit
d536d7aab8

+ 2 - 2
zhipuzi_pos_windows/ai/SQLiteVecManager.cpp

@@ -143,8 +143,8 @@ std::vector<std::pair<std::string, float>> SQLiteVecManager::searchSimilarVector
 		// 使用sqlite-vec的向量搜索功能
 		std::string blobData = vectorToBlob(queryVector);
 
-		std::string sql = "SELECT image_path, vec_distance_cosine(feature_vector, ?) AS distance FROM image_features "
-			"ORDER BY distance ASC "
+		std::string sql = "SELECT image_path, distance FROM image_features WHERE feature_vector MATCH ? "
+			"ORDER BY distance "
 			"LIMIT " + std::to_string(k) + ";";
 
 		sqlite3_stmt * stmt;

+ 30 - 55
zhipuzi_pos_windows/ai/YoloFeatureExtractor.cpp

@@ -89,8 +89,7 @@ std::vector<float> YoloFeatureExtractor::extractFeatures(const std::string& imag
 		cv::dnn::blobFromImage(image, blob, 1.0 / 255.0, cv::Size(inputWidth, inputHeight), cv::Scalar(0, 0, 0), true, false);
 		net.setInput(blob);
 
-		std::string info = custom_printf("✅ blob 形状:%d×%d×%d×%d\n", blob.size[0], blob.size[1], blob.size[2], blob.size[3]);
-		DEBUG_LOG(info.c_str());
+		DEBUG_LOG::debug_printf("✅ blob 形状:%d×%d×%d×%d\n", blob.size[0], blob.size[1], blob.size[2], blob.size[3]);
 
 		auto time_2 = std::chrono::high_resolution_clock::now();
 
@@ -99,68 +98,44 @@ std::vector<float> YoloFeatureExtractor::extractFeatures(const std::string& imag
 
 		std::vector<float> features;
 
-		int layerIndex = -6;
-		if (layerIndex == -1)
+		
+		// 选择GAP层(对于yolo2026,通常是倒数第6层)的输出作为特征向量
+		outputNames.push_back(layerNames[layerNames.size() - 6]);
+
+		std::vector<cv::Mat> outputs;
+		net.forward(outputs, outputNames);
+
+		// 检查输出是否有效
+		if (outputs.empty() || outputs[0].empty())
 		{
-			outputNames.push_back(layerNames[layerNames.size() - 1]);
-
-			std::vector<cv::Mat> outputs;
-			net.forward(outputs, outputNames);
-
-			for (size_t i = 0; i < outputs.size(); ++i)
-			{
-				cv::Mat output = outputs[i];
-				features.reserve(features.size() + output.total());
-				for (int j = 0; j < output.total(); ++j)
-				{
-					features.push_back(output.at<float>(j));
-				}
-			}
+			throw std::runtime_error("模型前向传播未产生有效输出");
 		}
-		else if (layerIndex == -6)
-		{
-			// 选择GAP层(对于yolo2026,通常是倒数第6层)的输出作为特征向量
-			outputNames.push_back(layerNames[layerNames.size() - 6]);
-
-			std::vector<cv::Mat> outputs;
-			net.forward(outputs, outputNames);
-
-			// 检查输出是否有效
-			if (outputs.empty() || outputs[0].empty())
-			{
-				throw std::runtime_error("模型前向传播未产生有效输出");
-			}
-
-			// 获取GAP层输出并转换为特征向量
-			cv::Mat featuresMat = outputs[0];
-			info = printf("✅ 原始特征形状:%d×%d,类型:%d(CV_32F=5)\n", featuresMat.cols, featuresMat.rows, featuresMat.type());
-			DEBUG_LOG(info.c_str());
-			
-			cv::Mat featuresMatVec = featuresMat.reshape(1, 1);
-			info = printf("✅ 重塑后特征形状:%d×%d,类型:%d\n", featuresMatVec.cols, featuresMatVec.rows, featuresMatVec.type());
-			DEBUG_LOG(info.c_str());
 
-			float norm_before = cv::norm(featuresMatVec, cv::NORM_L2);
-			printf("📌 归一化前 norm:%.6f\n", norm_before);
+		// 获取GAP层输出并转换为特征向量
+		cv::Mat featuresMat = outputs[0];
+		DEBUG_LOG::debug_printf("✅ 原始特征形状:%d×%d,类型:%d(CV_32F=5)\n", featuresMat.cols, featuresMat.rows, featuresMat.type());
+			
+		cv::Mat featuresMatVec = featuresMat.reshape(1, 1);
+		DEBUG_LOG::debug_printf("✅ 重塑后特征形状:%d×%d,类型:%d\n", featuresMatVec.cols, featuresMatVec.rows, featuresMatVec.type());
 
+		float norm_before = cv::norm(featuresMatVec, cv::NORM_L2);
+		DEBUG_LOG::debug_printf("📌 归一化前 norm:%.6f\n", norm_before);
 
-			normalizeL2(featuresMatVec);
-			//cv::normalize(featuresMat, featuresMat, 1.0, 0.0, cv::NORM_L2);
+		//normalizeL2(featuresMatVec);
+		cv::normalize(featuresMat, featuresMat, 1.0, 0.0, cv::NORM_L2);
 
-			float norm_after = cv::norm(featuresMatVec, cv::NORM_L2);
-			printf("📌 归一化后 norm:%.6f\n", norm_after);
+		float norm_after = cv::norm(featuresMatVec, cv::NORM_L2);
+		DEBUG_LOG::debug_printf("📌 归一化后 norm:%.6f\n", norm_after);
 
-			features.reserve(features.size() + featuresMat.total());
-			for (int j = 0; j < featuresMat.total(); ++j)
-			{
-				features.push_back(featuresMat.at<float>(j));
-			}
+		features.reserve(features.size() + featuresMat.total());
+		for (int j = 0; j < featuresMat.total(); ++j)
+		{
+			features.push_back(featuresMat.at<float>(j));
+		}
 
-			int a = 1;
 
-			// 转换为std::vector<float>
-			//features = std::vector<float>(featuresMat.begin<float>(), featuresMat.end<float>());
-		}
+		// 转换为std::vector<float>
+		//features = std::vector<float>(featuresMat.begin<float>(), featuresMat.end<float>());
 
 
 		auto time_3 = std::chrono::high_resolution_clock::now();

+ 1 - 7
zhipuzi_pos_windows/ai/test.cpp

@@ -2,8 +2,6 @@
 
 #include "test.h"
 
-#include <iostream>
-
 #include "YoloFeatureExtractor.h"
 #include "ImageProcessor.h"
 #include "SQLiteVecManager.h"
@@ -13,10 +11,6 @@
 
 #include <opencv2/opencv.hpp>
 
-#include <filesystem>
-
-
-
 int AITest()
 {
 	try
@@ -31,7 +25,7 @@ int AITest()
 		//用于测试的图片目录
 		std::string galleryDir = (mainDir.parent_path().parent_path().parent_path().parent_path() /"res"/"images").string();       // 图库目录路径
 
-		std::string modelPath = sMainDir + "/ai/best.onnx";           // YOLO2026模型路径
+		std::string modelPath = sMainDir + "/ai/yolo26s-cls.onnx";           // YOLO2026模型路径
 		std::string classesPath = sMainDir + "/ai/cls.names";             // 类别文件路径
 		std::string searchImagePath = sMainDir + "/3.jpg"; // 搜索图片路径
 

+ 1 - 0
zhipuzi_pos_windows/pch/pch.h

@@ -21,6 +21,7 @@
 #include <fstream>
 #include <iomanip>
 #include <regex>
+#include <filesystem>
 
 //windows库
 #include <WinSock2.h>

+ 14 - 12
zhipuzi_pos_windows/tool/debuglog.h

@@ -25,16 +25,18 @@
     OutputDebugString(__fullmsg); \
 } while(0)
 
-inline std::string custom_printf(const char* format, ...) {
-    std::ostringstream oss;
+class DEBUG_LOG
+{
+public:
+    static void debug_printf(const char * format, ...)
+    {
+        va_list args;
+        va_start(args, format);
+        vprintf(format, args); // 原生打印到控制台(或重定向的输出)
+        char buffer[1024]; // 创建一个足够大的缓冲区来存储格式化后的字符串(可选)
+        vsnprintf(buffer, sizeof(buffer), format, args); // 将格式化后的字符串存储到buffer中(可选)
+        va_end(args); // 清理变量参数列表(optional)
 
-    va_list args;
-    va_start(args, format);
-    vprintf(format, args); // 原生打印到控制台(或重定向的输出)
-    char buffer[1024]; // 创建一个足够大的缓冲区来存储格式化后的字符串(可选)
-    vsnprintf(buffer, sizeof(buffer), format, args); // 将格式化后的字符串存储到buffer中(可选)
-    oss << buffer; // 将格式化后的字符串追加到oss中(可选)
-    va_end(args); // 清理变量参数列表(optional)
-
-    return oss.str();
-}
+        DEBUG_LOG(buffer);
+    }
+};