C#+Halcon 图像拼接


近期在用线扫相机进行一些视觉检测,针对线扫相机的特性,对其输出的图像进行拼接,例如拼接上一张图像的最后64行到下本次图像中。

最开始的思路是在halcon中进行操作,利用paint_region进行重绘,发现效率极低。后来想起来不就是矩阵操作,数组拷贝之类的操作吗,最后直接在C#中进行拼接,对图像指针进行操作(效率还是不如C++)。分享代码如下:

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
   /// <summary>
        /// 将两个指针拼接成一个数组
        /// </summary>
        /// <param name="lastPtr">上一次数据指针</param>
        /// <param name="curPtr">本次数据指针</param>
        /// <param name="imgWidth">图片宽度</param>
        /// <param name="imgHeight">图片长度</param>
        /// <param name="concatRowCount">拼接行数</param>
        /// <param name="outputBytes">输出数组</param>
        public static void ConcatGrayIntptr(IntPtr lastPtr, IntPtr curPtr, int imgWidth,
            int imgHeight, int concatRowCount, out byte[] outputBytes)
        {
            outputBytes = new byte[(imgHeight + concatRowCount) * imgWidth];
            IntPtr offsetLastPtr = IntPtr.Zero;
            if (lastPtr != IntPtr.Zero)
            {
                if (IntPtr.Size == sizeof(Int64))
                    offsetLastPtr = new IntPtr(lastPtr.ToInt64() + imgWidth * (imgHeight - concatRowCount));
                else
                    offsetLastPtr = new IntPtr(lastPtr.ToInt32() + imgWidth * (imgHeight - concatRowCount));
            }
            if (offsetLastPtr != IntPtr.Zero)
            {
                System.Runtime.InteropServices.Marshal.Copy(offsetLastPtr, outputBytes, 0, concatRowCount * imgWidth);
            }
            System.Runtime.InteropServices.Marshal.Copy(curPtr, outputBytes, concatRowCount * imgWidth, imgWidth * imgHeight);
        }

        /// <summary>
        /// 把多个指针拼接成一个数组,其中忽略掉重叠部分
        /// </summary>
        /// <param name="ptrs"></param>
        /// <param name="imgWidth"></param>
        /// <param name="imgHeight"></param>
        /// <param name="concatRowCount"></param>
        /// <param name="outputBytes"></param>
        public static void ConcatGrayContinuesIntptr(IntPtr[] ptrs,int imgWidth,int imgHeight,int concatRowCount,out byte[] outputBytes)
        {

            int oneImageSize = imgWidth * (imgHeight - concatRowCount);

            outputBytes = new byte[oneImageSize * ptrs.Length];

            int iCopyIndex = 0;
            foreach(IntPtr ptr in ptrs)
            {
                if (ptr != IntPtr.Zero)
                {
                    IntPtr offsetPtr;
                    if (IntPtr.Size == sizeof(Int64))
                        offsetPtr = new IntPtr(ptr.ToInt64() + imgWidth *  concatRowCount);
                    else
                        offsetPtr = new IntPtr(ptr.ToInt32() + imgWidth *  concatRowCount);

                    System.Runtime.InteropServices.Marshal.Copy(offsetPtr, outputBytes, iCopyIndex, oneImageSize);
                }
             
                iCopyIndex += oneImageSize;
            }
        }


        /// <summary>
        /// 拼接连续的几张图片成一张图片
        /// </summary>
        /// <param name="images">图片集合</param>
        /// <param name="concatRowCount">其中每张图片重合的行数</param>
        /// <param name="concatedImage">拼接后的图片</param>
        /// <returns></returns>
        public static bool ConcatGrayImage(HImage[] images,int concatRowCount,out HImage concatedImage)
        {
            if(images.Length == 0)
            {
                concatedImage = null;
                return false;
            }
            List<IntPtr> ptrs = new List<IntPtr>();
            string type;
            int width = 0, height= 0;
            foreach(HImage img in images)
            {
                if (img == null)
                {
                    ptrs.Add(IntPtr.Zero);
                }
                else
                {
                    IntPtr ptr = img.GetImagePointer1(out type,out width, out height);
                    ptrs.Add(ptr);
                }
            }
            byte[] pixelBytes;
            ConcatGrayContinuesIntptr(ptrs.ToArray(), width, height, concatRowCount, out pixelBytes);


            new Lhxzn.Halcon.CameraImageData2HImage().Transform(
                 new CameraImageDataByte(width, images.Length *(height-concatRowCount), PixelType.Mono8, pixelBytes), out concatedImage);
            return true;
        }

        /// <summary>
        /// 拼接上一张图片的最后几行到本次图片中并输出
        /// </summary>
        /// <param name="lastImage">上一张图片</param>
        /// <param name="curImage">本次的图片</param>
        /// <param name="concatRowCount">需拼接的行数</param>
        /// <param name="concatedImage">输出的图像</param>
        /// <returns></returns>
        public static bool ConcatGrayImage(HImage lastImage, HImage curImage, int concatRowCount, out HImage concatedImage)
        {

            if (curImage == null || (lastImage == null && curImage == null))
            {
                concatedImage = null;
                return false;
            }
            else
            {
                string last_type, cur_type;
                int last_width, last_height, cur_width, cur_height;

                IntPtr lastPtr = IntPtr.Zero;
                if (lastImage != null)
                    lastPtr = lastImage.GetImagePointer1(out last_type, out last_width, out last_height);
                IntPtr curPtr = curImage.GetImagePointer1(out cur_type, out cur_width, out cur_height);

                int new_width = cur_width, new_height = cur_height + concatRowCount;
                byte[] pixelBytes;
                ConcatGrayIntptr(lastPtr, curPtr, cur_width, cur_height, concatRowCount, out pixelBytes);

                DateTime start = DateTime.Now;

                new Lhxzn.Halcon.CameraImageData2HImage().Transform(
                    new CameraImageDataByte(cur_width, new_height, PixelType.Mono8, pixelBytes), out concatedImage);
                double inter = (DateTime.Now - start).TotalMilliseconds;
                return true;
            }

        }