column to block using sliding window in matlab - matlab

using im2col sliding window in matlab i have converted the input image block into column and again by using col2im i do the inverse process but the output is not same as the input image. How can i recover the input image? can anyone please help me.
Here is the code
in=imread('tire.tif');
[mm nn]=size(in);
m=8;n=8;
figure,imshow(in);
i1=im2col(in,[8 8],'sliding');
i2 = reshape( sum(i1),mm-m+1,nn-n+1);
out=col2im(i2,[m n],[mm nn],'sliding');
figure,imshow(out,[]);
thanks in advance...

You didn't specify exactly what the problem is, but I see a few potential sources:
You shouldn't expect the output to be exactly the same as the input, since you're replacing each pixel value with the sum of pixels in an 8-by-8 neighborhood. Also, you will get a shrinkage of the resulting image by 7 pixels in each direction (i.e. [m-1 n-1]) since the 'sliding' option of IM2COL does not pad the array with zeroes to create neighborhoods for pixels near the edges.
These two lines are redundant:
i2 = reshape( sum(i1),mm-m+1,nn-n+1);
out=col2im(i2,[m n],[mm nn],'sliding');
You only need one or the other, not both:
%# Use this:
out = reshape(sum(i1),mm-m+1,nn-n+1);
%# OR this:
out = col2im(sum(i1),[m n],[mm nn],'sliding');
Image data in MATLAB is typically of type 'uint8', meaning each pixel is represented as an unsigned 8-bit integer spanning the range 0 to 255. Assuming this is what in is, when you perform your sum operation you will implicitly end up converting it to type 'double' (since an unsigned 8-bit integer will likely not be big enough to hold the sum totals). When image pixel values are represented with a double type, the pixel values are expected to span the range 0 to 1, so you will want to scale your resulting image by its maximum value to get it to display properly:
out = out./max(out(:));
Lastly, check what kind of input image you are using. For your code, you are essentially assuming in is 2-D (i.e. a grayscale intensity image). If it is a truecolor (i.e. RGB) image, the third dimension is going to cause you some trouble, and you will have to either process each color plane separately and recombine them or convert the RGB image to grayscale. If it is an indexed image (with an associated color map), you will not be able to do the sort of processing you describe above without first converting it to a grayscale representation.

Why are you expecting the output to be the same?
i2 is the result of performing a SUM around a pixel neighborhood (essentially a low-pass filter), which is the final blurry image that you see. i.e you are NOT doing an inverse process with the COL2IM call.

i1 obtained from 'sliding' option has the information that you would get from 'distinct' option as well, which you need to filter out. Now, this may not be the best way to code it up but it works. Assume that mm is a multiple of m and nn is a multiple of n. If this is not the case, then you'll have to zero-pad accordingly to make this the case.
in=imread('tire.tif');
[mm nn]=size(in);
m=8;n=8;
i1 = im2col(in,[m,n],'sliding');
inSel = [];
for k=0:mm/m-1
inSel = [inSel 1:n:nn+(nn-n+1)*n*k];
end
out = col2im(i1(:,inSel),[m,n],[mm,nn],'distinct');

Related

Matlab function reshape doesnt´t calculate the last dimension while trying to create a 3D image from .raw binary image file

I created binarized images by using the Otsu methode in Matlab and cut out parts of the resulting image using a function. Now i want to take a look at these images with the VolumeViewer command. I know the x,y and z dimensions of the resulting imgages. I currently run this code doing it(excluding the volumeViewerwhich happens after the loop):
files= {'C3\C3_000mal_550_539_527.raw';...
};
for i=1:numel(files)
Image = fopen(files{i},'r');
ImageData{i} = fread(Image,Inf,'uint16=>uint16');
ImageData{i} = reshape(ImageData{i},550,539,[]);
fclose(openedCrystalImage);
end
Using this code runs into the following error using reshape:
Error using reshape
Product of known dimensions, 296450, not divisible into total number of elements, 78114575.
I did the maths and 550*539=296450 and 296450 * 527=156229150: If we divide the last number by the number of elements it equals 2 and thus is divisible into the total number of elements. In my opinion the reshape function is not able to find the size of the last dimension or defines it as 1.
Defining the size of z also results in an error suggesting using the brackets [], so the function can find it.
Error using reshape
Number of elements must not change. Use [] as one of the size inputs to automatically calculate the appropriate size
for that dimension.
Now to the weird part. This code works for another set of images, with diffrent sizes of the x,y and z ranges. So don´t know where the issue lies to be frank. So i would really appreciate and Answer to my question
I figured it out. The error lies here:
ImageData{i} = fread(Image,Inf,'uint16=>uint16');
Apparently by saving them as .raw before it converts the image to an 8 bit file rather than 16 bits it had before. Therefore, my dimension is double the size of the number of elements. With this alteration it works:
ImageData{i} = fread(Image,Inf,'uint8=>uint8');
The reason i was able to look at the other pictures was that the z range was divisble by 2.
So the reshape function was not the problem but size of the integer data while creating the array for the variable ImageData.
P.S. I just started out programming so the accuracy in the answer should be taken with a grain of salt

