Camera.cs
9.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using WebCamLib;
namespace Touchless.Vision.Camera
{
/// <summary>
/// Represents a camera in use by the Touchless system
/// </summary>
public class Camera : IDisposable
{
private readonly CameraMethods _cameraMethods;
private RotateFlipType _rotateFlip = RotateFlipType.RotateNoneFlipNone;
public Camera(CameraMethods cameraMethods, string name, int index)
{
_cameraMethods = cameraMethods;
_name = name;
_index = index;
_cameraMethods.OnImageCapture += CaptureCallbackProc;
}
public string Name
{
get { return _name; }
}
/// <summary>
/// Defines the frames per second limit that is in place, -1 means no limit
/// </summary>
public int Fps
{
get { return _fpslimit; }
set
{
_fpslimit = value;
_timeBetweenFrames = (1000.0 / _fpslimit);
}
}
/// <summary>
/// Determines the width of the image captured
/// </summary>
public int CaptureWidth
{
get
{
return _width;
}
set
{
_width = value;
}
}
/// <summary>
/// Defines the height of the image captured
/// </summary>
public int CaptureHeight
{
get
{
return _height;
}
set
{
_height = value;
}
}
public bool HasFrameLimit
{
get { return _fpslimit != -1; }
}
public bool FlipHorizontal
{
get
{
return RotateFlip == RotateFlipType.RotateNoneFlipX || RotateFlip == RotateFlipType.Rotate180FlipNone;
}
set
{
if (value && FlipVertical)
{
RotateFlip = RotateFlipType.Rotate180FlipNone;
}
else if (value && !FlipVertical)
{
RotateFlip = RotateFlipType.RotateNoneFlipX;
}
else if (!value && FlipVertical)
{
RotateFlip = RotateFlipType.Rotate180FlipX;
}
else if (!value && !FlipVertical)
{
RotateFlip = RotateFlipType.RotateNoneFlipNone;
}
}
}
public bool FlipVertical
{
get
{
return RotateFlip == RotateFlipType.Rotate180FlipX || RotateFlip == RotateFlipType.Rotate180FlipNone;
}
set
{
if (value && FlipHorizontal)
{
RotateFlip = RotateFlipType.Rotate180FlipNone;
}
else if (value && !FlipHorizontal)
{
RotateFlip = RotateFlipType.Rotate180FlipX;
}
else if (!value && FlipHorizontal)
{
RotateFlip = RotateFlipType.RotateNoneFlipX;
}
else if (!value && !FlipHorizontal)
{
RotateFlip = RotateFlipType.RotateNoneFlipNone;
}
}
}
/// <summary>
/// Command for rotating and flipping incoming images
/// </summary>
public RotateFlipType RotateFlip
{
get { return _rotateFlip; }
set
{
// Swap height/width when rotating by 90 or 270
if ((int)_rotateFlip % 2 != (int)value % 2)
{
int temp = CaptureWidth;
CaptureWidth = CaptureHeight;
CaptureHeight = temp;
}
_rotateFlip = value;
}
}
#region IDisposable Members
/// <summary>
/// Cleanup function for the camera
/// </summary>
public void Dispose()
{
StopCapture();
}
#endregion
/// <summary>
/// Returns the last image acquired from the camera
/// </summary>
/// <returns>A bitmap of the last image acquired from the camera</returns>
public Bitmap GetCurrentImage()
{
Bitmap b = null;
lock (_bitmapLock)
{
if (_bitmap == null)
{
return null;
}
b = (Bitmap)_bitmap.Clone();
}
return b;
}
public void ShowPropertiesDialog()
{
_cameraMethods.DisplayCameraPropertiesDialog(_index);
}
public void GetCameraInfo()
{
_cameraMethods.GetCameraInfo(_index);
}
public void SetProperty(int property, int value, bool auto) // bntr
{
_cameraMethods.SetProperty(property, value, auto);
}
/// <summary>
/// Event fired when an image from the camera is captured
/// </summary>
public event EventHandler<CameraEventArgs> OnImageCaptured;
/// <summary>
/// Returns the camera name as the ToString implementation
/// </summary>
/// <returns>The name of the camera</returns>
public override string ToString()
{
return _name;
}
#region Internal Implementation
private readonly object _bitmapLock = new object();
private readonly int _index;
private readonly string _name;
private Bitmap _bitmap;
private DateTime _dtLastCap = DateTime.MinValue;
private int _fpslimit = -1;
private int _height = 240;
private double _timeBehind;
private double _timeBetweenFrames;
private int _width = 320;
internal void StartCapture()
{
_cameraMethods.StartCamera(_index, ref _width, ref _height);
}
internal void StopCapture()
{
_cameraMethods.StopCamera();
}
/// <summary>
/// Here is where the images come in as they are collected, as fast as they can and on a background thread
/// </summary>
private void CaptureCallbackProc(int dataSize, byte[] data)
{
// Do the magic to create a bitmap
int stride = _width * 3;
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var scan0 = (int)handle.AddrOfPinnedObject();
scan0 += (_height - 1) * stride;
var b = new Bitmap(_width, _height, -stride, PixelFormat.Format24bppRgb, (IntPtr)scan0);
b.RotateFlip(_rotateFlip);
// NOTE: It seems that bntr has made that resolution property work properly
var copyBitmap = (Bitmap)b.Clone();
// Copy the image using the Thumbnail function to also resize if needed
//var copyBitmap = (Bitmap)b.GetThumbnailImage(_width, _height, null, IntPtr.Zero);
// Now you can free the handle
handle.Free();
ImageCaptured(copyBitmap);
}
private void ImageCaptured(Bitmap bitmap)
{
DateTime dtCap = DateTime.Now;
// Always save the bitmap
lock (_bitmapLock)
{
_bitmap = bitmap;
}
// FPS affects the callbacks only
if (_fpslimit != -1)
{
if (_dtLastCap != DateTime.MinValue)
{
double milliseconds = ((dtCap.Ticks - _dtLastCap.Ticks) / TimeSpan.TicksPerMillisecond) * 1.15;
if (milliseconds + _timeBehind >= _timeBetweenFrames)
{
_timeBehind = (milliseconds - _timeBetweenFrames);
if (_timeBehind < 0.0)
{
_timeBehind = 0.0;
}
}
else
{
_timeBehind = 0.0;
return; // ignore the frame
}
}
}
if (OnImageCaptured != null)
{
var fps = (int)(1 / dtCap.Subtract(_dtLastCap).TotalSeconds);
OnImageCaptured.Invoke(this, new CameraEventArgs(bitmap, fps));
}
_dtLastCap = dtCap;
}
#endregion
}
/// <summary>
/// Camera specific EventArgs that provides the Image being captured
/// </summary>
public class CameraEventArgs : EventArgs
{
/// <summary>
/// Current Camera Image
/// </summary>
public Bitmap Image
{
get { return _image; }
}
public int CameraFps
{
get { return _cameraFps; }
}
#region Internal Implementation
private readonly int _cameraFps;
private readonly Bitmap _image;
internal CameraEventArgs(Bitmap i, int fps)
{
_image = i;
_cameraFps = fps;
}
#endregion
}
}