Аудиосигналы: сравнение
Сравнение означает относительную степень сходства, основанную на некоторых характеристиках между двумя вещами. И то, и другое должно быть на одной и той же основе, следовать одним и тем же базовым правилам, и сравнение звука ничем не отличается. Мы генерируем отпечатки пальцев из аудиофайлов и сравниваем их на основе них.
Создание отпечатков пальцев в аудиофайлах может быть выполнено с использованием нескольких алгоритмов, таких как Echoprint, Chromaprint и т. Д. Для дальнейшей реализации мы будем использовать Chromaprint. Есть 4 шага для сравнения двух аудиофайлов, которые перечислены ниже:
- Исходные и целевые аудиофайлы
В нашем примере мы будем писать скрипт на Python. Следующий фрагмент помогает инициализировать наши исходный и целевой файлы.
# compare.py import argparse def initialize(): parser = argparse.ArgumentParser() parser.add_argument("-i ", "--source-file", help="source file") parser.add_argument("-o ", "--target-file", help="target file") args = parser.parse_args() SOURCE_FILE = args.source_file if args.source_file else None TARGET_FILE = args.target_file if args.target_file else None if not SOURCE_FILE or not TARGET_FILE: raise Exception("Source or Target files not specified.") return SOURCE_FILE, TARGET_FILE if __name__ == "__main__": SOURCE_FILE, TARGET_FILE = initialize()
- Создание отпечатков пальцев для исходных и целевых файлов
Для генерации отпечатков пальцев с помощью алгоритма Chromaprint мы используем инструмент командной строки под названием fpcalc. Этот инструмент генерирует отпечатки пальцев с помощью Chromaprint, но для сборки требуется FFMPEG.
# correlation.py import commands # seconds to sample audio file for sample_time = 5000 # calculate fingerprint def calculate_fingerprints(filename): fpcalc_out = commands.getoutput('fpcalc -raw -length %i %s' % (sample_time, filename)) fingerprint_index = fpcalc_out.find('FINGERPRINT=') + 12 # convert fingerprint to list of integers fingerprints = map(int, fpcalc_out[fingerprint_index:].split(',')) return fingerprints def correlate(source, target): fingerprint_source = calculate_fingerprints(source) fingerprint_target = calculate_fingerprints(target)
Это генерирует два списка, fingerprint_source и fingerprint_target. Оба этих списка содержат сгенерированные 32-битные отпечатки пальцев из инструмента fpcalc.
- Рассчитать показатель сходства
Для сравнения исходного и целевого файлов мы не сравниваем напрямую все отпечатки пальцев. Мы сравниваем соответствующие отпечатки пальцев в обоих списках. Сравнение выполняется на основе количества совпадающих битов в данном пакете отпечатков пальцев. При генерации отпечатков аудиофайлов с помощью Chromaprint иногда генерируемые отпечатки пальцев заканчиваются некоторыми нежелательными ошибками, вызывающими некоторые перевороты в битах. Ошибка в перевернутых битах до 1 составляет 98% случаев. Таким образом, если разница между битами отпечатков пальцев равна 1, можно с уверенностью предположить, что отпечатки пальцев похожи.
# correlation.py # returns correlation between lists def correlation(listx, listy): if len(listx) == 0 or len(listy) == 0: # Error checking in main program should prevent us from ever being # able to get here. raise Exception('Empty lists cannot be correlated.') if len(listx) > len(listy): listx = listx[:len(listy)] elif len(listx) < len(listy): listy = listy[:len(listx)] covariance = 0 for i in range(len(listx)): covariance += 32 - bin(listx[i] ^ listy[i]).count("1") covariance = covariance / float(len(listx)) return covariance/32
Это обеспечивает сходство между любыми заданными списками отпечатков пальцев на основе разницы в битах между соответствующими отпечатками пальцев.
- Проверить смещение в аудиофайлах
Это относится к той части, схожи ли отпечатки пальцев для данного исходного и целевого файлов. Но это не распространяется на случаи, когда исходный и целевой файлы смещаются в начале или в конце. Это случаи, когда исходный и целевой файлы могут быть похожими, но иметь некоторый сдвиг или смещение в файле.
#correlation.py import numpy # number of points to scan cross correlation over span = 150 # step size (in points) of cross correlation step = 1 # minimum number of points that must overlap in cross correlation # exception is raised if this cannot be met min_overlap = 20 # return cross correlation, with listy offset from listx def cross_correlation(listx, listy, offset): if offset > 0: listx = listx[offset:] listy = listy[:len(listx)] elif offset < 0: offset = -offset listy = listy[offset:] listx = listx[:len(listy)] if min(len(listx), len(listy)) < min_overlap: # Error checking in main program should prevent us from ever being # able to get here. return #raise Exception('Overlap too small: %i' % min(len(listx), len(listy))) return correlation(listx, listy) # cross correlate listx and listy with offsets from -span to span def compare(listx, listy, span, step): if span > min(len(listx), len(listy)): # Error checking in main program should prevent us from ever being # able to get here. raise Exception('span >= sample size: %i >= %i\n' % (span, min(len(listx), len(listy))) + 'Reduce span, reduce crop or increase sample_time.') corr_xy = [] for offset in numpy.arange(-span, span + 1, step): corr_xy.append(cross_correlation(listx, listy, offset)) return corr_xy
Чтобы скрыть последнее, все, что нам нужно сделать, - это сделать небольшую петлю вокруг отпечатков пальцев. Мы можем ввести переменную step, представляющую текущее смещение от начала исходного файла, а затем повторить процесс сравнения и вычислить оценку сходства между списками. Этот процесс заканчивается массивом оценок сходства или достоверности между списками для всех смещений.
#correlation.py # report match when cross correlation has a peak exceeding threshold threshold = 0.5 # return index of maximum value in list def max_index(listx): max_index = 0 max_value = listx[0] for i, value in enumerate(listx): if value > max_value: max_value = value max_index = i return max_index def get_max_corr(corr, source, target): max_corr_index = max_index(corr) max_corr_offset = -span + max_corr_index * step print "max_corr_index = ", max_corr_index, "max_corr_offset = ", max_corr_offset # report matches if corr[max_corr_index] > threshold: print('%s and %s match with correlation of %.4f at offset %i' % (source, target, corr[max_corr_index], max_corr_offset))
Это позволяет найти максимальное сходство или достоверность и то, по какому смещению оно рассчитывается. Доверие и смещение говорят о том, похожи ли файлы и на сколько смещено или смещено от начала исходного файла.
Вот так сценарий выглядит в конце.
Дайте мне знать о любых предложениях или мыслях:
Insta + Twitter + LinkedIn + Medium + Facebook | @ shivama205