/// <summary> /// 这里面的去除噪声数据的处理,会影响到全球拼图处理中数据跨越+-180度数据的正确经纬度设置。 /// </summary> /// <param name="srcXs"></param> /// <param name="srcYs"></param> /// <param name="maskEnvelope"></param> /// <param name="dstSpatialRef"></param> /// <param name="progressCallback"></param> /// <returns></returns> public static PrjEnvelope GetEnvelope(double[] srcXs, double[] srcYs, PrjEnvelope maskEnvelope, SpatialReference dstSpatialRef, Action <int, string> progressCallback) { if (dstSpatialRef == null) { dstSpatialRef = new SpatialReference(""); dstSpatialRef.ImportFromEPSG(4326); } double noise = 0d; if (maskEnvelope == null) { noise = 0.001d; if (dstSpatialRef.IsGeographic() == 1 && maskEnvelope == null) //投影目标是地理坐标 { maskEnvelope = new PrjEnvelope(-180, 180, -90, 90, dstSpatialRef); //maskEnvelope = new PrjEnvelope(-145, 180, -75, 75); } else { maskEnvelope = new PrjEnvelope(double.MinValue, double.MaxValue, double.MinValue, double.MaxValue, dstSpatialRef); ; //... } } PrjEnvelope dstEnvelope = PrjEnvelope.GetEnvelope(srcXs, srcYs, maskEnvelope); bool spans180thMeridian = maskEnvelope.Width - dstEnvelope.Width < 0.011d; //(这里应当传入角度分辨率) if (spans180thMeridian) //跨越180度数据,不再去除噪声数据。 { dstEnvelope.MinX = maskEnvelope.MinX; dstEnvelope.MaxX = maskEnvelope.MaxX; } else if (noise != 0d) //可以去除0.1%以下的噪声数据 { dstEnvelope.MinX = dstEnvelope.MinX + dstEnvelope.Width * noise; dstEnvelope.MaxX = dstEnvelope.MaxX - dstEnvelope.Width * noise; dstEnvelope = PrjEnvelope.GetEnvelope(srcXs, srcYs, dstEnvelope); } return(dstEnvelope); }
public static bool HasValidEnvelope(double[] srcXs, double[] srcYs, PrjEnvelope validEnv, out double validRate, out PrjEnvelope outEnv) { if (validEnv == null || validEnv.IsEmpty) { throw new ArgumentNullException("validEnv", "参数[有效范围]不能为空"); } bool hasValid = false; double MaxX = validEnv.MaxX; double MinX = validEnv.MinX; double MaxY = validEnv.MaxY; double MinY = validEnv.MinY; double curMinX = srcXs[0]; double curMaxX = srcXs[0]; double curMinY = srcYs[0]; double curMaxY = srcYs[0]; int length = srcXs.Length; for (int i = 0; i < length; i++) { if (srcXs[i] < MinX || srcXs[i] > MaxX || srcYs[i] < MinY || srcYs[i] > MaxY) //当前坐标点不在指定有效范围 { continue; } curMinX = srcXs[i]; curMaxX = srcXs[i]; curMinY = srcYs[i]; curMaxY = srcYs[i]; hasValid = true; break; } if (!hasValid) { validRate = 0; outEnv = null; return(false); } int validCount = 0; unsafe { fixed(double *xP = srcXs, yP = srcYs) { double *px = xP; double *py = yP; for (int i = 0; i < length; i++, px++, py++) { if (*px < MinX || *px > MaxX || *py < MinY || *py > MaxY) { continue; } validCount++; if (curMaxX < *px) { curMaxX = *px; } else if (curMinX > *px) { curMinX = *px; } if (curMaxY < *py) { curMaxY = *py; } else if (curMinY > *py) { curMinY = *py; } } } } validRate = validCount * 1.0 / length; outEnv = new PrjEnvelope(curMinX, curMaxX, curMinY, curMaxY, validEnv._srs); return(true); }
public static PrjEnvelope GetEnvelope(double[] srcXs, double[] srcYs, PrjEnvelope validEnvelope) { double MaxX = double.MaxValue; double MinX = double.MinValue; double MaxY = double.MaxValue; double MinY = double.MinValue; if (validEnvelope != null) { MaxX = validEnvelope.MaxX; MinX = validEnvelope.MinX; MaxY = validEnvelope.MaxY; MinY = validEnvelope.MinY; } int length = srcXs.Length; double curMinX = MinX; double curMaxX = MaxX; double curMinY = MinY; double curMaxY = MaxY; //设置初始值 for (int i = 0; i < length; i++) { if (srcXs[i] < MinX || srcXs[i] > MaxX || srcYs[i] < MinY || srcYs[i] > MaxY) { continue; } curMinX = srcXs[i]; curMaxX = srcXs[i]; curMinY = srcYs[i]; curMaxY = srcYs[i]; break; } //开始遍历并计算最大最小值 unsafe { fixed(double *xP = srcXs, yP = srcYs) { double *px = xP; double *py = yP; for (int i = 0; i < length; i++, px++, py++) { //if (Math.Abs(*px - (-90d)) < 0.0000001) // Console.WriteLine(*px + "索引" + i); if (*px < MinX || *px > MaxX || *py < MinY || *py > MaxY) { continue; } if (curMaxX < *px) { curMaxX = *px; } else if (curMinX > *px) { curMinX = *px; } if (curMaxY < *py) { curMaxY = *py; } else if (curMinY > *py) { curMinY = *py; } } } } PrjEnvelope dstEnvelope = new PrjEnvelope(curMinX, curMaxX, curMinY, curMaxY, validEnvelope?._srs); return(dstEnvelope); }
/// <summary> /// 根据给出的经纬度数据集或者投影坐标数据集,计算其是否在指定的范围内,并且计算出有效率,以及实际输出范围 /// </summary> /// <param name="xs"></param> /// <param name="ys"></param> /// <param name="validEnv"></param> /// <param name="oSpatialRef"></param> /// <param name="tSpatialRef"></param> /// <param name="validRate"></param> /// <param name="outEnv"></param> /// <returns></returns> public bool VaildEnvelope(double[] xs, double[] ys, PrjEnvelope validEnv, SpatialReference oSpatialRef, SpatialReference tSpatialRef, out double validRate, out PrjEnvelope outEnv) { if (validEnv == null || validEnv.IsEmpty) { throw new ArgumentNullException("validEnv", "参数[有效范围]不能为空"); } if (tSpatialRef == null) { tSpatialRef = SpatialReferenceFactory.CreateSpatialReference(4326); } if (oSpatialRef == null) { oSpatialRef = SpatialReferenceFactory.CreateSpatialReference(4326); } using (IProjectionTransform transform = ProjectionTransformFactory.GetProjectionTransform(oSpatialRef, tSpatialRef)) { if (oSpatialRef.IsSame(tSpatialRef) != 1) { transform.Transform(xs, ys); } return(PrjEnvelope.HasValidEnvelope(xs, ys, validEnv, out validRate, out outEnv)); } }
public void ComputeDstEnvelope(SpatialReference srcSpatialRef, double[] srcXs, double[] srcYs, Size srcSize, SpatialReference dstSpatialRef, out PrjEnvelope dstEnvelope, Action <int, string> progressCallback) { ComputeDstEnvelope(srcSpatialRef, srcXs, srcYs, srcSize, dstSpatialRef, null, out dstEnvelope, progressCallback); }
/// <summary> /// 通过插值经纬度数据,生成查找表 /// 线性外插:从实际情况看,不需要执行这个线性外插,即可消除bow-tie弯弓效应。即:每个整扫描带跳过最后一行的插值。 /// 目前局部数据看到的情况是,Fy3AMERSI的原始数据已经处理了bow-tie,FY3B和FY3C的没处理。 /// 本插值仅适用于经纬度放大的情况,比如放大1倍,放大两倍等等。 /// </summary> /// <param name="srcToDstProjXs"></param> /// <param name="srcToDstProjYs"></param> /// <param name="srcJdSize"></param> /// <param name="srcDataSize"></param> /// <param name="dstDataSize"></param> /// <param name="dstEnvelope"></param> /// <param name="rowMapTable"></param> /// <param name="colMapTable"></param> /// <param name="progressCallback"></param> /// <param name="scanLineWidth"></param> public void ComputeIndexMapTable(double[] srcToDstProjXs, double[] srcToDstProjYs, Size srcJdSize, Size srcDataSize, Size dstDataSize, PrjEnvelope dstEnvelope, out UInt16[] rowMapTable, out UInt16[] colMapTable, Action <int, string> progressCallback, int scanLineWidth) { int dstHeight = dstDataSize.Height; int dstWidth = dstDataSize.Width; int srcHeight = srcJdSize.Height; int srcWidth = srcJdSize.Width; int srcDataWidth = srcDataSize.Width; int srcDataHeight = srcDataSize.Height; int srcLength = srcWidth * srcHeight; int srcDataLength = srcDataWidth * srcDataHeight; int dstLength = dstWidth * dstHeight; double dstResolutionsX = dstEnvelope.Width / dstWidth; double dstResolutionsY = dstEnvelope.Height / dstHeight; int slopeX = srcDataWidth / srcWidth; //4,2 int slopeY = srcDataHeight / srcHeight; //4,2 double dstMinX = dstEnvelope.MinX; double dstMaxX = dstEnvelope.MaxX; double dstMaxY = dstEnvelope.MaxY; double dstMinY = dstEnvelope.MinY; double srcValidMinX = dstEnvelope.MinX - dstResolutionsX * slopeX * 2; double srcValidMaxX = dstEnvelope.MaxX + dstResolutionsX * slopeX; double srcValidMaxY = dstEnvelope.MaxY + dstResolutionsY * slopeY * 2; double srcValidMinY = dstEnvelope.MinY - +dstResolutionsY * slopeY; float factorX = (float)srcWidth / srcDataWidth; //1/4;1/2 float factorY = (float)srcHeight / srcDataHeight; //1/4;1/2 byte[] lootUpTableTag = new byte[dstLength]; // UInt16[] tmpRowLookUpTable = new UInt16[dstLength]; // UInt16[] tmpColLookUpTable = new UInt16[dstLength]; // if (InvalidValue != 0) { for (int i = 0; i < dstLength; i++) { tmpRowLookUpTable[i] = InvalidValue; tmpColLookUpTable[i] = InvalidValue; } } //扫描带宽度:10//用于去除 Parallel.For(0, srcHeight, (oldRow) => //oldRow、oldCol插值前的行,列 { if (scanLineWidth > 1 && (oldRow + 1) % scanLineWidth == 0) //每条扫描线的最后一行。 { } else //线性内插 { int destRowIndex, destColIndex; int destIndex; double curX, curY; int dstCol; float oldRowF, oldColF; int newRow, newCol; int dstRow; int rowOffset = oldRow * srcWidth; int srcIndex; double srcX, srcY; //临时存储插后的经纬度数据集 double[,] m_fTempLat = new double[slopeX, slopeY]; double[,] m_fTempLon = new double[slopeX, slopeY]; double p1, p2, p3, p4; int v1, v2, v3, v4; double pu1; int vSrcWidth; int v1SrcWidth; int i, j; double v, u; //下面用双线性差值计算出放大后的经纬度(XY)值,公式如下: //f(i+u,j+v)=(1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1); //p1=(1-u)(1-v),p2=(1-u)v,p3=u * (1 - v),p4=u * v // for (int oldCol = 0; oldCol < srcWidth; oldCol++) { srcIndex = rowOffset + oldCol; srcX = srcToDstProjXs[srcIndex]; srcY = srcToDstProjYs[srcIndex]; if (srcY <= srcValidMaxY && srcY >= srcValidMinY && srcX >= srcValidMinX && srcX <= srcValidMaxX) { newRow = oldRow * slopeX; //记录插值后的行列号 newCol = oldCol * slopeX; //下面使用双线性插值,插值放大后的区域的值 for (int blockRow = 0; blockRow < slopeY; blockRow++) { dstRow = blockRow + newRow; //目标行 oldRowF = dstRow * factorY; i = (int)oldRowF; if (i > oldRowF) { --i; //x = (long)Math.Floor(fx);//取最大整数 } u = oldRowF - i; pu1 = 1 - u; vSrcWidth = i * srcWidth; v1SrcWidth = (i + 1) * srcWidth; for (int blockCol = 0; blockCol < slopeX; blockCol++) { dstCol = blockCol + newCol; //目标列 oldColF = dstCol * factorX; j = (int)oldColF; if (j > oldColF) { --j; } v = oldColF - j; if (i >= srcHeight - 1 && j >= srcWidth - 1) //>=最后一行,并且>=最后一列 { v1 = vSrcWidth + j; p1 = pu1 * (1 - v); m_fTempLon[blockRow, blockCol] = p1 * srcToDstProjXs[v1]; m_fTempLat[blockRow, blockCol] = p1 * srcToDstProjYs[v1]; } else if (i >= srcHeight - 1) //最后一行 { p1 = pu1 * (1 - v); p2 = pu1 * v; v1 = vSrcWidth + j; v2 = vSrcWidth + j + 1; m_fTempLon[blockRow, blockCol] = p1 * srcToDstProjXs[v1] + p2 * srcToDstProjXs[v2]; m_fTempLat[blockRow, blockCol] = p1 * srcToDstProjYs[v1] + p2 * srcToDstProjYs[v2]; } else if (j >= srcWidth - 1) //最后一列 { p1 = pu1 * (1 - v); p3 = u * (1 - v); v1 = vSrcWidth + j; v3 = v1SrcWidth + j; m_fTempLon[blockRow, blockCol] = p1 * srcToDstProjXs[v1] + p3 * srcToDstProjXs[v3]; m_fTempLat[blockRow, blockCol] = p1 * srcToDstProjYs[v1] + p3 * srcToDstProjYs[v3]; } else //其他位置,双线性插值。 { p1 = pu1 * (1 - v); p2 = pu1 * v; p3 = u * (1 - v); p4 = u * v; v1 = vSrcWidth + j; v2 = vSrcWidth + j + 1; v3 = v1SrcWidth + j; v4 = v1SrcWidth + j + 1; m_fTempLon[blockRow, blockCol] = p1 * srcToDstProjXs[v1] + p2 * srcToDstProjXs[v2] + p3 * srcToDstProjXs[v3] + p4 * srcToDstProjXs[v4]; m_fTempLat[blockRow, blockCol] = p1 * srcToDstProjYs[v1] + p2 * srcToDstProjYs[v2] + p3 * srcToDstProjYs[v3] + p4 * srcToDstProjYs[v4]; } } } //计算查找表,将上面插好值的经纬度数据集映射到查找表 for (int blockRow = 0; blockRow < slopeY; blockRow++) { for (int blockCol = 0; blockCol < slopeX; blockCol++) { curX = m_fTempLon[blockRow, blockCol]; curY = m_fTempLat[blockRow, blockCol]; if (curY <= dstMaxY && curY >= dstMinY && curX >= dstMinX && curX <= dstMaxX) { destRowIndex = (int)((dstMaxY - curY) / dstResolutionsY); //Y方向计算出目标行 destColIndex = (int)((curX - dstMinX) / dstResolutionsX); //X方向计算出目标列 destIndex = destRowIndex * dstWidth + destColIndex; if (lootUpTableTag[destIndex] == 0 && destRowIndex < dstHeight && destRowIndex >= 0 && destColIndex < dstWidth && destColIndex >= 0) { tmpRowLookUpTable[destIndex] = (UInt16)(oldRow * slopeX + blockRow); tmpColLookUpTable[destIndex] = (UInt16)(oldCol * slopeY + blockCol); lootUpTableTag[destIndex] = 1; } } } } } } } } ); Interpolation.ChazhiNear(lootUpTableTag, dstDataSize.Width, dstDataSize.Height, tmpRowLookUpTable, tmpColLookUpTable); rowMapTable = tmpRowLookUpTable; colMapTable = tmpColLookUpTable; lootUpTableTag = new byte[1]; lootUpTableTag = null; }
/* * /// <summary> * /// 这里的srcXs,srcYs是源参考投影(srcSpatialRef)下的值。 * /// </summary> * public void ComputeIndexMapTable(SpatialReference srcSpatialRef, double[] srcXs, double[] srcYs, Size srcSize, * SpatialReference dstSpatialRef, Size dstSize, PrjEnvelope dstEnvelope, * out UInt16[] rowMapTable, out UInt16[] colMapTable, Action<int, string> progressCallback) * { * PrjEnvelope maxDstEnvelope; * ComputeDstEnvelope(srcSpatialRef, srcXs, srcYs, srcSize, dstSpatialRef, out maxDstEnvelope, progressCallback); * ComputeIndexMapTable(srcXs, srcYs, srcSize, dstSize, dstEnvelope, maxDstEnvelope, * out rowMapTable, out colMapTable, progressCallback); * } */ /// <summary> /// 这里的srcToDstSpatialXs,srcToDstSpatialYs是目标参考投影(dstSpatialRef)下的值 /// </summary> public void ComputeIndexMapTable(double[] srcToDstSpatialXs, double[] srcToDstSpatialYs, Size srcSize, Size dstSize, PrjEnvelope dstEnvelope, PrjEnvelope maxDstEnvelope, out UInt16[] rowMapTable, out UInt16[] colMapTable, Action <int, string> progressCallback) { if (!maxDstEnvelope.IntersectsWith(dstEnvelope)) { throw new Exception("目标坐标数据不在指定区域范围内"); } double dstMinX = dstEnvelope.MinX; double dstMaxX = dstEnvelope.MaxX; double dstMaxY = dstEnvelope.MaxY; double dstMinY = dstEnvelope.MinY; double dstResolutionsX = dstEnvelope.Width / dstSize.Width; double dstResolutionsY = dstEnvelope.Height / dstSize.Height; int srcLength = srcSize.Width * srcSize.Height; int dstLength = dstSize.Width * dstSize.Height; int dstHeight = dstSize.Height; int dstWidth = dstSize.Width; int srcHeight = srcSize.Height; int srcWidth = srcSize.Width; byte[] lootUpTableTag = new byte[dstLength]; //投影蒙板,用于图像内外标识(0:外部,1:内部) UInt16[] tmpRowLookUpTable = new UInt16[dstLength]; UInt16[] tmpColLookUpTable = new UInt16[dstLength]; if (InvalidValue != 0) { for (int i = 0; i < dstLength; i++) { tmpRowLookUpTable[i] = InvalidValue; tmpColLookUpTable[i] = InvalidValue; } } int srcValidLeft = 0; int srcValidRight = srcWidth; Parallel.For((int)0, srcHeight, (j) => { int srcIndex = 0; int dstIndex = 0; //目标位置 int dstJ; //目标行 int dsti; //目标列 double curX, curY; for (int i = srcValidLeft; i < srcValidRight; i++) { srcIndex = (j * srcWidth + i); curX = srcToDstSpatialXs[srcIndex]; curY = srcToDstSpatialYs[srcIndex]; dstJ = (int)((dstMaxY - curY) / dstResolutionsY + 0.5); //Y方向计算出目标行 索引从0开始所以-1 dsti = (int)((curX - dstMinX) / dstResolutionsX + 0.5); //X方向计算出目标列 if (dstJ >= 0 && dstJ < dstHeight && dsti >= 0 && dsti < dstWidth) { dstIndex = dstJ * dstWidth + dsti; tmpRowLookUpTable[dstIndex] = (UInt16)j; tmpColLookUpTable[dstIndex] = (UInt16)i; lootUpTableTag[dstIndex] = 1; } } }); if (dstSize.Width >= 2 && dstSize.Height >= 2) { Interpolation.ChazhiNear(lootUpTableTag, dstSize.Width, dstSize.Height, tmpRowLookUpTable, tmpColLookUpTable); } rowMapTable = tmpRowLookUpTable; colMapTable = tmpColLookUpTable; lootUpTableTag = new byte[1]; lootUpTableTag = null; }