Plotting several sequences of frames from tiff files with a chosen size - image

I am analyzing some experimental data in the form of .tiff multi frames. Withins these tiff files i need to visualize and compare some specific sequences of frames. I want to generate a figure that contains the frames i have chosen from the files i have chosen. The file list and frames indexes list are generated with a user interface, which calls a plot function when parameters are filled.
The problem : What is the best solution so as to plot, with an optimal size BUT keeping square images (like the original), the chosen frames ? Simpler, how to choose the position and size of each frame i plot in the figure ?
I have tried with sub plot : it works but I can't manage to control the images size.
pos=0;
for j = 1:length(file_list)
for i = 1:length(index_list)
pos=pos+1;
subplot(size(file_list,1),length(index_list),pos)
a =imagesc(imread(file_list{j,:},index_list(i)));
I have also tried
for j = 1:length(file_list)
for i = 1:length(index_list)
a =imagesc(imread(file_list{j,:},index_list(i)));
set(gca,'Units','Pixels', 'Position', [10+100*i 10+100*j 100 100]);
But it seems like i can't set this individually without overwriting the last modification.
Finally, i have considered using "montage", but the way I save the images in a list doesn't seem to be ok.
frm_list=zeros(1,length(FL)*length(index_list));
for j = 1:length(FL)
for i = 1:length(index_list)
a =(imread(FL{j,:},index_list(i)));
frm_list=[frm_list a];
end
end
montage(frm_list,'Size', [length(FL) length(index_list)]);
Thanks
JC

You can use axis image to keep the same aspect ratio of the original image.
subplot('Position', [left bottom width height]) allows you to specify the relative position of the image to the figure window.
If you want to use a command other than imagesc, you can scale the data range of the image before drawing , then use colormap to apply false coloring to the image.

Related

Combine multiple images using vips (ruby-vips8)

How do I apply a function to corresponding pixels of two images of the same resolution? Like Photoshop does when covering one layer with another one. What about more than two images?
If it was Wolfram Mathematica I would take a List of those images and transpose them to get a single "image" where each "pixel" would be an array of N pixels -- there I would apply a Mean[] function to them.
But how do I do that with vips? There are so many Vips::Image methods and only here I could find some minimal description on what do they all mean. So for example:
images = Dir["shots/*"].map{ |i| Vips::Image.new_from_file(i) }
ims = images.map(&:bandmean)
(ims.inject(:+) / ims.size).write_to_file "temp.png"
I wanted it to mean "calculating an average image" but I'm not sure what I've done here.
ruby-vips8 comes with a complete set of operator overloads, so you can just do arithmetic on images. It also does automatic common-subexpression elimination, so you don't need to be too careful about ordering or grouping, you can just write an equation and it should work well.
In your example:
require 'vips8'
images = Dir["shots/*"].map{ |i| Vips::Image.new_from_file(i) }
sum = images.reduce (:+)
avg = sum / images.length
avg.write_to_file "out.tif"
+-*/ with a constant always makes a float image, so you might want to cast the result down to uchar before saving (or maybe ushort?) or you'll have a HUGE output tiff. You could write:
avg = sum / images.length
avg.cast("uchar").write_to_file "out.tif"
By default, new_from_file opens images for random access. If your sources images are JPG or PNG, this will involve decompressing them entirely to memory (or to a disk temp if they are very large) before processing can start.
In this case, you only need to scan the input images from top to bottom as you write the result, so you can stream the images through your system. Change the new_from_file to be:
images = Dir["shots/*"].map { |i| Vips::Image.new_from_file(i, :access => "sequential") }
to hint that you will only be using the image pixels sequentially, and you should see a nice drop in memory and CPU use.
PNG is a horribly slow format, I would use tiff if possible.
You could experiment with bandrank This does something like a median filter over a set of images: you give it an array of images and at each pixel position it sorts the images by pixel value and selects the Nth one. It's a very effective way to remove transitory artifacts.
You can use condition.ifthenelse(then, else) to compute more complex functions. For example, to set all pixels greater than their local average equal to the local average, you could write:
(image > image.gaussblur(1)).ifthenelse(image.gaussblur(1), image)
You might be curious how vips will execute the program above. The code:
(images.reduce(:+) / images.length).cast("uchar")
will construct a pipeline of image processing operations: a series of vips_add() to sum the array, then a vips_linear() to do the divide, and finally a vips_cast() to knock it back to uchar.
When you call write_to_file, each core on your machine will be given a copy of the pipeline and they will queue up to process tiles from the source images as they arrive from the decompressor. Each time a line of output tiles is completed, a background thread will use the selected image write library (libtiff in my example) to send those scanlines back to disk.
You should see low memory use and good CPU utilization.

Detecting black spots on image - Image Segmentation

