public static void Test() { IdentificationSet <int> set = new IdentificationSet <int>(); // 1 = 4 = 6 = 7 = 8 // 2 = 5 = 9 = 10 = 11 // 3 set.MakeEquivalent(1, 4); set.MakeEquivalent(5, 2); set.MakeEquivalent(3, 3); set.MakeEquivalent(5, 10); set.MakeEquivalent(11, 5); set.MakeEquivalent(5, 9); set.MakeEquivalent(6, 8); set.MakeEquivalent(7, 1); set.MakeEquivalent(7, 4); set.MakeEquivalent(7, 6); set.CompactIdentificationNumber(); StringBuilder ret = new StringBuilder(); for (int i = 1; i <= 11; i++) { ret.AppendLine(string.Format("{0} => {1}", i, set.ConvertToIdentificationNumber(i))); } System.Windows.MessageBox.Show(ret.ToString()); }
public static UserSegmentation[] Identification(FrameSequence frameseq, double maxDistance) { if (frameseq.Segmentations.Any(seg => seg == null)) { throw new InvalidOperationException("ユーザトラッキングデータがセグメンテーションされていません"); } HashSet <Tuple <RecordAndUser, RecordAndUser> > contemporaryList = new HashSet <Tuple <RecordAndUser, RecordAndUser> >(); for (int recordNo = 0; recordNo < frameseq.recordNum; recordNo++) { IEnumerable <MotionData> record = frameseq.GetMotionDataSequence(recordNo); int frameIndex = 0; foreach (MotionData motionData in record) { IList <ulong> users = motionData.bodies.ToList().Select(b => b.TrackingId).ToList(); foreach (var tuple in users.SelectMany(u => users.Select(v => new Tuple <RecordAndUser, RecordAndUser>(new RecordAndUser(recordNo, u), new RecordAndUser(recordNo, v))))) { contemporaryList.Add(tuple); } frameIndex++; } } DateTime beginTime = frameseq.startTime; DateTime endTime = frameseq.endTime; double frequency = frameseq.frameRate; TimeSpan increment = new TimeSpan((long)(10000000 / frequency)); long totalCount = (endTime.Ticks - beginTime.Ticks) / increment.Ticks; long totalIndex = 0; Dictionary <Tuple <RecordAndUser, RecordAndUser>, List <double> > distanceListMatrix = new Dictionary <Tuple <RecordAndUser, RecordAndUser>, List <double> >(); foreach (Frame frame in frameseq.Frames) { // 現在の時刻での各レコードの各ユーザの各骨格の絶対座標を求める Dictionary <ulong, Dictionary <JointType, CvPoint3D64f> >[] absPositions = new Dictionary <ulong, Dictionary <JointType, CvPoint3D64f> > [frameseq.recordNum]; for (int recordNo = 0; recordNo < frameseq.recordNum; recordNo++) { Dictionary <ulong, Dictionary <JointType, CvPoint3D64f> > recordUserPositions = new Dictionary <ulong, Dictionary <JointType, CvPoint3D64f> >(); foreach (SerializableBody body in frame.GetBodyList(recordNo)) { Dictionary <JointType, CvPoint3D64f> userPositions = new Dictionary <JointType, CvPoint3D64f>(); if (body.Joints == null) { continue; } foreach (var jointPair in body.Joints) { CvPoint3D64f posInCamera = jointPair.Value.Position.ToCvPoint3D(); CvPoint3D64f posInWorld = CvEx.ConvertPoint3D(posInCamera, frameseq.ToWorldConversions[recordNo]); userPositions[jointPair.Key] = posInWorld; } recordUserPositions[body.TrackingId] = userPositions; } absPositions[recordNo] = recordUserPositions; } // 現在の時刻で各レコード間のユーザ間の距離を求める for (int i = 0; i < frameseq.recordNum; i++) { if (absPositions[i] == null) { continue; } for (int j = i + 1; j < frameseq.recordNum; j++) { if (absPositions[j] == null) { continue; } foreach (var userJoint1 in absPositions[i]) { RecordAndUser recordUser1 = new RecordAndUser(i, userJoint1.Key); foreach (var userJoint2 in absPositions[j]) { RecordAndUser recordUser2 = new RecordAndUser(j, userJoint2.Key); double distanceNormal = getDistance(userJoint1.Value, userJoint2.Value, false); double distanceMirrored = getDistance(userJoint1.Value, userJoint2.Value, true); double distance = Math.Min(distanceNormal, distanceMirrored); Tuple <RecordAndUser, RecordAndUser> key = new Tuple <RecordAndUser, RecordAndUser>(recordUser1, recordUser2); List <double> distanceList; if (!distanceListMatrix.TryGetValue(key, out distanceList)) { distanceListMatrix[key] = distanceList = new List <double>(); } distanceList.Add(distance); } } } } totalIndex++; } // 中央値で集計して小さい順に並べる Dictionary <Tuple <RecordAndUser, RecordAndUser>, double> distanceMatrix = distanceListMatrix.ToDictionary(p => p.Key, p => CalcEx.GetMedian(p.Value)); List <Tuple <RecordAndUser, RecordAndUser, double> > neighborList = ( from x in distanceMatrix orderby x.Value select new Tuple <RecordAndUser, RecordAndUser, double>(x.Key.Item1, x.Key.Item2, x.Value) ).ToList(); IdentificationSet <RecordAndUser> identificationSet = new IdentificationSet <RecordAndUser>(); // 同一判定をする foreach (var neighbor in neighborList) { if (neighbor.Item3 > maxDistance) { identificationSet.Add(neighbor.Item1); identificationSet.Add(neighbor.Item2); continue; } IList <RecordAndUser> recordUsers1 = identificationSet.GetEquivalentElements(neighbor.Item1); IList <RecordAndUser> recordUsers2 = identificationSet.GetEquivalentElements(neighbor.Item2); // 同フレーム内にいるか判定 bool contemporary = ( from ru1 in recordUsers1 from ru2 in recordUsers2 select new Tuple <RecordAndUser, RecordAndUser>(ru1, ru2)).Any(pair => contemporaryList.Contains(pair)); if (!contemporary) { // 同フレーム内にいなければ同一視 identificationSet.MakeEquivalent(neighbor.Item1, neighbor.Item2); } } // 番号を圧縮 identificationSet.CompactIdentificationNumber(); // 新しいセグメンテーション番号を与える UserSegmentation[] ret = Enumerable.Range(0, frameseq.recordNum).Select(i => new UserSegmentation()).ToArray(); for (int recordNo = 0; recordNo < frameseq.recordNum; recordNo++) { foreach (var pair in frameseq.Segmentations[recordNo].Conversions) { int frameIndex = pair.Key; Dictionary <ulong, int> newConversions = new Dictionary <ulong, int>(); foreach (var conv in pair.Value) { int ident = identificationSet.ConvertToIdentificationNumber(new RecordAndUser(recordNo, conv.Key)); newConversions[conv.Key] = ident; } ret[recordNo].Conversions[frameIndex] = newConversions; } ret[recordNo].fixNumUsers(); } return(ret); }