|
|
|
@ -1,15 +1,17 @@
|
|
|
|
|
#include "Arith_BATask.h"
|
|
|
|
|
#include "ceres/ceres.h"
|
|
|
|
|
#include "Arith_GeoSolver.h"
|
|
|
|
|
#include "math.h"
|
|
|
|
|
using namespace ceres;
|
|
|
|
|
// 定义残差结构体
|
|
|
|
|
struct HomographyResidual
|
|
|
|
|
struct HomographyResidual
|
|
|
|
|
{
|
|
|
|
|
HomographyResidual(const cv::KeyPoint& keypoint_i, const cv::KeyPoint& keypoint_j,const cv::Mat H1, const cv::Mat H2)
|
|
|
|
|
: keypoint_i_(keypoint_i), keypoint_j_(keypoint_j),H1_(H1),H2_(H2) {}
|
|
|
|
|
HomographyResidual(const cv::KeyPoint& keypoint_i, const cv::KeyPoint& keypoint_j, const cv::Mat H1, const cv::Mat H2)
|
|
|
|
|
: keypoint_i_(keypoint_i), keypoint_j_(keypoint_j), H1_(H1), H2_(H2) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
bool operator()(const T* const h_i, const T* const h_j, T* residual) const
|
|
|
|
|
bool operator()(const T* const h_i, const T* const h_j, T* residual) const
|
|
|
|
|
{
|
|
|
|
|
// 残差计算逻辑
|
|
|
|
|
T H_i[9] = { h_i[0], h_i[1], h_i[2],
|
|
|
|
@ -26,15 +28,15 @@ struct HomographyResidual
|
|
|
|
|
T P_i[3] = { T(0), T(0), T(0) };
|
|
|
|
|
T P_j[3] = { T(0), T(0), T(0) };
|
|
|
|
|
|
|
|
|
|
for (int row = 0; row < 3; row++)
|
|
|
|
|
for (int row = 0; row < 3; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < 3; col++)
|
|
|
|
|
for (int col = 0; col < 3; col++)
|
|
|
|
|
{
|
|
|
|
|
P_i[row] += H_i[row * 3 + col] * p_i[col];
|
|
|
|
|
P_j[row] += H_j[row * 3 + col] * p_j[col];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
P_i[0] /= P_i[2];
|
|
|
|
|
P_i[1] /= P_i[2];
|
|
|
|
|
P_j[0] /= P_j[2];
|
|
|
|
@ -66,69 +68,31 @@ private:
|
|
|
|
|
const cv::KeyPoint keypoint_j_; // 第 j 帧图像中的特征点
|
|
|
|
|
|
|
|
|
|
const cv::Mat H1_;
|
|
|
|
|
const cv::Mat H2_;
|
|
|
|
|
const cv::Mat H2_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BA_Task::BA_Task(GeoSolver * pGeoTrans)
|
|
|
|
|
BA_Task::BA_Task(FileCache<FrameCache>* cache)
|
|
|
|
|
{
|
|
|
|
|
_GeoStitcher = pGeoTrans;
|
|
|
|
|
_cache = cache;
|
|
|
|
|
_FeaMatcher = new FeatureMatcher(DetectorType::SIFT, MatcherType::FLANN);
|
|
|
|
|
_imgVec.reserve(100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BA_Task::~BA_Task()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SINT32 BA_Task::addFrame(GD_VIDEO_FRAME_S img, FrameInfo para)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat frame = Mat(img.u32Height, img.u32Width, CV_8UC1, (void*)img.u64VirAddr[0]);
|
|
|
|
|
|
|
|
|
|
// 缓存图像帧
|
|
|
|
|
if (img.enPixelFormat == GD_PIXEL_FORMAT_E::GD_PIXEL_FORMAT_GRAY_Y8)
|
|
|
|
|
{
|
|
|
|
|
_imgVec.emplace_back(frame.clone());
|
|
|
|
|
}
|
|
|
|
|
// 缓存外参
|
|
|
|
|
_paraVec.push_back(para);
|
|
|
|
|
|
|
|
|
|
// 缓存初始H
|
|
|
|
|
auto H = _GeoStitcher->findHomography(para);
|
|
|
|
|
_origMatrix.push_back(H.clone());
|
|
|
|
|
_currMatrix.push_back(H.clone());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 提取特征点
|
|
|
|
|
std::vector<cv::KeyPoint> keypoints;
|
|
|
|
|
cv::Mat descriptors;
|
|
|
|
|
_FeaMatcher->extractFeatures(frame,keypoints,descriptors);
|
|
|
|
|
_FeaPtVec.push_back(keypoints);
|
|
|
|
|
_FeaDespVec.push_back(descriptors);
|
|
|
|
|
|
|
|
|
|
// 缓存包围多边形
|
|
|
|
|
_polygon.push_back(warpRectWithH(H,cv::Size(img.u32Width,img.u32Height)));
|
|
|
|
|
|
|
|
|
|
return _imgVec.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//void BA_Task::setPanPara(PanInfo info)
|
|
|
|
|
//{
|
|
|
|
|
// _panPara = info;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//#define SHOW_MATCH
|
|
|
|
|
void BA_Task::optimizeBA(cv::Mat H_pan)
|
|
|
|
|
void BA_Task::OptFrame(vector<KeyType> frameInd,cv::Mat H_map)
|
|
|
|
|
{
|
|
|
|
|
// 读取帧信息
|
|
|
|
|
readFrameInfo(frameInd);
|
|
|
|
|
|
|
|
|
|
// 邻接关系计算
|
|
|
|
|
CalMatchMat();
|
|
|
|
|
|
|
|
|
|
//remap(_origMatrix, H_pan, "_origMatrix");
|
|
|
|
|
|
|
|
|
|
// 计算匹配性矩阵
|
|
|
|
|
CalMatchMat(0.3);
|
|
|
|
|
// 开始BA
|
|
|
|
|
|
|
|
|
|
google::InitGoogleLogging("ceres");
|
|
|
|
|
|
|
|
|
@ -154,36 +118,7 @@ void BA_Task::optimizeBA(cv::Mat H_pan)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
#ifdef SHOW_MATCH
|
|
|
|
|
cv::Mat image(1000, 1000, CV_8UC3, cv::Scalar(0, 0, 0));
|
|
|
|
|
cv::Mat imagetmp(1000, 1000, CV_8UC3, cv::Scalar(0, 0, 0));
|
|
|
|
|
vector<vector<cv::Point2f>> tmpPoly;
|
|
|
|
|
tmpPoly.push_back(_polygon[i]);
|
|
|
|
|
tmpPoly.push_back(_polygon[j]);
|
|
|
|
|
|
|
|
|
|
cv::warpPerspective(_imgVec[i], imagetmp, _origMatrix[i], imagetmp.size());
|
|
|
|
|
|
|
|
|
|
// 生成遮罩(全白图像,表示有效区域)
|
|
|
|
|
cv::Mat mask1 = cv::Mat::ones(_imgVec[i].size(), CV_8UC1) * 255;
|
|
|
|
|
cv::Mat warped_mask1;
|
|
|
|
|
cv::warpPerspective(mask1, warped_mask1, _origMatrix[i], image.size());
|
|
|
|
|
|
|
|
|
|
imagetmp.copyTo(image, warped_mask1);
|
|
|
|
|
|
|
|
|
|
cv::warpPerspective(_imgVec[j], imagetmp, _origMatrix[j], imagetmp.size());
|
|
|
|
|
cv::Mat mask2 = cv::Mat::ones(_imgVec[i].size(), CV_8UC1) * 255;
|
|
|
|
|
cv::Mat warped_mask2;
|
|
|
|
|
cv::warpPerspective(mask2, warped_mask2, _origMatrix[j], image.size());
|
|
|
|
|
|
|
|
|
|
imagetmp.copyTo(image, warped_mask2);
|
|
|
|
|
|
|
|
|
|
drawPolygons(image, tmpPoly);
|
|
|
|
|
|
|
|
|
|
// 显示绘制结果
|
|
|
|
|
cv::imshow("Polygons", image);
|
|
|
|
|
cv::waitKey(1);
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
std::vector<cv::DMatch> matches;
|
|
|
|
|
//_FeaMatcher->matchFeatures(_FeaDespVec[i],_FeaDespVec[j],matches);
|
|
|
|
|
_FeaMatcher->matchFeatures_WithH(_FeaPtVec[i], _FeaDespVec[i], _FeaPtVec[j], _FeaDespVec[j], _origMatrix[i], _origMatrix[j], matches);
|
|
|
|
@ -199,27 +134,14 @@ void BA_Task::optimizeBA(cv::Mat H_pan)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SHOW_MATCH
|
|
|
|
|
// 可视化匹配结果
|
|
|
|
|
cv::Mat img_matches;
|
|
|
|
|
cv::drawMatches(
|
|
|
|
|
_imgVec[i], _FeaPtVec[i], // 第一幅图像及其特征点
|
|
|
|
|
_imgVec[j], _FeaPtVec[j], // 第二幅图像及其特征点
|
|
|
|
|
matches, // 匹配结果
|
|
|
|
|
img_matches, // 输出图像
|
|
|
|
|
cv::Scalar::all(-1), // 匹配线颜色(默认随机颜色)
|
|
|
|
|
cv::Scalar::all(-1), // 未匹配点颜色(默认不绘制)
|
|
|
|
|
std::vector<char>(), // 掩码(可选,用于筛选匹配)
|
|
|
|
|
cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS // 不绘制未匹配的点
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
cv::resize(img_matches, img_matches, cv::Size(1280, 512));
|
|
|
|
|
|
|
|
|
|
// 显示匹配结果
|
|
|
|
|
cv::imshow("Feature Matches", img_matches);
|
|
|
|
|
cv::waitKey(0);
|
|
|
|
|
// 绘制匹配结果
|
|
|
|
|
drawMatch(i, j, matches, H_map);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 添加匹配点对的残差块
|
|
|
|
|
for (int m = 0; m < matches.size(); m++)
|
|
|
|
|
{
|
|
|
|
@ -230,17 +152,17 @@ void BA_Task::optimizeBA(cv::Mat H_pan)
|
|
|
|
|
|
|
|
|
|
ceres::LossFunction* loss_function = new ceres::HuberLoss(35);
|
|
|
|
|
|
|
|
|
|
cv::Mat H1 = _origMatrix[i];
|
|
|
|
|
cv::Mat H1 = _origMatrix[i];
|
|
|
|
|
cv::Mat H2 = _origMatrix[j];
|
|
|
|
|
|
|
|
|
|
ceres::CostFunction* cost_function =
|
|
|
|
|
new ceres::AutoDiffCostFunction<HomographyResidual, 4, 8, 8>(
|
|
|
|
|
new HomographyResidual(keypoint_i, keypoint_j,H1,H2));
|
|
|
|
|
new HomographyResidual(keypoint_i, keypoint_j, H1, H2));
|
|
|
|
|
problem.AddResidualBlock(cost_function, loss_function, h_list[i], h_list[j]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nParaCnt += matches.size();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -258,50 +180,96 @@ void BA_Task::optimizeBA(cv::Mat H_pan)
|
|
|
|
|
// 求解
|
|
|
|
|
ceres::Solve(options, &problem, &summary);
|
|
|
|
|
|
|
|
|
|
//// 将优化后的参数转换回 cv::Mat
|
|
|
|
|
for (int i = 0; i < _currMatrix.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "------------" << std::endl;
|
|
|
|
|
std::cout << _origMatrix[i] << std::endl;
|
|
|
|
|
std::cout << _currMatrix[i] << std::endl;
|
|
|
|
|
std::cout << "------------" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
//for (int i = 0; i < _currMatrix.size(); i++)
|
|
|
|
|
//{
|
|
|
|
|
// std::cout << "------------" << std::endl;
|
|
|
|
|
// std::cout << _origMatrix[i] << std::endl;
|
|
|
|
|
// std::cout << _currMatrix[i] << std::endl;
|
|
|
|
|
// std::cout << "------------" << std::endl;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
// 输出结果
|
|
|
|
|
std::cout << summary.BriefReport() << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remap(_currMatrix, H_pan, "_currMatrix");
|
|
|
|
|
// 写入缓存
|
|
|
|
|
writeFrameInfo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cv::waitKey(0);
|
|
|
|
|
bool BA_Task::updateCacheH(KeyType Key, cv::Mat H)
|
|
|
|
|
{
|
|
|
|
|
auto _t_frame_cache = std::make_shared<FrameCache>();
|
|
|
|
|
|
|
|
|
|
if (_cache->get(Key, _t_frame_cache))
|
|
|
|
|
{
|
|
|
|
|
// 更新H
|
|
|
|
|
memcpy(_t_frame_cache->H, H.data, sizeof(double) * 9);
|
|
|
|
|
// 存储
|
|
|
|
|
_cache->set(Key, _t_frame_cache);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BA_Task::remap(vector<cv::Mat_<double>> H_Vec, cv::Mat_<double > H_pan, std::string winname)
|
|
|
|
|
int BA_Task::readFrameInfo(vector<KeyType> frameInd)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat image(1500, 1500, CV_8UC3, cv::Scalar(0, 0, 0));
|
|
|
|
|
auto _t_frame_cache = std::make_shared<FrameCache>();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < _imgVec.size(); i++)
|
|
|
|
|
for (size_t i = 0; i < frameInd.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat imagetmp(1500, 1500, CV_8UC3, cv::Scalar(0, 0, 0));
|
|
|
|
|
cv::warpPerspective(_imgVec[i], imagetmp, H_pan * H_Vec[i], imagetmp.size());
|
|
|
|
|
cv::Mat mask = cv::Mat::ones(_imgVec[i].size(), CV_8UC1) * 255;
|
|
|
|
|
cv::Mat warped_mask;
|
|
|
|
|
cv::warpPerspective(mask, warped_mask, H_pan * H_Vec[i], image.size());
|
|
|
|
|
imagetmp.copyTo(image, warped_mask);
|
|
|
|
|
}
|
|
|
|
|
KeyType key = frameInd[i];
|
|
|
|
|
if (_cache->get(key, _t_frame_cache))
|
|
|
|
|
{
|
|
|
|
|
// 记录key
|
|
|
|
|
_frameInd.push_back(key);
|
|
|
|
|
|
|
|
|
|
imshow(winname, image);
|
|
|
|
|
cv::waitKey(1);
|
|
|
|
|
// 特征点
|
|
|
|
|
vector<cv::KeyPoint> keypoints(_t_frame_cache->_pt, _t_frame_cache->_pt + _t_frame_cache->ptNum);
|
|
|
|
|
_FeaPtVec.push_back(keypoints);
|
|
|
|
|
// 描述子
|
|
|
|
|
cv::Mat descriptors(_t_frame_cache->ptNum, FEA_DES_SIZE, CV_32FC1, _t_frame_cache->_desp);
|
|
|
|
|
_FeaDespVec.push_back(descriptors);
|
|
|
|
|
// 原始外参
|
|
|
|
|
_paraVec.push_back(_t_frame_cache->_para);
|
|
|
|
|
|
|
|
|
|
// 初始H
|
|
|
|
|
cv::Mat H = cv::Mat(3, 3, CV_64FC1, _t_frame_cache->H);
|
|
|
|
|
_origMatrix.push_back(H.clone());
|
|
|
|
|
_currMatrix.push_back(H.clone());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 缓存包围多边形
|
|
|
|
|
_polygon.push_back(warpRectWithH(H, cv::Size(_t_frame_cache->_frame_info.u32Width, _t_frame_cache->_frame_info.u32Height)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SHOW_MATCH
|
|
|
|
|
// 读取图像
|
|
|
|
|
cv::Mat img = cv::Mat(_t_frame_cache->_frame_info.u32Height, _t_frame_cache->_frame_info.u32Width,CV_8UC1, _t_frame_cache->_data);
|
|
|
|
|
_imgVec.push_back(img.clone());
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BA_Task::writeFrameInfo()
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < _currMatrix.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
auto Key = _frameInd[i];
|
|
|
|
|
|
|
|
|
|
// 更新缓存
|
|
|
|
|
updateCacheH(Key, _currMatrix[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#define SHOW_MATCH
|
|
|
|
|
SINT32 BA_Task::CalMatchMat(float fiou_thre)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SINT32 BA_Task::CalMatchMat()
|
|
|
|
|
{
|
|
|
|
|
_IOUMat = cv::Mat::zeros(_polygon.size(),_polygon.size(),CV_32FC1);
|
|
|
|
|
_IOUMat = cv::Mat::zeros(_polygon.size(), _polygon.size(), CV_32FC1);
|
|
|
|
|
|
|
|
|
|
_MatchMat = cv::Mat::zeros(_polygon.size(), _polygon.size(), CV_32SC1);
|
|
|
|
|
|
|
|
|
@ -315,29 +283,79 @@ SINT32 BA_Task::CalMatchMat(float fiou_thre)
|
|
|
|
|
{
|
|
|
|
|
if (i == j)
|
|
|
|
|
{
|
|
|
|
|
_IOUMat.at<float>(i,j) = 1;
|
|
|
|
|
_IOUMat.at<float>(i, j) = 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
vector<cv::Point2f> poly_j = _polygon[j];
|
|
|
|
|
|
|
|
|
|
float fiou = computeQuadrilateralIOU(poly_i,poly_j);
|
|
|
|
|
_IOUMat.at<float>(i,j) = fiou;
|
|
|
|
|
_IOUMat.at<float>(j,i) = fiou;//是对称矩阵
|
|
|
|
|
|
|
|
|
|
float fiou = computeQuadrilateralIOU(poly_i, poly_j);
|
|
|
|
|
_IOUMat.at<float>(i, j) = fiou;
|
|
|
|
|
_IOUMat.at<float>(j, i) = fiou;//是对称矩阵
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BA_Task::drawMatch(int i, int j, std::vector<cv::DMatch> matches, cv::Mat H_map)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat image(1000, 1000, CV_8UC3, cv::Scalar(0, 0, 0));
|
|
|
|
|
cv::Mat imagetmp(1000, 1000, CV_8UC3, cv::Scalar(0, 0, 0));
|
|
|
|
|
vector<vector<cv::Point2f>> tmpPoly;
|
|
|
|
|
tmpPoly.push_back(_polygon[i]);
|
|
|
|
|
tmpPoly.push_back(_polygon[j]);
|
|
|
|
|
|
|
|
|
|
cv::warpPerspective(_imgVec[i], imagetmp, H_map * _origMatrix[i], imagetmp.size());
|
|
|
|
|
|
|
|
|
|
// 生成遮罩(全白图像,表示有效区域)
|
|
|
|
|
cv::Mat mask1 = cv::Mat::ones(_imgVec[i].size(), CV_8UC1) * 255;
|
|
|
|
|
cv::Mat warped_mask1;
|
|
|
|
|
cv::warpPerspective(mask1, warped_mask1, H_map * _origMatrix[i], image.size());
|
|
|
|
|
|
|
|
|
|
imagetmp.copyTo(image, warped_mask1);
|
|
|
|
|
|
|
|
|
|
cv::warpPerspective(_imgVec[j], imagetmp, H_map * _origMatrix[j], imagetmp.size());
|
|
|
|
|
cv::Mat mask2 = cv::Mat::ones(_imgVec[i].size(), CV_8UC1) * 255;
|
|
|
|
|
cv::Mat warped_mask2;
|
|
|
|
|
cv::warpPerspective(mask2, warped_mask2, H_map * _origMatrix[j], image.size());
|
|
|
|
|
|
|
|
|
|
imagetmp.copyTo(image, warped_mask2);
|
|
|
|
|
|
|
|
|
|
drawPolygons(image, tmpPoly);
|
|
|
|
|
|
|
|
|
|
// 显示绘制结果
|
|
|
|
|
cv::imshow("Polygons", image);
|
|
|
|
|
cv::waitKey(1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 可视化匹配结果
|
|
|
|
|
cv::Mat img_matches;
|
|
|
|
|
cv::drawMatches(
|
|
|
|
|
_imgVec[i], _FeaPtVec[i], // 第一幅图像及其特征点
|
|
|
|
|
_imgVec[j], _FeaPtVec[j], // 第二幅图像及其特征点
|
|
|
|
|
matches, // 匹配结果
|
|
|
|
|
img_matches, // 输出图像
|
|
|
|
|
cv::Scalar::all(-1), // 匹配线颜色(默认随机颜色)
|
|
|
|
|
cv::Scalar::all(-1), // 未匹配点颜色(默认不绘制)
|
|
|
|
|
std::vector<char>(), // 掩码(可选,用于筛选匹配)
|
|
|
|
|
cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS // 不绘制未匹配的点
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
cv::resize(img_matches, img_matches, cv::Size(1280, 512));
|
|
|
|
|
|
|
|
|
|
// 显示匹配结果
|
|
|
|
|
cv::imshow("Feature Matches", img_matches);
|
|
|
|
|
cv::waitKey(0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 函数:绘制多边形
|
|
|
|
|
void drawPolygons(cv::Mat& image, const std::vector<std::vector<cv::Point2f>>& polygons)
|
|
|
|
|
void drawPolygons(cv::Mat& image, const std::vector<std::vector<cv::Point2f>>& polygons)
|
|
|
|
|
{
|
|
|
|
|
// 定义颜色列表
|
|
|
|
|
std::vector<cv::Scalar> colors = {
|
|
|
|
|