CAIxuexiPageUI.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. #include "CAIxuexiPageUI.h"
  2. #include "../control/ControlEx.h"
  3. #include "../wnd/CMainWnd.h"
  4. #include "../worker/CVideoCaptureWorker.h"
  5. #include "../tool/CSqlite3.h"
  6. #include "../wnd/CMainWnd.h"
  7. #include "../ai/YoloFeatureManager.h"
  8. #include "../ai/ImageProcessor.h"
  9. #include "../ai/SQLiteVecManager.h"
  10. #include "../control/CFoodXuexiImageItemUI.h"
  11. CAIxuexiPageUI::CAIxuexiPageUI()
  12. {
  13. m_hBitmap = NULL;
  14. m_hMemDC = NULL;
  15. }
  16. CAIxuexiPageUI::~CAIxuexiPageUI()
  17. {
  18. if (m_hBitmap)
  19. {
  20. DeleteObject(m_hBitmap);
  21. m_hBitmap = NULL;
  22. }
  23. if (m_hMemDC)
  24. {
  25. DeleteDC(m_hMemDC);
  26. m_hMemDC = NULL;
  27. }
  28. }
  29. void CAIxuexiPageUI::InitShow()
  30. {
  31. if (m_isFirstInit)
  32. {
  33. m_isFirstInit = false;
  34. std::thread(&CAIxuexiPageUI::HandleUpdateVideo, this).detach();
  35. }
  36. //重新进来的时候,重置当前选中的分类和商品
  37. m_cur_click_food_item = NULL;
  38. CLabelUI* pLabel = static_cast<CLabelUI*>(this->FindSubControl(_T("aixuexi_page_xuanzhong_food_name")));
  39. std::wstring wsShow = L"当前选中商品:无";
  40. pLabel->SetText(wsShow.c_str());
  41. //先把之前的显示清空
  42. CTileLayoutUI* pXuexiScrollLayout = static_cast<CTileLayoutUI*>(this->FindSubControl(_T("aixuexi_page_food_xuexi_image_layout")));
  43. pXuexiScrollLayout->RemoveAll();
  44. //先初始化商品分类
  45. this->InitFoodtypeShow();
  46. //再初始化商品显示
  47. this->InitFoodShow();
  48. }
  49. void CAIxuexiPageUI::UpdatCurFoodXuexiShow()
  50. {
  51. //把当前选中商品的已学习显示更新一下
  52. std::string sFoodId = m_cur_click_food_item->GetFoodInfo().id;
  53. std::vector<std::pair<std::string, std::string>> food_vector = SQLiteVecManager::GetInstance()->GetFoodXueXiImageInfoByFoodId(sFoodId);
  54. //先把之前的显示清空
  55. CTileLayoutUI* pXuexiScrollLayout = static_cast<CTileLayoutUI*>(this->FindSubControl(_T("aixuexi_page_food_xuexi_image_layout")));
  56. pXuexiScrollLayout->RemoveAll();
  57. SIZE itemsize;
  58. itemsize.cx = 120;
  59. itemsize.cy = 90;
  60. pXuexiScrollLayout->SetItemSize(itemsize);
  61. //再把新的显示添加上
  62. for (std::vector<std::pair<std::string, std::string>>::iterator it = food_vector.begin(); it != food_vector.end(); it++)
  63. {
  64. std::pair<std::string, std::string> item = *it;
  65. std::string imageName = item.first;
  66. std::string imagePath = item.second;
  67. CDialogBuilder builder;
  68. CDialogBuilderCallbackEx cb;
  69. CFoodXuexiImageItemUI* pItem = static_cast<CFoodXuexiImageItemUI*>(builder.Create(_T("aixuexi_page_food_xuexi_image.xml"), (UINT)0, &cb, m_pManager));
  70. pItem->SetImageName(imageName);
  71. pItem->SetImagePath(imagePath);
  72. pXuexiScrollLayout->Add(pItem);
  73. }
  74. }
  75. void CAIxuexiPageUI::InitFoodtypeShow()
  76. {
  77. //初始化商品渲染相关的信息
  78. m_foodtype_mutex.lock();
  79. m_foodtypeLayout = static_cast<CHorizontalLayoutUI*>(this->FindSubControl(_T("aixuexi_page_fenlei_layout")));
  80. m_foodtypeLayout->RemoveAll();
  81. CSqlite3 sqlite;
  82. m_types = sqlite.GetFoodtypes(); //只包含收银机显示的分类
  83. if (m_types.size() > 0)
  84. {
  85. m_cur_type_id = m_types[0].id;
  86. }
  87. m_curFoodtypeOption = NULL;
  88. //接下来开始处理商品分类
  89. for (std::vector<CFoodType>::iterator it = m_types.begin(); it != m_types.end(); it++)
  90. {
  91. CFoodType type = *it;
  92. CDialogBuilder builder;
  93. CDialogBuilderCallbackEx cb;
  94. CFoodtypeOptionUI* pItem = static_cast<CFoodtypeOptionUI*>(builder.Create(_T("foodtype_option.xml"), (UINT)0, &cb, m_pManager));
  95. pItem->SetName(CLewaimaiString::UTF8ToUnicode(type.name));
  96. pItem->SetTypeId(type.id);
  97. pItem->SetGroup(L"aixuexi_page_foodtype");
  98. m_foodtypeLayout->Add(pItem);
  99. if (m_cur_type_id == type.id)
  100. {
  101. m_curFoodtypeOption = pItem;
  102. }
  103. }
  104. m_foodtype_mutex.unlock();
  105. if (m_curFoodtypeOption != NULL)
  106. {
  107. m_curFoodtypeOption->SetBkColor(0xFF3CB371);
  108. }
  109. //如果不是一个分类都没有,选中第一个分类
  110. if (m_cur_type_id != "")
  111. {
  112. CFoodtypeOptionUI* curTypeUI = static_cast<CFoodtypeOptionUI*>(m_foodtypeLayout->GetItemAt(0));
  113. curTypeUI->Selected(true, false);
  114. }
  115. UpdateFoodtypePos();
  116. }
  117. void CAIxuexiPageUI::UpdateFoodtypePos()
  118. {
  119. int nFoodtypeNum = m_types.size();
  120. //添加支付方式
  121. int nWidth = m_nPageWidth;
  122. if (nWidth == 0)
  123. {
  124. return;
  125. }
  126. //根据宽度计算每行显示的数量
  127. int nMeihangNum = (nWidth - 321) / 140;
  128. int num = 0;
  129. m_foodtype_mutex.lock();
  130. CHorizontalLayoutUI* pFenleiLayout = static_cast<CHorizontalLayoutUI*>(this->FindSubControl(_T("aixuexi_page_fenlei_layout")));
  131. for (int i = 0; i < nFoodtypeNum; i++)
  132. {
  133. CButtonUI* curItem = static_cast<CButtonUI*>(pFenleiLayout->GetItemAt(i));
  134. int curRow = num / nMeihangNum + 1;
  135. int curCol = num % nMeihangNum + 1;
  136. RECT rect;
  137. rect.left = (curCol - 1) * 140 + 10;
  138. rect.right = rect.left + 130;
  139. rect.top = (curRow - 1) * 52 + 10;
  140. rect.bottom = rect.top + 42;
  141. // 强制设置固定大小和位置
  142. SIZE size;
  143. size.cx = rect.left;
  144. size.cy = rect.top;
  145. curItem->SetFixedXY(size);
  146. curItem->SetFixedWidth(rect.right - rect.left);
  147. curItem->SetFixedHeight(rect.bottom - rect.top);
  148. num++;
  149. }
  150. m_foodtype_mutex.unlock();
  151. //调整区域高度
  152. int lastRow = (num - 1) / nMeihangNum + 1;
  153. pFenleiLayout->SetFixedHeight(lastRow * 52 + 10);
  154. //处理滚动条问题
  155. CVerticalLayoutUI* pFenleiScrollLayout = static_cast<CVerticalLayoutUI*>(this->FindSubControl(_T("aixuexi_page_fenlei_layout_scrolllayout")));
  156. if (lastRow > 2)
  157. {
  158. lastRow = 2;
  159. }
  160. pFenleiScrollLayout->SetFixedHeight(lastRow * 52 + 10);
  161. SIZE size;
  162. size.cx = 0;
  163. size.cy = 0;
  164. pFenleiScrollLayout->SetScrollPos(size);
  165. }
  166. void CAIxuexiPageUI::InitFoodShow()
  167. {
  168. bool is_youtu;
  169. if (CSetting::GetInstance()->GetParam("setting_xianshi_is_youtu") == "1")
  170. {
  171. is_youtu = true;
  172. }
  173. else
  174. {
  175. is_youtu = false;
  176. }
  177. m_foodLayout = static_cast<CTileLayoutUI*>(this->FindSubControl(_T("aixuexi_page_foodlist")));
  178. m_foodLayout->RemoveAll();
  179. std::wstring xml_name;
  180. if (is_youtu)
  181. {
  182. SIZE itemsize;
  183. itemsize.cx = 130;
  184. itemsize.cy = 220;
  185. m_foodLayout->SetItemSize(itemsize);
  186. xml_name = _T("aixuexi_page_fooditem.xml");
  187. }
  188. else
  189. {
  190. SIZE itemsize;
  191. itemsize.cx = 130;
  192. itemsize.cy = 90;
  193. m_foodLayout->SetItemSize(itemsize);
  194. xml_name = _T("aixuexi_page_fooditem_wutu.xml");
  195. }
  196. //如果当前一个分类都没有,那么就不处理了
  197. if (m_cur_type_id == "")
  198. {
  199. return;
  200. }
  201. else if (m_cur_type_id == "sousuo")
  202. {
  203. if (CLewaimaiString::is_only_number(m_sousuo_foodname))
  204. {
  205. //说明是纯数字,按商品条码来搜索
  206. CSqlite3 sqlite;
  207. CFood food;
  208. bool ret = sqlite.GetFoodByBarcode(m_sousuo_foodname, food);
  209. if (ret)
  210. {
  211. CDialogBuilder builder;
  212. CDialogBuilderCallbackEx cb;
  213. CAIXuexiPageFoodItemUI* pItem = static_cast<CAIXuexiPageFoodItemUI*>(builder.Create(xml_name.c_str(), (UINT)0, &cb, m_pManager));
  214. pItem->SetYoutuModel(is_youtu);
  215. pItem->SetFoodInfo(food);
  216. pItem->UpdateShow();
  217. m_foodLayout->Add(pItem);
  218. }
  219. }
  220. else
  221. {
  222. //当商品名字来搜索
  223. CSqlite3 sqlite;
  224. std::vector<CFood> foodlist = sqlite.GetFoodByFoodname(m_sousuo_foodname);
  225. for (std::vector<CFood>::iterator it = foodlist.begin(); it != foodlist.end(); it++)
  226. {
  227. CFood food = *it;
  228. CDialogBuilder builder;
  229. CDialogBuilderCallbackEx cb;
  230. CAIXuexiPageFoodItemUI* pItem = static_cast<CAIXuexiPageFoodItemUI*>(builder.Create(xml_name.c_str(), (UINT)0, &cb, m_pManager));
  231. pItem->SetYoutuModel(is_youtu);
  232. pItem->SetFoodInfo(food);
  233. pItem->UpdateShow();
  234. m_foodLayout->Add(pItem);
  235. }
  236. }
  237. }
  238. else
  239. {
  240. //选择的是普通商品分类
  241. CSqlite3 sqlite;
  242. std::vector<CFood> foodlist = sqlite.GetFoodByTypeid(m_cur_type_id);
  243. for (std::vector<CFood>::iterator it = foodlist.begin(); it != foodlist.end(); it++)
  244. {
  245. CFood food = *it;
  246. CDialogBuilder builder;
  247. CDialogBuilderCallbackEx cb;
  248. CAIXuexiPageFoodItemUI* pItem = static_cast<CAIXuexiPageFoodItemUI*>(builder.Create(xml_name.c_str(), (UINT)0, &cb, m_pManager));
  249. pItem->SetYoutuModel(is_youtu);
  250. pItem->SetFoodInfo(food);
  251. pItem->UpdateShow();
  252. m_foodLayout->Add(pItem);
  253. }
  254. }
  255. }
  256. //处理按钮点击类事件
  257. void CAIxuexiPageUI::HandleClickMsg(TNotifyUI& msg)
  258. {
  259. CDuiString name = msg.pSender->GetName();
  260. if (name == L"aixuexi_page_fooditem")
  261. {
  262. CAIXuexiPageFoodItemUI* fooditemUI = static_cast<CAIXuexiPageFoodItemUI*>(msg.pSender);
  263. m_cur_click_food_item = fooditemUI;
  264. this->ClickFoodAction();
  265. }
  266. else if (name == L"aixuexi_page_food_search_clear")
  267. {
  268. CEditUI* m_pEdit = static_cast<CEditUI*>(m_pManager->FindControl(_T("aixuexi_page_food_search_edit")));
  269. m_pEdit->SetText(L"");
  270. StopSerachFood();
  271. }
  272. else if (name == L"aixuexi_page_paishe_btn")
  273. {
  274. this->DoXuexi();
  275. }
  276. else if (name == L"aixuexi_page_food_image_delete")
  277. {
  278. CFoodXuexiImageItemUI* m_pImageItem = static_cast<CFoodXuexiImageItemUI*>(msg.pSender->GetParent());
  279. //先删除图片控件
  280. CTileLayoutUI* pXuexiScrollLayout = static_cast<CTileLayoutUI*>(this->FindSubControl(_T("aixuexi_page_food_xuexi_image_layout")));
  281. pXuexiScrollLayout->Remove(m_pImageItem);
  282. //然后从数据库中删除这个图片对应的向量
  283. std::string imageName = m_pImageItem->GetImageName();
  284. SQLiteVecManager::GetInstance()->DeleteFeatureVectorByImageName(imageName);
  285. }
  286. else if (name == L"aixuexi_page_return")
  287. {
  288. m_pMainWnd->SwitchPage(CMainWnd::DIANDAN);
  289. }
  290. }
  291. void CAIxuexiPageUI::HandleSelectChangeMsg(TNotifyUI& msg)
  292. {
  293. CDuiString name = msg.pSender->GetName();
  294. COptionUI* curOption = static_cast<COptionUI*>(msg.pSender);
  295. std::wstring groupname = curOption->GetGroup();
  296. if (groupname == L"aixuexi_page_foodtype")
  297. {
  298. //商品分类切换
  299. CFoodtypeOptionUI* typeUI = static_cast<CFoodtypeOptionUI*>(curOption);
  300. std::string id = typeUI->GetTypeId();
  301. if (m_cur_type_id != id)
  302. {
  303. //切换了商品分类
  304. m_curFoodtypeOption->SetBkColor(0xFFECECEC);
  305. msg.pSender->SetBkColor(0xFF3CB371);
  306. m_curFoodtypeOption = static_cast<CControlUI*>(msg.pSender);
  307. m_cur_type_id = id;
  308. this->InitFoodShow();
  309. return;
  310. }
  311. }
  312. }
  313. void CAIxuexiPageUI::HandleItemSelectMsg(TNotifyUI& msg)
  314. {
  315. }
  316. void CAIxuexiPageUI::HandleTextChangedMsg(TNotifyUI& msg)
  317. {
  318. CDuiString name = msg.pSender->GetName();
  319. if (name == L"aixuexi_page_food_search_edit")
  320. {
  321. //商品搜索框的输入事件
  322. CEditUI* m_pEdit = static_cast<CEditUI*>(m_pManager->FindControl(_T("aixuexi_page_food_search_edit")));
  323. std::wstring ws_Value = m_pEdit->GetText();
  324. std::string strValue = CLewaimaiString::UnicodeToUTF8(ws_Value);
  325. if (strValue.length() == 0)
  326. {
  327. //搜索词被清空了,退出搜索
  328. this->StopSerachFood();
  329. }
  330. else
  331. {
  332. //搜索词没清空,进入搜索
  333. this->StartSearchFood(strValue);
  334. }
  335. }
  336. }
  337. void CAIxuexiPageUI::HandleTextCapture(std::string content)
  338. {
  339. }
  340. bool CAIxuexiPageUI::HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  341. {
  342. if (uMsg == WM_AI_XUEXI_UPDATE)
  343. {
  344. UpdateVideoShow();
  345. }
  346. return false;
  347. }
  348. void CAIxuexiPageUI::HandleUpdateVideo()
  349. {
  350. while (true)
  351. {
  352. if (m_pMainWnd->GetCurPageName() != CMainWnd::AIXUEXI)
  353. {
  354. Sleep(30);
  355. continue;
  356. }
  357. cv::Mat img;
  358. CVideoCaptureWorker::GetInstance()->GetFrame(img);
  359. if (img.empty())
  360. {
  361. Sleep(30);
  362. continue;
  363. }
  364. if (img.type() != CV_8UC3)
  365. {
  366. // 仅支持 3 通道彩色图像
  367. cvtColor(img, img, cv::COLOR_GRAY2BGR);
  368. }
  369. //缩放尺寸,适合在界面上展示,过大过小都不好看,这个尺寸是根据界面上image控件的大小来定的,可以根据实际情况调整
  370. cv::resize(img, img, cv::Size(400, 300), 0, 0, cv::INTER_LINEAR);
  371. // 创建或更新位图
  372. HDC hDC = GetDC(NULL);
  373. if (m_hBitmap)
  374. {
  375. DeleteObject(m_hBitmap);
  376. }
  377. BITMAPINFO bmi = { 0 };
  378. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  379. bmi.bmiHeader.biWidth = img.cols;
  380. bmi.bmiHeader.biHeight = -img.rows; // 翻转 Y 轴(OpenCV 与 GDI 坐标方向相反)
  381. bmi.bmiHeader.biPlanes = 1;
  382. bmi.bmiHeader.biBitCount = 24;
  383. bmi.bmiHeader.biCompression = BI_RGB;
  384. m_hBitmap = CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT, img.data, &bmi, DIB_RGB_COLORS);
  385. ReleaseDC(NULL, hDC);
  386. ::PostMessage(m_pMainWnd->GetHWND(), WM_AI_XUEXI_UPDATE, 0, 0);
  387. // 控制帧率,避免过度占用 CPU,30 FPS 大约是每 33 毫秒更新一次
  388. Sleep(1000 / 30);
  389. }
  390. }
  391. void CAIxuexiPageUI::UpdateVideoShow()
  392. {
  393. HDC hDC = m_pManager->GetPaintDC();
  394. if (!m_hMemDC)
  395. {
  396. m_hMemDC = CreateCompatibleDC(hDC);
  397. }
  398. HBITMAP hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);
  399. BITMAP bm;
  400. GetObject(m_hBitmap, sizeof(BITMAP), &bm);
  401. CControlUI* pImage = static_cast<CControlUI*>(this->FindSubControl(_T("image")));
  402. if (!pImage)
  403. {
  404. return;
  405. }
  406. RECT imageRect = pImage->GetPos();
  407. StretchBlt(hDC, imageRect.left, imageRect.top, imageRect.right - imageRect.left,
  408. imageRect.bottom - imageRect.top, m_hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  409. SelectObject(m_hMemDC, hOldBitmap);
  410. return;
  411. }
  412. void CAIxuexiPageUI::ClickFoodAction()
  413. {
  414. //点击普通商品之后的处理逻辑
  415. CLabelUI* pLabel = static_cast<CLabelUI*>(this->FindSubControl(_T("aixuexi_page_xuanzhong_food_name")));
  416. std::string sName = m_cur_click_food_item->GetFoodInfo().name;
  417. std::wstring wsShow = L"当前选中商品:" + CLewaimaiString::UTF8ToUnicode(sName);
  418. pLabel->SetText(wsShow.c_str());
  419. //加载这个商品当前已经学习过的图片,并显示出来
  420. this->UpdatCurFoodXuexiShow();
  421. }
  422. //开始搜索某个商品名字
  423. void CAIxuexiPageUI::StartSearchFood(std::string foodname)
  424. {
  425. //展示删除按钮
  426. CButtonUI* pClear = static_cast<CButtonUI*>(this->FindSubControl(_T("aixuexi_page_food_search_clear")));
  427. pClear->SetVisible(true);
  428. //隐藏商品分类展示
  429. CVerticalLayoutUI* pFoodtype = static_cast<CVerticalLayoutUI*>(this->FindSubControl(_T("aixuexi_page_fenlei_layout_scrolllayout")));
  430. pFoodtype->SetVisible(false);
  431. if (m_cur_type_id != "sousuo")
  432. {
  433. m_type_id_before_sousuo = m_cur_type_id;
  434. }
  435. m_cur_type_id = "sousuo";
  436. m_sousuo_foodname = foodname;
  437. CLabelUI* pTishi = static_cast<CLabelUI*>(this->FindSubControl(_T("aixuexi_page_food_search_tishi")));
  438. pTishi->SetVisible(false);
  439. this->InitFoodShow();
  440. }
  441. //停止搜索商品
  442. void CAIxuexiPageUI::StopSerachFood()
  443. {
  444. //隐藏删除按钮
  445. CButtonUI* pClear = static_cast<CButtonUI*>(this->FindSubControl(_T("aixuexi_page_food_search_clear")));
  446. pClear->SetVisible(false);
  447. //展示商品分类展示
  448. CVerticalLayoutUI* pFoodtype = static_cast<CVerticalLayoutUI*>(this->FindSubControl(_T("aixuexi_page_fenlei_layout_scrolllayout")));
  449. pFoodtype->SetVisible(true);
  450. m_cur_type_id = m_type_id_before_sousuo;
  451. CLabelUI* pTishi = static_cast<CLabelUI*>(this->FindSubControl(_T("aixuexi_page_food_search_tishi")));
  452. pTishi->SetVisible(true);
  453. this->InitFoodShow();
  454. }
  455. void CAIxuexiPageUI::SetPos(RECT rc, bool bNeedInvalidate)
  456. {
  457. m_nPageWidth = rc.right - rc.left;
  458. //更新分类位置
  459. UpdateFoodtypePos();
  460. CContainerUI::SetPos(rc, bNeedInvalidate);
  461. }
  462. void CAIxuexiPageUI::DoXuexi()
  463. {
  464. if (m_cur_click_food_item == NULL)
  465. {
  466. m_pMainWnd->ShowToast(L"请先选择一个商品");
  467. return;
  468. }
  469. //第一步先把当前帧保存为图片
  470. std::wstring save_path = CSystem::GetTmpDir() + L"\\ai_xuexi_image";
  471. if (!CSystem::IsPathExist(save_path))
  472. {
  473. CSystem::CreateMultiLevel(CLewaimaiString::UnicodeToUTF8(save_path));
  474. }
  475. std::string filename = CLewaimaiString::generateRandomStr(32);
  476. std::wstring file_save_path = save_path + L"\\" + CLewaimaiString::UTF8ToUnicode(filename) + L".jpg";
  477. std::string s_file_save_path = CLewaimaiString::UnicodeToUTF8(file_save_path);
  478. cv::Mat img;
  479. CVideoCaptureWorker::GetInstance()->GetFrame(img);
  480. if (img.empty())
  481. {
  482. return;
  483. }
  484. if (img.type() != CV_8UC3)
  485. {
  486. // 仅支持 3 通道彩色图像
  487. cvtColor(img, img, cv::COLOR_GRAY2BGR);
  488. }
  489. cv::imwrite(CLewaimaiString::UnicodeToUTF8(file_save_path), img);
  490. //第二步把这个图片的特征向量提取出来,保存到数据库里,关联到当前选中的商品上
  491. std::cout << "开始提取图库图片特征..." << std::endl;
  492. std::vector<float> features = YoloFeatureManager::GetInstance()->extractFeatures(s_file_save_path);
  493. if (!features.empty())
  494. {
  495. std::string sName = m_cur_click_food_item->GetFoodInfo().name;
  496. std::string sFoodId = m_cur_click_food_item->GetFoodInfo().id;
  497. SQLiteVecManager::GetInstance()->addFeatureVector(features, sFoodId, sName, filename, s_file_save_path);
  498. }
  499. //第三步把刚拍摄的图片显示出来
  500. CTileLayoutUI* pXuexiScrollLayout = static_cast<CTileLayoutUI*>(this->FindSubControl(_T("aixuexi_page_food_xuexi_image_layout")));
  501. std::string imageName = filename;
  502. std::string imagePath = s_file_save_path;
  503. CDialogBuilder builder;
  504. CDialogBuilderCallbackEx cb;
  505. CFoodXuexiImageItemUI* pItem = static_cast<CFoodXuexiImageItemUI*>(builder.Create(_T("aixuexi_page_food_xuexi_image.xml"), (UINT)0, &cb, m_pManager));
  506. pItem->SetImageName(imageName);
  507. pItem->SetImagePath(imagePath);
  508. pXuexiScrollLayout->Add(pItem);
  509. }