본문 바로가기

이직로그/DSP

빔포밍 시뮬레이션 1 - 첫번째 프레임 찾기

 

전체코드

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert

file_path = r'./data/PhantomData/uri_SpV1556_VpF192_FpA343_20071121103247.rfd'

DATA_OFFSET = 22410 + 8
VECTOR_HEADER = 32
SAMPLES = 1556
VECTORS = 192
BYTES_PER_SAMPLE = 2

with open(file_path, "rb") as f:
    f.seek(DATA_OFFSET)
    raw = np.frombuffer(f.read(), dtype="<i2")

samples_per_vector = SAMPLES + VECTOR_HEADER
frame_size = samples_per_vector * VECTORS

frame = raw[:frame_size].reshape((samples_per_vector, VECTORS), order="F")
frame = frame[VECTOR_HEADER:, :]

analytic = hilbert(frame, axis=0)
envelope = np.abs(analytic)

bmode = np.log10(envelope + 1e-3)

plt.figure(figsize=(8,6))
plt.imshow(bmode, cmap="gray", aspect='auto')
plt.title('B-mode Image (hilbert envelop & log compression)')
plt.xlabel('Vector (channel)')
plt.ylabel('Depth (samples)')
plt.colorbar(label='log  amplitude')
plt.show()

해당 코드는

원래의 rfd 파일은 343개의 프레임으로 되어있는 사진들(을 이용한 동영상) 정보가 내장되어있는데,

우선 첫번재 프레임을 추출하기 위해서 작성된 코드이다.

 


 

아래는 주요 파라미터이다.

SAMPLES, VECTORS 값의 경우 가로 세로 비율이라고 생각하면 될거같다.

해당 내용까지는 사이트에서 잘 설명되어있어서 문제가 없었지만

파일의 어디까지가 헤더인지 같은 경우에는 제대로 설명이 되어있지않았다.

DATA_OFFSET = 22410 + 8
VECTOR_HEADER = 32
SAMPLES = 1556
VECTORS = 192

이후에는 RFD파일에서 RAW 데이터를 뽑아내는 것이다.

seek(number)를 할 경우 해당 파일의 number 번째 데이터부터 읽어내는것이다.

dtype='<i2'의 경우 인코딩에 관한것, 이것도 데이터 셋에 적혀있지 않아서 지피티랑 많은 씨름을 하면서 알아냈다.

'<i2'가 아니면 제대로 출력 이미지가 보이지 않음

with open(file_path, "rb") as f:
    f.seek(DATA_OFFSET)
    raw = np.frombuffer(f.read(), dtype="<i2")

 

RFD파일에 있는 raw RF 데이터의 경우 이런식으로 되어있다.

[Vector 0 Header][Vector 0 Samples]
[Vector 1 Header][Vector 1 Samples]
...
[Vector (VECTORS-1) Header][Vector (VECTORS-1) Samples]

벡터 한줄 = samples_per_vector 

프레임 한장 = 가로* 세로 = frame_size

samples_per_vector = SAMPLES + VECTOR_HEADER
frame_size = samples_per_vector * VECTORS

아래 줄부터 약간 머리가 띵해진다.

frame = raw[:frame_size].reshape((samples_per_vector, VECTORS), order="F")
#       1111111111111111.2222222222222222222222222222222222222222222222222

1 구간과 2구간으로 코드를 나눌수있을거같다.

1구간은 어렵지 않게 raw 데이터 중에서 프레임 한장만 잘라내는것

2구간

reshape는 말그대로 리스트를 reshape 하는 것인데

이렇게 2중리스트로 reshape할수있다.

 

order='F'

그러면 위의 코드는 무슨 의미일까? 

매트랩과 파이썬의 리스트 저장방식이 다르다.

# PYTHON, order="C"
[0 1 2]
[3 4 5]
[6 7 8]

# MATLAB, order="F"
[0 3 6]
[1 4 7]
[2 5 8]

파이썬의 경우 row-major 방식으로 데이터를 저장하는데 매트랩의 경우 column-major 방식으로 데이터를 저장한다.

따라서 파이썬의 데이터 저장방식으로 데이터를 변환하는 과정

frame = frame[VECTOR_HEADER:, :]

np의 경우 배열의 인덱스를 가져오는 과정이 순정 파이썬과 약간 다르다. 

 

더보기
더보기
a = np.array([
 [0,  1,  2,  3,  4,]
 [10, 11, 12, 13, 14,]
 [20, 21, 22, 23, 24,]
 [30, 31, 32, 33, 34,]
 [40, 41, 42, 43, 44]
 ])
 
a[2,3] # 23
a[2,:] #[20 21 22 23 24]

a[1:4,2:5]
# [12 13 14]
# [22 23 24]
# [32 33 34]

 이와같이 []안에 ,를 이용해서 특정 인덱스 혹은 인덱스 구간을 불러올수있다.

[Vector 0 Header][Vector 0 Samples]
[Vector 1 Header][Vector 1 Samples]
...
[Vector (VECTORS-1) Header][Vector (VECTORS-1) Samples]

이전에 설명했다싶이 모든 열에 header가 있으니 header 를 제거하는 라인이라고 보면될거같다.

 

이렇게 하면 첫번째 프레임의 데이터 값만을 추출할수있다.