using o0.Geometry2D.Float; using Org.BouncyCastle.Crypto.Macs; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using UnityEngine; namespace o0.Project { public static partial class Extension { static public (Matrix, Matrix) zimIdentifyEdge55GradientFull(this Matrix mat) { var conSize = 5; var conArea = conSize * conSize; var convolution = new Matrix(new Geometry2D.Vector(mat.Size.x - (conSize - 1), mat.Size.y - (conSize - 1)), Tiling: true); var pixelC = convolution.Element; var dirMat = new Matrix(convolution.Size, Tiling: true); var pixelDir = dirMat.Element; var convolutionWidth = convolution.Size.x; Parallel.For(0, convolution.Size.x * convolution.Size.y, i => { var iPx = i % convolutionWidth; var iPy = i / convolutionWidth; var sum = 0.0f; for (var jX = 0; jX < conSize; ++jX) for (var jY = 0; jY < conSize; ++jY) sum += mat.Element[(iPx + jX) + (iPy + jY) * mat.Size.x]; if (sum == 0.0f) return; var factor0 = new float[] { 1, 1.5f, 2 }; var factor1 = new float[] { 0.94868329805051379959966806332982f, 1.3416407864998738178455042012388f, 1.7888543819998317571273389349851f }; var factor2 = new float[] { 0.70710678118654752440084436210485f, 1.0606601717798212866012665431573f, 1.4142135623730950488016887242097f }; //float root2 = 1.4142135623730950488016887242097f; // 根号2 //float root5d4 = 1.1180339887498948482045868343656f; // 根号5/4 //float root10d3 = 1.0540925533894597773329645148109f; // 根号10/9 var g0 = mat.Element[(iPx + 4) + (iPy + 0) * mat.Size.x] * factor0[0] + mat.Element[(iPx + 4) + (iPy + 1) * mat.Size.x] * factor0[1] + mat.Element[(iPx + 4) + (iPy + 2) * mat.Size.x] * factor0[2] + mat.Element[(iPx + 4) + (iPy + 3) * mat.Size.x] * factor0[1] + mat.Element[(iPx + 4) + (iPy + 4) * mat.Size.x] * factor0[0] - mat.Element[(iPx + 0) + (iPy + 0) * mat.Size.x] * factor0[0] - mat.Element[(iPx + 0) + (iPy + 1) * mat.Size.x] * factor0[1] - mat.Element[(iPx + 0) + (iPy + 2) * mat.Size.x] * factor0[2] - mat.Element[(iPx + 0) + (iPy + 3) * mat.Size.x] * factor0[1] - mat.Element[(iPx + 0) + (iPy + 4) * mat.Size.x] * factor0[0]; var g26 = //梯度26.565度 mat.Element[(iPx + 4) + (iPy + 1) * mat.Size.x] * factor1[0] + mat.Element[(iPx + 4) + (iPy + 2) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 4) + (iPy + 3) * mat.Size.x] * factor1[2] + mat.Element[(iPx + 4) + (iPy + 4) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 3) + (iPy + 4) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 0) + (iPy + 3) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 0) + (iPy + 2) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 0) + (iPy + 1) * mat.Size.x] * factor1[2] - mat.Element[(iPx + 0) + (iPy + 0) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 1) + (iPy + 0) * mat.Size.x] * factor1[0]; var g45 = mat.Element[(iPx + 4) + (iPy + 2) * mat.Size.x] * factor2[0] + mat.Element[(iPx + 4) + (iPy + 3) * mat.Size.x] * factor2[1] + mat.Element[(iPx + 4) + (iPy + 4) * mat.Size.x] * factor2[2] + mat.Element[(iPx + 3) + (iPy + 4) * mat.Size.x] * factor2[1] + mat.Element[(iPx + 2) + (iPy + 4) * mat.Size.x] * factor2[0] - mat.Element[(iPx + 0) + (iPy + 2) * mat.Size.x] * factor2[0] - mat.Element[(iPx + 0) + (iPy + 1) * mat.Size.x] * factor2[1] - mat.Element[(iPx + 0) + (iPy + 0) * mat.Size.x] * factor2[2] - mat.Element[(iPx + 1) + (iPy + 0) * mat.Size.x] * factor2[1] - mat.Element[(iPx + 2) + (iPy + 0) * mat.Size.x] * factor2[0]; var g63 = //梯度63.435度 mat.Element[(iPx + 4) + (iPy + 3) * mat.Size.x] * factor1[0] + mat.Element[(iPx + 4) + (iPy + 4) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 3) + (iPy + 4) * mat.Size.x] * factor1[2] + mat.Element[(iPx + 2) + (iPy + 4) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 1) + (iPy + 4) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 0) + (iPy + 1) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 0) + (iPy + 0) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 1) + (iPy + 0) * mat.Size.x] * factor1[2] - mat.Element[(iPx + 2) + (iPy + 0) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 3) + (iPy + 0) * mat.Size.x] * factor1[0]; var g90 = mat.Element[(iPx + 4) + (iPy + 4) * mat.Size.x] * factor0[0] + mat.Element[(iPx + 3) + (iPy + 4) * mat.Size.x] * factor0[1] + mat.Element[(iPx + 2) + (iPy + 4) * mat.Size.x] * factor0[2] + mat.Element[(iPx + 1) + (iPy + 4) * mat.Size.x] * factor0[1] + mat.Element[(iPx + 0) + (iPy + 4) * mat.Size.x] * factor0[0] - mat.Element[(iPx + 0) + (iPy + 0) * mat.Size.x] * factor0[0] - mat.Element[(iPx + 1) + (iPy + 0) * mat.Size.x] * factor0[1] - mat.Element[(iPx + 2) + (iPy + 0) * mat.Size.x] * factor0[2] - mat.Element[(iPx + 3) + (iPy + 0) * mat.Size.x] * factor0[1] - mat.Element[(iPx + 4) + (iPy + 0) * mat.Size.x] * factor0[0]; var g116 = //梯度116.565度 mat.Element[(iPx + 3) + (iPy + 4) * mat.Size.x] * factor1[0] + mat.Element[(iPx + 2) + (iPy + 4) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 1) + (iPy + 4) * mat.Size.x] * factor1[2] + mat.Element[(iPx + 0) + (iPy + 4) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 0) + (iPy + 3) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 1) + (iPy + 0) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 2) + (iPy + 0) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 3) + (iPy + 0) * mat.Size.x] * factor1[2] - mat.Element[(iPx + 4) + (iPy + 0) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 4) + (iPy + 1) * mat.Size.x] * factor1[0]; var g135 = mat.Element[(iPx + 2) + (iPy + 4) * mat.Size.x] * factor2[0] + mat.Element[(iPx + 1) + (iPy + 4) * mat.Size.x] * factor2[1] + mat.Element[(iPx + 0) + (iPy + 4) * mat.Size.x] * factor2[2] + mat.Element[(iPx + 0) + (iPy + 3) * mat.Size.x] * factor2[1] + mat.Element[(iPx + 0) + (iPy + 2) * mat.Size.x] * factor2[0] - mat.Element[(iPx + 2) + (iPy + 0) * mat.Size.x] * factor2[0] - mat.Element[(iPx + 3) + (iPy + 0) * mat.Size.x] * factor2[1] - mat.Element[(iPx + 4) + (iPy + 0) * mat.Size.x] * factor2[2] - mat.Element[(iPx + 4) + (iPy + 1) * mat.Size.x] * factor2[1] - mat.Element[(iPx + 4) + (iPy + 2) * mat.Size.x] * factor2[0]; var g153 = // 梯度153.435度 mat.Element[(iPx + 1) + (iPy + 4) * mat.Size.x] * factor1[0] + mat.Element[(iPx + 0) + (iPy + 4) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 0) + (iPy + 3) * mat.Size.x] * factor1[2] + mat.Element[(iPx + 0) + (iPy + 2) * mat.Size.x] * factor1[1] + mat.Element[(iPx + 0) + (iPy + 1) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 3) + (iPy + 0) * mat.Size.x] * factor1[0] - mat.Element[(iPx + 4) + (iPy + 0) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 4) + (iPy + 1) * mat.Size.x] * factor1[2] - mat.Element[(iPx + 4) + (iPy + 2) * mat.Size.x] * factor1[1] - mat.Element[(iPx + 4) + (iPy + 3) * mat.Size.x] * factor1[0]; float[] gra = new float[] { MathF.Abs(g0), MathF.Abs(g26), MathF.Abs(g45), MathF.Abs(g63), MathF.Abs(g90), MathF.Abs(g116), MathF.Abs(g135), MathF.Abs(g153) }; var maxIndex = o0.MaxIndex(gra); pixelC[i] = gra[maxIndex]; switch (maxIndex) { case 0: pixelDir[i] = g0 > 0 ? 0 : 180; break; case 1: pixelDir[i] = g26 > 0 ? 26.565f : 206.565f; break; case 2: pixelDir[i] = g45 > 0 ? 45 : 225; break; case 3: pixelDir[i] = g63 > 0 ? 63.435f : 243.435f; break; case 4: pixelDir[i] = g90 > 0 ? 90 : 270; break; case 5: pixelDir[i] = g116 > 0 ? 116.565f : 296.565f; break; case 6: pixelDir[i] = g135 > 0 ? 135 : 315; break; case 7: pixelDir[i] = g153 > 0 ? 153.435f : 333.435f; break; } //pixelC[i] = MathF.Abs(gX) + MathF.Abs(gY) + MathF.Abs(gXY) + MathF.Abs(gYX); /* if (pixelC[i] / 9f < 1.0f / 256f) { pixelC[i] = 0; return; }/**/ /* if (sum < 100f/256f) { pixelC[i] = 0; return; }/**/ //pixelC[i] = o0.Max(MathF.Abs(gX), MathF.Abs(gY), MathF.Abs(gXY), MathF.Abs(gYX)); //pixelC[i] /= MathF.Pow(sum / 9, 0.1f); //pixelC[i] /= min + 0.5f; //pixelC[i] /= min + 0.1f; pixelC[i] /= sum / 25f + 1f;//+1是为了防止除数太小,结果不合理地过大 }); return (convolution.Map(ignoreExtremum: 10), dirMat); } static public (Matrix, Matrix) zimIdentifyEdgeGradient45(this Matrix mat, int conSizeLevel = 2) { var conSize = 4 * conSizeLevel + 1; // conSize一定 = 4 * n + 1 var conArea = conSize * conSize; var convolution = new Matrix(new Geometry2D.Vector(mat.Size.x - (conSize - 1), mat.Size.y - (conSize - 1)), Tiling: true); var pixelC = convolution.Element; var dirMat = new Matrix(convolution.Size, Tiling: true); var pixelDir = dirMat.Element; var convolutionWidth = convolution.Size.x; Parallel.For(0, convolution.Size.x * convolution.Size.y, i => { var iPx = i % convolutionWidth; var iPy = i / convolutionWidth; var sum = 0.0f; for (var jX = 0; jX < conSize; ++jX) for (var jY = 0; jY < conSize; ++jY) sum += mat.Element[(iPx + jX) + (iPy + jY) * mat.Size.x]; if (sum == 0.0f) return; float root2 = 1.4142135623730950488016887242097f; // 根号2 float root5d4 = 1.1180339887498948482045868343656f; // 根号5/4 //float root10d3 = 1.0540925533894597773329645148109f; // 根号10/9 var g0 = mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 1 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 2 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 3 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 3 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 2 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 1 * conSizeLevel) * mat.Size.x] * 1f; var g26 = //梯度26.565度 mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 2 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 3 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 2) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 1 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f; g26 /= root5d4; var g45 = mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 3 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 3 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 1 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 1 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f; g45 /= root2; var g63 = //梯度63.435度 mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 3 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 2 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 1 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 2 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f; g63 /= root5d4; var g90 = mat.Element[(iPx + 3 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 2 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 1 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 1 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 2 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 3 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f; var g116 = //梯度116.565度 mat.Element[(iPx + 2 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 1 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 2 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 3 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f; g116 /= root5d4; var g135 = mat.Element[(iPx + 1 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 3 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 3 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 1 * conSizeLevel) * mat.Size.x] * 1f; g135 /= root2; var g153 = // 梯度153.435度 mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 4 * conSizeLevel) * mat.Size.x] * 1f + mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 3 * conSizeLevel) * mat.Size.x] * 1.5f + mat.Element[(iPx + 0 * conSizeLevel) + (iPy + 2 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 0 * conSizeLevel) * mat.Size.x] * 1f - mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 1 * conSizeLevel) * mat.Size.x] * 1.5f - mat.Element[(iPx + 4 * conSizeLevel) + (iPy + 2 * conSizeLevel) * mat.Size.x] * 1f; g153 /= root5d4; float[] gra = new float[] { MathF.Abs(g0), MathF.Abs(g26), MathF.Abs(g45), MathF.Abs(g63), MathF.Abs(g90), MathF.Abs(g116), MathF.Abs(g135), MathF.Abs(g153) }; var maxIndex = o0.MaxIndex(gra); pixelC[i] = gra[maxIndex]; switch (maxIndex) { case 0: pixelDir[i] = g0 > 0 ? 0 : 180; break; case 1: pixelDir[i] = g26 > 0 ? 26.565f : 206.565f; break; case 2: pixelDir[i] = g45 > 0 ? 45 : 225; break; case 3: pixelDir[i] = g63 > 0 ? 63.435f : 243.435f; break; case 4: pixelDir[i] = g90 > 0 ? 90 : 270; break; case 5: pixelDir[i] = g116 > 0 ? 116.565f : 296.565f; break; case 6: pixelDir[i] = g135 > 0 ? 135 : 315; break; case 7: pixelDir[i] = g153 > 0 ? 153.435f : 333.435f; break; } //pixelC[i] = MathF.Abs(gX) + MathF.Abs(gY) + MathF.Abs(gXY) + MathF.Abs(gYX); /* if (pixelC[i] / 9f < 1.0f / 256f) { pixelC[i] = 0; return; }/**/ /* if (sum < 100f/256f) { pixelC[i] = 0; return; }/**/ //pixelC[i] = o0.Max(MathF.Abs(gX), MathF.Abs(gY), MathF.Abs(gXY), MathF.Abs(gYX)); //pixelC[i] /= MathF.Pow(sum / 9, 0.1f); //pixelC[i] /= min + 0.5f; //pixelC[i] /= min + 0.1f; pixelC[i] /= sum / 25f + 1f;//+1是为了防止除数太小,结果不合理地过大 }); return (convolution.Map(ignoreExtremum: 10), dirMat); } // conSize 应 ≥ 5 static public (Matrix, Matrix) zimIdentifyEdgeGradientAny(this Matrix mat, int conSize = 7) { var convolution = new Matrix(new Geometry2D.Vector(mat.Size.x - (conSize - 1), mat.Size.y - (conSize - 1)), Tiling: true); var pixelC = convolution.Element; var dirMat = new Matrix(convolution.Size, Tiling: true); var pixelDir = dirMat.Element; var convolutionWidth = convolution.Size.x; var sampleCount = conSize + conSize - 6; (Vector a, Vector b)[] samples = new (Vector, Vector)[sampleCount]; int[] angles = new int[sampleCount]; float[] scales = new float[sampleCount]; int ax = conSize - 2, ay = (conSize - 1) / 2, bx, by; for (int i = 0; i < samples.Length; i++) { bx = conSize - ax - 1; by = conSize - ay - 1; samples[i] = (new Vector(ax, ay), new Vector(bx, by)); var dir = new Vector(ax - bx, ay - by); scales[i] = dir.Length; if (ax > bx) angles[i] = (int)(Math.Atan(dir.y / dir.x) * 180 / Math.PI); else if (ax < bx) angles[i] = 180 + (int)(Math.Atan(dir.y / dir.x) * 180 / Math.PI); else angles[i] = 90; if (ax == 1) ay--; else if (ay == conSize - 2) ax--; else ay++; } //Debug.Log(angles.ToJson() + "\r\n" + samples.ToJson() +"\r\n" + scales.ToJson()); Parallel.For(0, convolution.Size.x * convolution.Size.y, i => { var iPx = i % convolutionWidth; var iPy = i / convolutionWidth; var avg = 0.0f; for (var jX = 0; jX < conSize; ++jX) for (var jY = 0; jY < conSize; ++jY) avg += mat.Element[(iPx + jX) + (iPy + jY) * mat.Size.x]; if (avg == 0.0f) return; avg /= conSize * conSize; var gra = new float[sampleCount]; //var gAvg = new Vector(); for (int j = 0; j < samples.Length; j++) { var a = samples[j].a; var b = samples[j].b; float aAvg = 0, bAvg = 0; for (int m = -1; m <= 1; m++) // 取像素点周围9格平均值 { for (int n = -1; n <= 1; n++) { aAvg += mat.Element[(iPx + (int)a.x + m) + (iPy + (int)a.y + n) * mat.Size.x]; bAvg += mat.Element[(iPx + (int)b.x + m) + (iPy + (int)b.y + n) * mat.Size.x]; } } aAvg /= 9; bAvg /= 9; gra[j] = (aAvg - bAvg) / scales[j]; //gAvg += (a - b) * gra[j] / scales[j]; } //gAvg /= samples.Length; int maxIndex = 0; float gMax = gra[0]; for (int k = 1; k < gra.Length; k++) { var gAbs = Math.Abs(gra[k]); if (gMax < gAbs) { maxIndex = k; gMax = gAbs; } } pixelC[i] = gMax / (avg + 1f); // +1是防止结果过大 pixelDir[i] = gra[maxIndex] > 0 ? angles[maxIndex] : angles[maxIndex] + 180; }); return (convolution.Map(ignoreExtremum: 10), dirMat); } static public (Matrix, Matrix) zimIdentifyEdgeGradientGroup(this Matrix mat, int conSize = 5) { var conArea = conSize * conSize; var convolution = new Matrix(new Geometry2D.Vector(mat.Size.x - (conSize - 1), mat.Size.y - (conSize - 1)), Tiling: true); var pixelC = convolution.Element; var dirMat = new Matrix(convolution.Size, Tiling: true); var pixelDir = dirMat.Element; var convolutionWidth = convolution.Size.x; Parallel.For(0, convolution.Size.x * convolution.Size.y, i => { var iPx = i % convolutionWidth; var iPy = i / convolutionWidth; var sum = 0.0f; for (var jX = 0; jX < conSize; ++jX) for (var jY = 0; jY < conSize; ++jY) sum += mat.Element[(iPx + jX) + (iPy + jY) * mat.Size.x]; if (sum == 0.0f) return; var convList = new List<(float, Vector)>(); for (var jX = 0; jX < conSize; ++jX) for (var jY = 0; jY < conSize; ++jY) convList.Add((mat.Element[(iPx + jX) + (iPy + jY) * mat.Size.x], new Vector(jX, jY))); ; convList.Sort((a, b) => a.Item1.CompareTo(b.Item1)); var vMean0 = Vector.Zero; // 暗区 var vMean1 = Vector.Zero; // 明区 for (int k = 0; k < convList.Count / 2; k++) { vMean0 += convList[k].Item2; pixelC[i] -= convList[k].Item1; } vMean0 /= convList.Count / 2; for (int k = convList.Count / 2; k < convList.Count; k++) { vMean1 += convList[k].Item2; pixelC[i] += convList[k].Item1; } vMean1 /= convList.Count - convList.Count / 2; pixelC[i] /= sum / convList.Count + 1f; var dir = vMean1 - vMean0; //pixelDir[i] = new Vector(dir.y, -dir.x); pixelDir[i] = dir.y > 0 ? (float)Math.Atan((double)(dir.y / dir.x)) : -(float)Math.Atan((double)(dir.y / dir.x)); pixelDir[i] *= 180 / (float)Math.PI; }); return (convolution.Map(ignoreExtremum: 10), dirMat); } } }