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 |
} |