AoiProject.cs
25.6 KB
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenCvSharp.Extensions;
using OpenCvSharp.XFeatures2D;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.ExceptionServices;
namespace AOI
{
public class AoiProject
{
private AoiProject()
{
}
public AoiProject(Image theImage, Image OrgImage)
{
this.standardImage = theImage;
this.OrgImage = OrgImage;
}
public AoiMethod BaseROI = new AoiEyemMarkMethod();
/// <summary>
/// 标准的Image
/// </summary>
public Image standardImage { get; set; }
/// <summary>
/// 原始基准大图
/// </summary>
public Image OrgImage { get; set; }
public Eyemlib.EyemImage eyemTemplateImage { get; set; }
/// <summary>
/// 所有的AOI方法
/// </summary>
public Dictionary<string, AoiMethod> methodMap = new Dictionary<string, AoiMethod>();
public List<ResultBean> CheckAll(Image scr, out Image resultImg)
{
// GC.Collect();
//Image image =ProcessTestImage((Bitmap)scr,"auro");
Image image;
if (scr.Width != standardImage.Width || scr.Height != standardImage.Height) {
//如果图像大小不一样,判定图像未剪裁重新对齐剪裁
image = ProcessTestImage((Bitmap)scr, "");
}else
image = Eyemlib.DeepClone(scr);
//如果设置了校准方法,先校准图片
//var markMethodMap = methodMap.Where(kv => kv.Value is AoiEyemMarkMethod);
//foreach (var item in markMethodMap)
//{
// ResultBean resultBean = item.Value.Check(standardImage, image);
// if (resultBean.result)
// {
// //校准成功
// image = resultBean.currentRoiImage;
// }
//}
List<ResultBean> resultBeans = new List<ResultBean>();
foreach(var item in methodMap)
{
AoiMethod method = item.Value;
if(method is AoiMarkMethod)
{
//校准图片的,忽略
}
else
{
ResultBean resultBean = method.Check(standardImage,image);
resultBean.roiPath = method.RoiPath;
resultBean.labelKey = item.Key;
resultBeans.Add(resultBean);
}
}
using (Graphics g = Graphics.FromImage(image))
{
foreach (ResultBean resultBean in resultBeans)
{
Pen pen = new Pen(Color.Lime, 5);
if (!resultBean.result)
{
pen = new Pen(Color.Red, 5);
}
if (resultBean.roiPath != null)
{
g.DrawPath(pen, resultBean.roiPath);
}
}
g.Dispose();
}
resultImg = image;
return resultBeans;
}
/// <summary>
/// 保存项目
/// </summary>
/// <param name="filePath"></param>
public void Save(string filePath)
{
Dictionary<string, string> projectMap = new Dictionary<string, string>();
// string base64ImgStr = Base64Util.ToBase64(this.standardImage);
// projectMap.Add("base64Img", base64ImgStr);
//this.standardImage.Save(GetStandardImgPath(filePath), ImageFormat.Bmp);
this.OrgImage.Save(GetStandardImgPath(filePath), ImageFormat.Bmp);
var mapForJson = new Dictionary<string, string>();
foreach(var item in this.methodMap)
{
mapForJson.Add(item.Key, GetItemObj(item.Value));
}
string methodMapJson = JsonUtil.SerializeObject(mapForJson);
projectMap.Add("methodMap", methodMapJson);
projectMap.Add("BaseROI", GetItemObj(BaseROI));
JsonUtil.SerializeObjectToFile(projectMap,filePath,false);
string GetItemObj(AoiMethod itemv) {
JObject obj = JObject.FromObject(itemv);
obj.Add("FullTypeName", itemv.GetType().FullName);
var roiPathData = itemv.GetRoiPathData();
string roiPathDataStr = JsonUtil.SerializeObject(roiPathData);
obj.Add("PathDataStr", roiPathDataStr);
string jsonStr = JsonUtil.SerializeObject(obj);
return jsonStr;
}
}
private static string GetStandardImgPath(string filePath)
{
string imageFilePath = "";
string extension = Path.GetExtension(filePath);
imageFilePath = filePath.Replace( extension, ".bmp");
return imageFilePath;
}
public static String FilePath = null;
/// <summary>
/// 加载项目
/// </summary>
/// <param name="filePath"></param>
public static AoiProject Load(string filePath, out string msg)
{
FilePath = filePath;
Thread.Sleep(1);
GC.Collect();
msg = "";
Thread.Sleep(1);
AoiProject aoiProject = new AoiProject();
try
{
string imageFile = GetStandardImgPath(filePath);
if (!File.Exists(imageFile))
{
msg = "no image ";
return null;
}
aoiProject.OrgImage = Eyemlib.DeepClone( new Bitmap(imageFile));
Dictionary<string, string> projectMap = JsonUtil.DeserializeJsonToObjectFromFile<Dictionary<string, string>>(filePath);
// string base64Img = projectMap["base64Img"];
// aoiProject.standardImage = Base64Util.ToImage(base64Img);
string methodMapJson = projectMap["methodMap"];
var jsonMap = JsonUtil.DeserializeJsonToObject<Dictionary<string, string>>(methodMapJson);
foreach (var item in jsonMap)
{
aoiProject.methodMap.Add(item.Key, GetAOIFromJson(item.Value));
Thread.Sleep(1);
}
aoiProject.BaseROI = GetAOIFromJson(projectMap["BaseROI"]);
aoiProject.standardImage = aoiProject.ProcessBaseImage((Bitmap)aoiProject.OrgImage,"基准图");
return aoiProject;
}
catch (Exception ex)
{
if (aoiProject.standardImage != null)
{
aoiProject.standardImage.Dispose();
}
aoiProject = null;
msg = ex.ToString();
return null;
}
AoiMethod GetAOIFromJson(string jsv)
{
JObject obj = JObject.Parse(jsv);
string fullTypeName = obj.Value<string>("FullTypeName");
Type t = Type.GetType(fullTypeName);
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(jsv);
object o = serializer.Deserialize(new JsonTextReader(sr), t);
AoiMethod aoiMethod = (AoiMethod)o;
string PathDataStr = obj.Value<string>("PathDataStr");
PathData pathData = JsonUtil.DeserializeJsonToObject<PathData>(PathDataStr);
if (pathData != null && pathData.Points.Length > 0)
aoiMethod.RoiPath = new GraphicsPath(pathData.Points, pathData.Types);
return aoiMethod;
}
}
public Bitmap ProcessBaseImage(Bitmap orgimage, string name)
{
var markroi = BaseROI;
if (markroi == null || markroi.RoiPath == null || markroi.RoiPath.GetBounds() == RectangleF.Empty)
{
return Eyemlib.DeepClone(orgimage);
}
else
{
try
{
var BaseImg = CropBitmap(orgimage, markroi.RoiPath.GetBounds());
return (Bitmap)BaseImg;
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
return Eyemlib.DeepClone(orgimage);
}
}
}
[HandleProcessCorruptedStateExceptions]
public Bitmap ProcessTestImage(Bitmap targetimage, string name)
{
var markroi = BaseROI;
if (markroi == null || markroi.RoiPath == null || markroi.RoiPath.GetBounds() == RectangleF.Empty)
{
return Eyemlib.DeepClone(targetimage);
}
else
{
targetimage.Save("\\temp1.bmp");
OrgImage.Save("\\temp2.bmp");
RectangleF rectangleF = markroi.RoiPath.GetBounds();
var result = SURF_MatchTemplate((Bitmap)OrgImage, targetimage, rectangleF, out Bitmap matchBitmap);
//var (BaseImg, EyemBaseImg, result) = Eyemlib.ExtractPCB(orgimage, markroi.RoiPath.GetBounds());
if (!result)
{
//MessageBox.Show(AOIResourceCulture.GetValue("在框选区域内没有找到PCB"));
MessageBox.Show("Not find pcb");
return CropBitmap(targetimage, rectangleF);
}
return matchBitmap;
}
}
[HandleProcessCorruptedStateExceptions]
public static bool SURF_MatchTemplate(Bitmap basebmp, Bitmap targetbmp, RectangleF rectangleF, out Bitmap matchBitmap)
{
//return Star_MatchTemplate(basebmp, targetbmp, rectangleF, out matchBitmap);
matchBitmap = null;
Rect baseRect = new Rect((int)rectangleF.X, (int)rectangleF.Y, (int)rectangleF.Width, (int)rectangleF.Height);
int SURF_Threshold = ConfigHelper.Config.Get("SURF_Threshold", 200);
float Rect_Inflate = ConfigHelper.Config.Get("SURF_Rect_Inflate", 0.1f);
double ratio_thresh = ConfigHelper.Config.Get("SURF_Ratio_Thresh", 0.1d);
int good_matches_thresh = ConfigHelper.Config.Get("SURF_Good_Matches_Thresh", 100);
bool debugshow = ConfigHelper.Config.Get("SURF_Debugshow", false);
Mat imgTemplate = null, imgTarget = null, tempDesc = null, imgMatches = null, resultmat = null;
try
{
imgTemplate = BitmapConverter.ToMat(basebmp);
imgTarget = BitmapConverter.ToMat(targetbmp);
//Cv2.CvtColor(imgTemplate, imgTemplate, ColorConversionCodes.BGR2GRAY);
//Cv2.CvtColor(imgTarget, imgTarget, ColorConversionCodes.BGR2GRAY);
// 3. 剪裁图像
imgTemplate = new Mat(imgTemplate, baseRect);
//Cv2.Circle(imgTemplate, new Point(250,250), 20, new Scalar(255,0,0), 1, LineTypes.AntiAlias, 0);
if (debugshow)
{
Cv2.NamedWindow("base", 0);
Cv2.ImShow("base", imgTemplate);
}
var surf = SURF.Create(SURF_Threshold);
KeyPoint[] tempKey;
tempDesc = new Mat();
surf.DetectAndCompute(imgTemplate, null, out tempKey, tempDesc);
Mat mask = new Mat(imgTarget.Size(), MatType.CV_8U, new Scalar(0, 0, 0));
var maskrect = new Rect(baseRect.X, baseRect.Y, baseRect.Width, baseRect.Height);
maskrect.Inflate((int)(baseRect.Width * Rect_Inflate), (int)(baseRect.Height * Rect_Inflate));
Cv2.Rectangle(mask, maskrect, new Scalar(255, 255, 255), -1);
KeyPoint[] targetKey;
Mat targetDesc = new Mat();
surf.DetectAndCompute(imgTarget, mask, out targetKey, targetDesc);
BFMatcher matcher = new BFMatcher(NormTypes.L2, crossCheck: false);
// 匹配两幅图中的描述子(descriptors)
DMatch[] matches = matcher.Match(targetDesc, tempDesc);
tempDesc.Dispose();
List<DMatch> good_matches = new List<DMatch>();
for (int i = 0; i < matches.Length; i++)
{
if (matches[i].Distance < ratio_thresh)
{
good_matches.Add(matches[i]);
}
}
// -------锚定物体------------
// 创建两个数组来存储匹配成功的特征点,一个用于物体图像(obj),另一个用于场景图像(scene)
Point2d[] obj = new Point2d[good_matches.Count()];
Point2d[] scene = new Point2d[good_matches.Count()];
// 遍历匹配成功的特征点
for (int i = 0; i < good_matches.Count(); i++)
{
// 获取查询图像中特征点的坐标,通过good_matches[i].QueryIdx找到对应特征点的索引
obj[i] = targetKey[good_matches[i].QueryIdx].Pt.ToPoint();
// 获取模板图像中对应的特征点坐标,通过good_matches[i].TrainIdx找到对应特征点的索引
scene[i] = tempKey[good_matches[i].TrainIdx].Pt.ToPoint();
}
if (obj.Length < good_matches_thresh)
{
return false;
}
if (scene.Length < good_matches_thresh)
{
//MessageBox.Show("匹配点不足,数量为" + scene.Length);
return false;
}
if (debugshow)
{
// 创建两点,初始值设为最小和最大的浮点数,用于存储最左上角和最右下角的点
Point2f topLeft = new Point2f(float.MaxValue, float.MaxValue);
Point2f bottomRight = new Point2f(float.MinValue, float.MinValue);
// 遍历所有匹配点
foreach (DMatch match in good_matches)
{
// 获取当前匹配对中源图像和目标图像的点坐标
Point2f srcPt = targetKey[match.QueryIdx].Pt;
Point2f dstPt = tempKey[match.TrainIdx].Pt;
// 寻找最左上角的点
topLeft.X = Math.Min(topLeft.X, srcPt.X);
topLeft.Y = Math.Min(topLeft.Y, srcPt.Y);
// 寻找最右下角的点
bottomRight.X = Math.Max(bottomRight.X, srcPt.X);
bottomRight.Y = Math.Max(bottomRight.Y, srcPt.Y);
}
// 将浮点数坐标转换为整数坐标
OpenCvSharp.Point topLeftPoint = new OpenCvSharp.Point((int)topLeft.X, (int)topLeft.Y);
OpenCvSharp.Point bottomRightPoint = new OpenCvSharp.Point((int)bottomRight.X, (int)bottomRight.Y);
imgMatches = new Mat();
Cv2.DrawMatches(imgTarget, targetKey, imgTemplate, tempKey, good_matches, imgMatches);
Cv2.Rectangle(imgMatches, topLeftPoint, bottomRightPoint, new Scalar(0, 255, 0), 5);
Cv2.NamedWindow("match", WindowFlags.GuiNormal);
Cv2.ImShow("match", imgMatches);
// 绘制一个矩形框,框住匹配的区域
imgMatches.Dispose();
}
// 使用Cv2.FindHomography方法计算透视变换矩阵H,它可以将物体图像映射到场景图像上
// HomographyMethods.Ransac表示使用RANSAC算法来估计透视变换矩阵,3表示RANSAC算法的最大迭代次数,null表示不使用掩码
Mat H = Cv2.FindHomography(obj, scene, HomographyMethods.Ransac, 3, null);
resultmat = new Mat();
Cv2.WarpPerspective(imgTarget, resultmat, H, imgTarget.Size());
baseRect.X = 0;
baseRect.Y = 0;
resultmat = new Mat(resultmat, baseRect);
if (debugshow)
{
Cv2.NamedWindow("最终图", WindowFlags.GuiNormal);
Cv2.ImShow("最终图", resultmat);
}
matchBitmap = BitmapConverter.ToBitmap(resultmat);
resultmat.Dispose();
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
finally
{
imgTemplate?.Dispose();
imgTarget?.Dispose();
tempDesc?.Dispose();
imgMatches?.Dispose();
resultmat?.Dispose();
}
}
public static bool Star_MatchTemplate(Bitmap basebmp, Bitmap targetbmp, RectangleF rectangleF, out Bitmap matchBitmap)
{
matchBitmap = null;
Rect baseRect = new Rect((int)rectangleF.X, (int)rectangleF.Y, (int)rectangleF.Width, (int)rectangleF.Height);
int SURF_Threshold = ConfigHelper.Config.Get("SURF_Threshold", 200);
float Rect_Inflate = ConfigHelper.Config.Get("SURF_Rect_Inflate", 0.1f);
double ratio_thresh = ConfigHelper.Config.Get("SURF_Ratio_Thresh", 0.1d);
int good_matches_thresh = ConfigHelper.Config.Get("SURF_Good_Matches_Thresh", 100);
bool debugshow = ConfigHelper.Config.Get("SURF_Debugshow", false);
Mat imgTemplate = null, imgTarget = null, tempDesc = null, imgMatches = null, resultmat = null;
try
{
imgTemplate = BitmapConverter.ToMat(basebmp);
imgTarget = BitmapConverter.ToMat(targetbmp);
//Cv2.CvtColor(imgTemplate, imgTemplate, ColorConversionCodes.BGR2GRAY);
//Cv2.CvtColor(imgTarget, imgTarget, ColorConversionCodes.BGR2GRAY);
// 3. 剪裁图像
imgTemplate = new Mat(imgTemplate, baseRect);
//Cv2.Circle(imgTemplate, new Point(250,250), 20, new Scalar(255,0,0), 1, LineTypes.AntiAlias, 0);
if (debugshow)
{
Cv2.NamedWindow("base", 0);
Cv2.ImShow("base", imgTemplate);
}
var surf = StarDetector.Create();
KeyPoint[] tempKey;
tempDesc = new Mat();
surf.DetectAndCompute(imgTemplate, null, out tempKey, tempDesc);
Mat mask = new Mat(imgTarget.Size(), MatType.CV_8U, new Scalar(0, 0, 0));
var maskrect = new Rect(baseRect.X, baseRect.Y, baseRect.Width, baseRect.Height);
maskrect.Inflate((int)(baseRect.Width * Rect_Inflate), (int)(baseRect.Height * Rect_Inflate));
Cv2.Rectangle(mask, maskrect, new Scalar(255, 255, 255), -1);
KeyPoint[] targetKey;
Mat targetDesc = new Mat();
surf.DetectAndCompute(imgTarget, mask, out targetKey, targetDesc);
BFMatcher matcher = new BFMatcher(NormTypes.L2, crossCheck: false);
// 匹配两幅图中的描述子(descriptors)
DMatch[] matches = matcher.Match(targetDesc, tempDesc);
tempDesc.Dispose();
List<DMatch> good_matches = new List<DMatch>();
for (int i = 0; i < matches.Length; i++)
{
if (matches[i].Distance < ratio_thresh)
{
good_matches.Add(matches[i]);
}
}
// -------锚定物体------------
// 创建两个数组来存储匹配成功的特征点,一个用于物体图像(obj),另一个用于场景图像(scene)
Point2d[] obj = new Point2d[good_matches.Count()];
Point2d[] scene = new Point2d[good_matches.Count()];
// 遍历匹配成功的特征点
for (int i = 0; i < good_matches.Count(); i++)
{
// 获取查询图像中特征点的坐标,通过good_matches[i].QueryIdx找到对应特征点的索引
obj[i] = targetKey[good_matches[i].QueryIdx].Pt.ToPoint();
// 获取模板图像中对应的特征点坐标,通过good_matches[i].TrainIdx找到对应特征点的索引
scene[i] = tempKey[good_matches[i].TrainIdx].Pt.ToPoint();
}
if (obj.Length < good_matches_thresh)
{
return false;
}
if (scene.Length < good_matches_thresh)
{
//MessageBox.Show("匹配点不足,数量为" + scene.Length);
return false;
}
if (debugshow)
{
// 创建两点,初始值设为最小和最大的浮点数,用于存储最左上角和最右下角的点
Point2f topLeft = new Point2f(float.MaxValue, float.MaxValue);
Point2f bottomRight = new Point2f(float.MinValue, float.MinValue);
// 遍历所有匹配点
foreach (DMatch match in good_matches)
{
// 获取当前匹配对中源图像和目标图像的点坐标
Point2f srcPt = targetKey[match.QueryIdx].Pt;
Point2f dstPt = tempKey[match.TrainIdx].Pt;
// 寻找最左上角的点
topLeft.X = Math.Min(topLeft.X, srcPt.X);
topLeft.Y = Math.Min(topLeft.Y, srcPt.Y);
// 寻找最右下角的点
bottomRight.X = Math.Max(bottomRight.X, srcPt.X);
bottomRight.Y = Math.Max(bottomRight.Y, srcPt.Y);
}
// 将浮点数坐标转换为整数坐标
OpenCvSharp.Point topLeftPoint = new OpenCvSharp.Point((int)topLeft.X, (int)topLeft.Y);
OpenCvSharp.Point bottomRightPoint = new OpenCvSharp.Point((int)bottomRight.X, (int)bottomRight.Y);
imgMatches = new Mat();
Cv2.DrawMatches(imgTarget, targetKey, imgTemplate, tempKey, good_matches, imgMatches);
Cv2.Rectangle(imgMatches, topLeftPoint, bottomRightPoint, new Scalar(0, 255, 0), 5);
Cv2.NamedWindow("match", WindowFlags.GuiNormal);
Cv2.ImShow("match", imgMatches);
// 绘制一个矩形框,框住匹配的区域
imgMatches.Dispose();
}
// 使用Cv2.FindHomography方法计算透视变换矩阵H,它可以将物体图像映射到场景图像上
// HomographyMethods.Ransac表示使用RANSAC算法来估计透视变换矩阵,3表示RANSAC算法的最大迭代次数,null表示不使用掩码
Mat H = Cv2.FindHomography(obj, scene, HomographyMethods.Ransac, 3, null);
resultmat = new Mat();
Cv2.WarpPerspective(imgTarget, resultmat, H, imgTarget.Size());
baseRect.X = 0;
baseRect.Y = 0;
resultmat = new Mat(resultmat, baseRect);
if (debugshow)
{
Cv2.NamedWindow("最终图", WindowFlags.GuiNormal);
Cv2.ImShow("最终图", resultmat);
}
matchBitmap = BitmapConverter.ToBitmap(resultmat);
resultmat.Dispose();
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
if (imgTemplate != null)
imgTemplate.Dispose();
if (imgTarget != null)
imgTarget.Dispose();
if (tempDesc != null)
tempDesc.Dispose();
if (imgMatches != null)
imgMatches.Dispose();
if (resultmat != null)
resultmat.Dispose();
}
}
public static Bitmap CropBitmap(Bitmap bitmap, RectangleF rect)
{
// 检查rect是否超出bitmap的尺寸
if (rect.Left < 0) rect = new RectangleF(0, rect.Top, rect.Width, rect.Height);
if (rect.Top < 0) rect = new RectangleF(rect.Left, 0, rect.Width, rect.Height);
if (rect.Right > bitmap.Width) rect = new RectangleF(rect.Left, rect.Top, bitmap.Width - rect.Left, rect.Height);
if (rect.Bottom > bitmap.Height) rect = new RectangleF(rect.Left, rect.Top, rect.Width, bitmap.Height - rect.Top);
// 创建新的Bitmap,大小与rect相同
Bitmap croppedBitmap = new Bitmap((int)rect.Width, (int)rect.Height);
// 创建Graphics对象并绘制裁剪后的图像
using (Graphics g = Graphics.FromImage(croppedBitmap))
{
g.DrawImage(bitmap, new Rectangle(0, 0, croppedBitmap.Width, croppedBitmap.Height),
rect,
GraphicsUnit.Pixel);
}
return croppedBitmap;
}
}
}