10. 인식 과정 - 음표(음정)
음표의 모양은 인식이 끝났고, 이제 음정을 알아낼 차례입니다.
음정은 크게 어려울 것이 없는데, 오선의 좌표와 음표 머리의 좌표만 비교해주면 되기 때문입니다.
음표 머리의 좌표는 정방향 음표냐 역방향 음표냐에 따라 달라지지만
기둥의 상단 좌표나 하단 좌표랑 같습니다.
# recognition_modules.py
import functions as fs
import cv2
def recognize_pitch(image, staff, head_center):
pitch_lines = [staff[4] + fs.weighted(30) - fs.weighted(5) * i for i in range(21)]
for i in range(len(pitch_lines)):
line = pitch_lines[i]
if line + fs.weighted(2) >= head_center >= line - fs.weighted(2):
return i
오선에 덧대어 가상 좌표를 만들어주겠습니다.
staves[4] + fs.weighted(30) ~ staves[0] - fs.weighted(30) 총 21개의 좌표가 나옵니다.
즉, 위와 같이 좌푯값 리스트가 만들어지는 건데, 중간 5개의 선은 원래 있던 오선이고
빨간 선들은 덧대어 만들어준 가상선이라고 보시면 됩니다.
해당 좌표에서 일정 범위안에 음표의 머리 위치가 포함되면 음정을 찾을 수 있죠.
예를 들어 5번이 반환됐다고 치면, 다장조 기준 계이름 '도'가 반환된 것이랑 같은 겁니다.
# recognition_modules.py
import functions as fs
import cv2
def recognize_note(image, staff, stats, stems, direction):
(x, y, w, h, area) = stats
notes = []
pitches = []
note_condition = (
len(stems) and
w >= fs.weighted(10) and # 넓이 조건
h >= fs.weighted(35) and # 높이 조건
area >= fs.weighted(95) # 픽셀 갯수 조건
)
if note_condition:
for i in range(len(stems)):
stem = stems[i]
head_exist, head_fill, head_center = recognize_note_head(image, stem, direction)
if head_exist:
tail_cnt = recognize_note_tail(image, i, stem, direction)
dot_exist = recognize_note_dot(image, stem, direction, len(stems), tail_cnt)
note_classification = (
((not head_fill and tail_cnt == 0 and not dot_exist), 2),
((not head_fill and tail_cnt == 0 and dot_exist), -2),
((head_fill and tail_cnt == 0 and not dot_exist), 4),
((head_fill and tail_cnt == 0 and dot_exist), -4),
((head_fill and tail_cnt == 1 and not dot_exist), 8),
((head_fill and tail_cnt == 1 and dot_exist), -8),
((head_fill and tail_cnt == 2 and not dot_exist), 16),
((head_fill and tail_cnt == 2 and dot_exist), -16),
((head_fill and tail_cnt == 3 and not dot_exist), 32),
((head_fill and tail_cnt == 3 and dot_exist), -32)
)
for j in range(len(note_classification)):
if note_classification[j][0]:
note = note_classification[j][1]
pitch = recognize_pitch(image, staff, head_center)
notes.append(note)
pitches.append(pitch)
break
return notes, pitches
이제 recognition 함수로 반환해주면 recognize_note 함수 부분은 완성되었습니다.
# modules.py
import cv2
import numpy as np
import functions as fs
import recognition_modules as rs
def recognition(image, staves, objects):
key = 0
time_signature = False
beats = [] # 박자 리스트
pitches = [] # 음이름 리스트
for i in range(1, len(objects) - 1):
obj = objects[i]
line = obj[0]
stats = obj[1]
stems = obj[2]
direction = obj[3]
(x, y, w, h, area) = stats
staff = staves[line * 5: (line + 1) * 5]
if not time_signature: # 조표가 완전히 탐색되지 않음 (아직 박자표를 찾지 못함)
ts, temp_key = rs.recognize_key(image, staff, stats)
time_signature = ts
key += temp_key
else: # 조표가 완전히 탐색되었음
notes = rs.recognize_note(image, staff, stats, stems, direction)
if len(notes[0]):
for beat in notes[0]:
beats.append(beat)
for pitch in notes[1]:
pitches.append(pitch)
cv2.rectangle(image, (x, y, w, h), (255, 0, 0), 1)
fs.put_text(image, i, (x, y - fs.weighted(20)))
return image, key, beats, pitches
다음 챕터에서는 쉼표 인식 알고리즘을 짜보도록 하겠습니다.
'인공지능 > 컴퓨터비전' 카테고리의 다른 글
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 12 (5) | 2021.08.08 |
---|---|
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 11 (0) | 2021.08.07 |
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 9 (0) | 2021.08.06 |
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 8 (0) | 2021.08.06 |
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 7 (6) | 2021.08.06 |
댓글