#include "StdAfx.h" #include "GCPGeoCorrect.h" #include "MapPrj.h" #include // 功能:空间分辨率估计(经纬度分辨率) bool CalLonLatResolution(double &LonResolution, double &LatResolution, const std::vector& GCP_XY, const std::vector& GCP_LonLat) { // 基本条件判断 if (GCP_XY.size() < 4 || GCP_LonLat.size() < 4 || GCP_XY.size() != GCP_LonLat.size()) { return false; } // 计算重心点坐标 double Center_Lon = 0.0; double Center_Lat = 0.0; double Center_x = 0.0; double Center_y = 0.0; // 控制点数目 int count = GCP_XY.size(); for (int i = 0; i < count; i++ ) { // 经纬度坐标 Center_Lon += GCP_LonLat[i].x / count; Center_Lat += GCP_LonLat[i].y / count; // 像素坐标 Center_x += GCP_XY[i].x / count; Center_y += GCP_XY[i].y / count; } // 计算各点到第一个点的距离 double Resolution = 0; for (int i = 1; i < count; i++ ) { double dis = 0; CalculateTwoPtsDistance(dis, GCP_LonLat[0].x, GCP_LonLat[0].y, GCP_LonLat[i].x, GCP_LonLat[i].y, 3); double L = cv::norm(GCP_XY[i] - GCP_XY[0]); Resolution += (dis / L); } Resolution /= (count - 1); //功能:计算目标点的经纬度 double targetPtLon = Center_Lon; double targetPtLat = Center_Lat; // 分辨率 CalculatePtCoordinate(targetPtLon, targetPtLat, Center_Lon, Center_Lat, 90, Resolution, 3); LonResolution = targetPtLon - Center_Lon; CalculatePtCoordinate(targetPtLon, targetPtLat, Center_Lon, Center_Lat, 0, Resolution, 3); LatResolution = targetPtLat - Center_Lat; return true; } // 计算线性变换系数 : A B prePoints ---> nextPoints bool CalLineTransformCoefficient(cv::Mat &A, cv::Mat &B, const std::vector& prePoints, const std::vector& nextPoints) { try { // 最少需要4对点 int size = 0; if (prePoints.size() < 4 || nextPoints.size() < 4 || prePoints.size() != nextPoints.size()) { return false; } else { size = prePoints.size(); } // 重新分配输出结果矩阵 A.create(3, 1, CV_64FC1); A = cv::Scalar(0); B.create(3, 1, CV_64FC1); B = cv::Scalar(0); // 构造输入 cv::Mat W, X, Y; W.create(size, 3, CV_64FC1); W = cv::Scalar(0); X.create(size, 1, CV_64FC1); X = cv::Scalar(0); Y.create(size, 1, CV_64FC1); Y = cv::Scalar(0); // 构造W X Y赋值 for (int i = 0; i < size; i++) { W.at(i, 0) = 1; W.at(i, 1) = prePoints[i].x; W.at(i, 2) = prePoints[i].y; X.at(i, 0) = nextPoints[i].x; Y.at(i, 0) = nextPoints[i].y; } // 计算A B // W * A = X // W * B = Y bool ret1 = cv::solve(W, X, A, CV_SVD); // 求A bool ret2 = cv::solve(W, Y, B, CV_SVD); // 求B if (ret1 == false || ret2 == false) { return false; } return true; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } // 计算二次多项式变换系数 : A B prePoints ---> nextPoints bool CalPolynomialCoefficient(cv::Mat &A, cv::Mat &B, const std::vector& prePoints, const std::vector& nextPoints) { try { // 最少需要6对点 int size = 0; if (prePoints.size() < 6 || nextPoints.size() < 6 || prePoints.size() != nextPoints.size()) { return false; } else { size = prePoints.size(); } // 重新分配输出结果矩阵 A.create(6, 1, CV_64FC1); A = cv::Scalar(0); B.create(6, 1, CV_64FC1); B = cv::Scalar(0); // 构造输入 cv::Mat W, X, Y; W.create(size, 6, CV_64FC1); W = cv::Scalar(0); X.create(size, 1, CV_64FC1); X = cv::Scalar(0); Y.create(size, 1, CV_64FC1); Y = cv::Scalar(0); // 构造W X Y赋值 for (int i = 0; i < size; i++) { W.at(i, 0) = 1; W.at(i, 1) = prePoints[i].x; W.at(i, 2) = prePoints[i].y; W.at(i, 3) = prePoints[i].x * prePoints[i].y; W.at(i, 4) = prePoints[i].x * prePoints[i].x; W.at(i, 5) = prePoints[i].y * prePoints[i].y; X.at(i, 0) = nextPoints[i].x; Y.at(i, 0) = nextPoints[i].y; } // 计算A B // W * A = X // W * B = Y bool ret1 = cv::solve(W, X, A, CV_SVD); // 求A bool ret2 = cv::solve(W, Y, B, CV_SVD); // 求B if (ret1 == false || ret2 == false) { return false; } return true; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } // 计算包含一幅图像有效区域的最小外接矩形(计算无效黑色区域) RECT GetMinEncloseRect(const cv::Mat& image) { RECT minRect; minRect.left = -1L; minRect.right = -1L; minRect.top = -1L; minRect.bottom = -1L; if (image.empty() == true) { return minRect; } else { minRect.left = 0L; minRect.right = static_cast(image.cols - 1); minRect.top = 0L; minRect.bottom = static_cast(image.rows - 1); } int type = image.type(); int i = 0, j = 0; int temp = 0; if (type == 0) // CV_8UC1 { // left for (i = 0; i < image.cols; ++i) { double count = 0; for (j = 0; j < image.rows; ++j) { temp = image.at(j, i); if (temp > 0) { break; } } if (0 == temp) { minRect.left++; } else { break; } } // 全黑 if (minRect.left == image.cols) { minRect.left = -1L; minRect.right = -1L; minRect.top = -1L; minRect.bottom = -1L; return minRect; } // right temp = 0; for (i = image.cols - 1; i > -1; --i) { for (j = 0;j < image.rows; ++j) { temp = image.at(j, i); if ( temp > 0) { break; } } if (0 == temp) { minRect.right--; } else { break; } } // top temp = 0; for (j = 0; j < image.rows; ++j) { for (i = 0; i < image.cols; ++i) { temp = image.at(j, i); if ( temp > 0 ) { break; } } if (0 == temp) { minRect.top++; } else { break; } } // bottom temp = 0; for ( j = image.rows - 1; j > -1; --j) { for (i = 0; i < image.cols; ++i) { temp = image.at(j, i); if (temp > 0) { break; } } if (0 == temp) { minRect.bottom--; } else { break; } } } else if(type == 16) // CV_8UC3 { // left for (i = 0; i < image.cols; ++i) { for (j = 0; j < image.rows; ++j) { temp = image.at(j, i)[0] + image.at(j, i)[1] + image.at(j, i)[2]; if (temp > 0) { break; } } if (0 == temp) { minRect.left++; } else { break; } } // 全黑 if (minRect.left == image.cols) { minRect.left = -1L; minRect.right = -1L; minRect.top = -1L; minRect.bottom = -1L; return minRect; } // right temp = 0; for (i = image.cols - 1; i > -1; --i) { for (j = 0;j < image.rows; ++j) { temp = image.at(j, i)[0] + image.at(j, i)[1] + image.at(j, i)[2]; if ( temp > 0) { break; } } if (0 == temp) { minRect.right--; } else { break; } } // top temp = 0; for (j = 0; j < image.rows; ++j) { for (i = 0; i < image.cols; ++i) { temp = image.at(j, i)[0] + image.at(j, i)[1] + image.at(j, i)[2]; if ( temp > 0 ) { break; } } if (0 == temp) { minRect.top++; } else { break; } } // bottom temp = 0; for ( j = image.rows - 1; j > -1; --j) { for (i = 0; i < image.cols; ++i) { temp = image.at(j, i)[0] + image.at(j, i)[1] + image.at(j, i)[2]; if (temp > 0) { break; } } if (0 == temp) { minRect.bottom--; } else { break; } } } return minRect; } // 线性变换 bool GCPGeoCorrectImgLineTransform( cv::Mat& dstImg, GeoBoundingBox& LBbox, const cv::Mat& srcImg, const std::vector& GCP_XY, const std::vector& GCP_LonLat) { try { // 指针空值判断 if (srcImg.empty() == true || GCP_XY.size() < 4 || GCP_LonLat.size() < 4 || GCP_XY.size() != GCP_LonLat.size()) { return false; } // 类型判断 if (srcImg.type() != CV_8UC1 && srcImg.type() != CV_8UC3) { return false; } // 地面控制点数目 int count = GCP_XY.size(); // 对每个GCP坐标验证 for(int i = 0; i < count; i++) { if (GCP_XY[i].x < 0 || GCP_XY[i].x > srcImg.cols - 1) { return false; } if (GCP_XY[i].y < 0 || GCP_XY[i].y > srcImg.rows - 1) { return false; } if (GCP_LonLat[i].x < -180.0F || GCP_LonLat[i].x > 180.0F) { return false; } if (GCP_LonLat[i].y < -90.0F || GCP_LonLat[i].y > 90.0F) { return false; } } // 输入图像空间分辨率估计:一个像素的经纬度分辨率 double deltaLon = 0.0; double deltaLat = 0.0; if ( false == CalLonLatResolution(deltaLon, deltaLat, GCP_XY, GCP_LonLat) ) { return false; } // 计算系数矩阵:A、B cv::Mat A, B; if (false == CalLineTransformCoefficient(A, B, GCP_XY, GCP_LonLat)) { return false; } // 图像四个顶点转换后的:经纬度坐标 cv::Point2f LeftUp, RightUp, LeftDown, RightDown; LeftUp.x = static_cast(A.at(0, 0)); LeftUp.y = static_cast(B.at(0, 0)); RightUp.x = static_cast(A.at(0, 0) + srcImg.cols * A.at(1, 0)); RightUp.y = static_cast(B.at(0, 0) + srcImg.cols * B.at(1, 0)); LeftDown.x = static_cast(A.at(0, 0) + srcImg.rows * A.at(2, 0)); LeftDown.y = static_cast(B.at(0, 0) + srcImg.rows * B.at(2, 0)); RightDown.x = static_cast(A.at(0, 0) + srcImg.cols * A.at(1, 0) + srcImg.rows * A.at(2, 0)); RightDown.y = static_cast(B.at(0, 0) + srcImg.cols * B.at(1, 0) + srcImg.rows * B.at(2, 0)); // 目标图像的边界 double Lon_min = 0.0; double Lon_max = 0.0; double Lat_min = 0.0; double Lat_max = 0.0; Lon_min = min(min(min(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x); Lon_max = max(max(max(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x); Lat_min = min(min(min(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y); Lat_max = max(max(max(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y); // 目标图像的尺寸 int dstWidth = 0; int dstHeight = 0; dstWidth = static_cast((Lon_max - Lon_min) / deltaLon); dstHeight = static_cast((Lat_max - Lat_min) / deltaLat); if (dstWidth <= 0 || dstHeight <= 0) { return false; } // 逆变换 if (false == CalLineTransformCoefficient(A, B, GCP_LonLat, GCP_XY)) { return false; } // 计算输出图像 dstImg = cv::Mat(dstHeight, dstWidth, srcImg.type()); if (dstImg.empty() == true) { return false; } dstImg = cv::Scalar(0,0,0); // 单通道 if (dstImg.type() == 0) { #pragma omp parallel for for (int x = 0; x < dstImg.cols; x++) { for (int y = 0; y < dstImg.rows; y++) { double dst_Lon = 0; double dst_Lat = 0; double src_x = 0.0; double src_y = 0.0; dst_Lon = Lon_min + x * deltaLon; dst_Lat = Lat_max - y * deltaLat; src_x = A.at(0, 0) + (dst_Lon) * A.at(1, 0) + (dst_Lat) * A.at(2, 0); src_y = B.at(0, 0) + (dst_Lon) * B.at(1, 0) + (dst_Lat) * B.at(2, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (srcImg.cols - 1)) && (nearest_y <= (srcImg.rows - 1))) { dstImg.at(y, x) = srcImg.at(nearest_y, nearest_x); } } } } else // 三通道 { #pragma omp parallel for for (int x = 0; x < dstImg.cols; x++) { for (int y = 0; y < dstImg.rows; y++) { double dst_Lon = 0; double dst_Lat = 0; double src_x = 0.0; double src_y = 0.0; dst_Lon = Lon_min + x * deltaLon; dst_Lat = Lat_max - y * deltaLat; src_x = A.at(0, 0) + (dst_Lon) * A.at(1, 0) + (dst_Lat) * A.at(2, 0); src_y = B.at(0, 0) + (dst_Lon) * B.at(1, 0) + (dst_Lat) * B.at(2, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (srcImg.cols - 1)) && (nearest_y <= (srcImg.rows - 1))) { dstImg.at(y, x) = srcImg.at(nearest_y, nearest_x); } } } } RECT ValidRect = GetMinEncloseRect(dstImg); if (ValidRect.left >= 0 && ValidRect.right >= 0 && ValidRect.right < dstImg.cols && ValidRect.right - ValidRect.left > 0 && ValidRect.top >= 0 && ValidRect.bottom >= 0 && ValidRect.bottom < dstImg.rows && ValidRect.bottom - ValidRect.top > 0) { dstImg(cv::Range(ValidRect.top, ValidRect.bottom + 1), cv::Range(ValidRect.left, ValidRect.right + 1)).copyTo(dstImg); LBbox.WestLon = Lon_min + ValidRect.left * deltaLon; LBbox.EastLon = LBbox.WestLon + dstImg.cols * deltaLon; LBbox.NorthLat = Lat_max - ValidRect.top * deltaLat; LBbox.SouthLat = LBbox.NorthLat - dstImg.rows * deltaLat; } else { LBbox.WestLon = Lon_min; LBbox.EastLon = Lon_max; LBbox.NorthLat = Lat_max; LBbox.SouthLat = Lat_min; } return true; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } // 二次多项式变换 bool GCPGeoCorrectImgPolynomialTransform( cv::Mat& dstImg, GeoBoundingBox& LBbox, const cv::Mat& srcImg, const std::vector& GCP_XY, const std::vector& GCP_LonLat) { try { // 指针空值判断 if (srcImg.empty() == true || GCP_XY.size() < 6 || GCP_LonLat.size() < 6 || GCP_XY.size() != GCP_LonLat.size()) { return false; } // 类型判断 if (srcImg.type() != CV_8UC1 && srcImg.type() != CV_8UC3) { return false; } // 地面控制点数目 int count = GCP_XY.size(); // 对每个GCP坐标验证 for(int i = 0; i < count; i++) { if (GCP_XY[i].x < 0 || GCP_XY[i].x > srcImg.cols - 1) { return false; } if (GCP_XY[i].y < 0 || GCP_XY[i].y > srcImg.rows - 1) { return false; } if (GCP_LonLat[i].x < -180.0F || GCP_LonLat[i].x > 180.0F) { return false; } if (GCP_LonLat[i].y < -90.0F || GCP_LonLat[i].y > 90.0F) { return false; } } // 输入图像空间分辨率估计:一个像素的经纬度分辨率 double deltaLon = 0.0; double deltaLat = 0.0; if ( false == CalLonLatResolution(deltaLon, deltaLat, GCP_XY, GCP_LonLat) ) { return false; } // 计算系数矩阵:A、B cv::Mat A, B; if (!CalPolynomialCoefficient(A, B, GCP_XY, GCP_LonLat)) { return false; } // 四个角点转换为经纬度后的坐标 cv::Point2f LeftUp, RightUp, LeftDown, RightDown; LeftUp.x = static_cast(A.at(0, 0)); LeftUp.y = static_cast(B.at(0, 0)); RightUp.x = static_cast(A.at(0, 0) + srcImg.cols * A.at(1, 0) + srcImg.cols * srcImg.cols * A.at(4, 0)); RightUp.y = static_cast(B.at(0, 0) + srcImg.cols * B.at(1, 0) + srcImg.cols * srcImg.cols * B.at(4, 0)); LeftDown.x = static_cast(A.at(0, 0) + srcImg.rows * A.at(2, 0) + srcImg.rows * srcImg.rows * A.at(5, 0)); LeftDown.y = static_cast(B.at(0, 0) + srcImg.rows * B.at(2, 0) + srcImg.rows * srcImg.rows * B.at(5, 0)); RightDown.x = static_cast(A.at(0, 0) + srcImg.cols * A.at(1, 0) + srcImg.rows * A.at(2, 0) + srcImg.cols * srcImg.rows * A.at(3, 0) + srcImg.cols * srcImg.cols * A.at(4, 0) + srcImg.rows * srcImg.rows * A.at(5, 0)); RightDown.y = static_cast(B.at(0, 0) + srcImg.cols * B.at(1, 0) + srcImg.rows * B.at(2, 0) + srcImg.cols * srcImg.rows * B.at(3, 0) + srcImg.cols * srcImg.cols * B.at(4, 0) + srcImg.rows * srcImg.rows * B.at(5, 0)); // 目标图像的边界 double Lon_min = 0.0; double Lon_max = 0.0; double Lat_min = 0.0; double Lat_max = 0.0; Lon_min = min(min(min(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x); Lon_max = max(max(max(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x); Lat_min = min(min(min(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y); Lat_max = max(max(max(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y); // 目标图像的尺寸 int dstWidth = 0; int dstHeight = 0; dstWidth = static_cast((Lon_max - Lon_min) / deltaLon); dstHeight = static_cast((Lat_max - Lat_min) / deltaLat); if (dstWidth <= 0 || dstHeight <= 0) { return false; } // 逆变换 if (false == CalPolynomialCoefficient(A, B, GCP_LonLat, GCP_XY)) { return false; } // 计算输出图像 dstImg = cv::Mat(dstHeight, dstWidth, srcImg.type()); if (dstImg.empty() == true) { return false; } dstImg = cv::Scalar(0,0,0); // 单通道 if (dstImg.type() == 0) { #pragma omp parallel for for (int x = 0; x < dstImg.cols; x++) { for (int y = 0; y < dstImg.rows; y++) { double dst_Lon = 0; double dst_Lat = 0; double src_x = 0.0; double src_y = 0.0; dst_Lon = Lon_min + x * deltaLon; dst_Lat = Lat_max - y * deltaLat; src_x = A.at(0, 0) + (dst_Lon) * A.at(1, 0) + (dst_Lat) * A.at(2, 0) + (dst_Lon) * (dst_Lat) * A.at(3, 0) + (dst_Lon) * (dst_Lon) * A.at(4, 0) + (dst_Lat) * (dst_Lat) * A.at(5, 0); src_y = B.at(0, 0) + (dst_Lon) * B.at(1, 0) + (dst_Lat) * B.at(2, 0) + (dst_Lon) * (dst_Lat) * B.at(3, 0) + (dst_Lon) * (dst_Lon) * B.at(4, 0) + (dst_Lat) * (dst_Lat) * B.at(5, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (srcImg.cols - 1)) && (nearest_y <= (srcImg.rows - 1))) { dstImg.at(y, x) = srcImg.at(nearest_y, nearest_x); } } } } else // 三通道 { #pragma omp parallel for for (int x = 0; x < dstImg.cols; x++) { for (int y = 0; y < dstImg.rows; y++) { double dst_Lon = 0; double dst_Lat = 0; double src_x = 0.0; double src_y = 0.0; dst_Lon = Lon_min + x * deltaLon; dst_Lat = Lat_max - y * deltaLat; src_x = A.at(0, 0) + (dst_Lon) * A.at(1, 0) + (dst_Lat) * A.at(2, 0) + (dst_Lon) * (dst_Lat) * A.at(3, 0) + (dst_Lon) * (dst_Lon) * A.at(4, 0) + (dst_Lat) * (dst_Lat) * A.at(5, 0); src_y = B.at(0, 0) + (dst_Lon) * B.at(1, 0) + (dst_Lat) * B.at(2, 0) + (dst_Lon) * (dst_Lat) * B.at(3, 0) + (dst_Lon) * (dst_Lon) * B.at(4, 0) + (dst_Lat) * (dst_Lat) * B.at(5, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (srcImg.cols - 1)) && (nearest_y <= (srcImg.rows - 1))) { dstImg.at(y, x) = srcImg.at(nearest_y, nearest_x); } } } } RECT ValidRect = GetMinEncloseRect(dstImg); if (ValidRect.left >= 0 && ValidRect.right >= 0 && ValidRect.right < dstImg.cols && ValidRect.right - ValidRect.left > 0 && ValidRect.top >= 0 && ValidRect.bottom >= 0 && ValidRect.bottom < dstImg.rows && ValidRect.bottom - ValidRect.top > 0) { dstImg(cv::Range(ValidRect.top, ValidRect.bottom + 1), cv::Range(ValidRect.left, ValidRect.right + 1)).copyTo(dstImg); LBbox.WestLon = Lon_min + ValidRect.left * deltaLon; LBbox.EastLon = LBbox.WestLon + dstImg.cols * deltaLon; LBbox.NorthLat = Lat_max - ValidRect.top * deltaLat; LBbox.SouthLat = LBbox.NorthLat - dstImg.rows * deltaLat; } else { LBbox.WestLon = Lon_min; LBbox.EastLon = Lon_max; LBbox.NorthLat = Lat_max; LBbox.SouthLat = Lat_min; return false; } return true; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } //功能:OpenCV图像格式基于地面控制点的几何精校正 //输入: 1. srcImg 输入图像数据 // 2. GCP_XY 控制点(像素坐标) // 3. GCP_LonLat 控制点(经纬度坐标) // 4. type: 变换类型 -1:自适应 0:线性 1:二次多项式 //输出: 1. dstImg 输出图像数据 // 2. 返回值:处理成功返回true,失败返回false bool GCPGeoCorrectImg( cv::Mat& dstImg, GeoBoundingBox& LBbox, const cv::Mat& srcImg, const std::vector& GCP_XY, const std::vector& GCP_LonLat, int type) { try { // 指针空值判断 if (srcImg.empty() == true || GCP_XY.size() < 4 || GCP_LonLat.size() < 4 || GCP_XY.size() != GCP_LonLat.size()) { return false; } // 变换类型判断 if(type != -1 && type != 0 && type != 1) { return false; } // 类型判断 if (srcImg.type() != CV_8UC1 && srcImg.type() != CV_8UC3) { return false; } if(type == 0) { // 线性变换 return GCPGeoCorrectImgLineTransform(dstImg, LBbox, srcImg, GCP_XY, GCP_LonLat); } else if(type == 1) { // 二次多项式 return GCPGeoCorrectImgPolynomialTransform(dstImg, LBbox, srcImg, GCP_XY, GCP_LonLat); } else { // 自适应计算 int count = GCP_XY.size(); if (count >= 9) // 最小要求6个,设置为9个 提高稳定度 { // 二次多项式 return GCPGeoCorrectImgPolynomialTransform(dstImg, LBbox, srcImg, GCP_XY, GCP_LonLat); } else { // 线性变换 return GCPGeoCorrectImgLineTransform(dstImg, LBbox, srcImg, GCP_XY, GCP_LonLat); } } } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } //功能:基于控制点的几何校正 //输入: 1. srcImg 输入图像数据 // 2. GCP_xy 控制点(畸变像素坐标) // 3. GCP_XY 控制点(参考图像像素坐标) //输出: 1. dstImg 输出图像数据 // 2. 返回值:处理成功返回true,失败返回false bool CPBasedImgCorrect( cv::Mat &dst, const cv::Mat &src, const std::vector& CP_xy, const std::vector& CP_XY) { try { // 输入有效性判断 if (src.empty() == true) { return false; } if (src.type() != 0 && src.type() != 16) { return false; } // 输入图像宽和高 int imgWidth = src.cols; int imgHeight = src.rows; // 控制点数目验证 if (CP_xy.size() < 4 || CP_XY.size() < 4 || CP_xy.size() != CP_XY.size()) { return false; } // 控制点数目 int size = CP_xy.size(); // 每个图像控制点验证 for(int i = 0; i < size; i++) { // 畸变图像参考点 if (CP_xy[i].x < 0 || CP_xy[i].x > imgWidth - 1) { return false; } if (CP_xy[i].y < 0 || CP_xy[i].y > imgHeight- 1) { return false; } // 参考图像控制点 if (CP_XY[i].x < 0) { return false; } if (CP_XY[i].y < 0) { return false; } } // 计算系数矩阵:A、B cv::Mat A, B; if (size >= 6) { if (false == CalPolynomialCoefficient(A, B, CP_xy, CP_XY)) { return false; } } else { if (false == CalLineTransformCoefficient(A, B, CP_xy, CP_XY)) { return false; } } // 计算输入图像四个角点转换后的坐标 cv::Point2f LeftUp, RightUp, LeftDown, RightDown; if (size >= 6) { LeftUp.x = static_cast(A.at(0, 0)); LeftUp.y = static_cast(B.at(0, 0)); RightUp.x = static_cast(A.at(0, 0) + src.cols * A.at(1, 0) + src.cols * src.cols * A.at(4, 0)); RightUp.y = static_cast(B.at(0, 0) + src.cols * B.at(1, 0) + src.cols * src.cols * B.at(4, 0)); LeftDown.x = static_cast(A.at(0, 0) + src.rows * A.at(2, 0) + src.rows * src.rows * A.at(5, 0)); LeftDown.y = static_cast(B.at(0, 0) + src.rows * B.at(2, 0) + src.rows * src.rows * B.at(5, 0)); RightDown.x = static_cast(A.at(0, 0) + src.cols * A.at(1, 0) + src.rows * A.at(2, 0) + src.cols * src.rows * A.at(3, 0) + src.cols * src.cols * A.at(4, 0) + src.rows * src.rows * A.at(5, 0)); RightDown.y = static_cast(B.at(0, 0) + src.cols * B.at(1, 0) + src.rows * B.at(2, 0) + src.cols * src.rows * B.at(3, 0) + src.cols * src.cols * B.at(4, 0) + src.rows * src.rows * B.at(5, 0)); } else { LeftUp.x = static_cast(A.at(0, 0)); LeftUp.y = static_cast(B.at(0, 0)); RightUp.x = static_cast(A.at(0, 0) + src.cols * A.at(1, 0)); RightUp.y = static_cast(B.at(0, 0) + src.cols * B.at(1, 0)); LeftDown.x = static_cast(A.at(0, 0) + src.rows * A.at(2, 0)); LeftDown.y = static_cast(B.at(0, 0) + src.rows * B.at(2, 0)); RightDown.x = static_cast(A.at(0, 0) + src.cols * A.at(1, 0) + src.rows * A.at(2, 0)); RightDown.y = static_cast(B.at(0, 0) + src.cols * B.at(1, 0) + src.rows * B.at(2, 0)); } // 目标图像的边界 int min_X = 0; int max_X = 0; int min_Y = 0; int max_Y = 0; min_X = static_cast(min(min(min(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x)); max_X = static_cast(max(max(max(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x)); min_Y = static_cast(min(min(min(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y)); max_Y = static_cast(max(max(max(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y)); // 目标图像的尺寸 int dstWidth = 0; int dstHeight = 0; dstWidth = static_cast(max_X - min_X); dstHeight = static_cast(max_Y - min_Y); // 逆变换 if (size >= 6) { if (false == CalPolynomialCoefficient(A, B, CP_XY, CP_xy)) { return false; } } else { if (false == CalLineTransformCoefficient(A, B, CP_XY, CP_xy)) { return false; } } // 计算输出图像 if (src.type() == CV_8UC1) { dst = cv::Mat(dstHeight, dstWidth, CV_8UC1); } else { dst = cv::Mat(dstHeight, dstWidth, CV_8UC3); } if (dst.empty() == true) { return false; } dst = cv::Scalar(0,0,0); // 图像重采样 if (size >= 6) // 二次多项式 { if (dst.type() == 0) { for (int x = min_X; x < max_X; x++) { for (int y = min_Y; y < max_Y; y++) { double src_x = 0.0; double src_y = 0.0; src_x = A.at(0, 0) + x * A.at(1, 0) + y * A.at(2, 0) + x * y * A.at(3, 0) + x * x * A.at(4, 0) + y * y * A.at(5, 0); src_y = B.at(0, 0) + x * B.at(1, 0) + y * B.at(2, 0) + x * y * B.at(3, 0) + x * x * B.at(4, 0) + y * y * B.at(5, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (src.cols - 1)) && (nearest_y <= (src.rows - 1))) { dst.at(y - min_Y, x - min_X) = src.at(nearest_y, nearest_x); } } } } else { for (int x = min_X; x < max_X; x++) { for (int y = min_Y; y < max_Y; y++) { double src_x = 0.0; double src_y = 0.0; src_x = A.at(0, 0) + x * A.at(1, 0) + y * A.at(2, 0) + x * y * A.at(3, 0) + x * x * A.at(4, 0) + y * y * A.at(5, 0); src_y = B.at(0, 0) + x * B.at(1, 0) + y * B.at(2, 0) + x * y * B.at(3, 0) + x * x * B.at(4, 0) + y * y * B.at(5, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (src.cols - 1)) && (nearest_y <= (src.rows - 1))) { dst.at(y - min_Y, x - min_X) = src.at(nearest_y, nearest_x); } } } } } else // 线性变换 { if (dst.type() == 0) { for (int x = min_X; x < max_X; x++) { for (int y = min_Y; y < max_Y; y++) { double src_x = 0.0; double src_y = 0.0; src_x = A.at(0, 0) + x * A.at(1, 0) + y * A.at(2, 0); src_y = B.at(0, 0) + x * B.at(1, 0) + y * B.at(2, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (src.cols - 1)) && (nearest_y <= (src.rows - 1))) { dst.at(y - min_Y, x - min_X) = src.at(nearest_y, nearest_x); } } } } else { for (int x = min_X; x < max_X; x++) { for (int y = min_Y; y < max_Y; y++) { double src_x = 0.0; double src_y = 0.0; src_x = A.at(0, 0) + x * A.at(1, 0) + y * A.at(2, 0); src_y = B.at(0, 0) + x * B.at(1, 0) + y * B.at(2, 0); // 最近邻点 int nearest_x = int(src_x + 0.5); int nearest_y = int(src_y + 0.5); if ((nearest_x >= 0) && (nearest_y >= 0) && (nearest_x <= (src.cols - 1)) && (nearest_y <= (src.rows - 1))) { dst.at(y - min_Y, x - min_X) = src.at(nearest_y, nearest_x); } } } } } RECT ValidRect = GetMinEncloseRect(dst); if (ValidRect.left >= 0 && ValidRect.right >= 0 && ValidRect.right < dst.cols && ValidRect.right - ValidRect.left > 0 && ValidRect.top >= 0 && ValidRect.bottom >= 0 && ValidRect.bottom < dst.rows && ValidRect.bottom - ValidRect.top > 0) { dst = dst(cv::Range(ValidRect.top, ValidRect.bottom), cv::Range(ValidRect.left, ValidRect.right)); } return true; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } //功能:基于地面控制点的几何精校正 bool GCPGeoCorrectImg( ImgStru *dstImg, const ImgStru *srcImg, const std::vector& GCP_XY, const std::vector& GCP_LonLat, int type) { try { // 指针空值判断 if (srcImg == NULL || dstImg == NULL) { return false; } // 输入图像有效性判断 if (srcImg->ImgWidth <= 0 || srcImg->ImgHeight <= 0 || srcImg->buff == NULL) { return false; } if (srcImg->bitcount != 8 && srcImg->bitcount != 24) { return false; } // 创建OpenCV结构输入图像 cv::Mat src; if (srcImg->bitcount == 8) { src = cv::Mat(srcImg->ImgHeight, srcImg->ImgWidth, CV_8UC1); } else { src = cv::Mat(srcImg->ImgHeight, srcImg->ImgWidth, CV_8UC3); } if (src.empty() == true) { return false; } // 数据复制 int lineByte = srcImg->ImgWidth * srcImg->bitcount / 8; unsigned int imgBufSize = static_cast(srcImg->ImgHeight * lineByte); memcpy(src.data, srcImg->buff, imgBufSize); // 创建输出图像 cv::Mat dst; if (GCPGeoCorrectImg(dst, dstImg->BoundingBox, src, GCP_XY, GCP_LonLat, type) == false) { return false; } // 数据复制 SAFE_DELETE_ARRAY(dstImg->buff); // 属性赋值 dstImg->ImgWidth = dst.cols; dstImg->ImgHeight = dst.rows; dstImg->bitcount = srcImg->bitcount; lineByte = (dst.cols * (dstImg->bitcount / 8)); imgBufSize = static_cast(dst.rows * lineByte); dstImg->buff = new unsigned char[imgBufSize]; if (dstImg->buff == NULL) { return false; } memcpy(dstImg->buff, dst.data, imgBufSize); return true; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } }