Example #1
0
        /// <summary>
        /// 将位图转换为层信息
        /// </summary>
        /// <param name="bmp">位图</param>
        /// <returns>返回LayerImageCollection</returns>
        public LayerImageCollection TransformBmpToLayerImg(Bitmap bmp)
        {
            if (bmp == null || bmp.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                throw new Exception("原位图为空或者不是灰度图。");
            }

            int        width   = bmp.Width;
            int        height  = bmp.Height;
            Rectangle  rect    = new Rectangle(0, 0, width, height);
            BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
            // Stride为位图中每一行以4字节对齐的行宽
            int strideSource = bmpdata.Stride;

            byte[]               byteData        = new byte[width * height];
            LayerImage           li              = null;
            LayerImageCollection layerCollection = null;

            unsafe
            {
                byte *ptr = (byte *)bmpdata.Scan0.ToPointer();
                for (int row = 0; row < height; row++)
                {
                    for (int col = 0; col < width; col++)
                    {
                        // 位图的在内存中的排列是从左到右,从下到上的,但BitmapData貌似做了优化,把位图数据在内存中的排列
                        // 顺序改为与坐标系一致,即从左到右、从上到下
                        byteData[col + row * width] = *ptr;

                        ptr++;
                    }
                }
                bmp.UnlockBits(bmpdata);
            }

            layerCollection = new LayerImageCollection();
            li = new LayerImage(byteData, width, height);
            layerCollection.Add(li);   // 加入I的第0层数据

            for (int l = 1; l < LN; l++)
            {
                int w, h;  // 当前层图像的宽和高
                // width和height为前一层图像的宽和高
                w        = (width + 1) / 2;
                h        = (height + 1) / 2;
                byteData = new byte[w * h];
                for (int row = 0; row < h; row++)
                {
                    for (int col = 0; col < w; col++)
                    {
                        int leftX   = 2 * col - 1;
                        int rightX  = 2 * col + 1;
                        int lowY    = 2 * row - 1;
                        int upY     = 2 * row + 1;
                        int centerX = 2 * col;
                        int centerY = 2 * row;
                        if (leftX < 0)
                        {
                            leftX = 0;
                        }
                        if (rightX >= width)
                        {
                            rightX = width - 1;
                        }
                        if (lowY < 0)
                        {
                            lowY = 0;
                        }
                        if (upY >= height)
                        {
                            upY = height - 1;
                        }

                        // 根据上一层的数据生成当前层的数据
                        byteData[col + row * w] = (byte)(0.25 * li.ImageData[centerX + centerY * width] +
                                                         0.125 * (li.ImageData[leftX + centerY * width] + li.ImageData[rightX + centerY * width] +
                                                                  li.ImageData[centerX + lowY * width] + li.ImageData[centerX + upY * width]) +
                                                         0.0625 * (li.ImageData[leftX + lowY * width] + li.ImageData[rightX + lowY * width] +
                                                                   li.ImageData[leftX + upY * width] + li.ImageData[rightX + upY * width]));
                    }
                }
                li = new LayerImage(byteData, w, h);
                layerCollection.Add(li);

                width  = w;
                height = h;
            }

            return(layerCollection);
        }
