#include <iostream>
#include <fstream>
#include <vector>
#include <regex>
#include <opencv2/opencv.hpp>
#include <exiv2/exiv2.hpp>
using namespace std;
using namespace cv;
// 结构体存储时间信息
struct DateTime {
int hour;
int minute;
int second;
};
// 从图像EXIF提取时间
DateTime getExifTime(const string& imgPath) {
DateTime imgTime = { 0,0,0 };
try {
auto image = Exiv2::ImageFactory::open(imgPath);
image->readMetadata();
auto& exifData = image->exifData();
if (exifData.empty())
throw runtime_error("No EXIF data found");
auto pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"));
if (pos == exifData.end())
throw runtime_error("DateTimeOriginal not found");
// 格式: "2025:10:23 19:43:15"
string timeStr = pos->toString().substr(11); // 取时间部分
vector<string> parts;
stringstream ss(timeStr);
string part;
while (getline(ss, part, ':')) {
parts.push_back(part);
}
if (parts.size() < 3)
throw runtime_error("Invalid time format");
imgTime.hour = stoi(parts[0]);
imgTime.minute = stoi(parts[1]);
imgTime.second = stoi(parts[2]);
}
catch (const exception& e) {
cerr << "EXIF Error: " << e.what() << endl;
}
return imgTime;
}
int main() {
// 配置路径参数
string imageFile = "C:/Users/chudemiao/Desktop/6018/af_log/AF_Log/1/debuglog10_25-2_06_37/pic/Camera/IMG_20251023_194315.jpg";
string logPath = "C:/Users/chudemiao/Desktop/6018/af_log/AF_Log/1/debuglog10_25-2_06_37/MiAFDebugLogger.log";
string savePath = "C:/Users/chudemiao/Desktop/6018/af_log/AF_Log/1/output_image.jpg";
string camera_id = "0";
// 1. 读取图像
Mat image = imread(imageFile);
if (image.empty()) {
cerr << "Error loading image: " << imageFile << endl;
return -1;
}
// 2. 提取拍摄时间
DateTime imgTime = getExifTime(imageFile);
// 3. 解析日志文件
ifstream logFile(logPath);
if (!logFile.is_open()) {
cerr << "Error opening log file: " << logPath << endl;
return -1;
}
// 关键词定义
string infaceKey = "InFaceROI_ALL:: cam_" + camera_id;
string finalfaceKey = " Process RoiHandler:: cam_" + camera_id;
string roiLeftKey = "roi_left";
string roiClass2Key = "roi_class 2";
string zoomKey = "SetupStatsGridConfig Sensor info res";
// 存储解析数据
vector<vector<double>> infaceData;
vector<vector<double>> finalfaceData;
vector<vector<double>> zoomData;
regex numPattern("-?\\d+\\.?\\d*"); // 匹配数字
string line;
while (getline(logFile, line)) {
// 检查关键词组合
bool isInface = line.find(infaceKey) != string::npos &&
line.find(roiClass2Key) != string::npos;
bool isFinalface = line.find(finalfaceKey) != string::npos &&
line.find(roiLeftKey) != string::npos;
bool isZoom = line.find(zoomKey) != string::npos;
if (!(isInface || isFinalface || isZoom)) continue;
// 提取所有数字
vector<double> numbers;
smatch matches;
string temp = line;
while (regex_search(temp, matches, numPattern)) {
numbers.push_back(stod(matches.str()));
temp = matches.suffix();
}
if (numbers.size() < 20) continue; // 确保有足够数据
// 验证时间戳匹配 [时、分、秒在索引2,3,4]
if (static_cast<int>(numbers[2]) != imgTime.hour ||
static_cast<int>(numbers[3]) != imgTime.minute ||
static_cast<int>(numbers[4]) != imgTime.second) continue;
// 存储有效数据
if (isInface) {
// 存储索引15-18 (MATLAB的16-19)
infaceData.push_back({
numbers[15], numbers[16],
numbers[17], numbers[18]
});
}
else if (isFinalface) {
finalfaceData.push_back({
numbers[15], numbers[16],
numbers[17], numbers[18]
});
}
else if (isZoom) {
// 存储索引10-15 (MATLAB的11-16)
zoomData.push_back({
numbers[10], numbers[11],
numbers[12], numbers[13],
numbers[14], numbers[15]
});
}
}
logFile.close();
// 4. 计算缩放比例
if (zoomData.empty() || infaceData.empty() || finalfaceData.empty()) {
cerr << "Insufficient log data for processing" << endl;
return -1;
}
size_t midIdx = zoomData.size() / 2;
vector<double> zoomRatio = zoomData[midIdx];
double ratio1 = zoomRatio[0] / zoomRatio[4]; // MATLAB索引5→C++索引4
double ratio2 = zoomRatio[1] / zoomRatio[5]; // MATLAB索引6→C++索引5
// 5. 坐标转换
midIdx = infaceData.size() / 2;
vector<double> rect1 = infaceData[midIdx];
rect1[0] = (rect1[0] - zoomRatio[2]) * ratio1; // x
rect1[1] = (rect1[1] - zoomRatio[3]) * ratio2; // y
rect1[2] *= ratio1; // width
rect1[3] *= ratio2; // height
midIdx = finalfaceData.size() / 2;
vector<double> rect2 = finalfaceData[midIdx];
rect2[0] = (rect2[0] - zoomRatio[2]) * ratio1;
rect2[1] = (rect2[1] - zoomRatio[3]) * ratio2;
rect2[2] *= ratio1;
rect2[3] *= ratio2;
// 6. 绘制矩形
int height = image.rows;
int width = image.cols;
if (height >= width) {
// 竖屏模式 (调整y原点)
rect1[1] = width - rect1[1] - rect1[3];
rect2[1] = width - rect2[1] - rect2[3];
// 绘制矩形 (OpenCV使用BGR)
rectangle(image,
Point(rect1[1] + 1, rect1[0] + 1),
Point(rect1[1] + rect1[3], rect1[0] + rect1[2]),
Scalar(0, 0, 255), 2); // 红色
rectangle(image,
Point(rect2[1], rect2[0]),
Point(rect2[1] + rect2[3], rect2[0] + rect2[2]),
Scalar(0, 255, 0), 2); // 绿色
}
else {
// 横屏模式
rectangle(image,
Point(rect1[0] + 1, rect1[1] + 1),
Point(rect1[0] + rect1[2], rect1[1] + rect1[3]),
Scalar(0, 0, 255), 2);
rectangle(image,
Point(rect2[0] + 1, rect2[1] + 1),
Point(rect2[0] + rect2[2], rect2[1] + rect2[3]),
Scalar(0, 255, 0), 2);
}
// 7. 保存结果
if (!imwrite(savePath, image)) {
cerr << "Failed to save image: " << savePath << endl;
return -1;
}
cout << "Processing completed. Output saved to: " << savePath << endl;
return 0;
}
这段代码报错:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK2019 无法解析的外部符号 "bool __cdecl cv::imwrite(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class cv::debug_build_guard::_InputArray const &,class std::vector<int,class std::allocator<int> > const &)" (?imwrite@cv@@YA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV_InputArray@debug_build_guard@1@AEBV?$vector@HV?$allocator@H@std@@@3@@Z),函数 main 中引用了该符号 AF_Tuning D:\CV_study\C++\AF_Tuning\face_roi.obj 1
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK2019 无法解析的外部符号 "void __cdecl cv::rectangle(class cv::debug_build_guard::_InputOutputArray const &,class cv::Point_<int>,class cv::Point_<int>,class cv::Scalar_<double> const &,int,int,int)" (?rectangle@cv@@YAXAEBV_InputOutputArray@debug_build_guard@1@V?$Point_@H@1@1AEBV?$Scalar_@N@1@HHH@Z),函数 main 中引用了该符号 AF_Tuning D:\CV_study\C++\AF_Tuning\face_roi.obj 1
最新发布