Browse Source

可以正常识别了

张洋 12 hours ago
parent
commit
6cb023ece8

+ 90 - 248
zhipuzi_pos_windows/ai/YoloClassName.h

@@ -6,256 +6,98 @@
 // 果蔬名称常量数组(索引对应英文名称)
 // 注释格式:[索引] 英文名称 // 中文名称
 const std::string FRUIT_VEGETABLE_NAMES[] = {
-    "apple_akosu",          // 0: 阿克苏苹果
-    "apple_gala",           // 1: 嘎啦苹果
-    "apple_green",          // 2: 青苹果
-    "apple_hua_niu",        // 3: 花牛苹果
-    "apple_red_fuji",       // 4: 红富士苹果
-    "apricot",              // 5: 杏
-    "asparagus",            // 6: 芦笋
-    "avocado",              // 7: 牛油果
-    "banana",               // 8: 香蕉
-    "bamboo_shoot",         // 9: 竹笋
-    "baby_cabbage",         // 10: 娃娃菜
-    "bean_green",           // 11: 四季豆
-    "bitter_gourd",         // 12: 苦瓜
-    "blueberry",            // 13: 蓝莓
-    "bokchoy",              // 14: 上海青
-    "broccoli",             // 15: 西兰花
-    "cabbage_chinese",      // 16: 大白菜
-    "cabbage_purple",       // 17: 紫甘蓝
-    "cabbage_round",        // 18: 圆白菜
-    "cabbage_small",        // 19: 小白菜
-    "cantaloupe",           // 20: 哈密瓜
-    "cantaloupe_nettle",    // 21: 网纹瓜
-    "cantaloupe_xizhou",    // 22: 西州蜜
-    "carrot",               // 23: 胡萝卜
-    "carrot_yellow",        // 24: 黄胡萝卜
-    "cauliflower",          // 25: 白花菜
-    "caixin",               // 26: 菜心
-    "celery",               // 27: 芹菜
-    "cherry",               // 28: 樱桃
-    "cherry_big",           // 29: 车厘子
-    "chili_small",          // 30: 小米辣
-    "chinese_yam",          // 31: 山药
-    "chives",               // 32: 韭菜
-    "coriander",            // 33: 香菜
-    "corn",                 // 34: 玉米
-    "cowpea",               // 35: 豇豆
-    "cucumber",             // 36: 黄瓜
-    "cucumber_fruit",       // 37: 水果黄瓜
-    "cucumber_white",       // 38: 白玉黄瓜
-    "durian",               // 39: 榴莲
-    "dragonfruit_red",      // 40: 红心火龙果
-    "dragonfruit_white",    // 41: 白心火龙果
-    "eggplant_long",        // 42: 长茄子
-    "eggplant_round",       // 43: 圆茄子
-    "garlic",               // 44: 大蒜
-    "garlic_scape",         // 45: 蒜苔
-    "ginger",               // 46: 生姜
-    "grape_black",          // 47: 夏黑
-    "grape_green",          // 48: 青提
-    "grape_kyoho",          // 49: 巨峰葡萄
-    "grape_red",            // 50: 红提
-    "grape_seedless",       // 51: 无籽葡萄
-    "grape_shine",          // 52: 阳光玫瑰
-    "grapefruit",           // 53: 西柚
-    "jujube_winter",        // 54: 冬枣
-    "kiwi_green",           // 55: 绿心猕猴桃
-    "kiwi_red",             // 56: 红心猕猴桃
-    "lemon",                // 57: 柠檬
-    "lime",                // 58: 青柠
-    "lettuce",              // 59: 生菜
-    "lettuce_romaine",      // 60: 罗马生菜
-    "litchi",               // 61: 荔枝
-    "loofah",               // 62: 丝瓜
-    "longan",               // 63: 龙眼
-    "lotus_root",           // 64: 莲藕
-    "mango_golden",         // 65: 金煌芒
-    "mango_guifei",         // 66: 贵妃芒
-    "mango_small",          // 67: 小台农芒果
-    "mangosteen",           // 68: 山竹
-    "muskmelon_common",     // 69: 香瓜
-    "muskmelon_green",      // 70: 绿宝甜瓜
-    "muskmelon_horn",       // 71: 羊角蜜
-    "mushroom_enoki",       // 72: 金针菇
-    "mushroom_king",        // 73: 杏鲍菇
-    "mushroom_oyster",      // 74: 平菇
-    "mushroom_shiitake",    // 75: 香菇
-    "okra",                 // 76: 秋葵
-    "oil_vegetable",        // 77: 油麦菜
-    "onion_purple",         // 78: 紫洋葱
-    "onion_white",          // 79: 白洋葱
-    "orange_mandarin",      // 80: 蜜橘
-    "orange_navel",         // 81: 脐橙
-    "orange_papa",          // 82: 耙耙柑
-    "orange_tangerine",     // 83: 砂糖橘
-    "orange_ugly",          // 84: 丑橘
-    "orange_wogan",         // 85: 沃柑
-    "papaya",               // 86: 木瓜
-    "peach_flat",           // 87: 蟠桃
-    "peach_honey",          // 88: 水蜜桃
-    "peach_nectarine",      // 89: 油桃
-    "peach_yellow",         // 90: 黄桃
-    "pear_kuerle",          // 91: 库尔勒香梨
-    "pear_qiuyue",          // 92: 秋月梨
-    "pear_snow",            // 93: 雪梨
-    "pear_ya",              // 94: 鸭梨
-    "pepper_bell_green",    // 95: 绿彩椒
-    "pepper_bell_red",      // 96: 红彩椒
-    "pepper_bell_yellow",   // 97: 黄彩椒
-    "pea",                  // 98: 豌豆
-    "pineapple",            // 99: 菠萝
-    "pineapple_yellow",     // 100: 凤梨
-    "plum",                 // 101: 李子
-    "plum_black",           // 102: 黑布林
-    "pomegranate",          // 103: 石榴
-    "potato",               // 104: 土豆
-    "pumpkin",              // 105: 南瓜
-    "pumpkin_baby",         // 106: 贝贝南瓜
-    "purple_potato",        // 107: 紫薯
-    "radish_cherry",        // 108: 樱桃萝卜
-    "radish_red",           // 109: 红萝卜
-    "radish_white",         // 110: 白萝卜
-    "spinach",              // 111: 菠菜
-    "strawberry",           // 112: 草莓
-    "sweet_potato",         // 113: 红薯
-    "tomato_big",           // 114: 大番茄
-    "tomato_cherry",        // 115: 圣女果
-    "tomato_qianxi",        // 116: 千禧果
-    "wax_gourd",            // 117: 冬瓜
-    "watermelon",           // 118: 西瓜
-    "watermelon_8424",      // 119: 8424西瓜
-    "watermelon_black_beauty", // 120: 黑美人西瓜
-    "watermelon_qilin",     // 121: 麒麟西瓜
-    "wood_ear",             // 122: 木耳
-    "zucchini"              // 123: 西葫芦
+    "baixianguo",
+    "biandou",
+    "bingtangcheng",
+    "boluo",
+    "caomei",
+    "chelizi",
+    "fanlizhi",
+    "fanshiliu",
+    "fengshuili",
+    "haitangguo",
+    "hamigua",
+    "hongmaodan",
+    "hongti",
+    "huangguanli",
+    "huluobo",
+    "huolongguo",
+    "kuerlexiangli",
+    "kugua",
+    "lanmei",
+    "liulian",
+    "lizhi",
+    "longyan",
+    "mangguo",
+    "mihoutao",
+    "miju",
+    "mugua",
+    "nanguoli",
+    "niuyouguo",
+    "pingguo",
+    "qicheng",
+    "qiezi",
+    "qingti",
+    "renxingguo",
+    "shanzhu",
+    "shatangju",
+    "shiliu",
+    "tudou",
+    "wandou",
+    "wandoujia",
+    "xiangjiao",
+    "xigua",
+    "xueli",
+    "yali",
+    "yezi",
+    "yumi"
 };
 
 // 果蔬英文名称 -> 中文名称 映射表(哈希表,查询效率O(1))
 const std::unordered_map<std::string, std::string> FRUIT_VEGETABLE_CN_MAP = {
-    {"apple_akosu", "阿克苏苹果"},
-    {"apple_gala", "嘎啦苹果"},
-    {"apple_green", "青苹果"},
-    {"apple_hua_niu", "花牛苹果"},
-    {"apple_red_fuji", "红富士苹果"},
-    {"apricot", "杏"},
-    {"asparagus", "芦笋"},
-    {"avocado", "牛油果"},
-    {"banana", "香蕉"},
-    {"bamboo_shoot", "竹笋"},
-    {"baby_cabbage", "娃娃菜"},
-    {"bean_green", "四季豆"},
-    {"bitter_gourd", "苦瓜"},
-    {"blueberry", "蓝莓"},
-    {"bokchoy", "上海青"},
-    {"broccoli", "西兰花"},
-    {"cabbage_chinese", "大白菜"},
-    {"cabbage_purple", "紫甘蓝"},
-    {"cabbage_round", "圆白菜"},
-    {"cabbage_small", "小白菜"},
-    {"cantaloupe", "哈密瓜"},
-    {"cantaloupe_nettle", "网纹瓜"},
-    {"cantaloupe_xizhou", "西州蜜"},
-    {"carrot", "胡萝卜"},
-    {"carrot_yellow", "黄胡萝卜"},
-    {"cauliflower", "白花菜"},
-    {"caixin", "菜心"},
-    {"celery", "芹菜"},
-    {"cherry", "樱桃"},
-    {"cherry_big", "车厘子"},
-    {"chili_small", "小米辣"},
-    {"chinese_yam", "山药"},
-    {"chives", "韭菜"},
-    {"coriander", "香菜"},
-    {"corn", "玉米"},
-    {"cowpea", "豇豆"},
-    {"cucumber", "黄瓜"},
-    {"cucumber_fruit", "水果黄瓜"},
-    {"cucumber_white", "白玉黄瓜"},
-    {"durian", "榴莲"},
-    {"dragonfruit_red", "红心火龙果"},
-    {"dragonfruit_white", "白心火龙果"},
-    {"eggplant_long", "长茄子"},
-    {"eggplant_round", "圆茄子"},
-    {"garlic", "大蒜"},
-    {"garlic_scape", "蒜苔"},
-    {"ginger", "生姜"},
-    {"grape_black", "夏黑"},
-    {"grape_green", "青提"},
-    {"grape_kyoho", "巨峰葡萄"},
-    {"grape_red", "红提"},
-    {"grape_seedless", "无籽葡萄"},
-    {"grape_shine", "阳光玫瑰"},
-    {"grapefruit", "西柚"},
-    {"jujube_winter", "冬枣"},
-    {"kiwi_green", "绿心猕猴桃"},
-    {"kiwi_red", "红心猕猴桃"},
-    {"lemon", "柠檬"},
-    {"lime", "青柠"},
-    {"lettuce", "生菜"},
-    {"lettuce_romaine", "罗马生菜"},
-    {"litchi", "荔枝"},
-    {"loofah", "丝瓜"},
-    {"longan", "龙眼"},
-    {"lotus_root", "莲藕"},
-    {"mango_golden", "金煌芒"},
-    {"mango_guifei", "贵妃芒"},
-    {"mango_small", "小台农芒果"},
-    {"mangosteen", "山竹"},
-    {"muskmelon_common", "香瓜"},
-    {"muskmelon_green", "绿宝甜瓜"},
-    {"muskmelon_horn", "羊角蜜"},
-    {"mushroom_enoki", "金针菇"},
-    {"mushroom_king", "杏鲍菇"},
-    {"mushroom_oyster", "平菇"},
-    {"mushroom_shiitake", "香菇"},
-    {"okra", "秋葵"},
-    {"oil_vegetable", "油麦菜"},
-    {"onion_purple", "紫洋葱"},
-    {"onion_white", "白洋葱"},
-    {"orange_mandarin", "蜜橘"},
-    {"orange_navel", "脐橙"},
-    {"orange_papa", "耙耙柑"},
-    {"orange_tangerine", "砂糖橘"},
-    {"orange_ugly", "丑橘"},
-    {"orange_wogan", "沃柑"},
-    {"papaya", "木瓜"},
-    {"peach_flat", "蟠桃"},
-    {"peach_honey", "水蜜桃"},
-    {"peach_nectarine", "油桃"},
-    {"peach_yellow", "黄桃"},
-    {"pear_kuerle", "库尔勒香梨"},
-    {"pear_qiuyue", "秋月梨"},
-    {"pear_snow", "雪梨"},
-    {"pear_ya", "鸭梨"},
-    {"pepper_bell_green", "绿彩椒"},
-    {"pepper_bell_red", "红彩椒"},
-    {"pepper_bell_yellow", "黄彩椒"},
-    {"pea", "豌豆"},
-    {"pineapple", "菠萝"},
-    {"pineapple_yellow", "凤梨"},
-    {"plum", "李子"},
-    {"plum_black", "黑布林"},
-    {"pomegranate", "石榴"},
-    {"potato", "土豆"},
-    {"pumpkin", "南瓜"},
-    {"pumpkin_baby", "贝贝南瓜"},
-    {"purple_potato", "紫薯"},
-    {"radish_cherry", "樱桃萝卜"},
-    {"radish_red", "红萝卜"},
-    {"radish_white", "白萝卜"},
-    {"spinach", "菠菜"},
-    {"strawberry", "草莓"},
-    {"sweet_potato", "红薯"},
-    {"tomato_big", "大番茄"},
-    {"tomato_cherry", "圣女果"},
-    {"tomato_qianxi", "千禧果"},
-    {"wax_gourd", "冬瓜"},
-    {"watermelon", "西瓜"},
-    {"watermelon_8424", "8424西瓜"},
-    {"watermelon_black_beauty", "黑美人西瓜"},
-    {"watermelon_qilin", "麒麟西瓜"},
-    {"wood_ear", "木耳"},
-    {"zucchini", "西葫芦"}
+    {"baixianguo", "百香果"},
+    {"biandou", "扁豆"},
+    {"bingtangcheng", "冰糖橙"},
+    {"boluo", "菠萝"},
+    {"caomei", "草莓"},
+    {"chelizi", "车厘子"},
+    {"fanlizhi", "番荔枝"},
+    {"fanshiliu", "番石榴"},
+    {"fengshuili", "凤梨"},
+    {"haitangguo", "海棠果"},
+    {"hamigua", "哈密瓜"},
+    {"hongmaodan", "红毛丹"},
+    {"hongti", "红提"},
+    {"huangguanli", "皇冠梨"},
+    {"huluobo", "胡萝卜"},
+    {"huolongguo", "火龙果"},
+    {"kuerlexiangli", "库尔勒香梨"},
+    {"kugua", "苦瓜"},
+    {"lanmei", "蓝莓"},
+    {"liulian", "榴莲"},
+    {"lizhi", "荔枝"},
+    {"longyan", "龙眼"},
+    {"mangguo", "芒果"},
+    {"mihoutao", "猕猴桃"},
+    {"miju", "蜜桔"},
+    {"mugua", "木瓜"},
+    {"nanguoli", "南国梨"},
+    {"niuyouguo", "牛油果"},
+    {"pingguo", "苹果"},
+    {"qicheng", "脐橙"},
+    {"qiezi", "茄子"},
+    {"qingti", "青提"},
+    {"renxingguo", "人参果"},
+    {"shanzhu", "山竹"},
+    {"shatangju", "砂糖橘"},
+    {"shiliu", "石榴"},
+    {"tudou", "土豆"},
+    {"wandou", "豌豆"},
+    {"wandoujia", "豌豆荚"},
+    {"xiangjiao", "香蕉"},
+    {"xigua", "西瓜"},
+    {"xueli", "雪梨"},
+    {"yali", "鸭梨"},
+    {"yezi", "椰子"},
+    {"yumi", "玉米"}
 };

