You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1418 lines
31 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "StdAfx.h"
#include "GCPGeoCorrect.h"
#include "MapPrj.h"
#include <omp.h>
// 功能:空间分辨率估计(经纬度分辨率)
bool CalLonLatResolution(double &LonResolution, double &LatResolution,
const std::vector<cv::Point2d>& GCP_XY,
const std::vector<cv::Point2d>& 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<cv::Point2d>& prePoints,
const std::vector<cv::Point2d>& 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<double>(i, 0) = 1;
W.at<double>(i, 1) = prePoints[i].x;
W.at<double>(i, 2) = prePoints[i].y;
X.at<double>(i, 0) = nextPoints[i].x;
Y.at<double>(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<cv::Point2d>& prePoints,
const std::vector<cv::Point2d>& 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<double>(i, 0) = 1;
W.at<double>(i, 1) = prePoints[i].x;
W.at<double>(i, 2) = prePoints[i].y;
W.at<double>(i, 3) = prePoints[i].x * prePoints[i].y;
W.at<double>(i, 4) = prePoints[i].x * prePoints[i].x;
W.at<double>(i, 5) = prePoints[i].y * prePoints[i].y;
X.at<double>(i, 0) = nextPoints[i].x;
Y.at<double>(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<LONG>(image.cols - 1);
minRect.top = 0L;
minRect.bottom = static_cast<LONG>(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<unsigned char>(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<unsigned char>(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<unsigned char>(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<unsigned char>(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<cv::Vec3b>(j, i)[0] + image.at<cv::Vec3b>(j, i)[1] + image.at<cv::Vec3b>(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<cv::Vec3b>(j, i)[0] + image.at<cv::Vec3b>(j, i)[1] + image.at<cv::Vec3b>(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<cv::Vec3b>(j, i)[0] + image.at<cv::Vec3b>(j, i)[1] + image.at<cv::Vec3b>(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<cv::Vec3b>(j, i)[0] + image.at<cv::Vec3b>(j, i)[1] + image.at<cv::Vec3b>(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<cv::Point2d>& GCP_XY, const std::vector<cv::Point2d>& 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<float>(A.at<double>(0, 0));
LeftUp.y = static_cast<float>(B.at<double>(0, 0));
RightUp.x = static_cast<float>(A.at<double>(0, 0) + srcImg.cols * A.at<double>(1, 0));
RightUp.y = static_cast<float>(B.at<double>(0, 0) + srcImg.cols * B.at<double>(1, 0));
LeftDown.x = static_cast<float>(A.at<double>(0, 0) + srcImg.rows * A.at<double>(2, 0));
LeftDown.y = static_cast<float>(B.at<double>(0, 0) + srcImg.rows * B.at<double>(2, 0));
RightDown.x = static_cast<float>(A.at<double>(0, 0) + srcImg.cols * A.at<double>(1, 0) + srcImg.rows * A.at<double>(2, 0));
RightDown.y = static_cast<float>(B.at<double>(0, 0) + srcImg.cols * B.at<double>(1, 0) + srcImg.rows * B.at<double>(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<int>((Lon_max - Lon_min) / deltaLon);
dstHeight = static_cast<int>((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<double>(0, 0) + (dst_Lon) * A.at<double>(1, 0) + (dst_Lat) * A.at<double>(2, 0);
src_y = B.at<double>(0, 0) + (dst_Lon) * B.at<double>(1, 0) + (dst_Lat) * B.at<double>(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<uchar>(y, x) = srcImg.at<uchar>(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<double>(0, 0) + (dst_Lon) * A.at<double>(1, 0) + (dst_Lat) * A.at<double>(2, 0);
src_y = B.at<double>(0, 0) + (dst_Lon) * B.at<double>(1, 0) + (dst_Lat) * B.at<double>(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<cv::Vec3b>(y, x) = srcImg.at<cv::Vec3b>(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<cv::Point2d>& GCP_XY, const std::vector<cv::Point2d>& 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<float>(A.at<double>(0, 0));
LeftUp.y = static_cast<float>(B.at<double>(0, 0));
RightUp.x = static_cast<float>(A.at<double>(0, 0) +
srcImg.cols * A.at<double>(1, 0) +
srcImg.cols * srcImg.cols * A.at<double>(4, 0));
RightUp.y = static_cast<float>(B.at<double>(0, 0) +
srcImg.cols * B.at<double>(1, 0) +
srcImg.cols * srcImg.cols * B.at<double>(4, 0));
LeftDown.x = static_cast<float>(A.at<double>(0, 0) +
srcImg.rows * A.at<double>(2, 0) +
srcImg.rows * srcImg.rows * A.at<double>(5, 0));
LeftDown.y = static_cast<float>(B.at<double>(0, 0) +
srcImg.rows * B.at<double>(2, 0) +
srcImg.rows * srcImg.rows * B.at<double>(5, 0));
RightDown.x = static_cast<float>(A.at<double>(0, 0) +
srcImg.cols * A.at<double>(1, 0) +
srcImg.rows * A.at<double>(2, 0) +
srcImg.cols * srcImg.rows * A.at<double>(3, 0) +
srcImg.cols * srcImg.cols * A.at<double>(4, 0) +
srcImg.rows * srcImg.rows * A.at<double>(5, 0));
RightDown.y = static_cast<float>(B.at<double>(0, 0) +
srcImg.cols * B.at<double>(1, 0) +
srcImg.rows * B.at<double>(2, 0) +
srcImg.cols * srcImg.rows * B.at<double>(3, 0) +
srcImg.cols * srcImg.cols * B.at<double>(4, 0) +
srcImg.rows * srcImg.rows * B.at<double>(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<int>((Lon_max - Lon_min) / deltaLon);
dstHeight = static_cast<int>((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<double>(0, 0) +
(dst_Lon) * A.at<double>(1, 0) +
(dst_Lat) * A.at<double>(2, 0) +
(dst_Lon) * (dst_Lat) * A.at<double>(3, 0) +
(dst_Lon) * (dst_Lon) * A.at<double>(4, 0) +
(dst_Lat) * (dst_Lat) * A.at<double>(5, 0);
src_y = B.at<double>(0, 0) +
(dst_Lon) * B.at<double>(1, 0) +
(dst_Lat) * B.at<double>(2, 0) +
(dst_Lon) * (dst_Lat) * B.at<double>(3, 0) +
(dst_Lon) * (dst_Lon) * B.at<double>(4, 0) +
(dst_Lat) * (dst_Lat) * B.at<double>(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<uchar>(y, x) = srcImg.at<uchar>(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<double>(0, 0) +
(dst_Lon) * A.at<double>(1, 0) +
(dst_Lat) * A.at<double>(2, 0) +
(dst_Lon) * (dst_Lat) * A.at<double>(3, 0) +
(dst_Lon) * (dst_Lon) * A.at<double>(4, 0) +
(dst_Lat) * (dst_Lat) * A.at<double>(5, 0);
src_y = B.at<double>(0, 0) +
(dst_Lon) * B.at<double>(1, 0) +
(dst_Lat) * B.at<double>(2, 0) +
(dst_Lon) * (dst_Lat) * B.at<double>(3, 0) +
(dst_Lon) * (dst_Lon) * B.at<double>(4, 0) +
(dst_Lat) * (dst_Lat) * B.at<double>(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<cv::Vec3b>(y, x) = srcImg.at<cv::Vec3b>(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<cv::Point2d>& GCP_XY, const std::vector<cv::Point2d>& 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<cv::Point2d>& CP_xy, const std::vector<cv::Point2d>& 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<float>(A.at<double>(0, 0));
LeftUp.y = static_cast<float>(B.at<double>(0, 0));
RightUp.x = static_cast<float>(A.at<double>(0, 0) +
src.cols * A.at<double>(1, 0) +
src.cols * src.cols * A.at<double>(4, 0));
RightUp.y = static_cast<float>(B.at<double>(0, 0) +
src.cols * B.at<double>(1, 0) +
src.cols * src.cols * B.at<double>(4, 0));
LeftDown.x = static_cast<float>(A.at<double>(0, 0) +
src.rows * A.at<double>(2, 0) +
src.rows * src.rows * A.at<double>(5, 0));
LeftDown.y = static_cast<float>(B.at<double>(0, 0) +
src.rows * B.at<double>(2, 0) +
src.rows * src.rows * B.at<double>(5, 0));
RightDown.x = static_cast<float>(A.at<double>(0, 0) +
src.cols * A.at<double>(1, 0) +
src.rows * A.at<double>(2, 0) +
src.cols * src.rows * A.at<double>(3, 0) +
src.cols * src.cols * A.at<double>(4, 0) +
src.rows * src.rows * A.at<double>(5, 0));
RightDown.y = static_cast<float>(B.at<double>(0, 0) +
src.cols * B.at<double>(1, 0) +
src.rows * B.at<double>(2, 0) +
src.cols * src.rows * B.at<double>(3, 0) +
src.cols * src.cols * B.at<double>(4, 0) +
src.rows * src.rows * B.at<double>(5, 0));
}
else
{
LeftUp.x = static_cast<float>(A.at<double>(0, 0));
LeftUp.y = static_cast<float>(B.at<double>(0, 0));
RightUp.x = static_cast<float>(A.at<double>(0, 0) + src.cols * A.at<double>(1, 0));
RightUp.y = static_cast<float>(B.at<double>(0, 0) + src.cols * B.at<double>(1, 0));
LeftDown.x = static_cast<float>(A.at<double>(0, 0) + src.rows * A.at<double>(2, 0));
LeftDown.y = static_cast<float>(B.at<double>(0, 0) + src.rows * B.at<double>(2, 0));
RightDown.x = static_cast<float>(A.at<double>(0, 0) + src.cols * A.at<double>(1, 0) + src.rows * A.at<double>(2, 0));
RightDown.y = static_cast<float>(B.at<double>(0, 0) + src.cols * B.at<double>(1, 0) + src.rows * B.at<double>(2, 0));
}
// 目标图像的边界
int min_X = 0;
int max_X = 0;
int min_Y = 0;
int max_Y = 0;
min_X = static_cast<int>(min(min(min(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x));
max_X = static_cast<int>(max(max(max(LeftUp.x, RightUp.x), RightDown.x), LeftDown.x));
min_Y = static_cast<int>(min(min(min(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y));
max_Y = static_cast<int>(max(max(max(LeftUp.y, RightUp.y), RightDown.y), LeftDown.y));
// 目标图像的尺寸
int dstWidth = 0;
int dstHeight = 0;
dstWidth = static_cast<int>(max_X - min_X);
dstHeight = static_cast<int>(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<double>(0, 0) +
x * A.at<double>(1, 0) +
y * A.at<double>(2, 0) +
x * y * A.at<double>(3, 0) +
x * x * A.at<double>(4, 0) +
y * y * A.at<double>(5, 0);
src_y = B.at<double>(0, 0) +
x * B.at<double>(1, 0) +
y * B.at<double>(2, 0) +
x * y * B.at<double>(3, 0) +
x * x * B.at<double>(4, 0) +
y * y * B.at<double>(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<uchar>(y - min_Y, x - min_X) = src.at<uchar>(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<double>(0, 0) +
x * A.at<double>(1, 0) +
y * A.at<double>(2, 0) +
x * y * A.at<double>(3, 0) +
x * x * A.at<double>(4, 0) +
y * y * A.at<double>(5, 0);
src_y = B.at<double>(0, 0) +
x * B.at<double>(1, 0) +
y * B.at<double>(2, 0) +
x * y * B.at<double>(3, 0) +
x * x * B.at<double>(4, 0) +
y * y * B.at<double>(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<cv::Vec3b>(y - min_Y, x - min_X) = src.at<cv::Vec3b>(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<double>(0, 0) + x * A.at<double>(1, 0) + y * A.at<double>(2, 0);
src_y = B.at<double>(0, 0) + x * B.at<double>(1, 0) + y * B.at<double>(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<uchar>(y - min_Y, x - min_X) = src.at<uchar>(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<double>(0, 0) + x * A.at<double>(1, 0) + y * A.at<double>(2, 0);
src_y = B.at<double>(0, 0) + x * B.at<double>(1, 0) + y * B.at<double>(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<cv::Vec3b>(y - min_Y, x - min_X) = src.at<cv::Vec3b>(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<Point2d>& GCP_XY,
const std::vector<Point2d>& 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<unsigned int>(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<unsigned int>(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;
}
}