Previous answers have suggested interesting mathematical methods for removing the baseline. But I guess this question is a continuation of your previous questions, and by "image" you mean that your data is really an image. If so, you can use image processing techniques to find the peaks and flatten the areas around them.
1. Preprocessing
Before applying different filters, it is better to map the pixel values to a certain range. this way we can have better control over the values of the required parameters of the filters.
First we convert the image data type to double, for cases when the pixel values are integers.
I = double(I);
Then, by applying the average filter, we reduce the noise in the image.
SI = imfilter(I,fspecial('disk',40),'replicate');
Finally, we map the values of all the pixels to the range of zero to one.
NI = SI-min(SI(:));
NI = NI/max(NI(:));
2. Segmentation
After preparing the image, we can identify the parts where each of the peaks is located. To do this, we first calculate the image gradient.
G = imgradient(NI,'sobel');
Then we identify the parts of the image that have a higher slope. Since "high slope" may have different meanings in different images, we use the graythresh
function to divide the image into two parts, low slope and high slope.
SA = im2bw(G, graythresh(G));
The segmented areas in the previous step can have several problems:
- Small continuous components, which are categorized as part of high slope area, may be caused only by noise. Therefore, components with an area less than a threshold value should be removed.
- Due to the fact that the slope reaches zero at the top of the peaks, there will likely be holes in the components found in the previous step.
- The slope of the peak is not necessarily the same along its boundaries, and the found areas can have irregular shapes. One solution could be to expand them by replacing them with their Convex Halls.
[L, nPeaks] = bwlabel(SA);
minArea = 0.03*numel(I);
P = false(size(I));
for i=1:nPeaks
P_i = bwconvhull(L==i);
area = sum(P_i(:));
if (area>minArea)
P = P|P_i;
end
end
3. Removing Baseline
The P
matrix, calculated in the previous step, contains the value of one at the peaks and zero at the other areas. So far, we can delete the base line by multiplying this matrix in the main image. But it is better to first soften the edges of the found areas so that the edges of the peaks do not suddenly fall to zero.
FC = imfilter(double(P),fspecial('disk',50),'replicate');
F = I.*FC;
You can also shift peaks with the least amount of image at their edges.
E = bwmorph(P, 'remove');
o = min(I(E));
T = max(0, F-o);
All the above steps in one function
function [hlink, T] = removeBaseline(I, demoSteps)
% converting image to double
I = double(I);
% smoothing image to reduce noise
SI = imfilter(I,fspecial('disk',40),'replicate');
% normalizing image in [0..1] range
NI = SI-min(SI(:));
NI = NI/max(NI(:));
% computng image gradient
G = imgradient(NI,'sobel');
% finding steep areas of the image
SA = im2bw(G, graythresh(G));
% segmenting image to find regions covered by each peak
[L, nPeaks] = bwlabel(SA);
% defining a threshold for minimum area covered by each peak
minArea = 0.03*numel(I);
% filling each of the regions, and eliminating small ones
P = false(size(I));
for i=1:nPeaks
% finding convex hull of the region
P_i = bwconvhull(L==i);
% computing area of the filled region
area = sum(P_i(:));
if (area>minArea)
% adding the region to peaks mask
P = P|P_i;
end
end
% applying the average filter on peaks mask to compute coefficients
FC = imfilter(double(P),fspecial('disk',50),'replicate');
% Removing baseline by multiplying the coefficients
F = I.*FC;
% finding edge of peaks
E = bwmorph(P, 'remove');
% finding minimum value of edges in the image
o = min(I(E));
% shifting the flattened image
T = max(0, F-o);
if demoSteps
figure
subplot 231, imshow(I, []); title('Original Image');
subplot 232, imshow(SI, []); title('Smoothed Image');
subplot 233, imshow(NI); title('Normalized in [0..1]');
subplot 234, imshow(G, []); title('Gradient of Image');
subplot 235, imshow(SA); title('Steep Areas');
subplot 236, imshow(P); title('Peaks');
figure;
subplot 221, imshow(FC); title('Flattening Coefficients');
subplot 222, imshow(F, []); title('Base Line Removed');
subplot 223, imshow(E); title('Peak Edge');
subplot 224, imshow(T, []); title('Final Result');
figure
h1 = subplot(1, 3, 1);
surf(I, 'edgecolor', 'none'); hold on;
contour3(I, 'k', 'levellist', o, 'linewidth', 2)
h2 = subplot(1, 3, 2);
surf(F, 'edgecolor', 'none'); hold on;
contour3(F, 'k', 'levellist', o, 'linewidth', 2)
h3 = subplot(1, 3, 3);
surf(T, 'edgecolor', 'none');
hlink = linkprop([h1 h2 h3],{'CameraPosition','CameraUpVector', 'xlim', 'ylim', 'zlim', 'clim'});
set(h1, 'zlim', [0 max(I(:))])
set(h1, 'ylim', [0 size(I, 1)])
set(h1, 'xlim', [0 size(I, 2)])
set(h1, 'clim', [0 max(I(:))])
end
end
To execute the function with an image containing several peaks with noise:
close all; clc; clear variables;
I = abs(peaks(1200));
J1 = imnoise(ones(size(I))*0.5,'salt & pepper', 0.05);
J1 = imfilter(double(J1),fspecial('disk',20),'replicate');
[X, Y] = meshgrid(linspace(0, 1, size(I, 2)), linspace(0, 1, size(I, 1)));
J2 = X.^3+Y.^2;
I = max(I, 2*J2) + 5*J1;
lp3 = removeBaseline(I, true);
To call the function for an image read from file:
I = rgb2gray(imread('imagefile.jpg'));
[~, I2] = removeBaseline(I, true);
Results for images provided in previous questions: