본문 바로가기

이직로그/DSP

USTB 스터디 3: 예제 분석하기

원본 코드는 아래와 같다(길어서 접을글 처리)

더보기

 

%% PICMUS challenge: experiment, contrast-speckle test
%
% This example reads (or downloads if the data is not local) a 
% dataset used in the <http://ieeexplore.ieee.org/document/7728908/ PICMUS challenge>
% and beamforms it with USTB's general beamformer.
% A 75 plane-wave sequence was recorded with a Verasonics Vantage 256 research 
% scanner and a L11 probe (Verasonics Inc., Redmond, WA). The dataset was recorded on 
% a CIRS Multi-Purpose Ultrasound Phantom (Model 040GSE) to estimate 
% the method contrast and speckle statistics. 
%
% _by Alfonso Rodriguez-Molares <alfonso.r.molares@ntnu.no> 
%  and Olivier Bernard <olivier.bernard@insa-lyon.fr>_
%
%   $Last updated: 2017/09/15$

%% Getting the data
%
% We define the local path and the url where the data is stored

% data location
url='http://ustb.no/datasets/';             % if not found data will be downloaded from here
filename='PICMUS_experiment_contrast_speckle.uff';

% checks if the data is in your data path, and downloads it otherwise.
% The defaults data path is under USTB's folder, but you can change this
% by setting an environment variable with setenv(DATA_PATH,'the_path_you_want_to_use');
tools.download(filename, url, data_path);   

%% What's inside?
%
% This dataset should contain the following structures:
% * *channel_data*,
% * *beamformed_data* and,
% * *scan*
%
% We can check it out with the *index* function
display=true;
content = uff.index([data_path filesep filename],'/',display);

%% Plotting beamformed_data
%
% We can read the *beamformed_data* object and plot it 

b_data=uff.read_object([data_path filesep filename],'/beamformed_data');
b_data.plot();

%% Loading channel data & scan
%
% The file also contain channel_data and scan. We read it so we can
% replicate the beamformed image in the UFF file.

channel_data=uff.read_object([data_path filesep filename],'/channel_data');
scan=uff.read_object([data_path filesep filename],'/scan');

%% Beamforming
%
% We define a pipeline, and the corresponding transmit and apodization
% windows, and launch it.

pipe=pipeline();
pipe.channel_data=channel_data;
pipe.scan=scan;
    
% receive apodization
pipe.receive_apodization.window=uff.window.tukey50;
pipe.receive_apodization.f_number=1.7;

% transmit apodization
pipe.transmit_apodization.window=uff.window.tukey50;
pipe.transmit_apodization.f_number=1.7;

% launch beamforming
b_data_new=pipe.go({midprocess.das  postprocess.coherent_compounding});

%% Comparing results
%
% We plot both images side by side.

figure;
b_data.plot(subplot(1,2,1),'Original');
b_data_new.plot(subplot(1,2,2),'New');
set(gcf,'Position',[100   100   750   450])

b_data_new.plot()

 

 

중요한건 아래 코드부터이다.

channel_data=uff.read_object([data_path filesep filename],'/channel_data');
scan=uff.read_object([data_path filesep filename],'/scan');

 해당 코드부터 데이터셋에 있는 raw데이터를 가져와서 시각화를 직접해보는 내용이다.

윗부분은 이미 잘 처리된 이미지를 가져오는것

 

여기서 제일 중요한 부분은 이 코드인 것 같다.

% receive apodization
pipe.receive_apodization.window=uff.window.tukey50;
pipe.receive_apodization.f_number=1.7;

% transmit apodization
pipe.transmit_apodization.window=uff.window.tukey50;
pipe.transmit_apodization.f_number=1.7;

 

Apodization: 

초음파 소자(element)들이 신호를 주고받을 때, 모든 소자에 똑같은 크기의 에너지를 주는 것이 아니라 중앙은 강하게, 외곽은 약하게 가중치를 두는 기술

이유: side-lobe를 제거한다.

 

side-lobe: 송/수신기에 반사되어서 잡음과 비슷하게 나타나는 신호들, 필요한 신호는 main-lobe라고 한다.https://en.wikipedia.org/wiki/Sidelobes 통신공학 수업 때 배웠던거같은데

 