Example #2
0
        /// <summary>
        /// 根据两幅图像金字塔和已选定的初始点,计算整体位移,返回位移值和缩放系数
        /// </summary>
        /// <param name="firstlayercollection">第一幅图像金字塔</param>
        /// <param name="secondlayercollection">第二幅图像金字塔</param>
        /// <param name="ipoints">第一幅图像中选中的初始点</param>
        ///  <param name="wx">计算每个点时,积分邻域横向半径,此值寻找初始点时只需要取1,跟踪时要取的大一些</param>
        /// <param name="wy">计算每个点时,积分邻域纵向半径,此值寻找初始点时只需要取1,跟踪时要取的大一些</param>
        /// <param name="reversebias">反向跟踪时,输出点和原来点之间的距离差阈值(像素值),该差值超过阈值被认为不是好的跟踪点,当被删除,建议取1</param>
        /// <param name="medianbias">每个点的位移与中值位移之间的最大距离(像素值),超过这个距离的点认为是跟踪失败的,建议取10</param>
        /// <param name="scalestep">缩放台阶,缩放系数的变化刻度,如变化差小于0.2的视为不变,大于0.2小于0.4的视为0.2,以此类推</param>
        /// <param name="firstlayerpoints">第一幅图像的最终输出点</param>
        /// <param name="secondlayerpoints">第二幅图像的最终输出点</param>
        /// <returns>位移值和缩放系数</returns>
        public float[] ComputerDisplacement(LayerImageCollection firstlayercollection, LayerImageCollection secondlayercollection, ArrayList ipoints,
                                            float reversebias, // 这个参数不好控制,导致跟踪非常不稳定
                                            int wx, int wy, float medianbias, float scalestep,
                                            ref ArrayList firstlayerpoints, ref ArrayList secondlayerpoints)
        {
            if (ipoints == null || secondlayercollection == null || firstlayercollection == null)
            {
                return(null);
            }

            // 输出结果,前两个维度表示位移,第三个维度表示区域缩放系数
            float[] outvector = new float[3];

            firstlayerpoints  = new ArrayList();
            secondlayerpoints = new ArrayList();

            ArrayList            jpoints       = new ArrayList();
            ValuePointCollection fbPointsArray = new ValuePointCollection();      // 用于计算Forward-Backward的集合,ValuePoint类型的
            ValuePoint           vp            = null;

            foreach (PointF p in ipoints)
            {
                PointF jpoint = TrackPoint(firstlayercollection, secondlayercollection, p, wx, wy);    // 正跟踪,第一幅图跟踪到第二幅图
                PointF ipoint;

                if (jpoint.X >= 0 && jpoint.Y >= 0)
                {
                    vp = new ValuePoint();

                    vp.Ptf1 = p;        // 第一幅图的点加入队列
                    vp.Ptf2 = jpoint;   // 第二幅图的对应点加入队列
                    fbPointsArray.Add(vp);

                    // 这段代码导致跟踪极不稳定
                    ipoint = TrackPoint(secondlayercollection, firstlayercollection, jpoint, wx, wy);                     // 反跟踪,第二幅图跟踪到第一幅图
                    vp.Val = (float)Math.Sqrt((p.X - ipoint.X) * (p.X - ipoint.X) + (p.Y - ipoint.Y) * (p.Y - ipoint.Y)); // 反向跟踪后产生的点与原来点的距离
                    if (vp.Val < reversebias)
                    {
                        fbPointsArray.Add(vp);
                    }
                }
            }

            if (fbPointsArray.Count == 0)
            {
                return(null);
            }

            //// 这段代码不是很合适
            //fbPointsArray = ValuePoint.SortValuePointCollection(fbPointsArray);
            //// 根据Forward-Backward值,去掉一半的不稳定点
            //int arraycont = fbPointsArray.Count;
            //for (int i = arraycont / 2; i < arraycont; i++)
            //{
            //    fbPointsArray.RemoveAt(arraycont / 2);
            //}  // Forward-Backward计算完成

            // 将fbPointsArray用于中值位移计算
            for (int i = 0; i < fbPointsArray.Count; i++)
            {
                vp = fbPointsArray[i];
                // 求每一点的位移值,不作开方减小计算量,不影响结果
                vp.Val = (vp.Ptf2.X - vp.Ptf1.X) * (vp.Ptf2.X - vp.Ptf1.X) + (vp.Ptf2.Y - vp.Ptf1.Y) * (vp.Ptf2.Y - vp.Ptf1.Y);
            }

            fbPointsArray = ValuePoint.SortValuePointCollection(fbPointsArray);

            ValuePoint median_vp = fbPointsArray[fbPointsArray.Count / 2];

            outvector[0] = median_vp.Ptf2.X - median_vp.Ptf1.X;
            outvector[1] = median_vp.Ptf2.Y - median_vp.Ptf1.Y;                   // 中值位移计算完毕

            // 去掉位移偏离中值位移过大的点
            ValuePointCollection tmpCollection = new ValuePointCollection();

            foreach (ValuePoint vpoint in fbPointsArray)
            {
                float dist = (float)Math.Sqrt(Math.Pow(vpoint.Ptf2.X - vpoint.Ptf1.X - median_vp.Ptf2.X + median_vp.Ptf1.X, 2) +
                                              Math.Pow(vpoint.Ptf2.Y - vpoint.Ptf1.Y - median_vp.Ptf2.Y + median_vp.Ptf1.Y, 2));
                if (dist > medianbias)      // 超过中值偏移的点删掉
                {
                    tmpCollection.Add(vpoint);
                }
                else      // 没超过中值位移的点加入图像金字塔
                {
                    firstlayerpoints.Add(vpoint.Ptf1);
                    secondlayerpoints.Add(vpoint.Ptf2);
                }
            }
            foreach (ValuePoint vpoint in tmpCollection)
            {
                fbPointsArray.Remove(vpoint);
            }

            // 计算区域的缩放值
            float[] scales = new float[fbPointsArray.Count - 1];
            for (int i = 0; i < fbPointsArray.Count - 1; i++)
            {
                ValuePoint v1 = fbPointsArray[i];
                ValuePoint v2 = fbPointsArray[i + 1];
                if ((v2.Ptf1.X - v1.Ptf1.X) * (v2.Ptf1.X - v1.Ptf1.X) + (v2.Ptf1.Y - v1.Ptf1.Y) * (v2.Ptf1.Y - v1.Ptf1.Y) == 0)
                {
                    scales[i] = 1;
                }
                else
                {
                    scales[i] = (float)(Math.Sqrt((v2.Ptf2.X - v1.Ptf2.X) * (v2.Ptf2.X - v1.Ptf2.X) + (v2.Ptf2.Y - v1.Ptf2.Y) * (v2.Ptf2.Y - v1.Ptf2.Y)) /
                                        Math.Sqrt((v2.Ptf1.X - v1.Ptf1.X) * (v2.Ptf1.X - v1.Ptf1.X) + (v2.Ptf1.Y - v1.Ptf1.Y) * (v2.Ptf1.Y - v1.Ptf1.Y)));
                }
            }
            outvector[2] = GetMedian(scales);
            if (outvector[2] < 0)
            {
                outvector[2] = 1;
            }
            else
            {
                outvector[2] = 1 + (int)((outvector[2] - 1) / scalestep) * scalestep;
            }

            return(outvector);
        }
