%% 초기화
clear; clc; close all;
cd(fileparts(matlab.desktop.editor.getActiveFilename));
% addpath('D:\추가\파일\경로'); % 파일 있는 경로 여기에 추가
data = {};
%% 개별 작업
% 이미지 로드 -------------------------------------------------
close all;
SCALE_BAR_LENGTH = 450; % nm
file_name = 'P1100-2.png';
img = imread(file_name);
% 그레이 스케일 ------------------------------------------------
% 확인용
%{
figure
subplot(1,3,1); imshow(img(:,:,1)); title('R');
subplot(1,3,2); imshow(img(:,:,2)); title('G');
subplot(1,3,3); imshow(img(:,:,3)); title('B');
figure
subplot(1,2,1); imshow(rgb2gray(img)); title('rgb2gray()');
subplot(1,2,2); imshow(max(img,[],3)); title('max()');
%}
% img_gray = rgb2gray(img); % Mean
img_gray = max(img,[],3); % Max
% 스케일바 픽셀 길이 측정 -------------------------------------
scale_bar = sum(img(:,:,3) == 255);
scale_bar(scale_bar < max(scale_bar)/2) = 0;
scale_bar_pixel = sum(scale_bar ~= 0);
% 점검
ii = 1;
while scale_bar(ii) == 0
ii = ii + 1;
end % black end
while scale_bar(ii) ~= 0
ii = ii + 1;
end % scale bar end
assert(sum(scale_bar(ii:end) ~= 0) == 0,'스케일바 길이 측정 실패')
pixel_length = SCALE_BAR_LENGTH/scale_bar_pixel;
% 이미지 전처리 -----------------------------------------------
% blur
img_blur = im2double(img_gray);
windowSize = 7; % 윈도우 사이즈
repeat_num = 3; % 반복 횟수
avg3 = ones(windowSize) / windowSize^2;
for ii = 1:repeat_num
img_blur = imfilter(img_blur, avg3, 'conv');
end
% 조도
img_blur = imadjust(img_blur,[0.05,0.7]); % saturation 양 조절
% ---------------------- 경계 검출
edge_method = 'Canny'; % 'Sobel', 'Prewitt', 'Roberts', 'log', 'zerocross', 'Canny', 'approxcanny'
edge_threshold = [];
edge_direction = 'vertical'; % 'both', 'horizontal', 'vertical'
edge_BW = edge(img_blur,edge_method,edge_threshold,edge_direction);
% 가장자리 제거
pad_size = 6; % 두께 설정
edge_BW(1:pad_size,:) = 0; % 상
edge_BW(:,1:pad_size) = 0; % 좌
edge_BW(end-pad_size+1:end,:) = 0; % 하
edge_BW(:,end-pad_size+1:end) = 0; % 우
% figure;
% subplot(2,2,1)
% imshow(img); title('Original')
% subplot(2,2,2)
% imshow(img_gray); title('Gray scale')
% subplot(2,2,3)
% imshow(img_blur); title('Preprocess')
% subplot(2,2,4)
% imshow(edge_BW); title('Edge detection')
% 구간 (라인) 선택 -------------------------------------------------
figure, imshow(edge_BW); title('Edge detection')
disp('그래프에서 영역 선택')
roi = drawrectangle('StripeColor','y');
sel_pos = round(roi.Position);
sel_pos(4) = sel_pos(4)-1;
sel_pos(3) = sel_pos(3)-1;
croped_BW = edge_BW(sel_pos(2):sel_pos(2)+sel_pos(4), sel_pos(1):sel_pos(1)+sel_pos(3));
% figure, imshow(croped_BW)
% 픽셀 좌표 검출 ------------------------------------------------
% % 히스토그램 확인
% hist_x = sum(croped_BW);
% figure, plot(hist_x,'-o','LineWidth',1.5)
% % 좌우 분리선
x_center = mean([1,size(croped_BW,2)]);
% hold on;
% axis_top = get(gca,'ylim'); axis_top = axis_top(2);
% plot([x_center;x_center],[0,axis_top],'-r','LineWidth',1)
% xlabel('Pixel number');
% ylabel('Edge pixel count')
% xlim([1,length(hist_x)]);
% grid on;
x_center_ind = round(x_center);
croped_BW_left = croped_BW(:,1:x_center_ind);
croped_BW_right = croped_BW(:,x_center_ind+1:end);
% figure;
% subplot(1,2,1); imshow(croped_BW_left);
% subplot(1,2,2); imshow(croped_BW_right);
x_coord_left = line_extract(croped_BW_left,pixel_length);
x_coord_right = line_extract(croped_BW_right,pixel_length) + x_center_ind*pixel_length;
y_coord = (0:length(x_coord_left)-1)'*pixel_length;
% figure, plot(y_coord, [x_coord_left, x_coord_right])
% xlabel('Y (nm)');
% ylabel('X (nm)');
% xlim([0,max(y_coord)]);
% grid on;
% FFT PSD ------------------------------------------------------
% left
x_pre_l = x_coord_left-mean(x_coord_left,'omitnan');
not_nan_ind(1) = find(~isnan(x_pre_l),1,"first");
not_nan_ind(2) = find(~isnan(x_pre_l),1,"last");
x_pre_l = x_pre_l(not_nan_ind(1):not_nan_ind(2));
% y_pre_l = y_coord(not_nan_ind(1):not_nan_ind(2));
x_pre_l = interpNan(x_pre_l); % 중간에 들어있는 nan제거
[X_l,freq_l] = ssfft(x_pre_l,1/pixel_length);
xlabel('Frequency (1/nm)');
psd_fft_l = length(x_pre_l)*pixel_length*abs(X_l).^2;
% right
x_pre_r = x_coord_right-mean(x_coord_right,'omitnan');
not_nan_ind(1) = find(~isnan(x_pre_r),1,"first");
not_nan_ind(2) = find(~isnan(x_pre_r),1,"last");
x_pre_r = x_pre_r(not_nan_ind(1):not_nan_ind(2));
% y_pre_r = y_coord(not_nan_ind(1):not_nan_ind(2));
x_pre_r = interpNan(x_pre_r); % 중간에 들어있는 nan제거
[X_r,freq_r] = ssfft(x_pre_r,1/pixel_length);
xlabel('Frequency (1/nm)');
psd_fft_r = length(x_pre_r)*pixel_length*abs(X_r).^2;
% figure, loglog(freq_l,psd_fft_l)
% hold on; loglog(freq_r,psd_fft_r)
% xlabel('Frequency (1/nm)');
% ylabel('PSD (nm^3)')
% legend({'Left PSD','Right PSD'},'Location','best');
% grid on
% correlation length fitting ----------------------------------------
% left -----------------------
freq = freq_l;
psd_fft = psd_fft_l;
H = 0.5;
% objective function
std_dev_l = std(x_coord_left,'omitnan');
objfunc = @(cl) log(PSD(freq,std_dev_l,cl,H)) - log(psd_fft);
bound = [pixel_length*2, pixel_length*2*length(croped_BW_left)];
InitCond = mean(bound);
LowBound = bound(1);
UppBound = bound(2);
options = optimset('TolFun',1e-8,'TolX',1e-8,...
'MaxFunEvals',100000,'MaxIter',10000,'Display','iter');
%'off' 'iter' 'iter-detailed' 'notify' 'notify-detailed' 'final' 'final-detailed'
cl_fit_l = lsqnonlin(objfunc,InitCond,LowBound,UppBound,options);
psd_fit_l = PSD(freq,std_dev_l,cl_fit_l,H);
figure, loglog(freq_l,psd_fft_l);
hold on; loglog(freq, psd_fit_l, 'LineWidth',2);
xlabel('Frequency (1/nm)');
ylabel('PSD (nm^3)')
legend({'Left FFT PSD','Fitted PSD'},'Location','best');
grid on
% right -----------------------
freq = freq_r;
psd_fft = psd_fft_r;
H = 0.5;
% objective function
std_dev_r = std(x_coord_right,'omitnan');
objfunc = @(cl) log(PSD(freq,std_dev_r,cl,H)) - log(psd_fft);
bound = [pixel_length*2, pixel_length*2*length(croped_BW_left)];
InitCond = mean(bound);
LowBound = bound(1);
UppBound = bound(2);
options = optimset('TolFun',1e-8,'TolX',1e-8,...
'MaxFunEvals',100000,'MaxIter',10000,'Display','iter');
%'off' 'iter' 'iter-detailed' 'notify' 'notify-detailed' 'final' 'final-detailed'
cl_fit_r = lsqnonlin(objfunc,InitCond,LowBound,UppBound,options);
psd_fit_r = PSD(freq,std_dev_r,cl_fit_r,H);
figure, loglog(freq_r,psd_fft_r);
hold on; loglog(freq, psd_fit_r, 'LineWidth',2);
xlabel('Frequency (1/nm)');
ylabel('PSD (nm^3)')
legend({'Right FFT PSD','Fitted PSD'},'Location','best');
grid on
% 데이터 수집 --------------------------------------------
this_data = {psd_fft_l, freq_l, std_dev_l, ...
psd_fft_r, freq_r, std_dev_r};
y_n = input('이번 결과를 데이터에 추가 : ','s');
if strcmp(y_n,'y')
data = [data;this_data];
disp('데이터 추가 완료!')
else
disp('데이터 추가 취소')
end
%% data 저장
save backup_data.mat data croped_BW_left
%% 데이터 평균, PSD fitting
% data = {psd_fft_l, freq_l, std_dev_l, ...
% psd_fft_r, freq_r, std_dev_r};
short_ind = min(length(data{1,1}),length(data{1,4}));
psd_fft_mean = log10(data{1,1}(1:short_ind))+log10(data{1,4}(1:short_ind));
for ii = 2:size(data,1)
short_ind = min(length(psd_fft_mean),length(data{ii,1}));
psd_fft_mean = psd_fft_mean(1:short_ind) ...
+ log10(data{ii,1}(1:short_ind));
short_ind = min(length(psd_fft_mean),length(data{ii,4}));
psd_fft_mean = psd_fft_mean(1:short_ind) ...
+ log10(data{ii,4}(1:short_ind));
end
psd_fft_mean = psd_fft_mean./(size(data,1)*2);
psd_fft_mean = 10.^psd_fft_mean;
freq = data{1,2}(1:short_ind);
std_dev = mean([data{:,[3,6]}]);
% correlation length fitting ----------------------------------------
psd_fft = psd_fft_mean;
H = 0.5;
H = 0.9;
std_dev = std_dev*1.5
% -------------------- 가중치
freq(1) = 0.0001; % 임시
segment_num = 20;
weight = zeros(size(freq));
freq_seg = 10.^(linspace(log10(freq(1)),log10(freq(end)),segment_num+1));
freq_seg(1) = 0; freq(1) = 0;
for ii = 1:segment_num
freq_window = freq >= freq_seg(ii) & freq <= freq_seg(ii+1);
weight(freq_window) = 1/sum(freq_window);
end
weight = ones(size(freq)); % 최적화 가중치 무효화
% objective function
objfunc = @(cl) (log10(PSD(freq,std_dev,cl,H)) - log10(psd_fft)).*weight;
bound = [pixel_length*2, pixel_length*2*length(croped_BW_left)];
InitCond = mean(bound);
LowBound = bound(1);
UppBound = bound(2);
options = optimset('TolFun',1e-8,'TolX',1e-8,...
'MaxFunEvals',100000,'MaxIter',10000,'Display','iter');
%'off' 'iter' 'iter-detailed' 'notify' 'notify-detailed' 'final' 'final-detailed'
cl_fit = lsqnonlin(objfunc,InitCond,LowBound,UppBound,options);
psd_fit = PSD(freq,std_dev,cl_fit,H);
figure, loglog(freq,psd_fft);
hold on; loglog(freq, psd_fit, 'LineWidth',2);
xlabel('Frequency (1/nm)');
ylabel('PSD (nm^3)')
legend({'FFT PSD','Fitted PSD'},'Location','best');
grid on
% FFT PSD plot ----------------------------
% freq = linspace(1/(pixel_length*2*length(croped_BW_left)),1,100)';
freq = logspace(log10(1/(pixel_length*2*length(croped_BW_left))),0,100)';
LER_psd = PSD(freq,std_dev,cl_fit,H);
figure, loglog(freq,LER_psd,'LineWidth',1.5)
xlabel('Frequency (1/nm)');
ylabel('PSD (nm^3)');
grid on;
%% 데이터 평균, polynomial fitting
% data = {psd_fft_l, freq_l, std_dev_l, ...
% psd_fft_r, freq_r, std_dev_r};
short_ind = min(length(data{1,1}),length(data{1,4}));
psd_fft_mean = log10(data{1,1}(1:short_ind))+log10(data{1,4}(1:short_ind));
for ii = 2:size(data,1)
short_ind = min(length(psd_fft_mean),length(data{ii,1}));
psd_fft_mean = psd_fft_mean(1:short_ind) ...
+ log10(data{ii,1}(1:short_ind));
short_ind = min(length(psd_fft_mean),length(data{ii,4}));
psd_fft_mean = psd_fft_mean(1:short_ind) ...
+ log10(data{ii,4}(1:short_ind));
end
psd_fft_mean = psd_fft_mean./(size(data,1)*2);
psd_fft_mean = 10.^psd_fft_mean;
freq = data{1,2}(1:short_ind);
std_dev = mean([data{:,[3,6]}]);
crop_ind = 6; % 최고점 잘라낼 위치
freq_log = log10(freq(2:end));
psd_log = log10(psd_fft_mean(2:end));
poly_coef = polyfit(freq_log,psd_log,5);
freq_log_poly_fit = linspace(freq_log(crop_ind),freq_log(end),100)';
psd_log_poly_fit = polyval(poly_coef,freq_log_poly_fit);
freq_poly_fit = 10.^freq_log_poly_fit;
psd_poly_fit = 10.^psd_log_poly_fit;
figure, loglog(freq(crop_ind+1:end),psd_fft_mean(crop_ind+1:end))
hold on; loglog(freq_poly_fit,psd_poly_fit,'LineWidth',2)
xlabel('Frequency (1/nm)');
ylabel('PSD (nm^3)');
legend({'FFT PSD','Polynomial fitting'},'Location','best');
grid on;