Tukey:

가중치 함수의 모양을 정하는 것이다.

Tueky Window: 사각형-코사인 중간의 형태

tukeyXX: XX값이 100에 가까울수록 코사인에 가까운 형태가 된다.

- tukey0(완전한 사각형)을 쓰면 해상도는 올라가지만 노이즈(side-lobe)가 심해지고
tukey100을 사용하면 노이즈는 줄어들지만 해상도가 떨어지는 trade-off관계이다.

따라서 중간값인 tukey50을 설정한것을 알수있다.

 

f_number = 1.7

초음파 빔의 집속력(얼마나 날카롭게 혹은 집중해서 쏠것인가)를 결정하는 수치이다.

광학카메라의 조리개와 비슷한 개념 

값이 작으면 해상도가 좋아지지만 초점 영역을 벗어나면 화질이 흐려질 수 있다.

값이 크면 해상도가 떨어질수있지만 영상 전체적으로 화질이 균일해진다.

Receive, Transmit (수신 vs 송신)

  • Transmit (송신): 초음파를 쏠 때 소자들을 어떻게 조절할 것인가.
  • Receive (수신): 반사되어 돌아온 신호를 처리할 때 어떤 가중치를 줄 것인가.

 


실제로 tukey와 f_number를 변경해보자

 

f_number이 1.7그리고 3일때,

tukey값이 각각 25 50 75 일때를 비교해보는 코드를 짜보았다.

% 1. Standard (F1.7, T50)
pipe.receive_apodization.f_number = 1.7;
pipe.receive_apodization.window = uff.window.tukey50; 
b_case1 = pipe.go({midprocess.das postprocess.coherent_compounding});
ax1 = subplot(2,2,1); 
b_case1.plot(ax1, 'Standard (F:1.7, T:0.5)'); % ax1이라는 특정 칸에 그리라고 명시

% 2. Higher F-number (F3.0)
pipe.receive_apodization.f_number = 3.0;
pipe.receive_apodization.window = uff.window.tukey50;
b_case2 = pipe.go({midprocess.das postprocess.coherent_compounding});
ax2 = subplot(2,2,2);
b_case2.plot(ax2, 'Higher F-number (F:3.0)');

% 3. Tukey 25% (Sharp/Noisy)
pipe.receive_apodization.f_number = 1.7; 
pipe.receive_apodization.window = uff.window.tukey25;
b_case3 = pipe.go({midprocess.das postprocess.coherent_compounding});
ax3 = subplot(2,2,3);
b_case3.plot(ax3, 'Tukey 25%');

% 4. Tukey 75% (Clean/Blurry)
pipe.receive_apodization.window = uff.window.tukey75;
b_case4 = pipe.go({midprocess.das postprocess.coherent_compounding});
ax4 = subplot(2,2,4);
b_case4.plot(ax4, 'Tukey 75%');

 

 

검정색 부근이 더 까맣게 보일수록 더 선명한 이미지라고 볼수있다. 1.7이 제일 선명해 보이는걸 알수있다.

1.7 에서 3.0의 숫자 차이가 큰거같아 2.0도 따로 출력해보았다. 직접 출력해서 비교해보면 2.0 의 검은 반점이 더 작고 덜 까만것을 확인할수있다.


이번에는 Tukey값을 변경해보겠다.

% 1. Tukey 25
pipe.receive_apodization.f_number = 1.7;
pipe.receive_apodization.window = uff.window.tukey25; 
b_case1 = pipe.go({midprocess.das postprocess.coherent_compounding});
% figure(...) 를 지우고 아래처럼 바로 plot 합니다.
b_case1.plot([], 'Tukey 25'); 

% 2. Tukey 50
pipe.receive_apodization.window = uff.window.tukey50;
b_case2 = pipe.go({midprocess.das postprocess.coherent_compounding});
b_case2.plot([], 'Tukey 50');

% 3. Tukey 75
pipe.receive_apodization.window = uff.window.tukey75; 
b_case3 = pipe.go({midprocess.das postprocess.coherent_compounding});
b_case3.plot([], 'Tueky 75');

f_number 는 1.7로 고정하고 여러 Tukey를 적용해본 결과이다.