9. 인식 과정 - 음표(점)
이제 마지막 음표의 구성요소인 점만 인식하면 됩니다.
점은 크게 어려울 것은 없는데 오선의 범위를 넘은 음표를 그릴 때
오선에 대한 보조선(?)을 그어주는 경우가 있습니다.
해당 부분이 점을 탐색하는 구역과 겹칠 수 있어 유의해야 합니다.
그리고 8분음표나 16분음표와 같이 꼬리가 있는 음표들과도 겹칠 수가 있습니다.
그래서 탐색하는 영역을 정교하게 정해주어야 합니다.
recognize_note_dot 함수를 만들고 영역부터 확인해보겠습니다.
# recognition_modules.py
import functions as fs
import cv2
def recognize_note_dot(image, stem, direction):
(x, y, w, h) = stem
if direction: # 정 방향 음표
area_top = y + h - fs.weighted(10) # 음표 점을 탐색할 위치 (상단)
area_bot = y + h + fs.weighted(5) # 음표 점을 탐색할 위치 (하단)
area_left = x + w + fs.weighted(2) # 음표 점을 탐색할 위치 (좌측)
area_right = x + w + fs.weighted(12) # 음표 점을 탐색할 위치 (우측)
else: # 역 방향 음표
area_top = y - fs.weighted(10) # 음표 점을 탐색할 위치 (상단)
area_bot = y + fs.weighted(5) # 음표 점을 탐색할 위치 (하단)
area_left = x + w + fs.weighted(14) # 음표 점을 탐색할 위치 (좌측)
area_right = x + w + fs.weighted(24) # 음표 점을 탐색할 위치 (우측)
dot_rect = (
area_left,
area_top,
area_right - area_left,
area_bot - area_top
)
cv2.rectangle(image, dot_rect, (255, 0, 0), 1)
pass
# 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)
recognize_note_dot(image, stem, direction)
pass
얼추 맞는 것 같습니다.
# recognition_modules.py
import functions as fs
import cv2
def recognize_note_dot(image, stem, direction):
(x, y, w, h) = stem
if direction: # 정 방향 음표
area_top = y + h - fs.weighted(10) # 음표 점을 탐색할 위치 (상단)
area_bot = y + h + fs.weighted(5) # 음표 점을 탐색할 위치 (하단)
area_left = x + w + fs.weighted(2) # 음표 점을 탐색할 위치 (좌측)
area_right = x + w + fs.weighted(12) # 음표 점을 탐색할 위치 (우측)
else: # 역 방향 음표
area_top = y - fs.weighted(10) # 음표 점을 탐색할 위치 (상단)
area_bot = y + fs.weighted(5) # 음표 점을 탐색할 위치 (하단)
area_left = x + w + fs.weighted(14) # 음표 점을 탐색할 위치 (좌측)
area_right = x + w + fs.weighted(24) # 음표 점을 탐색할 위치 (우측)
dot_rect = (
area_left,
area_top,
area_right - area_left,
area_bot - area_top
)
pixels = fs.count_rect_pixels(image, dot_rect)
fs.put_text(image, pixels, (x, y + h + fs.weighted(20)))
cv2.rectangle(image, dot_rect, (255, 0, 0), 1)
pass
count_rect_pixels 함수를 사용하여 픽셀의 개수를 찍어보겠습니다.
점음표 쪽에 픽셀들이 확실히 많은 것을 볼 수가 있습니다.
언뜻 봐도 13~15개씩은 존재하는 것 같습니다.
하지만 정방향 음표 중에 꼬리가 있는 음표들은 점이 없는데도 불구 픽셀이 많이 존재합니다.
이런 음표들에 한해 점이 있다고 판단하는 경곗값을 높여주도록 하겠습니다.
물론 빔 음표들은 꼬리가 내려와 있지 않기 때문에 제외하도록 하겠습니다.
그러기 위해선 음표 꼬리의 개수와 객체 안에 기둥이 몇 개 있는지 추가로 받아오도록 하겠습니다.
# recognition_modules.py
import functions as fs
import cv2
def recognize_note_dot(image, stem, direction, tail_cnt, stems_cnt):
(x, y, w, h) = stem
if direction: # 정 방향 음표
area_top = y + h - fs.weighted(10) # 음표 점을 탐색할 위치 (상단)
area_bot = y + h + fs.weighted(5) # 음표 점을 탐색할 위치 (하단)
area_left = x + w + fs.weighted(2) # 음표 점을 탐색할 위치 (좌측)
area_right = x + w + fs.weighted(12) # 음표 점을 탐색할 위치 (우측)
else: # 역 방향 음표
area_top = y - fs.weighted(10) # 음표 점을 탐색할 위치 (상단)
area_bot = y + fs.weighted(5) # 음표 점을 탐색할 위치 (하단)
area_left = x + w + fs.weighted(14) # 음표 점을 탐색할 위치 (좌측)
area_right = x + w + fs.weighted(24) # 음표 점을 탐색할 위치 (우측)
dot_rect = (
area_left,
area_top,
area_right - area_left,
area_bot - area_top
)
pixels = fs.count_rect_pixels(image, dot_rect)
threshold = (10, 15, 20, 30)
if direction and stems_cnt == 1:
return pixels >= fs.weighted(threshold[tail_cnt])
else:
return pixels >= fs.weighted(threshold[0])
경곗값에 따라 점음표인지 아닌지 반환해보겠습니다.
그런 다음 분류해주는 코드를 짜보면..
# 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]
notes.append(note)
fs.put_text(image, note, (stem[0] - fs.weighted(10), stem[1] + stem[3] + fs.weighted(30)))
break
return notes, pitches
모든 음표가 제대로 분류되었음을 볼 수 있습니다.
박자를 알아내었으니, 다음 챕터에서는 음정을 알아내는 알고리즘을 짜보도록 하겠습니다.
'인공지능 > 컴퓨터비전' 카테고리의 다른 글
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 11 (0) | 2021.08.07 |
---|---|
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 10 (0) | 2021.08.07 |
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 8 (0) | 2021.08.06 |
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 7 (6) | 2021.08.06 |
[OpenCV/Python] 악보 인식(디지털 악보 인식) - 6 (2) | 2021.08.05 |
댓글