/// <summary> /// Shift all lines in "list to change" by "offset", create a matching, rate the matching and shift lines back. /// </summary> public double GetRatingOfOffset(double offset, SubtitleMatcher.SubtitleMatcherCache subtitleMatcherParams) { /* * Other ideas for rating: * bonus value for censecutive good bi-match ratings */ // move timings of every line subtitleMatcherParams.ShiftTime(offset, false, true); // match lines var biMatchedLinesList = SubtitleMatcher.MatchSubtitles(subtitleMatcherParams); double finalRating = 0; foreach (var biMatchedLines in biMatchedLinesList) { double rating = RateBiMatchedLines(biMatchedLines); // use rating^3 because that way small values will become smaller finalRating += rating * rating * rating; } // shift timings back subtitleMatcherParams.ShiftTime(-offset, false, true); return(finalRating); }
/// <summary> /// Find best offset for "listToChange" so it matches "referenceList". There can be /// multiple "peaks" if one subtitle has additional breaks the other does not have. /// Only one of them will be returned. /// </summary> private double FindBestOffset(RemainingSlice slice) { var subtitleMatcherParams = SubtitleMatcher.GetParameterCache(slice.referenceListLines, slice.listToChangeLines); // the tuple is (offset, rating) var firstPassList = new List <OffsetRatingTuple>(5); FindGoodOffsets(subtitleMatcherParams, 0, 0.3, 1000, firstPassList); // find fine grained offsets around approximated offsets var secondPassList = new List <OffsetRatingTuple>(5); foreach (var offsetRatingTuple in firstPassList) { FindGoodOffsets(subtitleMatcherParams, offsetRatingTuple.offset, 0.01, 90, secondPassList); } return(secondPassList[0].offset); }
/// <summary> /// This function will... /// a) move all lines to change in slice by offset /// b) match the lines in "listToChange" and "referenceList" /// c) find a threshold value for matchings /// d) find the longest row of consecutive matchings that are above the threshold /// e) create slices for lines before and lines after this "good row" /// f) reset offset of these remaining lines and put slice into queue /// </summary> private void ApplyOffset(RemainingSlice slice, double offset, Queue <RemainingSlice> queue) { UtilsSubtitle.ShiftByTime(slice.listToChangeLines, offset); // match lines var subtitleMatcherParameters = SubtitleMatcher.GetParameterCache(slice.referenceListLines, slice.listToChangeLines); var biMatchedLinesLinkedList = SubtitleMatcher.MatchSubtitles(subtitleMatcherParameters); var biMatchedLinesList = new List <SubtitleMatcher.BiMatchedLines>(biMatchedLinesLinkedList); biMatchedLinesList.Sort(delegate(SubtitleMatcher.BiMatchedLines x, SubtitleMatcher.BiMatchedLines y) { return(GetStartTime(x) < GetStartTime(y) ? -1 : 1); }); // -------------------------------------------------- // find threshold rating double averageRating = 0; int numRatings = 0; foreach (var biMatchedLines in biMatchedLinesList) { double rating = RateBiMatchedLines(biMatchedLines); if (rating > 0.0001) // ignore "zero" ratings { averageRating += rating; numRatings++; } } averageRating /= numRatings; double thresholdValue = averageRating * 0.8; // -------------------------------------------------- // Find longest row over threshold rating. // // Zero ratings may be inbetween good ratings when some // lines couldn't get matched (for example street-sign // translations that aren't in subtitle file in native language). // These are stepped over: There can be a limited number of zero ratings // ratings in the row except at the beginning and the end (these will // get matched at a different time if possible). int numGoodMatched = 0; int currentRowStart = 0; int allowedZeroRatings = 0; int maxNumGoodMatched = -1; int bestRowStart = 0; for (int index = 0; index < biMatchedLinesList.Count; index++) { var biMatchedLines = biMatchedLinesList[index]; double rating = RateBiMatchedLines(biMatchedLines); if (rating < thresholdValue) { // step over zero ratings if (rating > 0.000001 || allowedZeroRatings-- < 0) { numGoodMatched = 0; // not a zero rating } } else { // update row start/end if (numGoodMatched == 0) { currentRowStart = index; } numGoodMatched = index - currentRowStart + 1; // save best value if (numGoodMatched > maxNumGoodMatched) { maxNumGoodMatched = numGoodMatched; bestRowStart = currentRowStart; } allowedZeroRatings = 4; } } // could good row be found? if (maxNumGoodMatched == -1) { return; } // create new slices left and right RemainingSlice newSlice; // left slice newSlice = GetSubSlice(biMatchedLinesList, 0, bestRowStart); //UtilsSubtitle.ShiftByTime(newSlice.listToChangeLines, -offset); // by disabling this code, remaining slices are now embedded in greater slices queue.Enqueue(newSlice); // right slice newSlice = GetSubSlice(biMatchedLinesList, bestRowStart + maxNumGoodMatched + 1, biMatchedLinesList.Count); //UtilsSubtitle.ShiftByTime(newSlice.listToChangeLines, -offset); queue.Enqueue(newSlice); }