본문 바로가기

AI/음성인식

바이든? 날리면? 주파수 기반 음성처리 노이즈 제거

동영상은 영상과 음성으로 이루어져 있다.

영상은 두 눈으로 명확히 보이므로 분석이 어렵지 않으나, 음성은 여러 잡음과 multi-speaker 문제로 분석이 어렵다.

본 글에서는 음성을 분석하여 노이즈를 제거하고 속도를 빠르거나 느리게 하는 실습을 진행한다.

 

음성은 아래와 같이 시간영역에서 파형으로 이뤄져 있다.

그리고 이 파형은 실제 우리가 원하는 음성과, 잡음으로 이뤄져 있다. 우리는 잡음을 제거하고, 원하는 음성 부분만 듣고 싶다.

 

실습 순서는 아래와 같다.

1) 유튜브에서 원하는 영상을 다운로드한다

2) 영상에서 음성을 추출한다

3) 전체 음성에서 원하는 부분만 자른다

4) 주파수 영역에서 음성을 분석한다

5) 주파수 변환(mel-spectogram)을 그래프로 확인한다

6) 음성을 빠르거나 느리게 재생한다

7) 원본 음성과 노이즈 제거 음성을 들어보며 분석한다

 

 

0) 환경 셋업

파이썬에서 분석하기 위하여 terminal에서 아래 라이브러리들을 설치한다

## setup
pip install pytube
pip install moviepy
pip install soundfile
pip install librosa
pip install scipy

 

 

1) 유튜브에서 원하는 영상을 다운

 본 실습에는 애매한 음성인 https://youtu.be/VE7d41xtPD4?feature=shared 를 대상으로 실습한다.

# 분석하고자 하는 유튜브 선정
from IPython.display import YouTubeVideo
video_id = "VE7d41xtPD4"  # 'https://youtu.be/VE7d41xtPD4?feature=shared' 
YouTubeVideo(video_id)

 

 

유튜브에서 영상을 다운로드한다

# 유튜브 영상 다운로드
from pytube import YouTube
from IPython.display import Audio
from IPython.display import HTML


def download_video(video_url):
    yt = YouTube(video_url)
    stream = yt.streams.get_highest_resolution()
    stream.download()
    return

video_url = 'https://youtu.be/VE7d41xtPD4?feature=shared'  # 유튜브 url 지정
download_video(video_url)

video_file = '바이든은 vs 날리면해명 이후 새로운 국면 맞이한 윤석열 대통령 비속어 논란 shorts.mp4'

video_html = f'''
<video width="640" height="360" controls>
  <source src="{video_file}" type="video/mp4">
  Your browser does not support the video tag.
</video>
'''

HTML(video_html)

 

 

2) 영상에서 음성을 추출

영상에서 음성 부분만 추출하여 따로 저장하고 확인한다

# 영상에서 음성 추출
from moviepy.editor import VideoFileClip

# 비디오 파일 경로 설정
audio_path = 'input_audio.mp3'  # 추출된 오디오를 저장할 파일 경로

# 비디오 파일 불러오기
video = VideoFileClip(video_file)

# 오디오 추출 및 저장
audio = video.audio
audio.write_audiofile(audio_path)
# 음성 파일 재생
print('## 추출된 음성파일 듣기')
Audio(audio_path)

 

 

3) 전체 음성에서 원하는 부분만 자른다

원하는 시간영역을 지정하여 자른다. 

# 음성 원하는 시간만큼 자르기
from pydub import AudioSegment

# 음성 파일 로드
audio = AudioSegment.from_mp3(audio_path)

# 시작 시간과 종료 시간 설정 (밀리초 단위)
start_time_ms = 10000  # 시작 시간 (10초)
end_time_ms = 13000    # 종료 시간 (13초)

# 음성 자르기
cut_audio = audio[start_time_ms:end_time_ms]

# 자른 음성을 새 파일로 저장
audio_file = 'input_audio_clipped.mp3'
cut_audio.export(audio_file, format="mp3")

print("음성 자르기 완료")
Audio(audio_file)

 

4) 주파수 영역에서 음성을 분석한다

주파수 영역으로 stft를 한 후 분석한다. 우선 high pass, low pass 필터를 이용하여 cutoff를 한다.

그리고 특정 주파수 영역은 없애면서 음성을 듣고, 조정하며 반복한다.

내가 원하는 음성 부분만 잘 들릴 수 있도록 cutoff_high_freq , cutoff_low_freq, min_freq, max_freq를 조종한다

 

- 노이즈를 제거할 주파수 범위 설정 

  • 2500 hz보다 높은 주파수 제거
    • cutoff_high_freq = 2500  
  • 200 hz보다 낮은 주파수 제거
    • cutoff_low_freq = 200

- 특정 주파수 제거: min_freq ~ max_freq는 제거 (예: 600Hz에서 1000Hz 사이)

  • min_freq = 600
  • max_freq = 1000
# 특정 주파수 대역 삭제
import numpy as np
import scipy.signal
import librosa
import soundfile as sf
import matplotlib.pyplot as plt


