프로젝트

일반

사용자정보

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

markus / ImageComparer / Markus.ImageComparer / ImageComparerBase.cs @ 6b6bc870

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

1
using OpenCvSharp;
2
using OpenCvSharp.CPlusPlus;
3
using System;
4
using System.Collections.Generic;
5
using System.Drawing;
6
using System.Drawing.Imaging;
7
using System.IO;
8
using System.Linq;
9
using System.Net;
10
using System.Runtime.InteropServices;
11
using System.Text;
12
using System.Threading.Tasks;
13
using Point = System.Drawing.Point;
14
using Size = System.Drawing.Size;
15

    
16
namespace Markus.Image
17
{
18
    public class ImageComparerBase : IDisposable
19
    {
20
        Mat OriginalImageData = null;
21
        Mat TargatImageData = null;
22

    
23
        /// <summary>
24
        /// 이미지 비교에 사용되는 점수
25
        /// </summary>
26
        double gMatchScore = 0.9;
27

    
28
        /// <summary>
29
        /// 이미지의 크기와 포멧을 변경한다.
30
        /// </summary>
31
        /// <param name="bitmap"></param>
32
        /// <param name="newSize"></param>
33
        /// <param name="pixelFormat"></param>
34
        /// <returns></returns>
35
        protected System.Drawing.Bitmap ChangeBitmapFormatAndSize(System.Drawing.Bitmap bitmap, Size newSize, PixelFormat pixelFormat)
36
        {
37
            Bitmap result = bitmap;
38

    
39
            //if (pixelFormat != result.PixelFormat)
40
            //{
41
            //    Point originPoint = new Point(0, 0);
42
            //    Rectangle rect = new Rectangle(originPoint, bitmap.Size);
43
            //    result = bitmap.Clone(rect, pixelFormat);
44
            //}
45

    
46
            if (result.Size != newSize || pixelFormat != result.PixelFormat)
47
            {
48

    
49
                using (Graphics g = Graphics.FromImage(bitmap))
50
                {
51
                    ColorMatrix cm = new ColorMatrix(new float[][]{ new
52
                                    float[]{0.3f,0.3f,0.3f,0,0},
53
                                    new float[]{0.59f,0.59f,0.59f,0,0},
54
                                    new float[]{0.11f,0.11f,0.11f,0,0},
55
                                    new float[]{0,0,0,1,0,0},
56
                                    new float[]{0,0,0,0,1,0},
57
                                    new float[]{0,0,0,0,0,1}});
58

    
59
                    ImageAttributes ia = new ImageAttributes();
60
                    ia.SetColorMatrix(cm);
61

    
62
                    g.DrawImage(result, new Rectangle(0, 0, newSize.Width, newSize.Height),
63
                                            0, 0, newSize.Width, newSize.Height, GraphicsUnit.Pixel, ia);
64
                    g.Dispose();
65
                }
66
            }
67

    
68
            return result;
69
        }
70

    
71
        /// <summary>
72
        /// Originalbitmap에서 TargatBitmap과 비교하여 틀린 부분의 데이터를 Emgu.CV.TDepth형식으로 반환한다.
73
        /// </summary>
74
        /// <param name="Originalbitmap">원본 이미지</param>
75
        /// <param name="TargatBitmap">비교대상 이미지</param>
76
        /// <returns>Emgu.CV.TDepth형식의 byte[,,]</returns>
77
        protected Mat MathchesImageData(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap)
78
        {
79
            Mat result = new Mat();
80

    
81
            try
82
            {
83
                Mat mask = new Mat();
84

    
85
                // 원본이미지의 크키와 Format24bppRgb로 타켓 이미지를 변경
86
                // 크기가 틀린 경우 비교시 바이트배열 오류 발생
87
                // 이미지 포멧은 24bit이하로 emgu CV가 작동
88
                //Originalbitmap = ChangeBitmapFormatAndSize(Originalbitmap, Originalbitmap.Size, PixelFormat.Format24bppRgb);
89
                //TargatBitmap = ChangeBitmapFormatAndSize(TargatBitmap, Originalbitmap.Size, PixelFormat.Format24bppRgb);
90
               
91
                OriginalImageData = OpenCvSharp.Extensions.BitmapConverter.ToMat(Originalbitmap);
92
                TargatImageData = OpenCvSharp.Extensions.BitmapConverter.ToMat(TargatBitmap);
93

    
94
                if (OriginalImageData.Size() != TargatImageData.Size())
95
                {
96
                    Cv2.Resize(TargatImageData, TargatImageData, OriginalImageData.Size());
97
                }
98

    
99
                //Cv2.ImWrite("d:\\testsave\\original.png", OriginalImageData);
100
                //Cv2.ImWrite("d:\\testsave\\Targat.png", TargatImageData);
101

    
102

    
103
                Cv2.CvtColor(OriginalImageData, OriginalImageData, ColorConversion.BgrToGray);
104
                Cv2.CvtColor(TargatImageData, TargatImageData, ColorConversion.BgrToGray);
105
                //Cv2.CvtColor(TargatImageData, TargatImageData, ColorConversion.RgbToGray);
106
                //Cv2.ImWrite("d:\\testsave\\original_Mask.png", OriginalImageData);
107

    
108

    
109
                //Cv2.Threshold(OriginalImageData, OriginalImageData, 127, 255,ThresholdType.Binary);
110
                //Cv2.Threshold(TargatImageData, TargatImageData, 127, 255, ThresholdType.Otsu);
111

    
112
                Mat outputData = new Mat(TargatImageData.Size(), MatType.CV_8UC1);
113

    
114
                Cv2.Absdiff(OriginalImageData, TargatImageData, outputData);
115

    
116
                //Cv2.ImWrite("d:\\testsave\\outputData.png", outputData);
117
       
118
                //Computes absolute different between this image and the other image
119
                // 원본이미지와 타겟이미지를 처리
120

    
121
                // 틀린부분을 반환
122
                Cv2.BitwiseNot(outputData, result);
123

    
124

    
125
               // Cv2.ImWrite("d:\\testsave\\result.png", outputData);
126

    
127
            }
128
            catch (Exception ex)
129
            {
130
                throw ex;
131
            }
132
            finally
133
            {
134
            }
135
            
136
            return result;
137
        }
138
        /// <summary>
139
        /// Image<TColor, TDepth>의 틀린 부분을 Rect로 반환
140
        /// </summary>
141
        /// <param name="data"></param>
142
        /// <param name="block"></param>
143
        /// <returns></returns>
144
        protected List<System.Windows.Rect> GetMatchPixels_test(OpenCvSharp.CPlusPlus.Mat data, Size block)
145
        {
146
            int width = data.Cols;
147
            int height = data.Rows;
148

    
149
            List<System.Windows.Rect> results = new List<System.Windows.Rect>();
150

    
151
            var heightRange = from h in Enumerable.Range(1, height)
152
                              where h % block.Height == 0
153
                              select h;
154

    
155
            var widthRange = from w in Enumerable.Range(1, width)
156
                             where w % block.Width == 0
157
                             select w;
158

    
159
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
160
            stopwatch.Start();
161

    
162
            Mat outputMat = new Mat();
163

    
164
            HierarchyIndex[] hierarchy;
165
            //OpenCvSharp.CPlusPlus.Point[][] contours;
166
            OpenCvSharp.CPlusPlus.Point[][] contours;
167

    
168
            Cv2.ImWrite("d:\\testsave\\CvtColor_before.png", data);
169
            Cv2.CvtColor(data, outputMat, ColorConversion.BgrToGray);
170

    
171
            Cv2.ImWrite("d:\\testsave\\CvtColor_after.png", outputMat);
172

    
173
            OpenCvSharp.CPlusPlus.Point testpoint = new OpenCvSharp.CPlusPlus.Point();
174

    
175
            Cv2.Threshold(outputMat, outputMat, 127, 255, ThresholdType.Binary);
176

    
177
            Cv2.FindContours(outputMat, out contours, out hierarchy, ContourRetrieval.Tree, ContourChain.ApproxSimple, testpoint);
178

    
179
            for (int i = 0; i < contours.Count(); i++)
180
            {
181
                Cv2.DrawContours(data, contours, i, Scalar.Red, 1, LineType.AntiAlias);
182
            }
183
            Cv2.ImWrite("d:\\testsave\\draw.png", data);
184

    
185

    
186
            //foreach (var y in heightRange)
187
            //{
188
            //    foreach (var x in widthRange)
189
            //    {
190
            //        var rect = DataMatchScore(data, x, y, width, height, block);
191

    
192
            //        if (rect != null)
193
            //        {
194
            //            results.Add(rect.Value);
195
            //        }
196
            //    }
197
            //}
198

    
199
            //var items = data.ToDataFloat();
200

    
201
            //var handle = GCHandle.Alloc(data);
202

    
203
            //foreach (var y in heightRange)
204
            //{
205
            //    foreach (var x in widthRange)
206
            //    {
207
            //           var rect = DataMatchScore(data, x, y, width, height, block);
208

    
209
            //        if (rect != null)
210
            //        {
211
            //            results.Add(rect.Value);
212
            //        }
213
            //    }
214
            //}
215
            //handle.Free();
216

    
217
            //Parallel.ForEach(heightRange, (y) =>
218
            //{
219
            //    Parallel.ForEach(widthRange, (x) =>
220
            //    {
221
            //        var rect = DataMatchScore(data, x, y, width, height, block);
222

    
223
            //        if (rect != null)
224
            //        {
225
            //            results.Add(rect.Value);
226
            //        }
227
            //    });
228
            //});
229

    
230

    
231
            //Parallel.ForEach(heightRange, (y) =>
232
            //{
233
            //    Parallel.ForEach(widthRange, (x) =>
234
            //    {
235
            //        var rect = DataMatchScore(data, x, y, width, height, block);
236

    
237
            //        if (rect != null)
238
            //        {
239
            //            results.Add(rect.Value);
240
            //        }
241
            //    });
242
            //});
243

    
244
            System.Diagnostics.Debug.WriteLine("1 - " + new TimeSpan(stopwatch.ElapsedTicks));
245
            return results;
246
        }
247

    
248

    
249
        /// <summary>
250
        /// Image<TColor, TDepth>의 틀린 부분을 Rect로 반환
251
        /// </summary>
252
        /// <param name="data"></param>
253
        /// <param name="block"></param>
254
        /// <returns></returns>
255
        protected List<System.Windows.Rect> GetMatchPixels(OpenCvSharp.CPlusPlus.Mat data, Size block)
256
        {
257
            int width = data.Cols;
258
            int height = data.Rows;
259

    
260
            List<System.Windows.Rect> results = new List<System.Windows.Rect>();
261

    
262
            //var heightRange = from h in Enumerable.Range(1, height)
263
            //                  where h % block.Height == 0
264
            //                  select h;
265

    
266
            //var widthRange = from w in Enumerable.Range(1, width)
267
            //                 where w % block.Width == 0
268
            //                 select w;
269

    
270
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
271
            stopwatch.Start();
272

    
273
            Mat outputMat = new Mat(data.Size(), MatType.CV_8UC1);
274

    
275
            HierarchyIndex[] hierarchy;
276
            //OpenCvSharp.CPlusPlus.Point[][] contours;
277
            OpenCvSharp.CPlusPlus.Point[][] contours;
278

    
279
            //Cv2.CvtColor(data, outputMat,ColorConversion.RgbToGray);
280

    
281
            OpenCvSharp.CPlusPlus.Point testpoint = new OpenCvSharp.CPlusPlus.Point();
282

    
283
            Cv2.Threshold(data, data, 200, 255,ThresholdType.Otsu);
284

    
285
            Cv2.FindContours(data, out contours, out hierarchy, ContourRetrieval.List, ContourChain.ApproxNone, testpoint);
286

    
287
            int blockWidthMargin = block.Width / 2;
288
            int blockHeightMargin = block.Height / 2;
289

    
290
            var rects = contours.SelectMany(p => p).OrderBy(p=>p.X + p.Y)
291
                            .Select(p=> 
292
                                new System.Windows.Rect {
293
                                    X = p.X - blockWidthMargin,
294
                                    Y = p.Y - blockHeightMargin,
295
                                    Width = block.Width,
296
                                    Height = block.Height
297
                                })
298
                                .ToArray();
299

    
300
            for (int i = 0; i < rects.Count(); i++)
301
            {
302
                if (results.Count(r => r.IntersectsWith(rects[i])) == 0)
303
                {
304
                    results.Add(rects[i]);
305
                }
306
            }
307

    
308
            //for (int i = 0; i < contours.Count(); i++)
309
            //{
310
            //    for (int j = 0; j < contours[i].Count(); j++)
311
            //    {
312
            //        if (results.Count(x => x.Contains()))
313
            //        {
314
            //            results.Add(contours)
315
            //        }
316
            //    }
317

    
318
            //    Cv2.DrawContours(data, contours, i, Scalar.Red, 1, LineType.AntiAlias);
319
            //}
320
            //Cv2.ImWrite("d:\\testsave\\draw.png", data);
321

    
322
            System.Diagnostics.Debug.WriteLine("1 - " + new TimeSpan(stopwatch.ElapsedTicks));
323
            return results;
324
        }
325

    
326

    
327
        /// <summary>
328
        /// MathchesImageData의 틀린 부분을 Rect로 반환
329
        /// </summary>
330
        /// <param name="data"></param>
331
        /// <param name="currentX"></param>
332
        /// <param name="currentY"></param>
333
        /// <param name="ImageWidth"></param>
334
        /// <param name="ImageHeight"></param>
335
        /// <param name="block"></param>
336
        /// <returns></returns>
337
        protected System.Windows.Rect? DataMatchScore(OpenCvSharp.CPlusPlus.Mat mat, int currentX, int currentY, int ImageWidth, int ImageHeight, Size block)
338
        {
339
            System.Windows.Rect? result = null;
340

    
341
            int x = currentX;
342
            int y = currentY;
343
            int width = ImageWidth;
344
            int height = ImageHeight;
345

    
346
            for (int i = 0; i < block.Width; i++)
347
            {
348
                int wi = x + i;
349
                if (wi >= width) break;
350

    
351
                for (int j = 0; j < block.Height; j++)
352
                {
353
                    int hj = y + j;
354
                    if (hj >= height) break;
355

    
356
                    try
357
                    {
358
                        //System.Diagnostics.Debug.WriteLine($"point :{wi},{hj}");
359
                        if (mat.GetValue<float>(wi,hj) < gMatchScore)
360
                        {
361
                            result = new System.Windows.Rect(y, x, block.Width, block.Height);
362
                            return result;
363
                        }
364
                    }
365
                    catch (Exception e)
366
                    {
367
                        System.Diagnostics.Debug.WriteLine(e);
368
                    }
369

    
370
                }
371
            }
372

    
373
            return result;
374
        }
375

    
376
        /// <summary>
377
        /// MathchesImageData의 틀린 부분을 Rect로 반환
378
        /// </summary>
379
        /// <param name="data"></param>
380
        /// <param name="currentX"></param>
381
        /// <param name="currentY"></param>
382
        /// <param name="ImageWidth"></param>
383
        /// <param name="ImageHeight"></param>
384
        /// <param name="block"></param>
385
        /// <returns></returns>
386
        protected System.Windows.Rect? DataMatchScore(IEnumerable<ImageData<float>> data, int currentX, int currentY, int ImageWidth, int ImageHeight, Size block)
387
        {
388
            System.Windows.Rect? result = null;
389

    
390
            int x = currentX;
391
            int y = currentY;
392
            int width = ImageWidth;
393
            int height = ImageHeight;
394

    
395
            for (int i = 0; i < block.Width; i++)
396
            {
397
                int wi = x + i;
398
                if (wi >= width) break;
399

    
400
                for (int j = 0; j < block.Height; j++)
401
                {
402
                    int hj = y + j;
403
                    if (hj >= height) break;
404

    
405
                    try
406
                    {
407
                        //System.Diagnostics.Debug.WriteLine($"point :{wi},{hj}");
408
                        if (data.FirstOrDefault(d=> d.Row == wi && d.Col == hj)?.Value < gMatchScore)
409
                        {
410
                            result = new System.Windows.Rect(y, x, block.Width, block.Height);
411
                            return result;
412
                        }
413
                    }
414
                    catch (Exception e)
415
                    {
416
                        System.Diagnostics.Debug.WriteLine(e);
417
                    }
418

    
419
                }
420
            }
421

    
422
            return result;
423
        }
424
        /// <summary>
425
        /// Image<TColor, TDepth>의 틀린 부분을 Rect로 반환
426
        /// </summary>
427
        /// <param name="data"></param>
428
        /// <param name="block"></param>
429
        /// <returns></returns>
430
        protected async Task<List<System.Windows.Rect>> GetMatchPixelsAsnc(OpenCvSharp.CPlusPlus.Mat data, Size block)
431
        {
432
            return await Task.Factory.StartNew<List<System.Windows.Rect>>(() =>
433
            {
434
                return GetMatchPixels(data, block);
435
            });
436
        }
437

    
438
        protected Bitmap LoadPicture(string url)
439
        {
440
            HttpWebRequest wreq;
441
            HttpWebResponse wresp;
442
            Stream mystream;
443
            Bitmap bmp;
444

    
445
            bmp = null;
446
            mystream = null;
447
            wresp = null;
448
            try
449
            {
450
                wreq = (HttpWebRequest)WebRequest.Create(url);
451
                wreq.AllowWriteStreamBuffering = true;
452

    
453
                wresp = (HttpWebResponse)wreq.GetResponse();
454

    
455
                if ((mystream = wresp.GetResponseStream()) != null)
456
                    bmp = new Bitmap(mystream);
457
            }
458
            finally
459
            {
460
                if (mystream != null)
461
                {
462
                    mystream.Close();
463
                    mystream.Dispose();
464
                }
465

    
466
                if (wresp != null)
467
                {
468
                    wresp.Close();
469
                    wresp.Dispose();
470
                }
471
            }
472
            return (bmp);
473
        }
474

    
475
        #region  IDisposable Support 
476

    
477
        private bool disposedValue = false;
478

    
479
        // 중복 호출을 검색하려면 
480
        protected virtual void Dispose(bool disposing)
481
        {
482
            if (!disposedValue)
483
            {
484
                if (disposing)
485
                {
486
                    // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다. 
487
                }
488
                // TODO: 관리되지 않는 리소스(관리되지 않는 개체)를 해제하고 아래의 종료자를 재정의합니다. 
489
                // TODO: 큰 필드를 null로 설정합니다. 
490
                disposedValue = true;
491
            }
492
        }
493

    
494
        // TODO: 위의 Dispose(bool disposing)에 관리되지 않는 리소스를 해제하는 코드가 포함되어 있는 경우에만 종료자를 재정의합니다.
495
        // 
496
        //~DisposeClass()
497
       // {
498
            // // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요. 
499
            // Dispose(false); // 
500
       // } 
501

    
502
        // 삭제 가능한 패턴을 올바르게 구현하기 위해 추가된 코드입니다. 
503
        public void Dispose()
504
        {
505
            // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요. 
506
            Dispose(true);
507

    
508

    
509
            if (OriginalImageData != null)
510
            {
511
                OriginalImageData.Dispose();
512
            }
513

    
514
            if (TargatImageData != null)
515
            {
516
                TargatImageData.Dispose();
517
            }
518

    
519
            // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다. 
520
            //  GC.SuppressFinalize(this);
521
            GC.Collect();
522
            GC.SuppressFinalize(this);
523
            GC.Collect();
524
        } 
525
        #endregion
526
    }
527
}
클립보드 이미지 추가 (최대 크기: 500 MB)