Аудиосигналы: сравнение

Сравнение означает относительную степень сходства, основанную на некоторых характеристиках между двумя вещами. И то, и другое должно быть на одной и той же основе, следовать одним и тем же базовым правилам, и сравнение звука ничем не отличается. Мы генерируем отпечатки пальцев из аудиофайлов и сравниваем их на основе них.

Создание отпечатков пальцев в аудиофайлах может быть выполнено с использованием нескольких алгоритмов, таких как 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