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 | using System;
using HalconDotNet;
class GrabRangeIntensity_StackLines
{
static void Main()
{
// --- ★ Points to adjust according to your environment ★ ---
const string IFace = "GigEVision2"; // e.g., "GigEVision2"
const string Device = "RULER3000_01"; // DeviceUserID or "169.254.x.x"
const int NumLines = 100; // Number of lines to acquire (assumes height is 1px per grab)
const string SaveDir = @"C:\temp\ruler_out"; // Destination folder for saving
const string PixelFmt = "Mono16"; // 12/16bit recommended for micrometer-level precision (must match camera settings)
HTuple acq = null;
HObject[] rangeLines = new HObject[NumLines];
HObject[] intenLines = new HObject[NumLines];
HObject rangeConcat = null, intenConcat = null;
HObject rangeStack = null, intenStack = null;
try
{
System.IO.Directory.CreateDirectory(SaveDir);
// 1) Open framegrabber
HOperatorSet.OpenFramegrabber(
IFace,
0, 0, 0, 0, 0, 0,
"default",
-1, "default", -1, "false",
"default",
Device,
0, -1,
out acq);
// 2) Recommended basic settings
// - Enable chunks (for simultaneous payload of Range+Intensity)
// - Pixel format (must match camera settings)
try { HOperatorSet.SetFramegrabberParam(acq, "ChunkModeActive", "true"); } catch {}
try { HOperatorSet.SetFramegrabberParam(acq, "PixelFormat", PixelFmt); } catch {}
// - Free run is OK for a start (see notes below if you need a software trigger)
HOperatorSet.SetFramegrabberParam(acq, "TriggerMode", "Off");
// 3) Acquisition loop (synchronous: grab_data)
// This part only performs the acquisition; concatenation and tiling are done in a later step.
for (int i = 0; i < NumLines; i++)
{
// grab_data returns a "tuple of images" and "metadata"
HObject imagesTuple; // Contains (Range, Intensity, ...)
HTuple metaTuple; // Contains metadata like 'mark' (can be discarded if not used)
HOperatorSet.GrabData(out imagesTuple, out metaTuple, acq);
// Extract Range / Intensity from the image tuple
// * The order may vary depending on the camera/settings.
// Typically, imagesTuple[0]=Range and imagesTuple[1]=Intensity.
HObject rangeImg, intenImg;
HOperatorSet.AccessChannel(imagesTuple, out rangeImg, 1); // 1st channel (=index 0)
HOperatorSet.AccessChannel(imagesTuple, out intenImg, 2); // 2nd channel (=index 1)
// This assumes 1 Grab = 1 line (height = 1px)
rangeLines[i] = rangeImg;
intenLines[i] = intenImg;
imagesTuple.Dispose(); // Release the tuple itself
// metaTuple is HTuple (managed) so explicit release is not needed
}
// 4) Concatenate -> tile in one go (vertical stack: Rows=NumLines, Cols=1)
HOperatorSet.GenEmptyObj(out rangeConcat);
HOperatorSet.GenEmptyObj(out intenConcat);
for (int i = 0; i < NumLines; i++)
{
HObject tmp;
HOperatorSet.ConcatObj(rangeConcat, rangeLines[i], out tmp);
rangeConcat.Dispose(); rangeConcat = tmp;
rangeLines[i].Dispose();
HOperatorSet.ConcatObj(intenConcat, intenLines[i], out tmp);
intenConcat.Dispose(); intenConcat = tmp;
intenLines[i].Dispose();
}
HOperatorSet.TileImages(rangeConcat, out rangeStack, NumLines, 1);
HOperatorSet.TileImages(intenConcat, out intenStack, NumLines, 1);
// 5) Save (16bit TIFF is recommended. PNG is also an option, but TIFF is safer for 16bit data)
string pathRange = System.IO.Path.Combine(SaveDir, "range_stack.tiff");
string pathInten = System.IO.Path.Combine(SaveDir, "intensity_stack.tiff");
HOperatorSet.WriteImage(rangeStack, "tiff", 0, pathRange);
HOperatorSet.WriteImage(intenStack, "tiff", 0, pathInten);
Console.WriteLine($"saved:\n {pathRange}\n {pathInten}");
}
finally
{
// Cleanup
if (rangeStack != null) rangeStack.Dispose();
if (intenStack != null) intenStack.Dispose();
if (rangeConcat != null) rangeConcat.Dispose();
if (intenConcat != null) intenConcat.Dispose();
if (acq != null) HOperatorSet.CloseFramegrabber(acq);
}
}
}
|