프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

markus / ImageComparer / Markus.ImageComparer / ImageComparer.cs @ 72424099

이력 | 보기 | 이력해설 | 다운로드 (16.9 KB)

1
using Emgu.CV;
2
using Emgu.CV.Structure;
3
using System;
4
using System.Collections.Generic;
5
using System.Drawing;
6
using System.Drawing.Imaging;
7
using System.Linq;
8
using System.Text;
9
using System.Threading.Tasks;
10

    
11
namespace Markus.Image
12
{
13
    public class ImageComparer : ImageComparerBase
14
    {
15
        /// <summary>
16
        /// 이미지를 비교 후 원본 이미지에 Rect를 그린다.
17
        /// </summary>
18
        /// <param name="Originalbitmap">원본 이미지</param>
19
        /// <param name="TargatBitmap">비교대상 이미지</param>
20
        /// <param name="ResultRectSize">반환되는 Rect의 사이즈</param>
21
        /// <returns></returns>
22
        public Bitmap CompareDrawRects(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap, Size ResultRectSize)
23
        {
24
            var rects =  CompareReturnRects(Originalbitmap, TargatBitmap, ResultRectSize);
25

    
26
            if (rects.Count != 0)
27
            {
28
                using (Graphics g = Graphics.FromImage(Originalbitmap))
29
                {
30
                    var rect = rects.Select(x => new System.Drawing.Rectangle((int)x.X, (int)x.Y, (int)x.Width, (int)x.Height)).ToList();
31

    
32
                    g.DrawRectangles(new Pen(Brushes.Blue, 3f), rect.ToArray());
33
                    g.Save();
34

    
35
                    g.Dispose();
36
                }
37
            }
38

    
39
            return Originalbitmap;
40
        }
41

    
42
        // JoinRects: will return a rectangle composed of r1 and r2.
43
        private System.Windows.Rect JoinRects(System.Windows.Rect r1, System.Windows.Rect r2)
44
        {
45
            return new System.Windows.Rect(Math.Min(r1.X, r2.X),
46
                            Math.Min(r1.Y, r2.Y),
47
                            Math.Max(r1.Y + r1.Width, r2.Y + r2.Width),
48
                            Math.Max(r1.X + r1.Height, r2.X + r2.Height));
49
        }
50

    
51
        private System.Windows.Rect RectSizeUp(System.Windows.Rect rect,int UpSize)
52
        {
53
            return new System.Windows.Rect(rect.X - UpSize, rect.Y - UpSize, rect.Width + UpSize, rect.Height + UpSize);
54
        }
55

    
56
        public System.Windows.Media.Imaging.BitmapSource CompareDrawRects(System.Windows.Media.Imaging.BitmapSource Originalbitmap, System.Windows.Media.Imaging.BitmapSource TargatBitmap, Size ResultRectSize)
57
        {
58
            var _Originalbitmap = CreateBitmapFromSource(Originalbitmap);
59
            var _TargatBitmap = CreateBitmapFromSource(TargatBitmap);
60

    
61
            var rects = CompareReturnRects(_Originalbitmap, _TargatBitmap, ResultRectSize);
62
         
63
            if (rects.Count != 0)
64
            {
65
                using (Graphics g = Graphics.FromImage(_Originalbitmap))
66
                {
67
                    var rect = rects.Select(x => new System.Drawing.Rectangle((int)x.X, (int)x.Y, (int)x.Width, (int)x.Height));
68

    
69
                    g.DrawRectangles(new Pen(Brushes.Blue, 3f), rect.ToArray());
70
                    g.Save();
71

    
72
                    g.Dispose();
73
                }
74
            }
75

    
76
            return CreateBitmapSourceFromBitmap(_Originalbitmap);
77
        }
78

    
79
        public List<System.Windows.Rect> CompareReturnRects(string OriginalbitmapUri, string TargatBitmapUri, Size ResultRectSize)
80
        {
81
            List<System.Windows.Rect> result = new List<System.Windows.Rect>();
82

    
83
            Bitmap Originalbitmap = null;
84
            Bitmap TargatBitmap = null;
85

    
86
            try
87
            {
88

    
89
                Originalbitmap = LoadPicture(OriginalbitmapUri);
90
                TargatBitmap = LoadPicture(TargatBitmapUri);
91

    
92
                result = CompareReturnRects(Originalbitmap, TargatBitmap, ResultRectSize);
93
            }
94
            catch (Exception)
95
            {
96
                throw;
97
            }
98
            finally
99
            {
100
                Originalbitmap.Dispose();
101
                TargatBitmap.Dispose();
102
            }
103

    
104
            return result;
105
        }
106

    
107
        /// <summary>
108
        /// 이미지를 비교 후 해당 영역을 Rect로 반환한다.
109
        /// </summary>
110
        /// <param name="Originalbitmap">원본 이미지</param>
111
        /// <param name="TargatBitmap">비교대상 이미지</param>
112
        /// <param name="ResultRectSize">반환되는 Rect의 사이즈</param>
113
        /// <returns></returns>
114
        public List<System.Windows.Rect> CompareReturnRects(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap, Size ResultRectSize)
115
        {
116
            List<System.Windows.Rect> result = new List<System.Windows.Rect>();
117

    
118
            try
119
            {
120
                List<System.Windows.Rect> rects = new List<System.Windows.Rect>();
121

    
122
                byte[,,] data = MathchesImageData(Originalbitmap, TargatBitmap);
123

    
124
                rects =  GetMatchPixels(data, ResultRectSize);
125

    
126
                if (rects.Count() > 0)
127
                {
128
                    result = Merge(rects, ResultRectSize.Height);
129
                }
130

    
131
                //result = JoinRectList(rects);
132
            }
133
            catch (Exception ex)
134
            {
135
                throw ex;
136
            }
137
            finally
138
            {
139

    
140
            }
141

    
142
            return result;
143
        }
144

    
145
        private List<System.Windows.Rect> JoinRectList(List<System.Windows.Rect> rects)
146
        {
147
            List<System.Windows.Rect> result = new List<System.Windows.Rect>();
148

    
149
            if (rects.Count() > 0)
150
            {
151
                System.Windows.Rect rect = rects[0];
152
                System.Windows.Rect joinRect = rects[0];
153

    
154
                while (rects.Count() > 0)
155
                {
156
                    var joinItems = rects.Where(x => RectSizeUp(joinRect, 1).Contains(x)).ToList();
157

    
158
                    if (joinItems.Count() == 0)
159
                    {
160
                        result.Add(joinRect);
161
                    }
162
                    else
163
                    {
164
                        for (int i = 0; i < joinItems.Count(); i++)
165
                        {
166
                            rect = JoinRects(rect, joinItems[i]);
167
                            rects.Remove(joinItems[i]);
168
                        }
169

    
170
                        if (rects.Count() > 0)
171
                        {
172
                            rects.RemoveAt(0);
173
                        }
174

    
175
                        result.Add(joinRect);
176
                    }
177
                }
178
            }
179

    
180
            return result;
181
        }
182

    
183
        private List<System.Windows.Rect> Merge(List<System.Windows.Rect> r,int rectHeight)
184
        {
185
            // Computing the bound
186
            System.Windows.Rect bound = new System.Windows.Rect(r[0].X, r[0].Y, r[0].Width, r[0].Height);
187
            for (int i = 1; i < r.Count(); ++i)
188
            {
189
                bound.X = Math.Min(bound.X, r[i].X);
190
                bound.Y = Math.Min(bound.Y, r[i].Y);
191
                bound.Width = Math.Max(bound.Right, r[i].Right) - bound.X;
192
                bound.Height = Math.Max(bound.Bottom, r[i].Bottom) - bound.Y;
193
            }
194

    
195
            // Create number of rectangle will be created by vertical strip expansion
196
            System.Windows.Rect[] m = new System.Windows.Rect[(int)bound.Height / (int)rectHeight];
197
            for (int i = 0; i < m.Length; ++i)
198
            {
199
                m[i] = new System.Windows.Rect(Int32.MaxValue,bound.Y + i * rectHeight, 0, rectHeight);
200
            }
201

    
202
            for (int i = 0; i < r.Count(); ++i)
203
            {
204
                int index = ((int)r[i].Y - (int)bound.Y) / rectHeight;
205

    
206
                if (m[index].Width <= 0)
207
                {
208
                    m[index].Width = r[i].Width;
209
                    m[index].X = r[i].X;
210
                }
211
                else
212
                {
213
                    int right = (int)m[index].Right;
214
                    m[index].X = Math.Min(m[index].X, r[i].X);
215
                    m[index].Width = Math.Max(right, r[i].Right) - m[index].X;
216
                }
217
            }
218

    
219
            // Merge horozontally
220
            for (int i = m.Length - 1; i > 0; --i)
221
            {
222
                // can only merge when two rect has the same X and Width
223
                if ((m[i].X == m[i - 1].X) && (m[i].Width == m[i - 1].Width))
224
                {
225
                    m[i - 1].Height += m[i].Height; // expanse the rectangle
226
                    m[i].Width = 0;                // remove one rectangle
227
                }
228
            }
229

    
230
            // Remove all the empty rectangle
231
            List<System.Windows.Rect> result = new List<System.Windows.Rect>();
232
            for (int i = m.Length - 1; i >= 0; --i)
233
            {
234
                if (m[i].Width > 0)
235
                    result.Add(m[i]);
236
            }
237

    
238
            return result;
239
        }
240
        /// <summary>
241
        /// 이미지를 비교 후 원본 이미지에 Rect를 그린다.
242
        /// 메모리 문제 발생
243
        /// </summary>
244
        /// <param name="Originalbitmap">원본 이미지</param>
245
        /// <param name="TargatBitmap">비교대상 이미지</param>
246
        /// <param name="ResultRectSize">반환되는 Rect의 사이즈</param>
247
        /// <returns></returns>
248
        public async Task<Bitmap> CompareDrawRectsAsync(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap, Size ResultRectSize)
249
        {
250
            System.Drawing.Bitmap cloneOriginal = Originalbitmap;
251

    
252
            var rects = await CompareReturnRectsAsync(cloneOriginal, TargatBitmap, ResultRectSize);
253

    
254
            if (rects.Count != 0)
255
            {
256
                using (Graphics g = Graphics.FromImage(cloneOriginal))
257
                {
258
               
259
                    var rect = rects.Select(x => new System.Drawing.Rectangle((int)x.X, (int)x.Y, (int)x.Width, (int)x.Height));
260

    
261
                    g.DrawRectangles(new Pen(Brushes.Blue, 3f), rect.ToArray());
262
                    g.Save();
263

    
264
                    g.Dispose();
265
                }
266
            }
267

    
268
            return cloneOriginal;
269
        }
270

    
271
        /// <summary>
272
        /// 이미지를 비교 후 원본 이미지에 Rect를 그린다.
273
        /// 메모리 문제 발생
274
        /// </summary>
275
        /// <param name="Originalbitmap">원본 이미지</param>
276
        /// <param name="TargatBitmap">비교대상 이미지</param>
277
        /// <param name="ResultRectSize">반환되는 Rect의 사이즈</param>
278
        /// <returns></returns>
279
        public async Task<System.Windows.Media.Imaging.BitmapSource> CompareDrawRectsAsync(System.Windows.Media.Imaging.BitmapSource Originalbitmap, System.Windows.Media.Imaging.BitmapSource TargatBitmap, Size ResultRectSize)
280
        {
281

    
282
            var _Originalbitmap = CreateBitmapFromSource(Originalbitmap);
283
            var _TargatBitmap = CreateBitmapFromSource(TargatBitmap);
284

    
285
            var rects = await CompareReturnRectsAsync(_Originalbitmap, _TargatBitmap, ResultRectSize);
286

    
287
            if (rects.Count != 0)
288
            {
289
                using (Graphics g = Graphics.FromImage(_Originalbitmap))
290
                {
291
                    var rect = rects.Select(x => new System.Drawing.Rectangle((int)x.X, (int)x.Y, (int)x.Width, (int)x.Height));
292

    
293
                    g.DrawRectangles(new Pen(Brushes.Blue, 3f), rect.ToArray());
294
                    g.Save();
295

    
296
                    g.Dispose();
297
                }
298
            }
299

    
300
            return CreateBitmapSourceFromBitmap(_Originalbitmap);
301
        }
302

    
303
        public Bitmap CreateBitmapFromSource(System.Windows.Media.Imaging.BitmapSource bitmapsource)
304
        {
305
            //convert image format
306
            var src = new System.Windows.Media.Imaging.FormatConvertedBitmap();
307
            src.BeginInit();
308
            src.Source = bitmapsource;
309
            src.DestinationFormat = System.Windows.Media.PixelFormats.Bgr24;
310
            src.EndInit();
311

    
312
            //copy to bitmap
313
            Bitmap bitmap = new Bitmap(src.PixelWidth, src.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
314
            var data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
315
            src.CopyPixels(System.Windows.Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
316
            bitmap.UnlockBits(data);
317

    
318
            return bitmap;
319
        }
320

    
321
        /// <summary>
322
        /// 메모리 문제 발생
323
        /// </summary>
324
        /// <param name="bitmap"></param>
325
        /// <returns></returns>
326
        public System.Windows.Media.Imaging.WriteableBitmap CreateWriteableBitmapFromBitmap(Bitmap bitmap)
327
        {
328
            System.Windows.Media.Imaging.WriteableBitmap result = null;
329

    
330
            if (bitmap == null)
331
                throw new ArgumentNullException("bitmap");
332

    
333
            try
334
            {
335
                int bytesPerPixel = 4;
336

    
337
                result = new System.Windows.Media.Imaging.WriteableBitmap(bitmap.Width, bitmap.Height,
338
                                                                   bitmap.HorizontalResolution ,bitmap.VerticalResolution,
339
                                                                   bitmap.PixelFormat.Convert(), null);
340

    
341
                Rectangle colorBitmapRectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
342
                System.Windows.Int32Rect colorBitmapInt32Rect = new System.Windows.Int32Rect(0, 0, bitmap.Width, bitmap.Height);
343

    
344
                BitmapData data = bitmap.LockBits(colorBitmapRectangle, ImageLockMode.WriteOnly, bitmap.PixelFormat);
345

    
346
                result.WritePixels(colorBitmapInt32Rect, data.Scan0, data.Width * data.Height * bytesPerPixel, data.Stride);
347

    
348
                bitmap.UnlockBits(data);
349
            }
350
            catch (Exception ex)
351
            {
352
                //throw ex;
353
            }
354
            finally
355
            {
356
                bitmap.Dispose();
357
                bitmap = null;
358
                //GC.Collect(2);
359
            }
360

    
361
            return result;
362
        }
363
    
364
        /// <summary>
365
        /// 메모리 문제 발생
366
        /// </summary>
367
        /// <param name="bitmap"></param>
368
        /// <returns></returns>
369
        public System.Windows.Media.Imaging.BitmapSource CreateBitmapSourceFromBitmap(Bitmap bitmap)
370
        {
371
            System.Windows.Media.Imaging.BitmapSource result = null;
372
            
373
            if (bitmap == null)
374
                throw new ArgumentNullException("bitmap");
375

    
376
            try
377
            {
378
                using (var hbitmap = new SafeHBitmapHandle(bitmap.GetHbitmap(), true))
379
                {
380

    
381
                    result = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
382
                        hbitmap.DangerousGetHandle(),
383
                        IntPtr.Zero,
384
                        System.Windows.Int32Rect.Empty,
385
                        System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
386

    
387
                   
388
                }
389
            }
390
            catch (Exception ex)
391
            {
392
                //throw ex;
393
            }
394
            finally
395
            {
396
                bitmap.Dispose();
397
                bitmap = null;
398
                //GC.Collect(2);
399
            }
400

    
401
            return result;
402
        }
403

    
404
        public async Task<List<System.Windows.Rect>> CompareReturnRectsAsync(string OriginalbitmapUri, string TargatBitmapUri, Size ResultRectSize)
405
        {
406
            List<System.Windows.Rect> result = new List<System.Windows.Rect>();
407

    
408
            Bitmap Originalbitmap = null;
409
            Bitmap TargatBitmap = null;
410

    
411
            try
412
            {
413

    
414
                Originalbitmap = LoadPicture(OriginalbitmapUri);
415
                TargatBitmap = LoadPicture(TargatBitmapUri);
416

    
417
                result = await CompareReturnRectsAsync(Originalbitmap, TargatBitmap, ResultRectSize);
418
            }
419
            catch (Exception)
420
            {
421
                throw;
422
            }
423
            finally
424
            {
425
                Originalbitmap.Dispose();
426
                TargatBitmap.Dispose();
427
            }
428

    
429
            return result;
430
        }
431

    
432
        /// <summary>
433
        /// 이미지를 비교 후 해당 영역을 Rect로 반환한다.
434
        /// </summary>
435
        /// <param name="Originalbitmap">원본 이미지</param>
436
        /// <param name="TargatBitmap">비교대상 이미지</param>
437
        /// <param name="ResultRectSize">반환되는 Rect의 사이즈</param>
438
        /// <returns></returns>
439
        public async Task<List<System.Windows.Rect>> CompareReturnRectsAsync(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap, Size ResultRectSize)
440
        {
441
            List<System.Windows.Rect> result = new List<System.Windows.Rect>();
442

    
443
            try
444
            {
445
                byte[,,] data = MathchesImageData(Originalbitmap, TargatBitmap);
446

    
447
                result = await GetMatchPixelsAsnc(data, ResultRectSize);
448

    
449
                //result = JoinRectList(result);
450
                if (result.Count() > 0)
451
                {
452
                    result = Merge(result, ResultRectSize.Height);
453
                }
454

    
455
                data = null;
456
            }
457
            catch (Exception ex)
458
            {
459
                throw ex;
460
            }
461
            finally
462
            {
463
            }
464

    
465
            return result;
466
        }
467

    
468
       
469
        protected override void Dispose(bool disposing)
470
        {
471
            base.Dispose(disposing);
472
        }
473
    }
474
}
클립보드 이미지 추가 (최대 크기: 500 MB)