# 음성 파일 로드
audio_file = "input_audio_clipped.mp3"
y, sr = librosa.load(audio_file)
# Mel spectrogram 계산 (노이즈 제거 전)
mel_spectrogram_before = librosa.feature.melspectrogram(y=y, sr=sr)

##########################################################################
# STFT (Short-Time Fourier Transform) 수행
n_fft = 2048
hop_length = 512
spec = librosa.stft(y, n_fft=n_fft, hop_length=hop_length)

# 노이즈를 제거할 주파수 범위 설정 (예: 20Hz에서 2000Hz 사이)
cutoff_high_freq = 2500  # 높은 주파수 제거
cutoff_low_freq = 200  # 낮은 주파수 제거

# 특정 주파수 제거: min_freq ~ max_freq는 제거
min_freq = 600
max_freq = 1000


min_bin = int(min_freq * n_fft / sr)
max_bin = int(max_freq * n_fft / sr)
cutoff_high_bin = int(cutoff_high_freq * n_fft / sr)
cutoff_low_bin = int(cutoff_low_freq * n_fft / sr)

# STFT에서 노이즈 주파수 영역을 제거
spec[min_bin:max_bin, :] = 0
spec[cutoff_high_bin:, :] = 0  # 고주파 제거
spec[:cutoff_low_bin, :] = 0  # 저주파 제거

# ISTFT (Inverse Short-Time Fourier Transform) 수행하여 노이즈 제거된 음성 생성
y_denoised = librosa.istft(spec, hop_length=hop_length)
# Mel spectrogram 계산 (노이즈 제거 후)
mel_spectrogram_after = librosa.feature.melspectrogram(y=y_denoised, sr=sr)

# 노이즈 제거된 음성 저장
sf.write("output_audio_노이즈제거_주파수.mp3", y_denoised, sr)
audio_file_after = "output_audio_노이즈제거_주파수.mp3"
y_after, sr_after = librosa.load(audio_file_after)
# Mel spectrogram 계산 (노이즈 제거 전)
mel_spectrogram_after = librosa.feature.melspectrogram(y=y_after, sr=sr_after)

 

 

5) 주파수 변환(mel-spectogram)을 그래프로 확인한다

원본 음성과, 주파수 필터링한 음성의 mel-spectogram(주파수 크기)를 비교해 본다. 필터링 한 주파수 영역은 설정한 cutoff와 min/max에 의해 특정 부분이 삭제되었다.(검은색)

# 노이즈 제거하기 전 Mel spectrogram 시각화
plt.figure(figsize=(10, 3))
librosa.display.specshow(librosa.power_to_db(mel_spectrogram_before, ref=np.max), y_axis='mel', x_axis='time')
plt.colorbar(format='%+2.0f dB')
plt.title('Mel Spectrogram (before noise reduction)')
plt.tight_layout()

# 노이즈 제거한 후 Mel spectrogram 시각화
plt.figure(figsize=(10, 3))
librosa.display.specshow(librosa.power_to_db(mel_spectrogram_after, ref=np.max), y_axis='mel', x_axis='time')
plt.colorbar(format='%+2.0f dB')
plt.title('Mel Spectrogram (after noise reduction)')
plt.tight_layout()

 

 

6) 음성을 빠르거나 느리게 재생한다

60%로 느리게 재생하거나, 150%로 빠르게 재생하면서 음성을 들어본다

# 느리게 재생
재생속도비율 = 0.6  # 50%로 느리게 재생

import librosa
import soundfile as sf
from scipy.signal import resample

# 음성 파일 로드
y, sr = librosa.load(audio_file_after, sr=None)  # sr=None은 원래 샘플링 레이트를 유지합니다.

# 재생 속도를 50%로 조정
y_slow = librosa.effects.time_stretch(y, rate=재생속도비율)

# 느린 버전의 음성을 파일로 저장
output_audio_file = "output_audio_노이즈제거_주파수_느리게재생.wav"
sf.write(output_audio_file, y_slow, sr)

Audio(output_audio_file)

 

 

7) 원본 음성과 노이즈 제거 음성을 들어보며 분석한다

 

# 원본 음성 파일 재생
Audio(audio_file)

 

# 노이즈 제거 음성 파일 재생
Audio(audio_file_after)

 

 

8) 결론

음성을 분석하기 위해 뉴스에 나오는 기법들을 구현해 보았다.

다양한 주파수 분석(low/high pass filtering)과 속도조절을 통해 음성을 분석해 보니 특정 단어로 들렸다. 노이즈가 없을 때, 같은 단어의 음성을 얻을 수 있다면 주파수 비교를 통해 명확히 알 수 있다. 하지만 본 음성만으로는 단정 지을 수 없다. 주파수 필터링은 좋은 방법이지만 실제 음성이 뭉개지는 한계가 있다. 즉 어느 누구도 명확히 답을 낼 수 없다고 본다.

'AI > 음성인식' 카테고리의 다른 글

TTS  (0) 2019.04.09