Поскольку MATLAB выпускает исходный код imflatfield
, его не так сложно реализовать в Python с использованием OpenCV.
Примечание. Реализация имеет тип c - uint8
и цветное изображение (формат BGR в Python).
Вот "ручная" реализация MATLAB imflatfield
:
function B = my_imflatfield(I, sigma)
A = im2single(I);
Ihsv = rgb2hsv(A);
A = Ihsv(:,:,3);
filterSize = 2*ceil(2*sigma)+1;
shading = imgaussfilt(A, sigma, 'Padding', 'symmetric', 'FilterSize', filterSize); % Calculate shading
meanVal = mean(A(:),'omitnan');
% Limit minimum to 1e-6 instead of testing using isnan and isinf after division.
shading = max(shading, 1e-6);
B = A*meanVal./shading;
%B(isnan(B)) = 0; % sometimes instances of 0/0 happen, making NaN values.
%B(isinf(B)) = 0; % sometimes values are divided by 0, making Inf values.
% Put processed V channel back into HSV image, convert to RGB
Ihsv(:,:,3) = B;
B = hsv2rgb(Ihsv);
B = im2uint8(B);
end
Вот эквивалентная реализация Python (с использованием OpenCV):
import cv2
import numpy as np
def imflatfield(I, sigma):
"""Python equivalent imflatfield implementation
I format must be BGR and type of I must be uint8"""
A = I.astype(np.float32) / 255 # A = im2single(I);
Ihsv = cv2.cvtColor(A, cv2.COLOR_BGR2HSV) # Ihsv = rgb2hsv(A);
A = Ihsv[:, :, 2] # A = Ihsv(:,:,3);
filterSize = int(2*np.ceil(2*sigma) + 1); # filterSize = 2*ceil(2*sigma)+1;
# shading = imgaussfilt(A, sigma, 'Padding', 'symmetric', 'FilterSize', filterSize); % Calculate shading
shading = cv2.GaussianBlur(A, (filterSize, filterSize), sigma, borderType=cv2.BORDER_REFLECT)
meanVal = np.mean(A) # meanVal = mean(A(:),'omitnan')
#% Limit minimum to 1e-6 instead of testing using isnan and isinf after division.
shading = np.maximum(shading, 1e-6) # shading = max(shading, 1e-6);
B = A*meanVal / shading # B = A*meanVal./shading;
#% Put processed V channel back into HSV image, convert to RGB
Ihsv[:, :, 2] = B # Ihsv(:,:,3) = B;
B = cv2.cvtColor(Ihsv, cv2.COLOR_HSV2BGR) # B = hsv2rgb(Ihsv);
B = np.round(np.clip(B*255, 0, 255)).astype(np.uint8) # B = im2uint8(B);
return B
# Read input imgae
I = cv2.imread('destroyer.jpg')
sigma = 30
out2 = imflatfield(I, sigma)
cv2.imwrite('imflatfield_py_destroyer.png', out2)
Приведенная выше реализация читает входное изображение и записывает результат в файл изображения.
Сравнение результатов с использованием MATLAB (для тестирования):
I = imread('destroyer.jpg');
out1 = imflatfield(I, 30);
out2 = my_imflatfield(I, 30);
% Compare results of imflatfield and my_imflatfield:
max(max(max(imabsdiff(out1, out2))))
% figure;imshow(out2)
imwrite(out2, 'imflatfield_destroyer.png');
% Read Python result
out3 = imread('imflatfield_py_destroyer.png');
% Compare results of imflatfield and Python imflatfield:
max(max(max(imabsdiff(out1, out3))))
- Максимальная абсолютная разница между MATALB
imflatfield
и my_imflatfield
составляет 0
. - Максимальная абсолютная разница между MATALB
imflatfield
и Python imflatfield
составляет 1
.
Преобразование полного кода MATLAB в Python:
sigma = 30
out2 = imflatfield(I, sigma)
# Conver out2 to float32 before converting to LAB
out2 = out2.astype(np.float32) / 255 # out2 = im2single(out2);
shadow_lab = cv2.cvtColor(out2, cv2.COLOR_BGR2Lab) # shadow_lab = rgb2lab(out2);
max_luminosity = 100
L = shadow_lab[:, :, 0] / max_luminosity # L = shadow_lab(:,:,1)/max_luminosity;
shadow_adapthisteq = shadow_lab.copy() # shadow_adapthisteq = shadow_lab;
# shadow_adapthisteq(:,:,1) = adapthisteq(L)*max_luminosity;
clahe = cv2.createCLAHE(clipLimit=20, tileGridSize=(8,8))
cl1 = clahe.apply((L*(2**16-1)).astype(np.uint16)) # CLAHE in OpenCV does not support float32 (convert to uint16 and back).
shadow_adapthisteq[:, :, 0] = cl1.astype(np.float32) * max_luminosity / (2**16-1)
shadow_adapthisteq = cv2.cvtColor(shadow_adapthisteq, cv2.COLOR_Lab2BGR) # shadow_adapthisteq = lab2rgb(shadow_adapthisteq);
# Convert shadow_adapthisteq to uint8
shadow_adapthisteq = np.round(np.clip(shadow_adapthisteq*255, 0, 255)).astype(np.uint8) # B = im2uint8(B);
cv2.imwrite('shadow_adapthisteq.jpg', shadow_adapthisteq) # imwrite(shadow_adapthisteq,'lcs2_adap.jpg');
Результат не будет идентичен MATLAB, потому что adapthisteq
в MATLAB не идентичен CLAHE
в OpenCV.
Результат: