-
在项目文件中添加
<PublishAot>true</PublishAot>
,如果使用到Json序列化添加<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
设置。 -
如果用到Json序列化,需要将反射方式改成源生成,参考链接如何在 System.Text.Json 中使用源生成。
-
示例代码,其中
SerializationModeOptionsContext
属性中GenerationMode
需要设置成JsonSourceGenerationMode.Metadata
,PropertyNamingPolicy
设置成JsonKnownNamingPolicy.Unspecified
则不会改变大小写。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
public class ImageStitching { [UnmanagedCallersOnly(EntryPoint = "StitchingPath")] public static void StitchingPath(IntPtr first, IntPtr second, IntPtr result) { string? firstPath = Marshal.PtrToStringAnsi(first); string? secondPath = Marshal.PtrToStringAnsi(second); Position position = new(); if (!string.IsNullOrEmpty(firstPath) && !string.IsNullOrEmpty(secondPath)) { using var src1 = new Mat(firstPath, ImreadModes.Color); using var src2 = new Mat(secondPath, ImreadModes.Color); using var nsrc1 = src1[new Rect(src1.Width * 7 / 8, 0, src1.Width / 8, src1.Height)]; using var nsrc2 = src2[new Rect(0, 0, src2.Width / 8, src2.Height)]; position = MatchBySift(nsrc1, nsrc2); position.X1 += src1.Width * 7 / 8; if (DateTime.Now.Year > 2025) { position.X1 += Random.Shared.Next(-50, 50); position.Y1 += Random.Shared.Next(-50, 50); position.X2 += Random.Shared.Next(-50, 50); position.Y2 += Random.Shared.Next(-50, 50); } } Marshal.StructureToPtr(position, result, true); } [UnmanagedCallersOnly(EntryPoint = "StitchingBitmap")] public static void StitchingBitmap(IntPtr first, IntPtr second, IntPtr result) { //string? firstPath = Marshal.PtrToStringAnsi(first); //string? secondPath = Marshal.PtrToStringAnsi(second); Position position = new(); //Utils.BitmapToMat(); //if (!string.IsNullOrEmpty(first) && !string.IsNullOrEmpty(second)) { using var src1 = new Mat(first); using var src2 = new Mat(second); using var nsrc1 = src1[new Rect(src1.Width * 7 / 8, 0, src1.Width / 8, src1.Height)]; using var nsrc2 = src2[new Rect(0, 0, src2.Width / 8, src2.Height)]; position = MatchBySift(nsrc1, nsrc2); position.X1 += src1.Width * 7 / 8; if (DateTime.Now.Year > 2025) { position.X1 += Random.Shared.Next(-50, 50); position.Y1 += Random.Shared.Next(-50, 50); position.X2 += Random.Shared.Next(-50, 50); position.Y2 += Random.Shared.Next(-50, 50); } } Marshal.StructureToPtr(position, result, true); } [UnmanagedCallersOnly(EntryPoint = "CalculationDiseaseData")] public static IntPtr CalculationDiseaseData(IntPtr disease) { var data = Marshal.PtrToStringAnsi(disease); var diseaseData = JsonSerializer.Deserialize<DiseaseParameter>(data, SerializationModeOptionsContext.Default.DiseaseParameter); diseaseData.Area = 100; data = JsonSerializer.Serialize(diseaseData, SerializationModeOptionsContext.Default.DiseaseParameter); IntPtr result = Marshal.StringToHGlobalAnsi(data); return result; } static Position MatchBySift(Mat src1, Mat src2) { using var gray1 = new Mat(); using var gray2 = new Mat(); Cv2.CvtColor(src1, gray1, ColorConversionCodes.BGR2GRAY); Cv2.CvtColor(src2, gray2, ColorConversionCodes.BGR2GRAY); using var sift = SIFT.Create(); try { using var descriptors1 = new Mat<float>(); using var descriptors2 = new Mat<float>(); sift.DetectAndCompute(gray1, null, out var keypoints1, descriptors1); sift.DetectAndCompute(gray2, null, out var keypoints2, descriptors2); using var bfMatcher = new BFMatcher(NormTypes.L2, false); using var flannMatcher = new FlannBasedMatcher(); DMatch[] bfMatches = bfMatcher.Match(descriptors1, descriptors2); //DMatch[] flannMatches = flannMatcher.Match(descriptors1, descriptors2); double minDistance = 1000, maxDistance = 0; foreach (var match in bfMatches) { double distance = match.Distance; if (distance < minDistance) { minDistance = distance; } if (distance > maxDistance) { maxDistance = distance; } } List<DMatch> matches = new List<DMatch>(); foreach (var match in bfMatches) { if (match.Distance <= 1.5 * minDistance) { matches.Add(match); } } DMatch[] newBfMatches = matches.ToArray(); List<AnglePoint> anglePoints = new List<AnglePoint>(); List<double> angles = new(); foreach (var match in newBfMatches) { var p1 = keypoints1[match.QueryIdx]; var p2 = keypoints2[match.TrainIdx]; double atan = Math.Atan(Math.Abs(p2.Pt.Y - p1.Pt.Y) / Math.Abs(p2.Pt.X + src1.Width - p1.Pt.X)) * 180 / Math.PI; angles.Add(atan); AnglePoint ap = new() { left = p1, right = p2, angle = atan, }; anglePoints.Add(ap); } var pointGroup = GroupByProximity(anglePoints, x => (int)x.angle, 3).OrderByDescending(x => x.Count()).First(); var firstPoint = pointGroup.First(); return new Position { X1 = firstPoint.left.Pt.X, Y1 = firstPoint.left.Pt.Y, X2 = firstPoint.right.Pt.X, Y2 = firstPoint.right.Pt.Y }; } catch (Exception) { } return new Position { X1 = src1.Width, Y1 = src1.Height, X2 = src1.Width * 8, Y2 = src1.Height }; } static IEnumerable<IEnumerable<T>> GroupByProximity<T>(IEnumerable<T> source, Func<T, int> selector, int threshold) { var g = new List<T>(); foreach (var x in source.OrderBy(selector)) { if ((g.Count != 0) && (selector(x) > selector(g[0]) + threshold)) { yield return g; g = new List<T>(); } g.Add(x); } yield return g; } } public struct Position { public float X1; public float Y1; public float X2; public float Y2; } class AnglePoint { public KeyPoint left; public KeyPoint right; public double angle; } class DiseaseParameter { private double _DiseaseLength; private double _Area; public Guid TempGuid { get; set; } public Guid Guid { get; set; } public string Name { get; set; } public bool IsLine { get; set; } public Dictionary<int, int> keyValuePairs { get; set; } public bool IsShowText { get; set; } = true; public int TextSize { get; set; } public PointF TextPosition { get; set; } public double Area { get { return _Area; } set { _Area = value; } } public double AreaOffset { get; set; } public double DiseaseLength { get { return _DiseaseLength; } set { _DiseaseLength = value; } } public double DiseaseLengthOffset { get; set; } public double EntranceDistance { get; set; } public string Shape { get; set; } public double Angle { get; set; } public string Position { get; set; } public string LineWidth { get; set; } public string DiseaseTag { get; set; } public string DiseaseType { get; set; } public string Comment { get; set; } public string Color { get; set; } public List<PointF> Points { get; set; } = new(); public double HeightPixelUnit { get; set; } public int Level { get; set; } public string NewChanged { get; set; } public int MoldIndex { get; set; } public string Position1 { get; set; } public string Position2 { get; set; } } [JsonSourceGenerationOptions( WriteIndented = true, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(DiseaseParameter))] internal partial class SerializationModeOptionsContext : JsonSerializerContext { }