一,首先先配置生成项目,根据官方文档步骤来:
这个没啥好说的,一步步照做就是了,就最后一步,开始我没重视,最后代码写完测试的时候还真的遇到问题了,一直出这样的错:
查了官方文档才看到最后一条~,然后在项目属性中把这个勾掉了,代码完美运行拉……
二,功能步骤
其实整个步骤很简单:
1,首先初始化连接相机:点击Init按钮会有MessageBox打印相机名
2,然后读取配置文件(配置文件是通过官方自带的CamExpert来生成的)读取参数,也可以在程序中配置,本程序有个setting按钮,按一下就可以配置拉,把想配置的参数写在对应的代码块里(当然小编很懒,没做显示的功能,所以按按钮的时候你可能觉得按了个寂寞,但已经配置好了)。还有个读取参数的按钮(当然小编也没做显示的功能,所以也按了个寂寞),但有助于debug的时候查看数据,也可以自己打印出来看看。
3,Snap是快照,可以设置快照的张数,因为写本程序时只有相机没有镜头,所以是黑乎乎一片…但用光源照的时候会呈现白色,所以还是有点反应知道不是卡住的哈哈。
4,Grab就是连续抓取图像了,Freeze是停止。
5,最后的保存结果(没有镜头只能可怜巴巴的用感光性来测试了T_T)
PS:程序最重要的是一个回调函数:m_Xfer_XferNotify,每读取一帧图片的时候会调用这个函数,当然回调函数是自己加的,通过这个命令:
m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);
这条命令和m_Xfer_XferNotify函数是精髓!精髓!精髓!
没啥说的,上代码。可运行代码一字不差的放上来咯,注释也尽可能详细了:
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
10 using System.Drawing.Imaging;
11 using DALSA.SaperaLT.SapClassBasic;
12
13 namespace dalsaSave
14 {
15 public partial class Form1 : Form
16 {
17 // 全局变量
18 private static int picCountNum = 0; // 统计采集了多少张图,有利于理解m_Xfer.Sanp(15)中15的意思
19 private string configFilePath = @"D:\T_Linea_M4096-7um_Default_Default.ccf"; // 配置文件的路径
20 private string imgPath = @"D:\imgs\"; //采集图片保存地址
21 private SapLocation m_ServerLocation; // 设备的连接地址
22 private SapAcqDevice m_AcqDevice; //采集设备
23 private SapBuffer m_Buffers; // 缓存对象
24 private SapAcqDeviceToBuf m_Xfer; // 传输对象
25
26
27 public Form1()
28 {
29 InitializeComponent();
30 }
31
32 private void Form1_Load(object sender, EventArgs e)
33 {
34
35 }
36
37 private void Form1_FormClosed(object sender, FormClosedEventArgs e)
38 {
39 DestroyObjects();
40 DisposeObjects();
41 }
42
43 // 初始化并连接相机
44 private void btn_init_Click(object sender, EventArgs e)
45 {
46 CreateNewObjects();
47 }
48
49 private void btn_setting_Click(object sender, EventArgs e)
50 {
51 // 设置曝光值,为了设置的值不超限,需要获取曝光值的允许范围(主要是最大值)
52 double valuetemp = GetMaxValue("ExposureTime");
53 if (valuetemp > 0)
54 {
55 m_AcqDevice.SetFeatureValue("ExposureTime", valuetemp);
56 }
57 m_AcqDevice.SetFeatureValue("Gain", "9.9");
58 }
59
60 private void btn_getValue_Click(object sender, EventArgs e)
61 {
62 string deviceModelName;
63 string deviceUserId;
64 string pixelFormat;
65 string triggerMode;
66
67 double acquisitionLineRate; // 行频和曝光时间不能设置为int类型
68 double exposureTime;
69 double gain;
70 int width;
71 int height;
72 int sensorWidth;
73 int sensorHeight;
74
75 m_AcqDevice.GetFeatureValue("DeviceModelName", out deviceModelName); //Linea M4096-7um
76 m_AcqDevice.GetFeatureValue("DeviceUserID", out deviceUserId); //空
77 m_AcqDevice.GetFeatureValue("PixelFormat", out pixelFormat); //Mono8
78 m_AcqDevice.GetFeatureValue("TriggerMode", out triggerMode); //Off
79
80 m_AcqDevice.GetFeatureValue("AcquisitionLineRate", out acquisitionLineRate); //10000.0
81 m_AcqDevice.GetFeatureValue("ExposureTime", out exposureTime); //70.0
82 m_AcqDevice.GetFeatureValue("Gain", out gain); //9.0
83 m_AcqDevice.GetFeatureValue("Width", out width); //4096
84 m_AcqDevice.GetFeatureValue("Height", out height); //2800
85 m_AcqDevice.GetFeatureValue("SensorWidth", out sensorWidth); //4096
86 m_AcqDevice.GetFeatureValue("SensorHeight", out sensorHeight); //1
87 }
88
89 #region
90 private void btn_snap_Click(object sender, EventArgs e)
91 {
92 // Snap() 只采集一张, 如果是Snap(15)则连续采集15张
93 m_Xfer.Snap(15); //m_Xfer.Snap(m_Buffers.Count)
94 }
95
96 private void btn_grab_Click(object sender, EventArgs e)
97 {
98 m_Xfer.Grab();
99 }
100
101
102 //关闭的时候,执行Freez()停止采集,线程等待5秒,
103 //目的是停止采集后,将还存在内存地址通道中的裸数据都取出来,
104 //如果freeze之后直接释放,就拿不到还在地址上的数据了,缓存对象释放之后,将本次采集所有对象摧毁。
105
106 private void btn_freeze_Click(object sender, EventArgs e)
107 {
108 m_Xfer.Freeze();
109 }
110 #endregion
111
112 //得到所有连接的相机信息,并将他们加入到ArrayList里面去
113 public bool GetCameraInfo(out string sCameraName, out int nIndex)
114 {
115 Console.WriteLine("开始获取相机信息");
116
117 sCameraName = "";
118 nIndex = 0;
119
120 // 查询相机数量
121 int serverCount = SapManager.GetServerCount();
122 int GenieIndex = 0;
123
124 // 实例化一个list,作为容器
125 System.Collections.ArrayList listServerNames = new System.Collections.ArrayList();
126
127 bool bFind = false;
128 string serverName = "";
129 for (int serverIndex = 0; serverIndex < serverCount; serverIndex++)
130 {
131 if (SapManager.GetResourceCount(serverIndex, SapManager.ResourceType.AcqDevice) != 0)
132 {
133 serverName = SapManager.GetServerName(serverIndex);
134 listServerNames.Add(serverName);
135 GenieIndex++;
136 bFind = true;
137 }
138 }
139
140 int count = 1;
141 string deviceName = "";
142 foreach (string sName in listServerNames)
143 {
144 deviceName = SapManager.GetResourceName(sName, SapManager.ResourceType.AcqDevice, 0);
145 count++;
146 }
147
148 sCameraName = serverName;
149 nIndex = GenieIndex;
150
151 return bFind;
152
153 }
154
155
156 // 初始化并连接相机
157 public bool CreateNewObjects()
158 {
159 Console.WriteLine("相机初始化");
160 string Name;
161 int Index;
162
163 // 获取相机详细信息
164 bool RTemp = GetCameraInfo(out Name, out Index);
165 if (RTemp)
166 {
167 MessageBox.Show(Name);
168 }
169 else
170 {
171 MessageBox.Show("Get camera info false!");
172 return false;
173 }
174
175 m_ServerLocation = new SapLocation(Name, 0);
176
177 //创建采集设备,new SapAcqDevice()的括号中第二个参数既可以写配置文件路径,也可以写false,false是用相机当前的设置
178 // 获取相机信息,加载相机配置文件(用相机专家调整好参数后导出ccf文件),加载参数
179 if (configFilePath.Length > 0)
180 m_AcqDevice = new SapAcqDevice(m_ServerLocation, configFilePath);
181 else
182 m_AcqDevice = new SapAcqDevice(m_ServerLocation, false);
183
184 Console.WriteLine(m_AcqDevice.Create());
185
186 if (m_AcqDevice.Create() == false)
187 {
188 DestroyObjects();
189 DisposeObjects();
190
191 return false;
192 }
193
194 // 创建缓存对象
195 if (SapBuffer.IsBufferTypeSupported(m_ServerLocation, SapBuffer.MemoryType.ScatterGather))
196 {
197 m_Buffers = new SapBufferWithTrash(2, m_AcqDevice, SapBuffer.MemoryType.ScatterGather);
198 }
199 else
200 {
201 m_Buffers = new SapBufferWithTrash(2, m_AcqDevice, SapBuffer.MemoryType.ScatterGatherPhysical);
202 }
203
204 if (m_Buffers.Create() == false)
205 {
206 DestroyObjects();
207 DisposeObjects();
208 return false;
209 }
210
211 //设置行频,注意:行频在相机工作时不能设置(曝光、增益可以),最好在初始化阶段设置
212 m_AcqDevice.SetFeatureValue("AcquisitionLineRate", 20000.0);
213
214 //创建传输对象
215 m_Xfer = new SapAcqDeviceToBuf(m_AcqDevice, m_Buffers);
216
217 // 这一句是核心,这是回调函数,就靠它采图了
218 m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);
219 m_Xfer.XferNotifyContext = this;
220 m_Xfer.Pairs[0].EventType = SapXferPair.XferEventType.EndOfFrame;
221 m_Xfer.Pairs[0].Cycle = SapXferPair.CycleMode.NextWithTrash;
222 if (m_Xfer.Pairs[0].Cycle != SapXferPair.CycleMode.NextWithTrash)
223 {
224 DestroyObjects();
225 DisposeObjects();
226 return false;
227 }
228 if (m_Xfer.Create() == false)
229 {
230 DestroyObjects();
231 DisposeObjects();
232 return false;
233 }
234
235 return true;
236 }
237
238
239 private void DestroyObjects()
240 {
241 if (m_Xfer != null && m_Xfer.Initialized)
242 m_Xfer.Destroy();
243 if (m_Buffers != null && m_Buffers.Initialized)
244 m_Buffers.Destroy();
245 if (m_AcqDevice != null && m_AcqDevice.Initialized)
246 m_AcqDevice.Destroy();
247 }
248
249
250 private void DisposeObjects()
251 {
252 if (m_Xfer != null)
253 {
254 m_Xfer.Dispose();
255 m_Xfer = null;
256 }
257 if (m_Buffers != null)
258 {
259 m_Buffers.Dispose();
260 m_Buffers = null;
261 }
262 if (m_AcqDevice != null)
263 {
264 m_AcqDevice.Dispose();
265 m_AcqDevice = null;
266 }
267 }
268
269
270 void m_Xfer_XferNotify(object sender, SapXferNotifyEventArgs argsNotify)
271 {
272 // 首先判断此帧是否为废弃帧,若是则立即返回,等待下一帧(但这句话有时候m_Xfer.Snap(n)时会导致丢帧,可以注释掉试试)
273 if (argsNotify.Trash) return;
274
275 // 获取m_Buffers的地址(指针),只要知道了图片内存的地址,其实就能有各种办法搞出图片了(例如转成Bitmap)
276 IntPtr addr;
277 m_Buffers.GetAddress(out addr);
278
279 // 观察buffer中的图片的一些属性值,语句后注释里面的值是可能的值
280 int count = m_Buffers.Count; //2
281 SapFormat format = m_Buffers.Format; //Uint8
282 double rate = m_Buffers.FrameRate; //30.0,连续采集时,这个值会动态变化
283 int height = m_Buffers.Height; //2800
284 int weight = m_Buffers.Width; //4096
285 int pixd = m_Buffers.PixelDepth; //8
286
287 //显示实时帧率
288 UpdateFrameRate();
289 lbl_FrameRate.BeginInvoke(new Action(() => { lbl_FrameRate.Text = m_Buffers.FrameRate.ToString(); }));
290
291
292 picCountNum++;
293
294 // 保存到本地。这个save方法就是从SDK中提取出来的,给上参数,就可以实现图片的保存,不用借助其他任何的技术方法
295 m_Buffers.Save(imgPath + picCountNum + ".bmp", "-format bmp" );
296
297
298 // 从内存读取图片,并转换成bitmap格式,创建调色板,打印到PictureBox
299 PixelFormat pf = PixelFormat.Format8bppIndexed;
300 Bitmap bmp = new Bitmap(weight, height, m_Buffers.Pitch, pf, addr);
301 ColorPalette m_grayPalette;
302 using (Bitmap tempbmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
303 {
304 m_grayPalette = tempbmp.Palette;
305 }
306 for (int i = 0; i <= 255; i++)
307 {
308 m_grayPalette.Entries[i] = Color.FromArgb(i, i, i);
309 }
310
311 bmp.Palette = m_grayPalette;
312
313 Image img = Image.FromHbitmap(bmp.GetHbitmap());
314 picBox.Image = img;
315 }
316
317 private void UpdateFrameRate()
318 {
319 if (m_Xfer.UpdateFrameRateStatistics())
320 {
321 float framerate = 0.0f;
322 SapXferFrameRateInfo stats = m_Xfer.FrameRateStatistics;
323
324 if (stats.IsBufferFrameRateAvailable)
325 framerate = stats.BufferFrameRate;
326 else if (stats.IsLiveFrameRateAvailable && !stats.IsLiveFrameRateStalled)
327 framerate = stats.LiveFrameRate;
328
329 m_Buffers.FrameRate = framerate;
330 }
331 }
332
333 // 获得相机参数的最大值(行频和曝光时间是近似倒数的关系,获得参数最大值可以防止设置参数超限)
334 private double GetMaxValue(string featureName)
335 {
336 SapFeature feature = new SapFeature(m_ServerLocation);
337 if (!feature.Create()) return -1;
338 if (!m_AcqDevice.GetFeatureInfo(featureName, feature)) return -1;
339
340 double maxValue = 0;
341 if (!feature.GetValueMax(out maxValue)) return -1;
342 return maxValue;
343 }
344
345 // 这个一般用的少,最小值一般是很小的数(比如Gain最小0.125, width最小128),我们一般不会设置这样的数
346 private double GetMinValue(string featureName)
347 {
348 SapFeature feature = new SapFeature(m_ServerLocation);
349 if (!feature.Create()) return -1;
350 if (!m_AcqDevice.GetFeatureInfo(featureName, feature)) return -1;
351
352 int minValue = 0;
353 if (!feature.GetValueMin(out minValue)) return -1;
354 return minValue;
355 }
356 }
357 }