【opencv】 报错:C2065 “CV_COVAR_ROWS”、“CV_COVAR_NORMAL”、“CV_COVAR_SCALE”: 未声明的标识符、

在使用VS2019调试基于OpenCV4.5.2的GitHub项目时,遇到了C2065等编译错误,这些错误提示未声明'CV_COVAR_ROWS'、'CV_COVAR_NORMAL'、'CV_COVAR_SCALE'等标识符,并指出'cv::calcCovarMatrix'函数缺少参数。解决方法是在源代码中引入头文件#include<opencv2/highgui/highgui_c.h>,以包含缺失的定义。

笔者这几天配置了VS2019+opencv4.5.2,调试GitHub上一个程序时遇到如下问题:
错误 C2065 “CV_COVAR_ROWS”: 未声明的标识符
错误 C2065 “CV_COVAR_NORMAL”: 未声明的标识符
错误 C2065 “CV_COVAR_SCALE”: 未声明的标识符
错误 C2661 “cv::calcCovarMatrix”: 没有重载函数接受 3 个参数
解决方法:在代码开头加入头文件#include <opencv2/highgui/highgui_c.h>

#include "mainwindow.h" #include "ui_mainwindow.h" #include <QFileDialog> #include <QMessageBox> #include <opencv2/opencv.hpp> #include <fstream> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); setWindowTitle("核线影像匹配实验"); } MainWindow::~MainWindow() { delete ui; } // 加载左影像 void MainWindow::on_loadLeftButton_clicked() { QString filename = QFileDialog::getOpenFileName(this, "选择左核线影像", "", "图像文件 (*.png *.jpg *.bmp)"); if (!filename.isEmpty()) { leftImage = cv::imread(filename.toStdString()); cv::cvtColor(leftImage, leftGray, cv::COLOR_BGR2GRAY); cv::Mat rgb; cv::cvtColor(leftImage, rgb, cv::COLOR_BGR2RGB); QImage img(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888); ui->leftImageLabel->setPixmap(QPixmap::fromImage(img).scaled(ui->leftImageLabel->size(), Qt::KeepAspectRatio)); } } // 加载右影像 void MainWindow::on_loadRightButton_clicked() { QString filename = QFileDialog::getOpenFileName(this, "选择右核线影像", "", "图像文件 (*.png *.jpg *.bmp)"); if (!filename.isEmpty()) { rightImage = cv::imread(filename.toStdString()); cv::cvtColor(rightImage, rightGray, cv::COLOR_BGR2GRAY); cv::Mat rgb; cv::cvtColor(rightImage, rgb, cv::COLOR_BGR2RGB); QImage img(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888); ui->rightImageLabel->setPixmap(QPixmap::fromImage(img).scaled(ui->rightImageLabel->size(), Qt::KeepAspectRatio)); } } // Moravec特征点提取 void MainWindow::extractFeatures() { const int windowSize = 5; // 窗口大小 const int threshold = 5000; // 特征点阈值 leftFeatures.clear(); cv::Mat varianceMap = cv::Mat::zeros(leftGray.size(), CV_32F); // 计算每个像素的Moravec响应值 for (int y = windowSize; y < leftGray.rows - windowSize; y++) { for (int x = windowSize; x < leftGray.cols - windowSize; x++) { float minVariance = FLT_MAX; // 计算4个方向的灰度差平方和 for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { if (dx == 0 && dy == 0) continue; float sum = 0; for (int wy = -windowSize/2; wy <= windowSize/2; wy++) { for (int wx = -windowSize/2; wx <= windowSize/2; wx++) { uchar p1 = leftGray.at<uchar>(y+wy, x+wx); uchar p2 = leftGray.at<uchar>(y+wy+dy, x+wx+dx); sum += (p1 - p2)*(p1 - p2); } } if (sum < minVariance) minVariance = sum; } } varianceMap.at<float>(y, x) = minVariance; } } // 非极大值抑制提取特征点 const int nmsSize = 7; for (int y = nmsSize; y < varianceMap.rows - nmsSize; y++) { for (int x = nmsSize; x < varianceMap.cols - nmsSize; x++) { if (varianceMap.at<float>(y, x) < threshold) continue; bool isMax = true; for (int ny = -nmsSize/2; ny <= nmsSize/2 && isMax; ny++) { for (int nx = -nmsSize/2; nx <= nmsSize/2; nx++) { if (nx == 0 && ny == 0) continue; if (varianceMap.at<float>(y+ny, x+nx) >= varianceMap.at<float>(y, x)) { isMax = false; break; } } } if (isMax) leftFeatures.push_back(cv::Point(x, y)); } } } // 相关系数匹配 void MainWindow::matchFeatures() { const int windowSize = 15; // 匹配窗口大小 const int searchRange = 50; // 右影像搜索范围 const double nccThreshold = 0.7; // NCC阈值 matchedPoints.clear(); matchedPoints.resize(leftFeatures.size(), cv::Point(-1, -1)); for (size_t i = 0; i < leftFeatures.size(); i++) { cv::Point p = leftFeatures[i]; cv::Rect leftROI(p.x - windowSize/2, p.y - windowSize/2, windowSize, windowSize); cv::Mat leftPatch = leftGray(leftROI).clone(); double maxNCC = -1.0; int bestX = -1; // 在右影像同一行上搜索 int startX = std::max(windowSize/2, p.x - searchRange); int endX = std::min(rightGray.cols - windowSize/2 - 1, p.x + searchRange); for (int x = startX; x <= endX; x++) { cv::Rect rightROI(x - windowSize/2, p.y - windowSize/2, windowSize, windowSize); cv::Mat rightPatch = rightGray(rightROI).clone(); // 计算NCC cv::Mat meanLeft, meanRight; cv::Mat stdDevLeft, stdDevRight; cv::meanStdDev(leftPatch, meanLeft, stdDevLeft); cv::meanStdDev(rightPatch, meanRight, stdDevRight); double covar = 0; for (int wy = 0; wy < windowSize; wy++) { for (int wx = 0; wx < windowSize; wx++) { double lVal = leftPatch.at<uchar>(wy, wx) - meanLeft.at<double>(0); double rVal = rightPatch.at<uchar>(wy, wx) - meanRight.at<double>(0); covar += lVal * rVal; } } double ncc = covar / ((stdDevLeft.at<double>(0)*stdDevRight.at<double>(0)) * windowSize*windowSize); if (ncc > maxNCC) { maxNCC = ncc; bestX = x; } } if (maxNCC > nccThreshold) { matchedPoints[i] = cv::Point(bestX, p.y); } } } // 执行匹配操作 void MainWindow::on_matchButton_clicked() { if (leftGray.empty() || rightGray.empty()) { QMessageBox::warning(this, "错误", "请先加载左右影像!"); return; } extractFeatures(); // 特征提取 matchFeatures(); // 相关系数匹配 saveMatchesToFile(); // 保存匹配结果 // 在左影像上显示特征点 cv::Mat leftDisplay = leftImage.clone(); for (const auto& p : leftFeatures) { cv::circle(leftDisplay, p, 3, cv::Scalar(0, 0, 255), -1); } cv::cvtColor(leftDisplay, leftDisplay, cv::COLOR_BGR2RGB); QImage img(leftDisplay.data, leftDisplay.cols, leftDisplay.rows, leftDisplay.step, QImage::Format_RGB888); ui->leftImageLabel->setPixmap(QPixmap::fromImage(img).scaled(ui->leftImageLabel->size(), Qt::KeepAspectRatio)); QMessageBox::information(this, "匹配完成", "特征匹配完成!同名点已保存到matches.txt"); } // 保存匹配点到文件 void MainWindow::saveMatchesToFile() { std::ofstream outFile("matches.txt"); if (!outFile) { QMessageBox::critical(this, "错误", "无法创建输出文件!"); return; } outFile << "left_x,left_y,right_x,right_y" << std::endl; for (size_t i = 0; i < leftFeatures.size(); i++) { if (matchedPoints[i].x != -1) { outFile << leftFeatures[i].x << "," << leftFeatures[i].y << "," << matchedPoints[i].x << "," << matchedPoints[i].y << std::endl; } } outFile.close(); } // 显示匹配结果 void MainWindow::on_showMatchesButton_clicked() { if (matchedPoints.empty() || leftImage.empty() || rightImage.empty()) { QMessageBox::warning(this, "错误", "请先执行匹配操作!"); return; } visualizeMatches(); } void MainWindow::visualizeMatches() { // 1. 创建合成图像(左图在上,右图在下) const int padding = 20; // 添加边距方便观察 int maxWidth = std::max(leftImage.cols, rightImage.cols) + 2*padding; int totalHeight = leftImage.rows + rightImage.rows + 3*padding; cv::Mat resultImage(totalHeight, maxWidth, CV_8UC3, cv::Scalar(40, 40, 40)); // 深灰背景 // 2. 放置图像(水平居中) int leftX = padding + (maxWidth - 2*padding - leftImage.cols)/2; int rightX = padding + (maxWidth - 2*padding - rightImage.cols)/2; int rightY = leftImage.rows + 2*padding; // 左图区域(添加边框) cv::rectangle(resultImage, cv::Rect(leftX-1, padding-1, leftImage.cols+2, leftImage.rows+2), cv::Scalar(200, 200, 200), 1); leftImage.copyTo(resultImage(cv::Rect(leftX, padding, leftImage.cols, leftImage.rows))); // 右图区域(添加边框) cv::rectangle(resultImage, cv::Rect(rightX-1, rightY-1, rightImage.cols+2, rightImage.rows+2), cv::Scalar(200, 200, 200), 1); rightImage.copyTo(resultImage(cv::Rect(rightX, rightY, rightImage.cols, rightImage.rows))); // 3. 计算坐标偏移量 cv::Point leftOffset(leftX, padding); cv::Point rightOffset(rightX, rightY); // 4. 绘制匹配点连线(添加校验和抗锯齿) for (size_t i = 0; i < leftFeatures.size(); i++) { if (matchedPoints[i].x < 0) continue; // 跳过无效点 // 计算实际绘制位置 cv::Point leftPt = leftFeatures[i] + leftOffset; cv::Point rightPt = matchedPoints[i] + rightOffset; // 校验点是否在图像区域内 cv::Rect leftROI(leftX, padding, leftImage.cols, leftImage.rows); cv::Rect rightROI(rightX, rightY, rightImage.cols, rightImage.rows); if (!leftROI.contains(leftPt - leftOffset) || !rightROI.contains(rightPt - rightOffset)) { continue; // 跳过越界点 } // ************ 新增红色连接线 ************ // 绘制红色直线连接同名点(在箭头下方) cv::line(resultImage, leftPt, rightPt, cv::Scalar(0, 0, 255), // 纯红色 (BGR格式) 3, // 线宽3像素 cv::LINE_AA); // 抗锯齿 // 绘制抗锯齿连线(带箭头指示方向)- 保持原有绿色箭头 cv::arrowedLine(resultImage, leftPt, rightPt, cv::Scalar(0, 255, 0), // 绿色箭头 2, // 线宽2像素 cv::LINE_AA, // 抗锯齿 0, // 箭头尖端无偏移 0.01); // 箭头长度比例 // 绘制同名点(使用相同颜色) cv::Scalar color = cv::Scalar( rand() % 256, rand() % 256, rand() % 256); // 随机颜色区分不同点对 cv::circle(resultImage, leftPt, 6, color, -1, cv::LINE_AA); cv::circle(resultImage, rightPt, 6, color, -1, cv::LINE_AA); // 添加点编号(显示匹配误差) double error = cv::norm(leftFeatures[i] - matchedPoints[i]); std::string label = "#" + std::to_string(i+1) + " (err:" + std::to_string(error).substr(0,4) + ")"; cv::putText(resultImage, label, leftPt + cv::Point(10, -10), cv::FONT_HERSHEY_SIMPLEX, 0.5, color, 1); } // 5. 添加参考网格(辅助视觉对齐) for (int x = 0; x < maxWidth; x += 50) { cv::line(resultImage, cv::Point(x, 0), cv::Point(x, totalHeight), cv::Scalar(100, 100, 100), 1); } for (int y = 0; y < totalHeight; y += 50) { cv::line(resultImage, cv::Point(0, y), cv::Point(maxWidth, y), cv::Scalar(100, 100, 100), 1); } // 6. 添加图例说明 cv::rectangle(resultImage, cv::Rect(10, totalHeight-100, 250, 90), cv::Scalar(80, 80, 80), -1); cv::putText(resultImage, "Legend:", cv::Point(20, totalHeight-80), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(200, 200, 0), 1); cv::putText(resultImage, "Red Line: Direct Connection", cv::Point(20, totalHeight-60), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1); cv::putText(resultImage, "Green Arrow: Matching Direction", cv::Point(20, totalHeight-40), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 1); cv::putText(resultImage, "Colored Dot: Matched Point Pair", cv::Point(20, totalHeight-20), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 255), 1); // 7. 显示结果 cv::cvtColor(resultImage, resultImage, cv::COLOR_BGR2RGB); QImage img(resultImage.data, resultImage.cols, resultImage.rows, resultImage.step, QImage::Format_RGB888); ui->resultLabel->setPixmap(QPixmap::fromImage(img).scaled( ui->resultLabel->size(), Qt::KeepAspectRatio)); }这是.cpp的代码我希望修改 void MainWindow::visualizeMatches()的代码并实现将左影像和右影像按照上下的顺序排列并连接合并后的影像上的同名点,其它代码保持不变
最新发布
10-30
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值