Example #3
0
        /// <summary>
        /// 跟踪给定点的算法
        /// </summary>
        /// <param name="firstlayercollection">第一幅图像金字塔</param>
        /// <param name="secondlayercollection">第二幅图像金字塔</param>
        /// <param name="u">第一幅图像中给定的点</param>
        /// <param name="wx">计算每个点时,积分邻域横向半径,此值寻找初始点时只需要取1,跟踪时要取的大一些</param>
        /// <param name="wy">计算每个点时,积分邻域纵向半径,此值寻找初始点时只需要取1,跟踪时要取的大一些</param>
        /// <returns>返回第二幅图像中对应的点</returns>
        public PointF TrackPoint(LayerImageCollection firstlayercollection, LayerImageCollection secondlayercollection, PointF u, int wx, int wy)
        {
            float[]  G   = null;
            float[]  G_1 = null;              // G的逆矩阵
            PointF[] g   = new PointF[LN];    // 前一层估计的光流
            PointF[] d   = new PointF[LN];    // 本层计算出来的剩余光流
            PointF[] p   = new PointF[LN];    // 原始点坐标在本层的映射坐标
            PointF[] v   = new PointF[K + 1]; // 本层每次迭代计算出来的剩余光流

            Wx = wx;
            Wy = wy;

            if (firstlayercollection == null || secondlayercollection == null)
            {
                throw new Exception("有图像为空,无法跟踪。");
            }

            if (firstlayercollection[0].Width != secondlayercollection[0].Width)
            {
                throw new Exception("两幅图像大小不一致,无法跟踪。");
            }

            g[LN - 1].X = 0;
            g[LN - 1].Y = 0;

            for (int l = LN - 1; l >= 0; l--)
            {
                p[l].X = (float)(u.X / Math.Pow(2, l));
                p[l].Y = (float)(u.Y / Math.Pow(2, l));

                // 原图中给定的点已经在边界上,无法跟踪
                if (p[l].X > firstlayercollection[l].Width - 1 || p[l].Y > firstlayercollection[l].Height - 1)
                {
                    // 返回值中带有负数表示没有正确的结果
                    return(new PointF(-1, -1));
                }

                G = new float[4] {
                    0, 0, 0, 0
                };
                for (float x = p[l].X - Wx; x <= p[l].X + Wx; x++)
                {
                    for (float y = p[l].Y - Wy; y <= p[l].Y + Wy; y++)
                    {
                        float ix = Ix(l, x, y);
                        float iy = Iy(l, x, y);
                        G[0] += ix * ix;       // 第0行第0列
                        G[1] += ix * iy;       // 第0行第1列
                        G[2] += ix * iy;       // 第1行第0列
                        G[3] += iy * iy;       // 第1行第1列
                    }
                }

                // 求G的逆矩阵G_1
                float gdet = G[0] * G[3] - G[1] * G[2];

                // G的行列式为0,无法计算,跟踪丢失
                if (gdet == 0)
                {
                    return(new PointF(-1, -1));
                }

                G_1 = new float[4] {
                    0, 0, 0, 0
                };
                G_1[0] = G[3] / gdet;
                G_1[1] = -G[2] / gdet;
                G_1[2] = -G[1] / gdet;
                G_1[3] = G[0] / gdet;

                v[0].X = 0;
                v[0].Y = 0;
                for (int k = 1; k < K + 1; k++)
                {
                    int    delt;
                    PointF b    = new PointF(0, 0);
                    PointF yeta = new PointF(0, 0);
                    for (float x = p[l].X - Wx; x <= p[l].X + Wx; x++)
                    {
                        for (float y = p[l].Y - Wy; y <= p[l].Y + Wy; y++)
                        {
                            // 第二幅图的点已超出边界,跟踪丢失
                            if (x + g[l].X + v[k - 1].X <0 || x + g[l].X + v[k - 1].X> secondlayercollection[l].Width - 1 ||
                                y + g[l].Y + v[k - 1].Y <0 || y + g[l].Y + v[k - 1].Y> secondlayercollection[l].Height - 1)
                            {
                                return(new PointF(-1, -1));
                            }

                            delt = firstlayercollection[l][x, y] - secondlayercollection[l][x + g[l].X + v[k - 1].X, y + g[l].Y + v[k - 1].Y];
                            b.X += delt * Ix(l, x, y);
                            b.Y += delt * Iy(l, x, y);
                        }
                    }

                    yeta.X = G_1[0] * b.X + G_1[1] * b.Y;
                    yeta.Y = G_1[2] * b.X + G_1[3] * b.Y;

                    v[k].X = v[k - 1].X + yeta.X;
                    v[k].Y = v[k - 1].Y + yeta.Y;
                }

                d[l].X = v[K].X;
                d[l].Y = v[K].Y;

                if (l > 0)
                {
                    g[l - 1].X = 2 * (g[l].X + d[l].X);
                    g[l - 1].Y = 2 * (g[l].Y + d[l].Y);
                }
            }
            return(new PointF(u.X + g[0].X + d[0].X, u.Y + g[0].Y + d[0].Y));
        }