/* * @Author: your name * @Date: 2022-04-20 15:50:00 * @LastEditTime: 2025-09-13 17:12:17 * @LastEditors: xiewenji 527774126@qq.com * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp */ #include #include "ExtractInstance.h" #include #include #include #include #include #include #include ExtractInstance::ExtractInstance() { } ExtractInstance::~ExtractInstance() { } int ExtractInstance::ReadImgData(const std::string &file_path, unsigned char *&buffer, size_t *fileSize) { std::ifstream file(file_path, std::ios::binary); if (!file.is_open()) { std::cerr << "Error opening file!" << std::endl; return 1; } // 获取文件的大小 file.seekg(0, std::ios::end); size_t fileSize123 = file.tellg(); file.seekg(0, std::ios::beg); // printf("file size %d \n", fileSize); // 分配内存来存储文件内容 buffer = new unsigned char[fileSize123]; // 读取文件内容到内存 file.read(reinterpret_cast(buffer), fileSize123); file.close(); // 关闭文件 *fileSize = fileSize123; return 0; } int ExtractInstance::CalAllImgPtrDate(unsigned char *buffer, size_t fileSize, std::vector &ptrImgdataList) { int count = 0; int start = 0; // 循环提取图片,最多提取 3 张 while (count < 3) { unsigned char *ptr = buffer + start; bool found_soi = false; bool found_eoi = false; unsigned char *soi1 = nullptr; unsigned char *eoi1 = nullptr; // 寻找SOI标记(0xFF 0xD8) for (; ptr < buffer + fileSize - 1; ++ptr) { if (*ptr == 0xFF && *(ptr + 1) == 0xD8) { soi1 = ptr; found_soi = true; break; } } if (!found_soi) break; // 在找结束标志时又找到了一个 开始表示。 bool brestart = false; // 寻找EOI标记(0xFF 0xD9) for (ptr = soi1 + 2; ptr < buffer + fileSize - 1; ++ptr) { if (*ptr == 0xFF && *(ptr + 1) == 0xD9) { eoi1 = ptr + 2; // 包括EOI的结束部分 found_eoi = true; break; } // 在找结束标志时又找到了一个 开始表示。 if (*ptr == 0xFF && *(ptr + 1) == 0xD8) { eoi1 = ptr - 1; printf("error s %x %x -> %p \n ", *ptr, *(ptr + 1), ptr); brestart = true; break; } } if (brestart) { start = eoi1 - buffer; continue; } if (!found_eoi) break; size_t jpegSize = eoi1 - soi1; // 更新起始位置 start = eoi1 - buffer; JPGImgDataPtr temdata; temdata.buffer = buffer; temdata.imgDataSize = jpegSize; temdata.ptr_start = soi1; temdata.ptr_end = eoi1; ptrImgdataList.push_back(temdata); count++; } return 0; } int ExtractInstance::DecodeJpgImg(std::vector &ptrImgdataList, cv::Mat &outImg) { if (ptrImgdataList.empty()) return -1; int commonWidth = 0; int totalHeight = 0; // 第一步:读取所有头信息,检查宽度一致,累加高度 for (auto &imgData : ptrImgdataList) { tjhandle handle = tjInitDecompress(); if (!handle) { std::cerr << "tjInitDecompress failed!" << std::endl; return -2; } int jpegSubsamp = 0, jpegColorspace = 0; if (tjDecompressHeader3(handle, imgData.ptr_start, imgData.imgDataSize, &imgData.width, &imgData.height, &jpegSubsamp, &jpegColorspace) != 0) { std::cerr << "tjDecompressHeader3 error: " << tjGetErrorStr() << std::endl; tjDestroy(handle); return -3; } tjDestroy(handle); if (commonWidth == 0) commonWidth = imgData.width; else if (commonWidth != imgData.width) { std::cerr << "All images must have the same width!" << std::endl; return -4; } totalHeight += imgData.height; } // 第二步:分配大图 outImg = cv::Mat(totalHeight, commonWidth, CV_8UC1); // 第三步:多线程解码到不同位置 auto worker = [&](JPGImgDataPtr &imgData, int yOffset) { tjhandle handle = tjInitDecompress(); if (!handle) { std::cerr << "tjInitDecompress failed!" << std::endl; return; } if (tjDecompress2(handle, imgData.ptr_start, imgData.imgDataSize, outImg.ptr(yOffset), imgData.width, outImg.step, imgData.height, TJPF_GRAY, TJFLAG_FASTDCT) != 0) { std::cerr << "tjDecompress2 error: " << tjGetErrorStr() << std::endl; } tjDestroy(handle); }; std::vector threads; threads.reserve(ptrImgdataList.size()); int yOffset = 0; for (auto &imgData : ptrImgdataList) { threads.emplace_back(worker, std::ref(imgData), yOffset); yOffset += imgData.height; // 下一张图拼在下方 } for (auto &t : threads) { if (t.joinable()) t.join(); } return 0; } int ExtractInstance::ReadCELLImg(std::string strimgPath, cv::Mat &outImg, bool bdecode) { int re = -1; // 不解码模式:直接用 opencv 读取图片 if (!bdecode) { outImg = cv::imread(strimgPath, cv::IMREAD_GRAYSCALE); if (outImg.empty()) { std::cerr << "错误:无法读取图片,请检查路径是否正确!" << std::endl; return -1; } return 0; } // 解码模式: 处理 .ytimage 格式 // if(bdecode) // { // printf("ReadCELLImg========= %s \n", strimgPath.c_str()); // int re = decode_Img(strimgPath, outImg); // } // else { size_t lastSlashIndex = strimgPath.find_last_of("/"); std::string basePath; std::string pureFileName; if (lastSlashIndex != std::string::npos) { basePath = strimgPath.substr(0, lastSlashIndex); pureFileName = strimgPath.substr(lastSlashIndex + 1); } else { pureFileName = strimgPath; } // 4. 拼接出目标图片的完整路径 std::string targetImgPath; if (pureFileName.find("CA") != std::string::npos || pureFileName.find("CF") != std::string::npos) { // 如果是 CA 开头,读取 CELL_CF.jpg targetImgPath = basePath + "/CELL_CF.jpg"; } else if (pureFileName.find("TA") != std::string::npos || pureFileName.find("TFT") != std::string::npos) { // 如果是 TA 开头,读取 CELL_TFT.jpg targetImgPath = basePath + "/CELL_TFT.jpg"; } else { std::cerr << "未知文件名: " << pureFileName << std::endl; return -1; } printf("ReadCELLImg========= %s \n", targetImgPath.c_str()); outImg = cv::imread(targetImgPath, cv::IMREAD_GRAYSCALE); // 6. 检查是否成功加载 if (outImg.empty()) { std::cerr << "错误:无法读取图片,请检查路径是否正确!" << std::endl; return -1; } re = 0; } return re; } std::string ExtractInstance::GetVersion() { std::string str = ""; return str; } std::string ExtractInstance::GetErrorInfo() { std::string str = ""; return str; } bool ExtractInstance::decode_Img(const std::string &file_path, cv::Mat &img) { long t1 = getcurTime(); unsigned char *buffer = NULL; size_t fileSize; // 1、读入图片 int re = ReadImgData(file_path, buffer, &fileSize); if (re != 0 || buffer == NULL) { printf("error re %d buffer == NULL\n", re); return false; } long t2 = getcurTime(); // 2、获取图片地址指针 std::vector ptrImgdataList; re = CalAllImgPtrDate(buffer, fileSize, ptrImgdataList); if (re != 0 || ptrImgdataList.size() <= 0) { printf("error re %d size %ld \n", re, ptrImgdataList.size()); return false; } long t3 = getcurTime(); // 3、解码 jpg 图片 re = DecodeJpgImg(ptrImgdataList, img); long t4 = getcurTime(); // printf("time %ld read %ld call ptrdata %ld decode %ld\n", t4 - t1, t2 - t1, t3 - t2, t4 - t3); if (re != 0 || img.empty()) { printf("error re %d outimg.empty()\n", re); return false; } // if (true) // { // cv::imwrite("outimg_img11.png", outimg); // } // getchar(); delete[] buffer; return true; } long ExtractInstance::getcurTime() { struct timeval tv; gettimeofday(&tv, NULL); return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000; }