I'm trying to segment an image with Color-Based Segmentation Using K-Means Clustering. I already created 3 clusters, and the cluster number 3 is like this image:
This cluster has 3 different colors. And I want to only display the black spots of this image. How can I do that?
The image is 500x500x3 uint8.
Those "holes" look like they are well defined with the RGB values all being set to 0. To make things easy, convert the image to grayscale, then threshold the image so that any intensities less than 5 set the output to white. I use a threshold of 5 instead to ensure that we capture object pixels in their entirety taking variations into account.
Once that's done, you can use the function bwlabel from the image processing toolbox (I'm assuming you have it as you're dealing with images) where the second output tells you how many distinct white objects there are.
Something like this could work:
im = imread('http://i.stack.imgur.com/buW8C.png');
im_gray = rgb2gray(im);
holes = im_gray < 5;
[~,count] = bwlabel(holes);
I read in the image directly from StackOverflow, convert the image to grayscale, then determine a binary mask where any intensity that is less than 5, set the output to white or true. Once we have this image, we can use bwlabel's second output to determine how many objects there are.
I get this:
>> count
count =
78
As an illustration, if we show the image where the holes appear, I get this:
>> imshow(holes);
The amount of "holes" is a bit misleading though. If you specifically take a look at the bottom right of the image, there are some noisy pixels that don't belong to any of the "holes" so we should probably filter that out. As such, a simple morphological opening filter with a suitable sized structure will help remove spurious noisy islands. As such, use imopen combined with strel to define the structuring element (I'll choose a square) as well as a suitable size of the structuring element. After, use the structuring element and filter the resulting image and you can use this image to count the number of objects.
Something like this:
%// Code the same as before
im = imread('http://i.stack.imgur.com/buW8C.png');
im_gray = rgb2gray(im);
holes = im_gray < 5;
%// Further processing
se = strel('square', 5);
holes_process = imopen(holes, se);
%// Back to where we started
[~,count] = bwlabel(holes_process);
We get the following count of objects:
>> count
count =
62
This seems a bit more realistic. I get this image now instead:
>> imshow(holes_process);

copyobj copies entire image instead of axes only

What I have is a plot showing the area of connected components. What I want to do is to further work on the plot figure such as clean it up a bit or imcomplement it etc. and then be able to apply the axes from the original plot to this image and be able to extract the ylabel.
Let me explain the above issue with my code and some examples.
This is the plot I have, the y-axis represents the object areas. This is the important axis that I want to transfer to the new image.
Since I am interested in the axes only I copy that using
h = findobj(gcf,'type','axes');
So that I can work with the figure without the axes and borders interfering I save it without these attributes
set(gca, 'visible', 'off'); % Hide the axis and borders
hgexport(gcf, 'plot1.jpg', hgexport('factorystyle'), 'Format', 'jpeg');
This is what I get:
So far so good.
Now comes the processing or in other words changing the plot to my needs.
plot_img = rgb2gray(imread('plot1.jpg'));
img_bw_plot = im2bw(plot_img, graythresh(plot_img));
[rows cols] = size(plot_img);
new = zeros(size(plot_img));
for i = 1: rows
for j = 1: cols
if (img_bw_plot(i,j) == 0)
new(i, 1:10) = 255;
end
end
end
f = figure;
imshow(new);
copyobj(h,f)
This produces a weird overlapped image where instead of copying only the axes, the entire image is copied on top of the new. The datacursormode also fails to work beyond the over lapping image.
First of all I'm a little bit confused that if you have the figure in the first place why aren't you extracting your data from it using something like:
lines=findobj(gca,'type','line');
y=zeros(1,length(lines));
for i=1:length(lines)
y(i)=get(lines(i),'ydata');
end
and there you'll have all the data.
But let's say the original figure isn't like a figure figure where you'd have access to the children of the axes object (though all of them being copied together kind of suggests that this is not the case). What you need to realize is that an "axes" object in MATLAB isn't just the axes of the graph, but the whole graph. For example when you have 5 subplots, each of those smaller plots is an axes object and the graph itself is one of its children which is a "line" object (refer to my example above).
So after this long lecture :), one solution is that you could manually create those axes around your newly drawn image instead of copying the axes object as such:
set(gca,'visible','on');
s=size(new);
set(gca,'ytick',linspace(1,s(1),7),'yticklabel',linspace(6000,0,7));
This should do the trick of placing 7 ticks on the y-axis in the same manner as you have on your original figure. The same method would apply to manually creating the labels for the x-axis.
(I tried putting the resulting image here but I don't have the enough reputations to do so. That's on stackoverflow bro!)
Mind you, though, that this creates the labels on the graph giving you the illusion of the same axis while the actual coordinates of the points are actually determined by the size of the image you're saving. So if you want to make sure the image is the same size, you need to work on resizing your original figure to end up being the same size, which given then 0-6000, would be a really big image.

Normalization of handwritten characters w.r.t size and position

I am doing a project on offline handwriting recognition.In the preprocessing stage,I need to normalize the handwritten part in binary image w.r.t its size and position.Can anyone tell me how to access just the writing part(black pixels) in the image and resize and shift its position?
Your problem is as broad as the field of image processing. There is no one way to segment an image into foreground and background so whatever solution you find here works on some cases and doesn't in others. However, the most basic way to segment a grayscale image is:
% invert your grayscale so text is white and background is black
gray_im = 1 - im2double(gray_im);
% compute the best global threshold
level = graythresh(gray_im);
% convert grayscale image to black and white based on best threshold
bw_im = im2bw(gray_im, level);
% find connected regions in the foreground
CC = bwconncomp(bw_im);
% if necessary, get the properties of those connected regions for further analysis
S = regionsprops(CC);
Note: Many people have much more sophisticated methods to segment and this is by no means the best way of doing it.
After post-processing, you will end up with one (or more) image containing only a single character. To resize to a specific size M x N, use:
resized_bw = imresize(single_char_im, [M N]);
To shift its position, the easiest way I know is to use circshift() function:
shifted_bw = circshift(resized_bw, [shift_pixels_up_down, shift_pixels_left_right]);
Note: circshift wraps the shifted columns or rows so if your bounding box is too tight, the best method is to pad your image, and re-crop it at the new location.

Autocorrection between the position of two images

I have two images and have to divide that image. Due to manual error the area in the image is not as same. How can i correct it automatically using matlab so as to perform divison pixel by pixel accurately?
Once you've read both image files into the variables, say A and B, assuming A contains the image of the size you actually want and B contains the image of the size you want to change, you could use:
[numrows numcols] = size(A);
A = imresize(A, [numrows numcols]);

Resources