/// <summary> /// 将ValuePointCollection按照val值从小到大排序 /// </summary> /// <param name="vpCollection">ValuePointCollection</param> /// <returns></returns> public static ValuePointCollection SortValuePointCollection(ValuePointCollection vpCollection) { if (vpCollection == null || vpCollection.Count == 0) { return(new ValuePointCollection()); } int min; for (int i = 0; i < vpCollection.Count - 1; i++) { min = i; for (int j = i + 1; j < vpCollection.Count; j++) { if (((ValuePoint)vpCollection[j]).Val < ((ValuePoint)vpCollection[min]).Val) { min = j; } } ValuePoint t = (ValuePoint)vpCollection[min]; vpCollection[min] = vpCollection[i]; vpCollection[i] = t; } return(vpCollection); }
/// <summary> /// 集合中删除元素(线程安全), 必须调用base,否则会造成无限递归 /// </summary> /// <param name="vp"></param> public void Remove(ValuePoint vp) { lock (this.SyncRoot) { base.Remove(vp); } }
/// <summary> /// 集合中增加元素(线程安全), 必须调用base,否则会造成无限递归 /// </summary> /// <param name="vp">ValuePoint元素</param> public void Add(ValuePoint vp) { if (vp.GetType() != typeof(ValuePoint)) { throw new Exception("类型不匹配,不能加入集合。"); } lock (this.SyncRoot) { base.Add(vp); } }
/// <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); }