Binarization of an image with desired threshold

I am trying to make a function, that would be given a grayscale image, which it will binarize depending on the set threshold. I've been at this all day but no success.
Here is the code I implemented. With the image being a specific image; Not a variable.
function [ output_args ] = thresholdImg(X)
A=imread('car_gray.jpg');
B=zeros(size(A,1),size(A,2));
for l=1:size(A,1)
for m=1:size(A,2)
if(sum(A(l,m,:))>X)
B(l,m)=1;
end
end
end
B=logical(B);
figure,imshow(B);
I don't want to use imbinarize. I want this to be preformed manually, and the code to be as simple as possible. The output of the image looks like it is binary, but when you print the matrix, you see that the values are not only 0s and 1s or 255s
What am I doing wrong?
It'd be faster to get rid of the loop altogether:
function [] = thresholdImg(X)
A=imread('car_gray.jpg');
tmp=sum(A,3); % sum along the third dimension
B = zeros(size(tmp));
B(tmp>X) = 1; % Set all values above the threshold to be one
B=logical(B);
figure,imshow(B);
Using the following conditions: A = rand(100,100,3);X=0.6; we get this picture:
We see that this is indeed, as we expected, fully binary. Additionally, you can check this by calling whos B, which tells us B is indeed of type logical and hence has only zeros and ones.
whos B
Name Size Bytes Class Attributes
B 100x100 10000 logical
Your problem appears when you save the image. If you check the description of imwrite, you will see that if you want to save your image as binary, you are supposed to choose BMP, PNG or TIFF. These are lossless formats. JPEG on the other hand is a lossy compression format.
In addition, I made your code very compact, according to Adriaan's answer:
function [] = thresholdImg(X)
A=imread('car_gray.jpg');
B = sum(A, 3) > X
figure,imshow(B);

How to restore previous colormap in matlab?

