My supervisor has suggested the following code for extracting vertical slices from a set of 40 x 40 images and plotting them as a time series (24hrs), with images stored in an array 'images = FLTARR(no_images, 40,40)', and corresponding times in array UT=FLTARR(no_images):
PLOT, [0],[0], /NODATA, XRANGE=[0,24], XSTYLE, YRANGE=[-40,40], /YSTYLE
FOR i=0, no_images-1 DO BEGIN
FOR j=0, 39 DO BEGIN
POLYFILL, UT(i)+[0,0,1,1]*2/60.0, (j+[0,1,1,0])*2-40, COL=[work out what colour you want the pixel to be in terms of the value in images(i,20,j) ]
ENDFOR
ENDFOR
The images were taken at 2 minute intervals.
I understand what is being done here - essentially drawing small rectangles to represent the pixels in the images. My question is what should the COL argument be? Can someone give me an example? At the minute to test the code i've just put a fixed value (e.g. 255), which obviously just gives a block of the same color. How can i get different colours corresponding to the pixel values?
Just use:
max_value = max(ut[*, 20, *])
color=images[i, 20, j] / float(max_value) * 255
Make sure you are in indexed color, i.e., you have done:
device, decomposed=0
and used used LOADCT or TVLCT to load the color table you want to use.
You could also use new graphics if you have IDL 8.4+
no_images = 100
ut = FINDGEN(100)/100*24
img = bytscl(randomu(seed,no_images,40))
y = FINDGEN(40)
p = PLOT(ut, y, XSTYLE=1, YSTYLE=1, XRANGE=[0,24], YRANGE=[0,40], $
/NODATA, TITLE='My Data',XTITLE='X',YTITLE='Y')
i = IMAGE(img, ut, y, /OVERPLOT, RGB_TABLE=74, ASPECT_RATIO=0.5)
You can adjust the ASPECT_RATIO to make your image appear more or less square. And it's easy to change the RGB_TABLE to whatever one you'd like.
Related
I have an image of size (224 x 224) and I want to extract a number of random patches from the original image using Matlab (let say 5 patches). One of these patch should be at the centre of the original image. The patch size is (128 x 128).
I have tried this to crop just the centre patch:
II = imread('img.png')
[p3, p4] = size(II);
q1 = 50; // size of the crop box
i3_start = floor((p3-q1)/2); % or round instead of floor; using neither gives warning
i3_stop = i3_start + q1;
i4_start = floor((p4-q1)/2);
i4_stop = i4_start + q1;
II = II(i3_start:i3_stop, i4_start:i4_stop, :);
figure ,imshow(II);
I've tried to accomplish this in the following way:
A=imread('Lena.bmp');%sample image
rnd_x = randperm(size(A,1)-128,5);%choose 5 tandom unique points on x-axis
rnd_y = randperm(size(A,2)-128,5);%choose 5 tandom unique points on y-axis
for ii = 1:5
piece{ii} = A((rnd_x(ii):(rnd_x(ii)+127)),(rnd_y(ii):(rnd_y(ii)+127)),1:3);%Convert chosen numbers to image pieces
figure(ii)
imshow(piece{ii});
end
This takes image like this:
This gives 5 pics like this:
Here our image size is 512x512. So, if we want to cut the 128x128 piece from it, we need to seek from 385x385 grid (512-127). We find 5 random points on the grid expressed in rnd_x and rnd_y. Finally, we take the found points as the upper-left corners of the pieces and construct 128x128 images from them. The 5 pieces are recorded in piece cell array.
EDIT: forgot to add how to extract the center patch. The following code performs the task:
A=imread('Lena.bmp');%sample image
if mod(size(A,1),2)
A = A(1:(end-1),:,:);
end
if mod(size(A,2),2)
A = A(:,1:(end-1),:);
end
while size(A,1) > 128
A = A(2:(end-1),:,:);
end
while size(A,2) > 128
A = A(:,2:(end-1),:);
end
imshow(A)
The code removes one pixel from each side until we get the 128-pixel image.
Careful! In your code, if you load a color image (3 channels) and call size with only two outputs, you will have an incorrect value for p4.
Use three outputs when loading images to avoid this problem:
[nrows ncols nchannels] = size(II);
Your code correctly extracts a (q1 x q1) from the center of the image.
If you want a random patch just generate a random integer for the top-left column of the patch with the correct range to ensure that it doesn't fall outside the image. You can generate random integers using the function randi.
i3_start = randi(floor((p3-q1));
i4_start = randi(floor((p4-q1));
The rest of the code is the same. If you want several patches you can generate several values when calling the randi function with a second and third parameter for the desired number of rows and columns. And then process each patch inside a for loop.
BTW: In the third line you have an invalid Matlab comment (use % for comments). Also you should name your variables with more intuitive names.
Eg: [nrows ncols nchannels] = size(II);
does anybody know how to crop an image with a sliding window in Matlab?
e.g. I have an image of 1000x500 pixels, I would like to crop from this image blocks of 50x50 pixels... Of course I have to handle uneven divisions, but it is not necessary to have block of the same size.
Some details that have helped me in the past related to (i) ways to divide an image while block processing and (ii) "uneven division", as mentioned by OP.
(i) Ways to divide/process an image:
1. Process non-overlapping blocks:
Using default parameter {'BorderSize',[0 0]}, this can be handled with blockproc as below.
Example for (i)-1: Note the blocked nature of the output. Here each non-overlapping block of size 32 x 32 is used to calculate the std2() and the output std2 value is used to fill that particular block. The input and output are of size 32 x 32.
fun = #(block_struct) std2(block_struct.data) * ones(size(block_struct.data));
I2 = blockproc('moon.tif',[32 32],fun);
figure; subplot(1, 2, 1);
imshow('moon.tif'); title('input');
subplot(1,2, 2)
imshow(I2,[]); title('output');
Input and Output Image:
(i)-2: Process overlapping blocks:
Using parameter {'BorderSize',[V H]}: V rows are added above and below the block and H columns are added to the left and right of the block. The block that is processed has (N + 2*V) rows and (M + 2*H) columns. Using default parameter {'TrimBorder',true}, the border of the output is trimmed to the original input block size of N rows and M columns.
Example for (i)-2: Below code using blockproc uses {'BorderSize',[15 15]} with [N M] = [1 1]. This is similar to filtering each pixel of the image with a custom kernel. So the input to the processing unit is a block of size (1 + 2*15) rows and (1 + 2*15) columns. And since {'TrimBorder',true} by default, the std2 of the 31 rows by 31 columns block is provided as output for each pixel. The output is of size 1 by 1 after trimming border. Consequently, note that this example output is 'non-blocked' in contrast to the previous example. This code takes much longer time to process all the pixels.
fun = #(block_struct) std2(block_struct.data) * ones(size(block_struct.data));
I2 = blockproc('moon.tif',[1 1],fun,'BorderSize',[15 15]);
figure; subplot(1, 2, 1);
imshow('moon.tif'); title('input');
subplot(1,2, 2)
imshow(I2,[]); title('output');
Input and Output Image:
(ii) "Uneven division":
1. Zero/replicate/symmetric padding:
Zero padding so that an integer multiple of the blocks (N rows by M cols sized) can cover the [image + bounding zeros] in the uneven dimension. This can be achieved by using the default parameter {'PadMethod', 0} along with {'PadPartialBlocks' , true} ( which is false by default ). If a bounding region of zeros causes a high discontinuity in values computed from the bounding blocks, {'PadMethod', 'replicate'} or {'PadMethod', 'symmetric'} can be used.
2. Assume an "Active Region" within the image for block processing
For the case of processing each pixel, as in case (i)-2, we could assuming a bounding region of floor(block_size/2) pixels on all sides along the periphery of the image that is used as "Dummy" region. The Active region for block processing is contained within the Dummy region.
Something similar is used in imaging sensors where Dummy Pixels located at the periphery of an imaging array of Active Pixels allow for an operation like the color interpolation of all active area pixels. As color interpolation usually needs a 5x5 pixel mask to interpolate the color values of a pixel a bounding Dummy periphery of 2 pixels can be used.
Assuming MATLAB indexing, the region ( floor(block_size/2) + 1 ) to ( Input_Image_Rows - floor(block_size)/2) ) Rows by ( floor(block_size/2) + 1 ) to ( Input_ImageCols - floor(block_size)/2) ) Columns is considered as Active region (assuming a square block of side, block_size) which undergoes block processing for each pixel as in (i)-2.
Assuming a square block size of 5 by 5, this is shown by the following:
block_size = 5;
buffer_size = floor(block_size/2);
for i = (buffer_size+1):(image_rows-buffer_size)
for j = (buffer_size+1):(image_cols-buffer_size)
... % block processing for each pixel Image(i,j)
end
end
Matlab ver: R2013a
I would first look into the function blockproc to see if it can do what you want.
If you're sure you want to manually crop the image into blocks, you can use this script. It both writes the cropped images to .png files and saves the cropped images in the pages of a 3D array. You can modify it as you need.
This script assumes the image in evenly divisible by the block size. If it isn't, you'll need to pad it with zeros.
[rowstmp,colstmp]= size(myImage);
block_height = 50;
block_width = 50;
blocks_per_row = rows/block_height;
blocks_per_col = cols/block_width;
number_of_blocks = blocks_per_row*blocks_per_col;
%// pad image with zeros if needed
if ~(mod(rowstmp-1,block_height)==0)
rows = ceil(rowstmp/block_height)*block_height;
end
if ~(mod(colstmp-1,block_width)==0)
cols = ceil(colstmp/block_width)*block_width;
end
Im = uint8(zeros(rows,cols));
Im(1:rowstmp,1:colstmp) = myImage;
%// make sure these image have type uint8 so they save properly
cropped_image = uint8(zeros(rows,cols));
img_stack = uint8(zeros(rows,cols,number_of_blocks));
%// loop over the image blocks
for i = 1:blocks_per_row
for j = 1:blocks_per_col
%// get the cropped image from the original image
idxI = 1+(i-1)*block_height:i*block_height;
idxJ = 1+(j-1)*block_width :j*block_width;
cropped_image(idxI,idxJ) = Im(idxI,idxJ);
%//imshow(cropped_image)
%// write the cropped image to the current folder
filename = sprintf('block_row%d_col%d.png',i,j);
imwrite(cropped_image,filename);
cropped_image(idxI,idxJ) = 0;
%// keep all the blocks in a 3D array if we want to use them later
img_stack(:,:,(i-1)*blocks_per_col+j);
end
end
I am trying to do some image processing for which I am given an 8-bit grayscale image. I am supposed to change the contrast of the image by generating a lookup table that increases the contrast for pixel values between 50 and 205. I have generated a look up table using the following MATLAB code.
a = 2;
x = 0:255;
lut = 255 ./ (1+exp(-a*(x-127)/32));
When I plot lut, I get a graph shown below:
So far so good, but how do I go about increasing the contrast for pixel values between 50 and 205? Final plot of the transform mapping should be something like:
Judging from your comments, you simply want a linear map where intensities that are < 50 get mapped to 0, intensities that are > 205 get mapped to 255, and everything else is a linear mapping in between. You can simply do this by:
slope = 255 / (205 - 50); % // Generate equation of the line -
% // y = mx + b - Solve for m
intercept = -50*slope; %// Solve for b --> b = y - m*x, y = 0, x = 50
LUT = uint8(slope*(0:255) + intercept); %// Generate points
LUT(1:51) = 0; %// Anything < intensity 50 set to 0
LUT(206:end) = 255; %// Anything > intensity 205 set to 255
The LUT now looks like:
plot(0:255, LUT);
axis tight;
grid;
Take note at how I truncated the intensities when they're < 50 and > 205. MATLAB starts indexing at index 1, and so we need to offset the intensities by 1 so that they correctly map to pixel intensities which start at 0.
To finally apply this to your image, all you have to do is:
out = LUT(img + 1);
This is assuming that img is your input image. Again, take note that we had to offset the input by +1 as MATLAB starts indexing at location 1, while intensities start at 0.
Minor Note
You can easily do this by using imadjust, which basically does this for you under the hood. You call it like so:
outAdjust = imadjust(in, [low_in; high_in], [low_out; high_out]);
low_in and high_in represent the minimum and maximum input intensities that exist in your image. Note that these are normalized between [0,1]. low_out and high_out adjust the intensities of your image so that low_in maps to low_out, high_in maps to high_out, and everything else is contrast stretched in between. For your case, you would do:
outAdjust = imadjust(img, [0; 1], [50/255; 205/255]);
This should stretch the contrast such that the input intensity 50 maps to the output intensity 0 and the input intensity 205 maps to the output intensity 255. Any intensities < 50 and > 205 get automatically saturated to 0 and 255 respectively.
You need to take each pixel in your image and replace it with the corresponding value in the lookup table. This can be done with some nested for loops, but it is not the most idiomatic way to do it. I would recommend using arrayfun with a function that replaces a pixel.
new_image = arrayfun(#(pixel) lut(pixel), image);
It might be more efficient to use the code that generates lut directly on the image. If performance is a concern and you don't need to use a lookup table, try comparing both methods.
new_image = 255 ./ (1 + exp(-image * (x-127) / 32));
Note that the new_image variable will no longer be of type uint8. If you need to display it again (say, with imshow) you will need to convert it back by writing uint8(new_image).
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.
A biologist friend of mine asked me if I could help him make a program to count the squama (is this the right translation?) of lizards.
He sent me some images and I tried some things on Matlab. For some images it's much harder than other, for example when there are darker(black) regions. At least with my method. I'm sure I can get some useful help here. How should I improve this? Have I taken the right approach?
These are some of the images.
I got the best results by following Image Processing and Counting using MATLAB. It's basically turning the image into Black and white and then threshold it. But I did add a bit of erosion.
Here's the code:
img0=imread('C:...\pic.png');
img1=rgb2gray(img0);
%The output image BW replaces all pixels in the input image with luminance greater than level with the value 1 (white) and replaces all other pixels with the value 0 (black). Specify level in the range [0,1].
img2=im2bw(img1,0.65);%(img1,graythresh(img1));
imshow(img2)
figure;
%erode
se = strel('line',6,0);
img2 = imerode(img2,se);
se = strel('line',6,90);
img2 = imerode(img2,se);
imshow(img2)
figure;
imshow(img1, 'InitialMag', 'fit')
% Make a truecolor all-green image. I use this later to overlay it on top of the original image to show which elements were counted (with green)
green = cat(3, zeros(size(img1)),ones(size(img1)), zeros(size(img1)));
hold on
h = imshow(green);
hold off
%counts the elements now defined by black spots on the image
[B,L,N,A] = bwboundaries(img2);
%imshow(img2); hold on;
set(h, 'AlphaData', img2)
text(10,10,strcat('\color{green}Objects Found:',num2str(length(B))))
figure;
%this produces a new image showing each counted element and its count id on top of it.
imshow(img2); hold on;
colors=['b' 'g' 'r' 'c' 'm' 'y'];
for k=1:length(B),
boundary = B{k};
cidx = mod(k,length(colors))+1;
plot(boundary(:,2), boundary(:,1), colors(cidx),'LineWidth',2);
%randomize text position for better visibility
rndRow = ceil(length(boundary)/(mod(rand*k,7)+1));
col = boundary(rndRow,2); row = boundary(rndRow,1);
h = text(col+1, row-1, num2str(L(row,col)));
set(h,'Color',colors(cidx),'FontSize',14,'FontWeight','bold');
end
figure;
spy(A);
And these are some of the results. One the top-left corner you can see how many were counted.
Also, I think it's useful to have the counted elements marked in green so at least the user can know which ones have to be counted manually.
There is one route you should consider: watershed segmentation. Here is a quick and dirty example with your first image (it assumes you have the IP toolbox):
raw=rgb2gray(imread('lCeL8.jpg'));
Icomp = imcomplement(raw);
I3 = imhmin(Icomp,20);
L = watershed(I3);
%%
imagesc(L);
axis image
Result shown with a colormap:
You can then count the cells as follows:
count = numel(unique(L));
One of the advantages is that it can be directly fed to regionprops and give you all the nice details about the individual 'squama':
r=regionprops(L, 'All');
imshow(raw);
for k=2:numel(r)
if r(k).Area>100 % I chose 100 to filter out the objects with a small are.
rectangle('Position',r(k).BoundingBox, 'LineWidth',1, 'EdgeColor','b', 'Curvature', [1 1]);
end
end
Which you could use to monitor over/under segmentation:
Note: special thanks to #jucestain for helping with the proper access to the fields in the r structure here