+ 92 - 23
zhipuzi_pos_windows/ai/YoloFeatureManager.cpp

@@ -37,14 +37,14 @@ std::string YoloFeatureManager::getClassName(std::size_t classId) const
 	if (classId >= 0 && classId < FRUIT_VEGETABLE_COUNT)
 	{
 		std::string englishName = FRUIT_VEGETABLE_NAMES[classId];
-		
+
 		// 这里可以添加一个映射表,将英文名称映射到中文名称
 		auto it = FRUIT_VEGETABLE_CN_MAP.find(englishName);
-		if (it != FRUIT_VEGETABLE_CN_MAP.end()) 
+		if (it != FRUIT_VEGETABLE_CN_MAP.end())
 		{
 			return it->second; // 找到则返回中文名称
 		}
-		else 
+		else
 		{
 			return "Unknown"; // 未找到则返回默认值
 		}
@@ -53,7 +53,7 @@ std::string YoloFeatureManager::getClassName(std::size_t classId) const
 	return "Unknown";
 }
 
-std::vector<float> YoloFeatureManager::extractFeatures(const std::string& imagePath)
+std::vector<float> YoloFeatureManager::extractFeatures(const std::string & imagePath)
 {
 	try
 	{
@@ -67,7 +67,7 @@ std::vector<float> YoloFeatureManager::extractFeatures(const std::string& imageP
 
 		// 转换为blob(归一化+通道转换)
 		cv::Mat blob;
-		cv::dnn::blobFromImage(image, blob, 1.0 / 255, cv::Size(inputWidth, inputHeight), cv::Scalar(0,0,0), true, false);
+		cv::dnn::blobFromImage(image, blob, 1.0 / 255, cv::Size(inputWidth, inputHeight), cv::Scalar(0, 0, 0), true, false);
 		net.setInput(blob);
 
 		auto time_2 = std::chrono::high_resolution_clock::now();
@@ -118,7 +118,7 @@ std::vector<float> YoloFeatureManager::extractFeatures(const std::string& imageP
 
 		return feature_vector;
 	}
-	catch (const std::exception& e)
+	catch (const std::exception & e)
 	{
 		std::string aa = std::string(e.what());
 		DEBUG_LOG(("提取特征失败: " + std::string(e.what())).c_str());
@@ -126,7 +126,7 @@ std::vector<float> YoloFeatureManager::extractFeatures(const std::string& imageP
 	}
 }
 
-void YoloFeatureManager::Detection(const std::string& imagePath)
+void YoloFeatureManager::Detection(const std::string & imagePath)
 {
 	cv::Mat image = cv::imread(imagePath);
 	if (image.empty())
@@ -156,10 +156,12 @@ void YoloFeatureManager::Detection(const std::string& imagePath)
 	std::vector<float> confidences; // 置信度
 
 	// 遍历所有输出层的结果
-	for (const cv::Mat& out : outs) {
-		float* data = (float*)out.data;
+	for (const cv::Mat & out : outs)
+	{
+		float * data = (float *)out.data;
 		// 遍历每个检测结果
-		for (int i = 0; i < out.rows; i++, data += out.cols) {
+		for (int i = 0; i < out.rows; i++, data += out.cols)
+		{
 			// 获取类别置信度
 			cv::Mat scores = out.row(i).colRange(5, out.cols);
 			cv::Point classIdPoint;
@@ -169,7 +171,8 @@ void YoloFeatureManager::Detection(const std::string& imagePath)
 			cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
 
 			// 过滤低置信度结果
-			if (confidence > CONF_THRESHOLD) {
+			if (confidence > CONF_THRESHOLD)
+			{
 				// 解析检测框坐标(YOLO输出的是相对坐标,需转换为绝对坐标)
 				int centerX = (int)(data[0] * image.cols);
 				int centerY = (int)(data[1] * image.rows);
@@ -196,7 +199,8 @@ void YoloFeatureManager::Detection(const std::string& imagePath)
 	std::vector<cv::Rect> finalBoxes;
 	std::vector<int> finalClassIds;
 	std::vector<float> finalConfidences;
-	for (int idx : indices) {
+	for (int idx : indices)
+	{
 		finalBoxes.push_back(boxes[idx]);
 		finalClassIds.push_back(classIds[idx]);
 		finalConfidences.push_back(confidences[idx]);
@@ -215,13 +219,14 @@ void YoloFeatureManager::Detection(const std::string& imagePath)
 }
 
 // 绘制检测结果
-void YoloFeatureManager::drawDetection(cv::Mat& img, const std::vector<cv::Rect>& boxes, const std::vector<int>& classIds,
-	const std::vector<float>& confidences) 
+void YoloFeatureManager::drawDetection(cv::Mat & img, const std::vector<cv::Rect> & boxes, const std::vector<int> & classIds,
+	const std::vector<float> & confidences)
 {
 	// 生成随机颜色(每个类别一种颜色)
 	std::vector<cv::Scalar> colors;
 	srand(time(0));
-	for (std::size_t i = 0; i < FRUIT_VEGETABLE_COUNT; i++) {
+	for (std::size_t i = 0; i < FRUIT_VEGETABLE_COUNT; i++)
+	{
 		int r = rand() % 256;
 		int g = rand() % 256;
 		int b = rand() % 256;
@@ -229,7 +234,8 @@ void YoloFeatureManager::drawDetection(cv::Mat& img, const std::vector<cv::Rect>
 	}
 
 	// 绘制每个检测框
-	for (size_t i = 0; i < boxes.size(); i++) {
+	for (size_t i = 0; i < boxes.size(); i++)
+	{
 		cv::Rect box = boxes[i];
 		// 绘制矩形框
 		cv::rectangle(img, box, colors[classIds[i]], 2);
@@ -268,22 +274,21 @@ std::string YoloFeatureManager::Class(cv::Mat & image)
 	float topConfidence = output.at<float>(topClassIdx);
 
 	// 只显示置信度高于阈值的结果
-	if (topConfidence > 0.5)
+	if (topConfidence > 0.8)
 	{
 		className = this->getClassName(topClassIdx);
+
+		// 在画面上绘制分类结果
+		std::wstring resultText = CLewaimaiString::ANSIToUnicode(className) + L" : " + std::to_wstring(round(topConfidence * 10000) / 100) + L"%";
+		this->drawChineseText(image, resultText.c_str(), cv::Point(20, 50), cv::Scalar(0, 255, 0), 24);
 	}
 	else
 	{
 		className = "Unknown";
 	}
 
-	// ====================== 显示画面 ======================
-	// 在画面上绘制分类结果
-	std::string resultText = className + " : " + std::to_string(round(topConfidence * 10000) / 100) + "%";
-
-	cv::putText(image, resultText, cv::Point(20, 50), cv::FONT_HERSHEY_SIMPLEX, 1.2, cv::Scalar(0, 255, 0), 3);
 	cv::imshow("YOLOv8s-cls 实时图像分类", image);
-	if (cv::waitKey(30) >= 0) ; // 按任意键退出
+	if (cv::waitKey(30) >= 0); // 按任意键退出
 
 	return className;
 }
@@ -301,4 +306,68 @@ std::string YoloFeatureManager::ClassFromVideoCapture()
 	}
 
 	return Class(image);
+}
+
+void YoloFeatureManager::drawChineseText(cv::Mat & img, const wchar_t * text, cv::Point pos, cv::Scalar color, int fontSize)
+{
+	// 1. 检查输入有效性
+	if (img.empty() || text == nullptr || wcslen(text) == 0)
+	{
+		return;
+	}
+	if (img.type() != CV_8UC3)
+	{ 
+		// 仅支持 3 通道彩色图像
+		cvtColor(img, img, cv::COLOR_GRAY2BGR);
+	}
+
+	// 2. 创建内存 DC 并关联临时位图(关键:基于图像的 DC 创建,而非屏幕 DC)
+	HDC hScreenDC = GetDC(NULL);
+	HDC hMemDC = CreateCompatibleDC(hScreenDC);
+	// 创建与原图像尺寸、格式匹配的位图
+	HBITMAP hMemBmp = CreateCompatibleBitmap(hScreenDC, img.cols, img.rows);
+	// 保存原始位图句柄,用于后续恢复
+	HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hMemBmp);
+
+	// 3. 将 OpenCV 图像数据复制到内存位图(保留原图像内容,而非黑色)
+	BITMAPINFO bmi = { 0 };
+	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+	bmi.bmiHeader.biWidth = img.cols;
+	bmi.bmiHeader.biHeight = -img.rows; // 翻转 Y 轴(OpenCV 与 GDI 坐标方向相反)
+	bmi.bmiHeader.biPlanes = 1;
+	bmi.bmiHeader.biBitCount = 24;
+	bmi.bmiHeader.biCompression = BI_RGB;
+	// 将 OpenCV 图像写入内存位图
+	SetDIBits(hScreenDC, hMemBmp, 0, img.rows, img.data, &bmi, DIB_RGB_COLORS);
+
+	// 4. 设置中文字体(修复字体创建参数,增加容错)
+	HFONT hFont = CreateFont(
+		fontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0,
+		GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+		DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"黑体"
+	);
+	HFONT hOldFont = (HFONT)SelectObject(hMemDC, hFont);
+
+	// 5. 设置文字绘制属性(背景透明、颜色正确)
+	SetBkMode(hMemDC, TRANSPARENT);
+	// OpenCV 是 BGR,GDI 是 RGB,需转换
+	SetTextColor(hMemDC, RGB((int)color[2], (int)color[1], (int)color[0]));
+
+	// 6. 绘制中文字符(确保坐标在图像范围内)
+	int textLen = wcslen(text);
+	if (pos.x >= 0 && pos.y >= 0 && pos.x < img.cols && pos.y < img.rows)
+	{
+		TextOutW(hMemDC, pos.x, pos.y, text, textLen);
+	}
+
+	// 7. 将绘制后的位图数据复制回 OpenCV 图像
+	GetDIBits(hScreenDC, hMemBmp, 0, img.rows, img.data, &bmi, DIB_RGB_COLORS);
+
+	// 8. 释放资源(关键:恢复原始句柄后再删除,避免内存泄漏)
+	SelectObject(hMemDC, hOldFont); // 恢复原始字体
+	DeleteObject(hFont);            // 删除自定义字体
+	SelectObject(hMemDC, hOldBmp);  // 恢复原始位图
+	DeleteObject(hMemBmp);          // 删除内存位图
+	DeleteDC(hMemDC);               // 删除内存 DC
+	ReleaseDC(NULL, hScreenDC);     // 释放屏幕 DC
 }

+ 4 - 1
zhipuzi_pos_windows/ai/YoloFeatureManager.h

@@ -15,7 +15,7 @@ private:
 	float CONF_THRESHOLD;
 	float NMS_THRESHOLD;
 
-	int FRUIT_VEGETABLE_COUNT;
+	std::size_t FRUIT_VEGETABLE_COUNT;
 
 public:
 	YoloFeatureManager();
@@ -49,6 +49,7 @@ private:
 		double maxVal;
 
 		cv::Point maxLoc;
+
 		// 找到最大值的位置(即最高置信度类别索引)
 		cv::minMaxLoc(flatOutput, nullptr, &maxVal, nullptr, &maxLoc);
 
@@ -57,4 +58,6 @@ private:
 
 	//	获取类别名称
 	std::string getClassName(std::size_t classId) const;
+
+	void drawChineseText(cv::Mat & img, const wchar_t * text, cv::Point pos, cv::Scalar color, int fontSize);
 };

+ 3 - 5
zhipuzi_pos_windows/page/CDiandanPageUI.cpp

@@ -4012,16 +4012,14 @@ void CDiandanPageUI::HandleDiandanAIShibie()
 		if (m_ai_shibie_foodname != "Unknown")
 		{
 			std::cout << "检测到类别: " << m_ai_shibie_foodname << std::endl;
-			
-			//主线程里面去处理界面刷新
-			::SendMessage(m_pMainWnd->GetHWND(), WM_AI_RECOGNITION_SUCCESS, 0, 0);
 		}
 		else
 		{
 			std::cout << "未检测到任何类别。" << std::endl;
-
-			Sleep(100);
 		}
+
+		//主线程里面去处理界面刷新
+		::SendMessage(m_pMainWnd->GetHWND(), WM_AI_RECOGNITION_SUCCESS, 0, 0);
 	}
 }