I have a image that includes object and some unwanted region (small dots). I want to remove it. Hence, I use some morphological operator example 'close' to remove. But it is not perfect. Do you have other way to remove more clear? You can download example image at raw image
This is my code
load Image.mat %load Img value
Img= bwmorph(Img,'close');
imshow(Img);
You might prefer a faster and vectorized approach using bsxfun along with the information obtained from bwlabel itself.
Note: bsxfun is memory intensive, but that's precisely what makes it faster. Therefore, watch out for the size of B1 in the code below. This method will get slower once it reaches the memory constraints set by the system, but until then it provides good speedup over the regionprops method.
Code
[L,num] = bwlabel( Img );
counts = sum(bsxfun(#eq,L(:),1:num));
B1 = bsxfun(#eq,L,permute(find(counts>threshold),[1 3 2]));
NewImg = sum(B1,3)>0;
EDIT 1: Few benchmarks for comparisons between bsxfun and regionprops approaches are discussed next.
Case 1
Benchmark Code
Img = imread('coins.png');%%// This one is chosen as it is available in MATLAB image library
Img = im2bw(Img,0.4); %%// 0.4 seemed good to make enough blobs for this image
lb = bwlabel( Img );
threshold = 2000;
disp('--- With regionprops method:');
tic,out1 = regionprops_method1(Img,lb,threshold);toc
clear out1
disp('---- With bsxfun method:');
tic,out2 = bsxfun_method1(Img,lb,threshold);toc
%%// For demo, that we have rejected enough unwanted blobs
figure,
subplot(211),imshow(Img);
subplot(212),imshow(out2);
Output
Benchmark Results
--- With regionprops method:
Elapsed time is 0.108301 seconds.
---- With bsxfun method:
Elapsed time is 0.006021 seconds.
Case 2
Benchmark Code (Only the changes from Case 1 are listed)
Img = imread('snowflakes.png');%%// This one is chosen as it is available in MATLAB image library
Img = im2bw(Img,0.2); %%// 0.2 seemed good to make enough blobs for this image
threshold = 20;
Output
Benchmark Results
--- With regionprops method:
Elapsed time is 0.116706 seconds.
---- With bsxfun method:
Elapsed time is 0.012406 seconds.
As pointed out earlier, I have tested with other bigger images and with a lot of unwanted blobs, for which bsxfun method doesn't provide any improvement over regionprops method. Due to the unavailability of any such bigger images in MATLAB library, they couldn't be discussed here. To sum up, it could be suggested to use either of these two approaches based on the input features. It would be interesting to see how these two approaches perform for your input images.
You can use regionprops and bwlabel to select all regions that are smaller than a certain area (=number of pixels)
lb = bwlabel( Img );
st = regionprops( lb, 'Area', 'PixelIdxList' );
toRemove = [st.Area] < threshold; % fix your threshold here
newImg = Img;
newImg( vertcat( st(toRemove).PixelIdxList ) ) = 0; % remove
Related
I am working on a signal processing related problem. I have a dataset of >2000 EEG signals. Each EEG Signal is represented by a 2D Numpy array (19 x 30000). Each row of the array is one of the channels of the signal. What I have to do is to find the spectrograms on these individual channels (rows) and concatenate them vertically. Here is the code I wrote so far.
raw = np.load('class_1_ar/'+filename)
images = []
for i in range(19):
print(i,end=" ")
spec,freq,t,im = plt.specgram(raw[i],Fs=100,NFFT=100,noverlap=50)
plt.axis('off')
figure = plt.gcf()
figure.set_size_inches(12, 1)
figure.canvas.draw()
img = np.array(figure.canvas.buffer_rgba())
img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA)
b = figure.axes[0].get_window_extent()
img = np.array(figure.canvas.buffer_rgba())
img = img[int(b.y0):int(b.y1),int(b.x0):int(b.x1),:]
img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA)
images.append(img)
base = cv2.vconcat(images)
cv2.imwrite('class_1_sp/'+filename[:-4]+'.png',base)
c -= 1
print(c)
And here is my output:
However, the process is taking too much time to process. It took almost 8 hours for the first 200 samples to process.
My question is, What can I do to make it faster?
Like others have said, the overhead of going through matplotlib is likely slowing things down. It would be better to just compute (and not plot) the spectrogram with scipy.signal.spectrogram. This function directly returns the spectrogram as a 2D numpy array, so that you don't have the roundabout step of getting it out of the canvas. Note, that does mean you'll have to map the spectrogram output yourself to pixel intensities. In doing that, beware scipy.signal.spectrogram returns the spectrogram as powers, not decibels, so you probably want to do 10*np.log10(Sxx) to the result (see also scipy.signal.spectrogram compared to matplotlib.pyplot.specgram).
Plotting aside, the bottleneck operation in computing a spectrogram are the FFTs. Instead of using a transform size of 100 samples, 128 or some other power of 2 is more efficient. With scipy.signal.spectrogram this is done by setting nfft=128. Note, you can set nperseg=100 and nfft=128 so that 100 samples are still used for each segment, but zero-padded to 128 before doing the FFT. One other thought: if raw is 64-bit float, it may help to cast it to 32-bit: raw = np.load(...).astype(np.float32).
I am trying to "translate" what's mentioned in Gonzalez and Woods (2nd Edition) about the Laplacian filter.
I've read in the image and created the filter. However, when I try to display the result (by subtraction, since the center element in -ve), I don't get the image as in the textbook.
I think the main reason is the "scaling". However, I'm not sure how exactly to do that. From what I understand, some online resources say that the scaling is just so that the values are between 0-255. From my code, I see that the values are already within that range.
I would really appreciate any pointers.
Below is the original image I used:
Below is my code, and the resultant sharpened image.
Thanks!
clc;
close all;
a = rgb2gray(imread('e:\moon.png'));
lap = [1 1 1; 1 -8 1; 1 1 1];
resp = uint8(filter2(lap, a, 'same'));
sharpened = imsubtract(a, resp);
figure;
subplot(1,3,1);imshow(a); title('Original image');
subplot(1,3,2);imshow(resp); title('Laplacian filtered image');
subplot(1,3,3);imshow(sharpened); title('Sharpened image');
I have a few tips for you:
This is just a little thing but filter2 performs correlation. You actually need to perform convolution, which rotates the kernel by 180 degrees before performing the weighted sum between neighbourhoods of pixels and the kernel. However because the kernel is symmetric, convolution and correlation perform the same thing in this case.
I would recommend you use imfilter to facilitate the filtering as you are using methods from the Image Processing Toolbox already. It's faster than filter2 or conv2 and takes advantage of the Intel Integrated Performance Primitives.
I highly recommend you do everything in double precision first, then convert back to uint8 when you're done. Use im2double to convert your image (most likely uint8) to double precision. When performing sharpening, this maintains precision and prematurely casting to uint8 then performing the subtraction will give you unintended side effects. uint8 will cap results that are negative or beyond 255 and this may also be a reason why you're not getting the right results. Therefore, convert the image to double, filter the image, sharpen the result by subtracting the image with the filtered result (via the Laplacian) and then convert back to uint8 by im2uint8.
You've also provided a link to the pipeline that you're trying to imitate: http://www.idlcoyote.com/ip_tips/sharpen.html
The differences between your code and the link are:
The kernel has a positive centre. Therefore the 1s are negative while the centre is +8 and you'll have to add the filtered result to the original image.
In the link, they normalize the filtered response so that the minimum is 0 and the maximum is 1.
Once you add the filtered response onto the original image, you also normalize this result so that the minimum is 0 and the maximum is 1.
You perform a linear contrast enhancement so that intensity 60 becomes the new minimum and intensity 200 becomes the new maximum. You can use imadjust to do this. The function takes in an image as well as two arrays - The first array is the input minimum and maximum intensity and the second array is where the minimum and maximum should map to. As such, I'd like to map the input intensity 60 to the output intensity 0 and the input intensity 200 to the output intensity 255. Make sure the intensities specified are between 0 and 1 though so you'll have to divide each quantity by 255 as stated in the documentation.
As such:
clc;
close all;
a = im2double(imread('moon.png')); %// Read in your image
lap = [-1 -1 -1; -1 8 -1; -1 -1 -1]; %// Change - Centre is now positive
resp = imfilter(a, lap, 'conv'); %// Change
%// Change - Normalize the response image
minR = min(resp(:));
maxR = max(resp(:));
resp = (resp - minR) / (maxR - minR);
%// Change - Adding to original image now
sharpened = a + resp;
%// Change - Normalize the sharpened result
minA = min(sharpened(:));
maxA = max(sharpened(:));
sharpened = (sharpened - minA) / (maxA - minA);
%// Change - Perform linear contrast enhancement
sharpened = imadjust(sharpened, [60/255 200/255], [0 1]);
figure;
subplot(1,3,1);imshow(a); title('Original image');
subplot(1,3,2);imshow(resp); title('Laplacian filtered image');
subplot(1,3,3);imshow(sharpened); title('Sharpened image');
I get this figure now... which seems to agree with the figures seen in the link:
I have to create a contrast map about images. The method is easy: estimate the contrast (C=SD/Mean) in a 5x5 (sliding) window. Move the window pixel by pixel trough the entire picture and save the results in a new matrix.
I created this script to solve the problem, but it is too slow. The base picture is a 1024x1024 16-bit .tif image. The process is ~40-50 sec long, but other programs solve it in less than 3 secs. How can I speed up my script?
My original script:
M=imread('image.tif');
for S=1:2 SM1_b=size(M,1); SM2_b=size(M,2);
M(:,SM2_b+1)=M(:,SM2_b);
M(SM1_b+1,:)=[M(SM1_b,1:SM2_b) M(SM1_b,SM2_b)];
end
M=[M(1,1:SM2_b+1);M(1,1:SM2_b+1);M]; M=[M(1:(size(M,1)),1) M(1:(size(M,1)),1) M]; clear S SM1_b SM2_b
KPic=zeros(1024);
for i=1:1024 for j=1:1024
KPic(i,j)=std2(M(i:i+4,j:j+4))/mean2(M(i:i+4,j:j+4));
end
end
One way could be building an image of the mean using a window size of 5x5, then a local standard deviation filter with a window size of 5x5. After this is done you can calculate the result fairly quickly.
M = imread('image.tif');
h = fspecial('average', 5);
mean_im = filter2(M, h);
std_im = stdfilt(M, 5);
KPic = std_im ./ mean_im;
I have a large set of microscopy images and each image has several hundreds of spots (ROIs). These spots are fixed in space. I want to extract each spot from each image and save into workspace so that I can analyze them further.
I have written a code myself and it working perfectly but its too slow. It takes around 250 sec to completely read out all the spots from every image.
The core of my code looks as following:
for s=1:NumberImages
im1=imread(fn(s,1).name);
im=im1-medfilt2(im1,[15,15]);
for i=1:length(p_g_x)
GreenROI(i,s)=double(sum(sum(im(round(p_g_y(i))+(-2:2), round(p_g_x(i))+(-2:2)))));
RedROI(i,s)=double(sum(sum(im(round(p_r_y(i))+(-2:2), round(p_r_x(i))+(-2:2)))));
end
end
As you can see from the code I am extracting 5x5 regions. Length of p_g_x is between 500-700.
Thanks for your input. I used profile viewer to figure out which function exactly is taking more time. It was median filter which is taking a lot of time (~90%).
Any suggestion to fast it up will be greatly appreciated.
thanks
Mahipal
Use Matlab's profiling tools!
profile on % Starts the profiler
% Run some code now.
profile viewer % Shows you how often each function was called, and
% where most time was spent. Try to start with the slowest part.
profile off % Resets the Profiler, so you can measure again.
Pre-allocate
Preallocate the output because you know the size and this way it is much faster. (Matlab told you this already!)
GreenROI = zeros(length(p_g_x), NumberImages); % And the same for RedROI.
Use convolution
Read about Matlab's conv2 code.
for s=1:NumberImages
im=imread(fn(s,1).name);
im=im-medfilt2(im,[15,15]);
% Pre-compute the sums first. This will only be faster for large p_g_x
roi_image = conv2(im, ones(5,5));
for i=1:length(p_g_x)
GreenROI(i,s)=roi_image(round(p_g_y(i)), round(p_g_x(i))); % You might have to offset the indices by 2, because of the convolution. Check that results are the same.
RedROI(i,s)=roi_image(round(p_r_y(i)), round(p_r_x(i)));
end
end
Matlab-ize the code
Now, that you've used convolution to get an image of sums over 5x5 windows (or you could've used #Shai's accumarray, same thing), you can speed things up further by not iterating through each element in p_g_x but use it as a vector straight away.
I leave that as an exercise for the reader. (convert p_g_x and p_g_y to indices using sub2ind, as a hint).
Update
Our answers, mine included, showed how premature optimisation is a bad thing. Without knowing, I assumed that your loop would take most of the time, but when you measured it (thanks!) it turns out that is not the problem. The bottleneck is medfilt2 the median filter, which takes 90% of the time. So you should address this first. (Note, that on my computer your original code is fast enough for my taste but it is still the median filter taking up most of the time.)
Looking at what the median filter operation does might help us figure out how to make it faster. Here is an image. On the left you see the original image. In the middle the median filter and on the right there is the result.
To me the result looks awfully similar to an edge detection result. (Mathematically this is no surprise.)
I would suggest you start experimenting with various edge detections. Have a look at Canny and Sobel. Or just use conv2(image, kernel_x) where kernel_x = [1, 2, 1; 0, 0, 0; -1, -2, -1] and the same but transposed for a kernel_y. You can find various edge detection options here: edge(im, option). I tried all options from {'sobel', 'canny', 'roberts', 'prewitt'}. Except for Canny, they all take about the same time as your median filter method. Canny is 4x slower, the rest (including the original) take 7.x seconds. All of this without a GPU. imgradient was 9 seconds.
So from this I would say that you can't get any faster. If you have a GPU and it works with Matlab, you could speed it up. Load your image as gpuArrays. There is an example on the medfilt2 documentation. You can still do minor speed ups but they can only amount to a 10% speed increase, so are hardly worthwile.
A few things you should do
Pre-allocate as suggested by Didac Perez.
Use profiler to see what exactly takes long in your code, is it the median filter? is it the indexing?
Assuming all images are of the same size, you can use accumarray and a fixed mask subs to quickly sum the values:
subs_g = zeros( h, w ); %// allocate mask for green
subs_r = zeros( h, w );
subs_g( sub2ind( [h w], round(p_g_y), round(p_g_x) ) = 1:numel(p_g_x); %//index each region
subs_g = conv2( subs_g, ones(5), 'same' );
subs_r( sub2ind( [h w], round(p_r_y), round(p_r_x) ) = 1:numel(p_r_x); %//index each region
subs_r = conv2( subs_r, ones(5), 'same' );
sel_g = subs_g > 0;
sel_r = subs_r > 0;
subs_g = subs_g(sel_g);
subs_r = subs_r(sel_r);
once these masks are fixed, you can process all images
%// pre-allocation goes here - I'll leave it to you
for s=1:NumberImages
im1=imread(fn(s,1).name);
im=double( im1-medfilt2(im1,[15,15]) );
accumarray( subs_g, im( sel_g ) ); % summing all the green ROIs
accumarray( subs_r, im( sel_r ) ); % summing all the green ROIs
end
First, preallocate your GreenROI and RedROI structures since you previously know the final size. Now, you are resizing them again and again in each iteration.
Secondly, I do recommend you to use "tic" and "toc" to investigate where is the problem, it will give you useful timings.
Vectorized code that operates on each image -
%// Pre-compute green and red indices to be used across all the images
r1 = round(bsxfun(#plus,permute(p_g_y,[3 2 1]),[-2:2]'));
c1 = round(bsxfun(#plus,permute(p_g_x,[3 2 1]),[-2:2]));
green_ind = reshape(bsxfun(#plus,(c1-1)*size(im,1),r1),[],numel(p_g_x));
r2 = round(bsxfun(#plus,permute(p_r_y,[3 2 1]),[-2:2]'));
c2 = round(bsxfun(#plus,permute(p_r_x,[3 2 1]),[-2:2]));
red_ind = reshape(bsxfun(#plus,(c2-1)*size(im,1),r2),[],numel(p_g_x));
for s=1:NumberImages
im1=imread(fn(s,1).name);
im=double(im1-medfilt2(im1,[15,15]));
GreenROI=sum(im(green_ind));
RedROI =sum(im(red_ind));
end
I have to process a very large image ( say 10 MB image file or even more).I have to remove artifacts and dead pixels in MATLAB
I have read about Block Processing of Large Images, but have no idea how to apply it to a 16 bit image.
I am referring to removal of pixels which have highest value into the average value of surrounding pixel .my code is not working on my image which is 80 MB of size
numIterations = 30;
avgPrecisionSize = 16; % smaller is better, but takes longer
% Read in the image grayscale:
originalImage = double(rgb2gray(imread('C:\Documents and Settings\admin\Desktop\TM\image5.tif')));
% get the bad pixels where = 0 and dilate to make sure they get everything:
badPixels = (originalImage == 0);
badPixels = imdilate(badPixels, ones(12));
%# Create a big gaussian and an averaging kernel to use:
G = fspecial('gaussian',[1 1]*100,50);
H = fspecial('average', [1,1]*avgPrecisionSize);
%# User a big filter to get started:
newImage = imfilter(originalImage,G,'same');
newImage(~badPixels) = originalImage(~badPixels);
% Now average to
for count = 1:numIterations
newImage = imfilter(newImage, H, 'same');
newImage(~badPixels) = originalImage(~badPixels);
end
%% Plot the results
figure(123);
clf;
% Display the mask:
subplot(1,2,1);
imagesc(badPixels);
axis image
title('Region Of the Bad Pixels');
% Display the result:
subplot(1,2,2);
imagesc(newImage);
axis image
set(gca,'clim', [0 255])
title('Infilled Image');
colormap gray
newImage2 = roifill(originalImage, badPixels);
figure(44);
clf;
imagesc(newImage2);
colormap gray
You are doing a few things which are obvious problems (but it might depend specifically on how far you can get into the code before you run out of memory)
1) You are immediately converting the whole image to double
2) You are identifying certain pixels which you want to replace, but passing the whole image to imfilter and then throwing away (presumably) most of the output:
newImage = imfilter(originalImage,G,'same'); % filter across the entire image
newImage(~badPixels) = originalImage(~badPixels); % replace all the good pixels!
Without converting to double, why not first check where the bad pixels are, do your processing on subregions of the appropriate size around those pixels (the subregions can be converted to double and back), and then reassemble the image at the end?
blockproc may work if you can write your filtering option as a function which takes in an image area and returns the correct area - you'll have to use the border_size option appropriately and make sure your function just returns the original image without bothering to do any filtering if it hits a block with no bad pixels in. You can even have it write out to file as well.