I have some images in some range of numbers. Here's an example of an image:
This is a level in a Laplacian Pyramid of an image. (It's not necessary to understand what a Laplacian Pyramid is...)
Now I need to make some operations on those images, and I need to change the colormap for that. I changed it to gray(256) and made the operations i need. So now I have different images in colormap(gray(256)).
Now I need to scale back to the previous range. But I don't know the previous range or colormap. I tried saving the colormap before the operations.
I tried this:
imwrite(img,colormap(gray(256)),str);
but that changed the whole matrix to 255.
What's the right way to do it?
imwrite(img,colormap(gray(256)),str);
colormap only sets the color of a figure, so you don't need it in imwrite. In fact, it does nothing of value here. If you pass a map, gray(256), it will write this as an indexed image. That is, it saves in the file both the values of the pixels and the map which says what those values mean.
However, it doesn't scale the input image to match the colormap neatly. As stated in the docs:
If A is an indexed image of data type double or single, then imwrite
converts the indices to zero-based indices by subtracting 1 from each
element, and then writes the data as uint8. If the data in A is
single, convert A to double before writing to a GIF or TIFF file.
What this means is if your img contains all values of 256 or above, imwrite will subtract one, and write as uint8, clipping values over 255 to 255 (and below 0 to 0). So your image appears as all 255.
You need to first scale img to an appropriate range (e.g. record the max and min values of your input matrix - not the colormap! - before you do anything to it). This is just math - e.g. something like img = img/256 may be all you need. It is unnecessary to save it with a map in most cases - you're just writing your values as grayscale, you can save them with imwrite into a normal image.
imwrite generally expects double to be in the range of 0 to 1 and uint8 in the range of 0 to 255. If your values don't match up to this, you will get clipping/"blank" images, etc.
However, because values are stored as integers (uint8) in most image formats, I don't see how you can use imwrite to save the sort of values you display in your example without losing precision. You also won't be able to save any negative values. So it would be best to save your real values in a different format (*.mat file, csv, etc.) and save an image if you need it for visualisation, but not for storing calculated values.

How to efficiently loop through matrix elements

I have a matlab script for 8-bit image analysis and I'm trying to enhance objects in the image by subtracting the background with no objects present. What I want to do at a pixel level is:
if B-I>50 then E=I
else E=255-B-I
Where, B is the background, I the image and E my enhanced image. I know I can do this by looping through each element of the image matrix by the following:
diff=imsubtract(B,I);
nrows=1024;
ncols=1360;
for r=1:nrows
for c=1:ncols
if diff(r,c)>50
E=I(r,c);
else
E=255-diff(r,c);
end
end
end
But is this rather slow when going multiple images. I've also tried the follow:
E=255-diff;
E(diff>50)=I;
But receive the following error:
In an assignment A(I) = B, the
number of elements in B and I must
be the same.
Any tips on optimizing this would be greatly apprenticed!
In an assignment A(I) = B, the number of elements in B and I must be
the same.
The reason for this error is that you are trying to assign all the content of I to a subset of E (those pixels where diff>50). You have to specifically tell MATLAB that you want those pixels set to the matching pixels in I.
E(diff>50)=I(diff>50);
Incidentally you should be careful using imsubtract here. For pixels where I has a higher value than B, that will result in zeros (if your values are uint8). It may be okay (not 100% clear if you're looking for the absolute difference or really just where B is larger than I)
What if you use use find()
ind = find(B-I>50)
E(ind) = I(ind)
% And then the ones that are not `B-I>50`
E(~ind) = 255-B(~ind)-I(~ind)
Try this vectorized approach that uses logical indexing. I could not test it out on images though, so would be great if that's taken care of.
Code
diff1=double(imsubtract(B,I));
E = double(I).*(diff1>50) + (255-diff1).*(diff1<=50);
You might be needed to convert the datatype back to unsigned integer formats as used for images.

Difference between hist and imhist in matlab

What is the difference between hist and imhist functions in Matlab? I have a matrix of color levels values loaded from image with imread and need to count entropy value of the image using histogram.
When using imhist the resulting matrix contains zeros in all places except the last one (lower-right) which contains some high value number (few thousands or so).
Because that output seems to be wrong, I have tried to use hist instead of imhist and the resulting values are much better, the matrix is fulfilled with correct-looking values instead of zeros.
However, according to the docs, imhist should be better in this case and hist should give weird results..
Unfortunately I am not good at Matlab, so I can not provide you with better problem description. I can add some other information in the future, though.
So I will try to better explain my problem..I have an image, for which I should count entropy and few other values (how much bytes it will take to save that image,..). I wrote this function and it works pretty well
function [entropy, bytes_image, bytes_coding] = entropy_single_pixels(im)
im = double(im);
histg = hist(im);
histg(histg==0) = [];
nzhist = histg ./ numel(im);
entropy = -sum(nzhist.*log2(nzhist));
bytes_image = (entropy*(numel(im))/8);
bytes_coding = 2*numel(unique(im));
fprintf('ENTROPY_VALUE:%s\n',num2str(entropy));
fprintf('BYTES_IMAGE:%s\n',num2str(bytes_image));
fprintf('BYTES_CODING:%s\n',num2str(bytes_coding));
end
Then I have to count the same, but I have to make "pairs" from pixels which are below each other. So I have only half the rows and the same count of columns. I need to express every unique pixel pair as a different number, so I multiplied the first one by 1000 and added the second one to it... Subsequently I need to actually apply the same function as in the first example, but that is the time, when I am getting weird numbers from the imhist function. When using hist, it seems to be OK, but I really don't think that behavior is correct, so that must be my error somewhere. I actually understand pretty good, to what I want to do, or at least I hope so, but unfortunately Matlab makes all that kind of hard for me :)
hist- compute histogram(count number of occurance of each pixel) in color image.........
imhist- compute histogram in two dimensional image.
Use im2double instead of double if you want to use imhist. The imhist function expects double or single-precision data to be in the [0,1] data range, which is why you see everything in the last bin of the histogram.