Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2484 | - | 1 | using System; |
2 | using System.Collections.Generic; |
||
3 | using System.Drawing; |
||
4 | using System.Drawing.Imaging; |
||
5 | using System.Runtime.InteropServices; |
||
6 | using WebCamLib; |
||
7 | |||
8 | namespace Touchless.Vision.Camera |
||
9 | { |
||
10 | public enum CameraProperty : int |
||
11 | { |
||
12 | Pan_degrees = WebCamLib.CameraProperty.Pan_degrees, |
||
13 | Tilt_degrees = WebCamLib.CameraProperty.Tilt_degrees, |
||
14 | Roll_degrees = WebCamLib.CameraProperty.Roll_degrees, |
||
15 | Zoom_mm = WebCamLib.CameraProperty.Zoom_mm, |
||
16 | Exposure_lgSec = WebCamLib.CameraProperty.Exposure_lgSec, |
||
17 | Iris_10f = WebCamLib.CameraProperty.Iris_10f, |
||
18 | FocalLength_mm = WebCamLib.CameraProperty.FocalLength_mm, |
||
19 | Flash = WebCamLib.CameraProperty.Flash, |
||
20 | Brightness = WebCamLib.CameraProperty.Brightness, |
||
21 | Contrast = WebCamLib.CameraProperty.Brightness, |
||
22 | Hue = WebCamLib.CameraProperty.Contrast, |
||
23 | Saturation = WebCamLib.CameraProperty.Saturation, |
||
24 | Sharpness = WebCamLib.CameraProperty.Sharpness, |
||
25 | Gamma = WebCamLib.CameraProperty.Gamma, |
||
26 | ColorEnable = WebCamLib.CameraProperty.ColorEnable, |
||
27 | WhiteBalance = WebCamLib.CameraProperty.WhiteBalance, |
||
28 | BacklightCompensation = WebCamLib.CameraProperty.BacklightCompensation, |
||
29 | Gain = WebCamLib.CameraProperty.Gain, |
||
30 | } |
||
31 | |||
32 | public sealed class CameraPropertyValue : IComparable<CameraPropertyValue>, IEquatable<CameraPropertyValue> |
||
33 | { |
||
34 | public CameraPropertyValue( bool isPercentageValue, int value, bool isAuto ) |
||
35 | { |
||
36 | IsPercentageValue = isPercentageValue; |
||
37 | Value = value; |
||
38 | IsAuto = isAuto; |
||
39 | } |
||
40 | |||
41 | public int Value |
||
42 | { |
||
43 | get; |
||
44 | set; |
||
45 | } |
||
46 | |||
47 | private bool isAuto; |
||
48 | |||
49 | public bool IsAuto |
||
50 | { |
||
51 | get |
||
52 | { |
||
53 | return isAuto; |
||
54 | } |
||
55 | |||
56 | set |
||
57 | { |
||
58 | isAuto = value; |
||
59 | } |
||
60 | } |
||
61 | |||
62 | public bool IsManual |
||
63 | { |
||
64 | get |
||
65 | { |
||
66 | return !IsAuto; |
||
67 | } |
||
68 | |||
69 | set |
||
70 | { |
||
71 | IsAuto = !value; |
||
72 | } |
||
73 | } |
||
74 | |||
75 | private bool isPercentageValue; |
||
76 | |||
77 | public bool IsActualValue |
||
78 | { |
||
79 | get |
||
80 | { |
||
81 | return !IsPercentageValue; |
||
82 | } |
||
83 | |||
84 | set |
||
85 | { |
||
86 | IsPercentageValue = !value; |
||
87 | } |
||
88 | } |
||
89 | |||
90 | public bool IsPercentageValue |
||
91 | { |
||
92 | get |
||
93 | { |
||
94 | return isPercentageValue; |
||
95 | } |
||
96 | |||
97 | set |
||
98 | { |
||
99 | isPercentageValue = value; |
||
100 | } |
||
101 | } |
||
102 | |||
103 | #region ICompare<CameraPropertyValue> Members |
||
104 | |||
105 | public int CompareTo( CameraPropertyValue other ) |
||
106 | { |
||
107 | int result = 0; |
||
108 | |||
109 | if( IsActualValue && other.IsPercentageValue ) |
||
110 | result = -1; |
||
111 | else if( IsPercentageValue && other.IsActualValue ) |
||
112 | result = 1; |
||
113 | else |
||
114 | { |
||
115 | if( Value < other.Value ) |
||
116 | result = -1; |
||
117 | else if( Value > other.Value ) |
||
118 | result = 1; |
||
119 | else |
||
120 | { |
||
121 | if( IsAuto && other.IsManual ) |
||
122 | result = -1; |
||
123 | else if( IsManual && other.IsAuto ) |
||
124 | result = 1; |
||
125 | } |
||
126 | } |
||
127 | |||
128 | return result; |
||
129 | } |
||
130 | |||
131 | #endregion |
||
132 | |||
133 | #region IEquatable<CameraPropertyValue> Members |
||
134 | |||
135 | public bool Equals( CameraPropertyValue other ) |
||
136 | { |
||
137 | return Object.ReferenceEquals( this, other ) || CompareTo( other ) == 0; |
||
138 | } |
||
139 | |||
140 | #endregion |
||
141 | |||
142 | public override bool Equals( Object obj ) |
||
143 | { |
||
144 | bool result; |
||
145 | |||
146 | if( !( result = Object.ReferenceEquals( this, obj ) ) ) |
||
147 | { |
||
148 | CameraPropertyValue other = obj as CameraPropertyValue; |
||
149 | |||
150 | if( result = other != null ) |
||
151 | result = Equals( other ); |
||
152 | } |
||
153 | |||
154 | return result; |
||
155 | } |
||
156 | } |
||
157 | |||
158 | public sealed class CameraPropertyRange : IComparable<CameraPropertyRange>, IEquatable<CameraPropertyRange> |
||
159 | { |
||
160 | public CameraPropertyRange( int minimum, int maximum, int step, int defaults, bool isAuto ) |
||
161 | { |
||
162 | Minimum = minimum; |
||
163 | Maximum = maximum; |
||
164 | Step = step; |
||
165 | Defaults = defaults; |
||
166 | IsAuto = isAuto; |
||
167 | } |
||
168 | |||
169 | public int Minimum |
||
170 | { |
||
171 | get; |
||
172 | private set; |
||
173 | } |
||
174 | |||
175 | public int Maximum |
||
176 | { |
||
177 | get; |
||
178 | private set; |
||
179 | } |
||
180 | |||
181 | public int Range |
||
182 | { |
||
183 | get |
||
184 | { |
||
185 | return Maximum - Minimum; |
||
186 | } |
||
187 | } |
||
188 | |||
189 | public int DomainSize |
||
190 | { |
||
191 | get |
||
192 | { |
||
193 | return Range + 1; |
||
194 | } |
||
195 | } |
||
196 | |||
197 | public int Step |
||
198 | { |
||
199 | get; |
||
200 | private set; |
||
201 | } |
||
202 | |||
203 | public int Defaults |
||
204 | { |
||
205 | get; |
||
206 | private set; |
||
207 | } |
||
208 | |||
209 | public bool IsAuto |
||
210 | { |
||
211 | get; |
||
212 | private set; |
||
213 | } |
||
214 | |||
215 | public bool IsManual |
||
216 | { |
||
217 | get |
||
218 | { |
||
219 | return !IsAuto; |
||
220 | } |
||
221 | } |
||
222 | |||
223 | #region ICompare<CameraPropertyRange> Members |
||
224 | |||
225 | public int CompareTo( CameraPropertyRange other ) |
||
226 | { |
||
227 | int result = 0; |
||
228 | |||
229 | if( Minimum < other.Minimum ) |
||
230 | result = -1; |
||
231 | else if( Minimum > other.Minimum ) |
||
232 | result = 1; |
||
233 | else |
||
234 | { |
||
235 | if( Maximum < other.Maximum ) |
||
236 | result = -1; |
||
237 | else if( Maximum > other.Maximum ) |
||
238 | result = 1; |
||
239 | else |
||
240 | { |
||
241 | if( Step < other.Step ) |
||
242 | result = -1; |
||
243 | else if( Step > other.Step ) |
||
244 | result = 1; |
||
245 | else |
||
246 | { |
||
247 | if( Defaults < other.Defaults ) |
||
248 | result = -1; |
||
249 | else if( Defaults > other.Defaults ) |
||
250 | result = 1; |
||
251 | else |
||
252 | { |
||
253 | if( IsAuto && other.IsManual ) |
||
254 | result = -1; |
||
255 | else if( IsManual && other.IsAuto ) |
||
256 | result = 1; |
||
257 | } |
||
258 | } |
||
259 | } |
||
260 | } |
||
261 | |||
262 | return result; |
||
263 | } |
||
264 | |||
265 | #endregion |
||
266 | |||
267 | #region IEquatable<CameraPropertyRange> Members |
||
268 | |||
269 | public bool Equals( CameraPropertyRange other ) |
||
270 | { |
||
271 | return Object.ReferenceEquals( this, other ) || CompareTo( other ) == 0; |
||
272 | } |
||
273 | |||
274 | #endregion |
||
275 | |||
276 | public override bool Equals( Object obj ) |
||
277 | { |
||
278 | bool result; |
||
279 | |||
280 | if( !( result = Object.ReferenceEquals( this, obj ) ) ) |
||
281 | { |
||
282 | CameraPropertyRange other = obj as CameraPropertyRange; |
||
283 | |||
284 | if( result = other != null ) |
||
285 | result = Equals( other ); |
||
286 | } |
||
287 | |||
288 | return result; |
||
289 | } |
||
290 | } |
||
291 | |||
292 | public sealed class CameraPropertyCapabilities : IComparable<CameraPropertyCapabilities>, IEquatable<CameraPropertyCapabilities> |
||
293 | { |
||
294 | internal CameraPropertyCapabilities( Camera camera, WebCamLib.CameraPropertyCapabilities capabilities ) |
||
295 | { |
||
296 | Camera = camera; |
||
297 | InternalCapabilities = capabilities; |
||
298 | } |
||
299 | |||
300 | public Camera Camera |
||
301 | { |
||
302 | get; |
||
303 | private set; |
||
304 | } |
||
305 | |||
306 | internal WebCamLib.CameraPropertyCapabilities InternalCapabilities |
||
307 | { |
||
308 | get; |
||
309 | private set; |
||
310 | } |
||
311 | |||
312 | public bool IsSupported |
||
313 | { |
||
314 | get |
||
315 | { |
||
316 | return InternalCapabilities.IsSupported; |
||
317 | } |
||
318 | } |
||
319 | |||
320 | public bool IsFullySupported |
||
321 | { |
||
322 | get |
||
323 | { |
||
324 | return InternalCapabilities.IsFullySupported; |
||
325 | } |
||
326 | } |
||
327 | |||
328 | public bool IsGetSupported |
||
329 | { |
||
330 | get |
||
331 | { |
||
332 | return InternalCapabilities.IsGetSupported; |
||
333 | } |
||
334 | } |
||
335 | |||
336 | public bool IsSetSupported |
||
337 | { |
||
338 | get |
||
339 | { |
||
340 | return InternalCapabilities.IsSetSupported; |
||
341 | } |
||
342 | } |
||
343 | |||
344 | public bool IsGetRangeSupported |
||
345 | { |
||
346 | get |
||
347 | { |
||
348 | return InternalCapabilities.IsGetRangeSupported; |
||
349 | } |
||
350 | } |
||
351 | |||
352 | #region IComparable<CameraPropertyCapabilities> Members |
||
353 | // sort order: IsGetSupported, IsSetSupported, IsGetRangeSupported; this exists and other doesn't first/less for all keys |
||
354 | public int CompareTo( CameraPropertyCapabilities other ) |
||
355 | { |
||
356 | int result = 0; |
||
357 | |||
358 | if( IsGetSupported && !other.IsGetSupported ) |
||
359 | result = -1; |
||
360 | else if( !IsGetSupported && other.IsGetSupported ) |
||
361 | result = 1; |
||
362 | else |
||
363 | { |
||
364 | if( IsSetSupported && !other.IsSetSupported ) |
||
365 | result = -1; |
||
366 | else if( !IsSetSupported && other.IsSetSupported ) |
||
367 | result = 1; |
||
368 | else |
||
369 | { |
||
370 | if( IsGetRangeSupported && !other.IsGetRangeSupported ) |
||
371 | result = -1; |
||
372 | else if( !IsGetRangeSupported && other.IsGetRangeSupported ) |
||
373 | result = 1; |
||
374 | } |
||
375 | } |
||
376 | |||
377 | return result; |
||
378 | } |
||
379 | #endregion |
||
380 | |||
381 | #region IEquatable<CameraPropertyCapabilities> |
||
382 | public bool Equals( CameraPropertyCapabilities other ) |
||
383 | { |
||
384 | return CompareTo( other ) == 0; |
||
385 | } |
||
386 | #endregion |
||
387 | |||
388 | public override bool Equals( object obj ) |
||
389 | { |
||
390 | bool result; |
||
391 | |||
392 | CameraPropertyCapabilities capabilities = obj as CameraPropertyCapabilities; |
||
393 | |||
394 | if( result = capabilities != null ) |
||
395 | result = Equals( capabilities ); |
||
396 | |||
397 | return result; |
||
398 | } |
||
399 | } |
||
400 | |||
401 | public sealed class CaptureSize : IComparable<CaptureSize>, IEquatable<CaptureSize> |
||
402 | { |
||
403 | public CaptureSize( int width, int height, int colorDepth ) |
||
404 | { |
||
405 | Width = width; |
||
406 | Height = height; |
||
407 | ColorDepth = colorDepth; |
||
408 | } |
||
409 | |||
410 | public int Width |
||
411 | { |
||
412 | get; |
||
413 | private set; |
||
414 | } |
||
415 | |||
416 | public int Height |
||
417 | { |
||
418 | get; |
||
419 | private set; |
||
420 | } |
||
421 | |||
422 | public int ColorDepth |
||
423 | { |
||
424 | get; |
||
425 | private set; |
||
426 | } |
||
427 | |||
428 | public override String ToString() |
||
429 | { |
||
430 | return String.Format( "{0} x {1} @ {2}", Width, Height, ColorDepth ); |
||
431 | } |
||
432 | |||
433 | #region IComparable<CaptureSize> Members |
||
434 | |||
435 | public int CompareTo( CaptureSize other ) |
||
436 | { |
||
437 | int result; |
||
438 | |||
439 | if( Width < other.Width ) |
||
440 | result = -1; |
||
441 | else if( Width > other.Width ) |
||
442 | result = 1; |
||
443 | else |
||
444 | { |
||
445 | if( Height < other.Height ) |
||
446 | result = -1; |
||
447 | else if( Height > other.Height ) |
||
448 | result = 1; |
||
449 | else |
||
450 | { |
||
451 | if( ColorDepth < other.ColorDepth ) |
||
452 | result = -1; |
||
453 | else if( ColorDepth > other.ColorDepth ) |
||
454 | result = 1; |
||
455 | else |
||
456 | result = 0; |
||
457 | } |
||
458 | } |
||
459 | |||
460 | return result; |
||
461 | } |
||
462 | |||
463 | #endregion |
||
464 | |||
465 | #region IEquatable<CaptureSize> Members |
||
466 | |||
467 | public bool Equals( CaptureSize other ) |
||
468 | { |
||
469 | return Object.ReferenceEquals( this, other ) || CompareTo( other ) == 0; |
||
470 | } |
||
471 | |||
472 | #endregion |
||
473 | |||
474 | public override bool Equals( Object obj ) |
||
475 | { |
||
476 | bool result; |
||
477 | |||
478 | if( !( result = Object.ReferenceEquals( this, obj ) ) ) |
||
479 | { |
||
480 | CaptureSize other = obj as CaptureSize; |
||
481 | if( result = other != null ) |
||
482 | result = Equals( other ); |
||
483 | } |
||
484 | |||
485 | return result; |
||
486 | } |
||
487 | |||
488 | public override int GetHashCode() |
||
489 | { |
||
490 | int result = 0; |
||
491 | |||
492 | result ^= Width; |
||
493 | result ^= Height << 11; |
||
494 | result ^= ColorDepth << 23; |
||
495 | |||
496 | return result; |
||
497 | } |
||
498 | } |
||
499 | |||
500 | /// <summary> |
||
501 | /// Represents a camera in use by the Touchless system |
||
502 | /// </summary> |
||
503 | public class Camera : IDisposable |
||
504 | { |
||
505 | public const int IgnoredBitsPerPixel = -1; |
||
506 | |||
507 | private readonly Object CameraMethodsLock = new Object(); |
||
508 | |||
509 | private readonly CameraMethods _cameraMethods; |
||
510 | private RotateFlipType _rotateFlip = RotateFlipType.RotateNoneFlipNone; |
||
511 | |||
512 | public Camera( CameraMethods cameraMethods, string name, int index ) |
||
513 | { |
||
514 | _name = name; |
||
515 | _index = index; |
||
516 | |||
517 | lock( CameraMethodsLock ) |
||
518 | { |
||
519 | _cameraMethods = cameraMethods; |
||
520 | _cameraMethods.OnImageCapture += CaptureCallbackProc; |
||
521 | } |
||
522 | } |
||
523 | |||
524 | public string Name |
||
525 | { |
||
526 | get |
||
527 | { |
||
528 | return _name; |
||
529 | } |
||
530 | } |
||
531 | |||
532 | /// <summary> |
||
533 | /// Defines the frames per second limit that is in place, -1 means no limit |
||
534 | /// </summary> |
||
535 | public int Fps |
||
536 | { |
||
537 | get |
||
538 | { |
||
539 | return _fpslimit; |
||
540 | } |
||
541 | set |
||
542 | { |
||
543 | _fpslimit = value; |
||
544 | _timeBetweenFrames = ( 1000.0 / _fpslimit ); |
||
545 | } |
||
546 | } |
||
547 | |||
548 | /// <summary> |
||
549 | /// Determines the width of the image captured |
||
550 | /// </summary> |
||
551 | public int CaptureWidth |
||
552 | { |
||
553 | get |
||
554 | { |
||
555 | return _width; |
||
556 | } |
||
557 | set |
||
558 | { |
||
559 | _width = value; |
||
560 | } |
||
561 | } |
||
562 | |||
563 | /// <summary> |
||
564 | /// Defines the height of the image captured |
||
565 | /// </summary> |
||
566 | public int CaptureHeight |
||
567 | { |
||
568 | get |
||
569 | { |
||
570 | return _height; |
||
571 | } |
||
572 | set |
||
573 | { |
||
574 | _height = value; |
||
575 | } |
||
576 | } |
||
577 | |||
578 | /// <summary> |
||
579 | /// Defines the bits per pixel of image captured. |
||
580 | /// </summary> |
||
581 | public int CaptureBitsPerPixel |
||
582 | { |
||
583 | get |
||
584 | { |
||
585 | return _bpp; |
||
586 | } |
||
587 | |||
588 | set |
||
589 | { |
||
590 | _bpp = value; |
||
591 | } |
||
592 | } |
||
593 | |||
594 | public bool HasFrameLimit |
||
595 | { |
||
596 | get |
||
597 | { |
||
598 | return _fpslimit != -1; |
||
599 | } |
||
600 | } |
||
601 | |||
602 | public bool FlipHorizontal |
||
603 | { |
||
604 | get |
||
605 | { |
||
606 | return RotateFlip == RotateFlipType.RotateNoneFlipX || RotateFlip == RotateFlipType.Rotate180FlipNone; |
||
607 | } |
||
608 | |||
609 | set |
||
610 | { |
||
611 | if( value && FlipVertical ) |
||
612 | { |
||
613 | RotateFlip = RotateFlipType.Rotate180FlipNone; |
||
614 | } |
||
615 | else if( value && !FlipVertical ) |
||
616 | { |
||
617 | RotateFlip = RotateFlipType.RotateNoneFlipX; |
||
618 | } |
||
619 | else if( !value && FlipVertical ) |
||
620 | { |
||
621 | RotateFlip = RotateFlipType.Rotate180FlipX; |
||
622 | } |
||
623 | else if( !value && !FlipVertical ) |
||
624 | { |
||
625 | RotateFlip = RotateFlipType.RotateNoneFlipNone; |
||
626 | } |
||
627 | } |
||
628 | } |
||
629 | |||
630 | public bool FlipVertical |
||
631 | { |
||
632 | get |
||
633 | { |
||
634 | return RotateFlip == RotateFlipType.Rotate180FlipX || RotateFlip == RotateFlipType.Rotate180FlipNone; |
||
635 | } |
||
636 | |||
637 | set |
||
638 | { |
||
639 | if( value && FlipHorizontal ) |
||
640 | { |
||
641 | RotateFlip = RotateFlipType.Rotate180FlipNone; |
||
642 | } |
||
643 | else if( value && !FlipHorizontal ) |
||
644 | { |
||
645 | RotateFlip = RotateFlipType.Rotate180FlipX; |
||
646 | } |
||
647 | else if( !value && FlipHorizontal ) |
||
648 | { |
||
649 | RotateFlip = RotateFlipType.RotateNoneFlipX; |
||
650 | } |
||
651 | else if( !value && !FlipHorizontal ) |
||
652 | { |
||
653 | RotateFlip = RotateFlipType.RotateNoneFlipNone; |
||
654 | } |
||
655 | } |
||
656 | } |
||
657 | |||
658 | /// <summary> |
||
659 | /// Command for rotating and flipping incoming images |
||
660 | /// </summary> |
||
661 | public RotateFlipType RotateFlip |
||
662 | { |
||
663 | get |
||
664 | { |
||
665 | return _rotateFlip; |
||
666 | } |
||
667 | set |
||
668 | { |
||
669 | // Swap height/width when rotating by 90 or 270 |
||
670 | if( ( int ) _rotateFlip % 2 != ( int ) value % 2 ) |
||
671 | { |
||
672 | int temp = CaptureWidth; |
||
673 | CaptureWidth = CaptureHeight; |
||
674 | CaptureHeight = temp; |
||
675 | } |
||
676 | _rotateFlip = value; |
||
677 | } |
||
678 | } |
||
679 | |||
680 | #region IDisposable Members |
||
681 | |||
682 | /// <summary> |
||
683 | /// Cleanup function for the camera |
||
684 | /// </summary> |
||
685 | public void Dispose() |
||
686 | { |
||
687 | StopCapture(); |
||
688 | } |
||
689 | |||
690 | #endregion |
||
691 | |||
692 | /// <summary> |
||
693 | /// Returns the last image acquired from the camera |
||
694 | /// </summary> |
||
695 | /// <returns>A bitmap of the last image acquired from the camera</returns> |
||
696 | public Bitmap GetCurrentImage() |
||
697 | { |
||
698 | Bitmap b = null; |
||
699 | lock( _bitmapLock ) |
||
700 | { |
||
701 | if( _bitmap == null ) |
||
702 | { |
||
703 | return null; |
||
704 | } |
||
705 | |||
706 | b = new Bitmap( _bitmap ); |
||
707 | } |
||
708 | |||
709 | return b; |
||
710 | } |
||
711 | |||
712 | public void ShowPropertiesDialog() |
||
713 | { |
||
714 | lock( CameraMethodsLock ) |
||
715 | { |
||
716 | _cameraMethods.DisplayCameraPropertiesDialog( _index ); |
||
717 | } |
||
718 | } |
||
719 | |||
720 | public CameraInfo GetCameraInfo() |
||
721 | { |
||
722 | lock( CameraMethodsLock ) |
||
723 | { |
||
724 | return _cameraMethods.GetCameraInfo( _index ); |
||
725 | } |
||
726 | } |
||
727 | |||
728 | #region Camera Properties |
||
729 | public bool IsCameraPropertySupported( CameraProperty property ) |
||
730 | { |
||
731 | bool result = false; |
||
732 | |||
733 | lock( CameraMethodsLock ) |
||
734 | { |
||
735 | _cameraMethods.IsPropertySupported( ( WebCamLib.CameraProperty ) property, ref result ); |
||
736 | } |
||
737 | |||
738 | return result; |
||
739 | } |
||
740 | |||
741 | public bool SetCameraProperty( CameraProperty property, CameraPropertyValue value ) |
||
742 | { |
||
743 | bool result; |
||
744 | |||
745 | if( value.IsActualValue ) |
||
746 | result = SetCameraProperty_value( property, value.Value, value.IsAuto ); |
||
747 | else // if( value.IsPercentageValue ) |
||
748 | result = SetCameraProperty_percentage( property, value.Value, value.IsAuto ); |
||
749 | |||
750 | return result; |
||
751 | } |
||
752 | |||
753 | public bool SetCameraProperty( CameraProperty property, bool isActualValue, int value ) |
||
754 | { |
||
755 | bool result = false; |
||
756 | |||
757 | if( isActualValue ) |
||
758 | result = SetCameraProperty_value( property, value ); |
||
759 | else // is percentage value |
||
760 | result = SetCameraProperty_percentage( property, value ); |
||
761 | |||
762 | return result; |
||
763 | } |
||
764 | |||
765 | public bool SetCameraProperty( CameraProperty property, bool isActualValue, int value, bool auto ) |
||
766 | { |
||
767 | bool result = false; |
||
768 | |||
769 | if( isActualValue ) |
||
770 | result = SetCameraProperty_value( property, value, auto ); |
||
771 | else // is percentage value |
||
772 | result = SetCameraProperty_percentage( property, value, auto ); |
||
773 | |||
774 | return result; |
||
775 | } |
||
776 | |||
777 | public bool SetCameraProperty_value( CameraProperty property, bool auto ) |
||
778 | { |
||
779 | return SetCameraProperty_value( property, 0, auto ); |
||
780 | } |
||
781 | |||
782 | // Assume manual control |
||
783 | public bool SetCameraProperty_value( CameraProperty property, int value ) |
||
784 | { |
||
785 | return SetCameraProperty_value( property, value, false ); |
||
786 | } |
||
787 | |||
788 | public bool SetCameraProperty_value( CameraProperty property, int value, bool auto ) |
||
789 | { |
||
790 | bool result = false; |
||
791 | |||
792 | lock( CameraMethodsLock ) |
||
793 | { |
||
794 | _cameraMethods.SetProperty_value( ( WebCamLib.CameraProperty ) property, value, auto, ref result ); |
||
795 | } |
||
796 | |||
797 | return result; |
||
798 | } |
||
799 | |||
800 | public bool SetCameraProperty_percentage( CameraProperty property, bool auto ) |
||
801 | { |
||
802 | return SetCameraProperty_percentage( property, 0, auto ); |
||
803 | } |
||
804 | |||
805 | // Assume manual control |
||
806 | public bool SetCameraProperty_percentage( CameraProperty property, int percentage ) |
||
807 | { |
||
808 | return SetCameraProperty_percentage( property, percentage, false ); |
||
809 | } |
||
810 | |||
811 | public bool SetCameraProperty_percentage( CameraProperty property, int percentage, bool auto ) |
||
812 | { |
||
813 | bool result = false; |
||
814 | |||
815 | lock( CameraMethodsLock ) |
||
816 | { |
||
817 | _cameraMethods.SetProperty_percentage( ( WebCamLib.CameraProperty ) property, percentage, auto, ref result ); |
||
818 | } |
||
819 | |||
820 | return result; |
||
821 | } |
||
822 | |||
823 | public CameraPropertyValue GetCameraProperty( CameraProperty property, bool isActualValue ) |
||
824 | { |
||
825 | CameraPropertyValue result; |
||
826 | |||
827 | if( isActualValue ) |
||
828 | result = GetCameraProperty_value( property ); |
||
829 | else // is percentage value |
||
830 | result = GetCameraProperty_percentage( property ); |
||
831 | |||
832 | return result; |
||
833 | } |
||
834 | |||
835 | public CameraPropertyValue GetCameraProperty_value( CameraProperty property ) |
||
836 | { |
||
837 | CameraPropertyValue result; |
||
838 | |||
839 | bool successful = false; |
||
840 | |||
841 | int value = -1; |
||
842 | bool isAuto = false; |
||
843 | |||
844 | lock( CameraMethodsLock ) |
||
845 | { |
||
846 | _cameraMethods.GetProperty_value( ( WebCamLib.CameraProperty ) property, ref value, ref isAuto, ref successful ); |
||
847 | } |
||
848 | |||
849 | if( successful ) |
||
850 | result = new CameraPropertyValue( false, value, isAuto ); |
||
851 | else |
||
852 | result = null; |
||
853 | |||
854 | return result; |
||
855 | } |
||
856 | |||
857 | public CameraPropertyValue GetCameraProperty_percentage( CameraProperty property ) |
||
858 | { |
||
859 | CameraPropertyValue result; |
||
860 | |||
861 | bool successful = false; |
||
862 | |||
863 | int value = -1; |
||
864 | bool isAuto = false; |
||
865 | |||
866 | lock( CameraMethodsLock ) |
||
867 | { |
||
868 | _cameraMethods.GetProperty_percentage( ( WebCamLib.CameraProperty ) property, ref value, ref isAuto, ref successful ); |
||
869 | } |
||
870 | |||
871 | if( successful ) |
||
872 | result = new CameraPropertyValue( true, value, isAuto ); |
||
873 | else |
||
874 | result = null; |
||
875 | |||
876 | return result; |
||
877 | } |
||
878 | |||
879 | public CameraPropertyRange GetCameraPropertyRange( CameraProperty property ) |
||
880 | { |
||
881 | CameraPropertyRange result; |
||
882 | |||
883 | bool successful = false; |
||
884 | |||
885 | int minimum, maximum, step, defaults; |
||
886 | bool isAuto; |
||
887 | |||
888 | minimum = maximum = step = defaults = -1; |
||
889 | isAuto = false; |
||
890 | |||
891 | lock( CameraMethodsLock ) |
||
892 | { |
||
893 | _cameraMethods.GetPropertyRange( ( WebCamLib.CameraProperty ) property, ref minimum, ref maximum, ref step, ref defaults, ref isAuto, ref successful ); |
||
894 | } |
||
895 | |||
896 | if( successful ) |
||
897 | result = new CameraPropertyRange( minimum, maximum, step, defaults, isAuto ); |
||
898 | else |
||
899 | result = null; |
||
900 | |||
901 | return result; |
||
902 | } |
||
903 | |||
904 | public bool CameraPropertyHasRange( CameraProperty property ) |
||
905 | { |
||
906 | bool result = false; |
||
907 | |||
908 | _cameraMethods.PropertyHasRange( ( WebCamLib.CameraProperty ) property, ref result ); |
||
909 | |||
910 | return result; |
||
911 | } |
||
912 | |||
913 | public bool ValidateCameraProperty( CameraProperty property, int value ) |
||
914 | { |
||
915 | bool result = false; |
||
916 | |||
917 | _cameraMethods.ValidatePropertyValue( ( WebCamLib.CameraProperty ) property, value, ref result ); |
||
918 | |||
919 | return result; |
||
920 | } |
||
921 | |||
922 | public IDictionary<CameraProperty, CameraPropertyCapabilities> CameraPropertyCapabilities |
||
923 | { |
||
924 | get |
||
925 | { |
||
926 | IDictionary<CameraProperty, CameraPropertyCapabilities> result = new Dictionary<CameraProperty, CameraPropertyCapabilities>( _cameraMethods.PropertyCapabilities.Count ); |
||
927 | |||
928 | foreach( WebCamLib.CameraProperty property in _cameraMethods.PropertyCapabilities.Keys ) |
||
929 | { |
||
930 | CameraProperty prop = ( CameraProperty ) property; |
||
931 | CameraPropertyCapabilities capabilities = new CameraPropertyCapabilities( this, _cameraMethods.PropertyCapabilities[ property ] ); |
||
932 | |||
933 | result.Add( prop, capabilities ); |
||
934 | } |
||
935 | |||
936 | return result; |
||
937 | } |
||
938 | } |
||
939 | #endregion |
||
940 | |||
941 | public IList<CaptureSize> CaptureSizes |
||
942 | { |
||
943 | get |
||
944 | { |
||
945 | IList<Tuple<int, int, int>> rawSizes = new List<Tuple<int, int, int>>(); |
||
946 | |||
947 | lock( CameraMethodsLock ) |
||
948 | { |
||
949 | _cameraMethods.GetCaptureSizes( _index, rawSizes ); |
||
950 | } |
||
951 | |||
952 | IList<CaptureSize> result = new List<CaptureSize>( rawSizes.Count ); |
||
953 | foreach( Tuple<int, int, int> size in rawSizes ) |
||
954 | { |
||
955 | CaptureSize newSize = new CaptureSize( size.Item1, size.Item2, size.Item3 ); |
||
956 | result.Add( newSize ); |
||
957 | } |
||
958 | |||
959 | return result; |
||
960 | } |
||
961 | } |
||
962 | |||
963 | /// <summary> |
||
964 | /// Event fired when an image from the camera is captured |
||
965 | /// </summary> |
||
966 | public event EventHandler<CameraEventArgs> OnImageCaptured; |
||
967 | |||
968 | /// <summary> |
||
969 | /// Returns the camera name as the ToString implementation |
||
970 | /// </summary> |
||
971 | /// <returns>The name of the camera</returns> |
||
972 | public override string ToString() |
||
973 | { |
||
974 | return _name; |
||
975 | } |
||
976 | |||
977 | #region Internal Implementation |
||
978 | |||
979 | private readonly object _bitmapLock = new object(); |
||
980 | private readonly int _index; |
||
981 | private readonly string _name; |
||
982 | private Bitmap _bitmap; |
||
983 | private DateTime _dtLastCap = DateTime.MinValue; |
||
984 | private int _fpslimit = -1; |
||
985 | private int _height = 240; |
||
986 | private double _timeBehind; |
||
987 | private double _timeBetweenFrames; |
||
988 | private int _width = 320; |
||
989 | private int _bpp = 24; |
||
990 | |||
991 | internal bool StartCapture() |
||
992 | { |
||
993 | bool result = false; |
||
994 | |||
995 | lock( CameraMethodsLock ) |
||
996 | { |
||
997 | _cameraMethods.StartCamera( _index, ref _width, ref _height, ref _bpp, ref result ); |
||
998 | _cameraMethods.OnImageCapture += CaptureCallbackProc; |
||
999 | } |
||
1000 | |||
1001 | return result; |
||
1002 | } |
||
1003 | |||
1004 | internal void StopCapture() |
||
1005 | { |
||
1006 | lock( CameraMethodsLock ) |
||
1007 | { |
||
1008 | _cameraMethods.StopCamera(); |
||
1009 | _cameraMethods.OnImageCapture -= CaptureCallbackProc; |
||
1010 | } |
||
1011 | } |
||
1012 | |||
1013 | /// <summary> |
||
1014 | /// Here is where the images come in as they are collected, as fast as they can and on a background thread |
||
1015 | /// </summary> |
||
1016 | private void CaptureCallbackProc( int dataSize, byte[] data ) |
||
1017 | { |
||
1018 | // Do the magic to create a bitmap |
||
1019 | int stride = _width * 3; |
||
1020 | GCHandle handle = GCHandle.Alloc( data, GCHandleType.Pinned ); |
||
1021 | var scan0 = handle.AddrOfPinnedObject(); |
||
1022 | scan0 += ( _height - 1 ) * stride; |
||
1023 | var b = new Bitmap( _width, _height, -stride, PixelFormat.Format24bppRgb, scan0 ); |
||
1024 | b.RotateFlip( _rotateFlip ); |
||
1025 | // NOTE: It seems that bntr has made that resolution property work properly |
||
1026 | var copyBitmap = ( Bitmap ) b.Clone(); |
||
1027 | // Copy the image using the Thumbnail function to also resize if needed |
||
1028 | //var copyBitmap = (Bitmap)b.GetThumbnailImage(_width, _height, null, IntPtr.Zero); |
||
1029 | |||
1030 | // Now you can free the handle |
||
1031 | handle.Free(); |
||
1032 | |||
1033 | ImageCaptured( copyBitmap ); |
||
1034 | } |
||
1035 | |||
1036 | private void ImageCaptured( Bitmap bitmap ) |
||
1037 | { |
||
1038 | DateTime dtCap = DateTime.Now; |
||
1039 | |||
1040 | // Always save the bitmap |
||
1041 | lock( _bitmapLock ) |
||
1042 | { |
||
1043 | _bitmap = bitmap; |
||
1044 | } |
||
1045 | |||
1046 | // FPS affects the callbacks only |
||
1047 | if( _fpslimit != -1 ) |
||
1048 | { |
||
1049 | if( _dtLastCap != DateTime.MinValue ) |
||
1050 | { |
||
1051 | double milliseconds = ( ( dtCap.Ticks - _dtLastCap.Ticks ) / TimeSpan.TicksPerMillisecond ) * 1.15; |
||
1052 | if( milliseconds + _timeBehind >= _timeBetweenFrames ) |
||
1053 | { |
||
1054 | _timeBehind = ( milliseconds - _timeBetweenFrames ); |
||
1055 | if( _timeBehind < 0.0 ) |
||
1056 | { |
||
1057 | _timeBehind = 0.0; |
||
1058 | } |
||
1059 | } |
||
1060 | else |
||
1061 | { |
||
1062 | _timeBehind = 0.0; |
||
1063 | return; // ignore the frame |
||
1064 | } |
||
1065 | } |
||
1066 | } |
||
1067 | |||
1068 | var handler = OnImageCaptured; |
||
1069 | |||
1070 | if ( handler != null ) |
||
1071 | { |
||
1072 | var fps = ( int ) ( 1 / dtCap.Subtract( _dtLastCap ).TotalSeconds ); |
||
1073 | handler.Invoke( this, new CameraEventArgs( bitmap, fps ) ); |
||
1074 | } |
||
1075 | |||
1076 | _dtLastCap = dtCap; |
||
1077 | } |
||
1078 | |||
1079 | #endregion |
||
1080 | } |
||
1081 | |||
1082 | /// <summary> |
||
1083 | /// Camera specific EventArgs that provides the Image being captured |
||
1084 | /// </summary> |
||
1085 | public class CameraEventArgs : EventArgs |
||
1086 | { |
||
1087 | /// <summary> |
||
1088 | /// Current Camera Image |
||
1089 | /// </summary> |
||
1090 | public Bitmap Image |
||
1091 | { |
||
1092 | get |
||
1093 | { |
||
1094 | return _image; |
||
1095 | } |
||
1096 | } |
||
1097 | |||
1098 | public int CameraFps |
||
1099 | { |
||
1100 | get |
||
1101 | { |
||
1102 | return _cameraFps; |
||
1103 | } |
||
1104 | } |
||
1105 | |||
1106 | #region Internal Implementation |
||
1107 | |||
1108 | private readonly int _cameraFps; |
||
1109 | private readonly Bitmap _image; |
||
1110 | |||
1111 | internal CameraEventArgs( Bitmap i, int fps ) |
||
1112 | { |
||
1113 | _image = i; |
||
1114 | _cameraFps = fps; |
||
1115 | } |
||
1116 | |||
1117 | #endregion |
||
1118 | } |
||
1119 | } |