프로젝트

일반

사용자정보

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

markus / ImageComparer / Markus.ImageComparer / ImageComparerBase - 복사본.cs @ d7e20d2d

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

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

    
14
namespace Markus.Image
15
{
16
    public class ImageComparerBase : IDisposable
17
    {
18
        Image<Gray, Byte> OriginalImageData = null;
19
        Image<Gray, Byte> TargatImageData = null;
20

    
21
        int Threshold = 60; //stores threshold for thread access
22

    
23
        /// <summary>
24
        /// 이미지 비교에 사용되는 점수
25
        /// </summary>
26
        double gMatchScore = 0.09;
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 != bitmap.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 (bitmap.Size != newSize)
47
            {
48
                result = new Bitmap(newSize.Width, newSize.Height);
49

    
50
                using (Graphics g = Graphics.FromImage(result))
51
                {
52
                    g.DrawImage(bitmap, 0, 0, newSize.Width, newSize.Height);
53
                    g.Dispose();
54
                }
55
            }
56

    
57
            return result;
58
        }
59

    
60
        /// <summary>
61
        /// Originalbitmap에서 TargatBitmap과 비교하여 틀린 부분의 데이터를 Emgu.CV.TDepth형식으로 반환한다.
62
        /// </summary>
63
        /// <param name="Originalbitmap">원본 이미지</param>
64
        /// <param name="TargatBitmap">비교대상 이미지</param>
65
        /// <returns>Emgu.CV.TDepth형식의 byte[,,]</returns>
66
        protected byte[,,] MathchesImageData_old(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap)
67
        {
68
            byte[,,] result = null;
69

    
70
            try
71
            {
72
                // 원본이미지의 크키와 Format24bppRgb로 타켓 이미지를 변경
73
                // 크기가 틀린 경우 비교시 바이트배열 오류 발생
74
                // 이미지 포멧은 24bit이하로 emgu CV가 작동
75
                Originalbitmap = ChangeBitmapFormatAndSize(Originalbitmap, Originalbitmap.Size, PixelFormat.Format24bppRgb);
76
                TargatBitmap = ChangeBitmapFormatAndSize(TargatBitmap, Originalbitmap.Size, PixelFormat.Format24bppRgb);
77
                
78
                OriginalImageData = new Image<Gray, Byte>(Originalbitmap);
79
                TargatImageData = new Image<Gray, Byte>(TargatBitmap);
80

    
81
                //OriginalImageData = OriginalImageData.SmoothBilateral(10,50,50);
82
                //TargatImageData = TargatImageData.SmoothBilateral(10, 50, 50);
83

    
84
                #region Apply dilation and erosion to remove some noise 효과없음
85
                //OriginalImageData = OriginalImageData.Dilate(1);
86
                //TargatImageData = TargatImageData.Dilate(1);
87
                //OriginalImageData = OriginalImageData.Erode(1);
88
                //TargatImageData = TargatImageData.Erode(1);
89

    
90
                //threshold(OriginalImageData);
91
                //threshold(TargatImageData);
92
                #endregion
93

    
94
                //Computes absolute different between this image and the other image
95
                // 원본이미지와 타겟이미지를 처리
96
                var tmp = OriginalImageData.AbsDiff(TargatImageData).ThresholdBinary(new Gray(50), new Gray(255));
97
                var matches = tmp.Not();
98

    
99
                // 틀린부분을 반환
100
                result = matches.Data;
101

    
102
            
103

    
104

    
105
                matches.Dispose();
106
                tmp.Dispose();
107
            }
108
            catch (Exception ex)
109
            {
110
                throw ex;
111
            }
112
            
113
            return result;
114
        }
115

    
116
        protected Point[][] MathchesImageData(System.Drawing.Bitmap Originalbitmap, System.Drawing.Bitmap TargatBitmap)
117
        {
118
            Point[][] result = null;
119

    
120
            try
121
            {
122
                // 원본이미지의 크키와 Format24bppRgb로 타켓 이미지를 변경
123
                // 크기가 틀린 경우 비교시 바이트배열 오류 발생
124
                // 이미지 포멧은 24bit이하로 emgu CV가 작동
125
                Originalbitmap = ChangeBitmapFormatAndSize(Originalbitmap, Originalbitmap.Size, PixelFormat.Format24bppRgb);
126
                TargatBitmap = ChangeBitmapFormatAndSize(TargatBitmap, Originalbitmap.Size, PixelFormat.Format24bppRgb);
127

    
128
                OriginalImageData = new Image<Gray, Byte>(Originalbitmap);
129
                TargatImageData = new Image<Gray, Byte>(TargatBitmap);
130

    
131
                //OriginalImageData = OriginalImageData.SmoothBilateral(10,50,50);
132
                //TargatImageData = TargatImageData.SmoothBilateral(10, 50, 50);
133

    
134
                #region Apply dilation and erosion to remove some noise 효과없음
135
                //OriginalImageData = OriginalImageData.Dilate(1);
136
                //TargatImageData = TargatImageData.Dilate(1);
137
                //OriginalImageData = OriginalImageData.Erode(1);
138
                //TargatImageData = TargatImageData.Erode(1);
139

    
140
                //threshold(OriginalImageData);
141
                //threshold(TargatImageData);
142
                #endregion
143

    
144
                //Computes absolute different between this image and the other image
145
                // 원본이미지와 타겟이미지를 처리
146
                var tmp = OriginalImageData.AbsDiff(TargatImageData).ThresholdBinary(new Gray(50), new Gray(255));
147

    
148
                Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint();
149
                Mat m = new Mat();
150

    
151
                CvInvoke.FindContours(tmp, contours, m, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
152

    
153
                result = contours.ToArrayOfArray();
154
                tmp.Dispose();
155
            }
156
            catch (Exception ex)
157
            {
158
                throw ex;
159
            }
160

    
161
            return result;
162
        }
163

    
164
        private void threshold(Emgu.CV.Image<Gray, byte> image)
165
        {
166
            Emgu.CV.Image<Gray, byte> outImg = new Image<Gray, byte>(image.Size);
167

    
168
            //CvInvoke.Threshold(image.SmoothGaussian(5), outImg,0, 255, ThresholdType.Mask);
169
            CvInvoke.AdaptiveThreshold(image.SmoothMedian(1), outImg, 255,AdaptiveThresholdType.GaussianC,ThresholdType.Binary,31,2);
170
            //CvInvoke.Threshold(image.SmoothGaussian(9), outImg, 100, 255, ThresholdType.Binary | ThresholdType.Otsu);
171

    
172
            image = outImg;
173
        }
174

    
175
        /// <summary>
176
        /// MathchesImageData의 틀린 부분을 Rect로 반환
177
        /// </summary>
178
        /// <param name="data"></param>
179
        /// <param name="currentX"></param>
180
        /// <param name="currentY"></param>
181
        /// <param name="ImageWidth"></param>
182
        /// <param name="ImageHeight"></param>
183
        /// <param name="block"></param>
184
        /// <returns></returns>
185
        protected System.Windows.Rect? DataMatchScore(byte[,,] data, int currentX, int currentY, int ImageWidth, int ImageHeight, Size block)
186
        {
187
            System.Windows.Rect? result = null;
188

    
189
            int x = currentX;
190
            int y = currentY;
191
            int width = ImageWidth;
192
            int height = ImageHeight;
193

    
194
            for (int i = 0; i < block.Width; i++)
195
            {
196
                int wi = x + i;
197
                if (wi >= width) break;
198

    
199
                for (int j = 0; j < block.Height; j++)
200
                {
201
                    int hj = y + j;
202
                    if (hj >= height) break;
203

    
204
                    double matchScore = data[wi, hj, 0];
205

    
206
                    if (matchScore < gMatchScore)
207
                    {
208
                        result = new System.Windows.Rect(y, x, block.Width, block.Height);
209
                        return result;
210
                    }
211
                }
212
            }
213

    
214
            return result;
215
        }
216

    
217
        /// <summary>
218
        /// Image<TColor, TDepth>의 틀린 부분을 Rect로 반환
219
        /// </summary>
220
        /// <param name="data"></param>
221
        /// <param name="block"></param>
222
        /// <returns></returns>
223
        protected List<System.Windows.Rect> GetMatchPixels(byte[,,] data, Size block)
224
        {
225
            int width = data.GetLength(0);
226
            int height = data.GetLength(1);
227

    
228
            List<System.Windows.Rect> results = new List<System.Windows.Rect>();
229

    
230
            var heightRange = from h in Enumerable.Range(1, height)
231
                              where h % block.Height == 0
232
                              select h;
233

    
234
            var widthRange = from w in Enumerable.Range(1, width)
235
                             where w % block.Width == 0
236
                             select w;
237

    
238
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
239
            stopwatch.Start();
240

    
241
            Parallel.ForEach(heightRange, (y) =>
242
            {
243
                Parallel.ForEach(widthRange, (x) =>
244
                {
245
                    var rect = DataMatchScore(data, x, y, width, height, block);
246

    
247
                    if (rect != null)
248
                    {
249
                        results.Add(rect.Value);
250
                    }
251
                });
252
            });
253

    
254
            System.Diagnostics.Debug.WriteLine("1 - " + new TimeSpan(stopwatch.ElapsedTicks));
255
            return results;
256
        }
257

    
258
        protected List<System.Windows.Rect> GetMatchPixels(byte[,,] data, Size block)
259
        {
260
            int width = data.GetLength(0);
261
            int height = data.GetLength(1);
262

    
263
            List<System.Windows.Rect> results = new List<System.Windows.Rect>();
264

    
265
            var heightRange = from h in Enumerable.Range(1, height)
266
                              where h % block.Height == 0
267
                              select h;
268

    
269
            var widthRange = from w in Enumerable.Range(1, width)
270
                             where w % block.Width == 0
271
                             select w;
272

    
273
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
274
            stopwatch.Start();
275

    
276
            Parallel.ForEach(heightRange, (y) =>
277
            {
278
                Parallel.ForEach(widthRange, (x) =>
279
                {
280
                    var rect = DataMatchScore(data, x, y, width, height, block);
281

    
282
                    if (rect != null)
283
                    {
284
                        results.Add(rect.Value);
285
                    }
286
                });
287
            });
288

    
289
            System.Diagnostics.Debug.WriteLine("1 - " + new TimeSpan(stopwatch.ElapsedTicks));
290
            return results;
291
        }
292

    
293
        /// <summary>
294
        /// Image<TColor, TDepth>의 틀린 부분을 Rect로 반환
295
        /// </summary>
296
        /// <param name="data"></param>
297
        /// <param name="block"></param>
298
        /// <returns></returns>
299
        protected async Task<List<System.Windows.Rect>> GetMatchPixelsAsnc(byte[,,] data, Size block)
300
        {
301
            return await Task.Factory.StartNew<List<System.Windows.Rect>>(() =>
302
            {
303
                return GetMatchPixels(data, block);
304
            });
305
        }
306

    
307
        protected Bitmap LoadPicture(string url)
308
        {
309
            HttpWebRequest wreq;
310
            HttpWebResponse wresp;
311
            Stream mystream;
312
            Bitmap bmp;
313

    
314
            bmp = null;
315
            mystream = null;
316
            wresp = null;
317
            try
318
            {
319
                wreq = (HttpWebRequest)WebRequest.Create(url);
320
                wreq.AllowWriteStreamBuffering = true;
321

    
322
                wresp = (HttpWebResponse)wreq.GetResponse();
323

    
324
                if ((mystream = wresp.GetResponseStream()) != null)
325
                    bmp = new Bitmap(mystream);
326
            }
327
            finally
328
            {
329
                if (mystream != null)
330
                {
331
                    mystream.Close();
332
                    mystream.Dispose();
333
                }
334

    
335
                if (wresp != null)
336
                {
337
                    wresp.Close();
338
                    wresp.Dispose();
339
                }
340
            }
341
            return (bmp);
342
        }
343

    
344
        #region  IDisposable Support 
345

    
346
        private bool disposedValue = false;
347

    
348
        // 중복 호출을 검색하려면 
349
        protected virtual void Dispose(bool disposing)
350
        {
351
            if (!disposedValue)
352
            {
353
                if (disposing)
354
                {
355
                    // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다. 
356
                }
357
                // TODO: 관리되지 않는 리소스(관리되지 않는 개체)를 해제하고 아래의 종료자를 재정의합니다. 
358
                // TODO: 큰 필드를 null로 설정합니다. 
359
                disposedValue = true;
360
            }
361
        }
362

    
363
        // TODO: 위의 Dispose(bool disposing)에 관리되지 않는 리소스를 해제하는 코드가 포함되어 있는 경우에만 종료자를 재정의합니다.
364
        // 
365
        //~DisposeClass()
366
       // {
367
            // // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요. 
368
            // Dispose(false); // 
369
       // } 
370

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

    
377

    
378
            if (OriginalImageData != null)
379
            {
380
                OriginalImageData.Dispose();
381
            }
382

    
383
            if (TargatImageData != null)
384
            {
385
                TargatImageData.Dispose();
386
            }
387

    
388
            // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다. 
389
            //  GC.SuppressFinalize(this);
390
            GC.Collect();
391
            GC.SuppressFinalize(this);
392
            GC.Collect();
393
        } 
394
        #endregion
395
    }
396
}
클립보드 이미지 추가 (최대 크기: 500 MB)