How to represent points from PCA space in the RGB space - matlab

I'm trying to implement a morphological method for image colors from the article: "Probabilistic pseudo-morphology for grayscale and color images". At one point, we compute the PCA on the entire image, calculate a chebyschev inequality ( the equation 11 in the paper: http://perso.telecom-paristech.fr/~bloch/P6Image/Projets/pseudoMorphology/Caliman-PR2014.pdf) of each 3 components which gives us 3 pairs of vector. We next have to represent these vectors back in the RGB space. I don't understand how do we do that? Can someone help me?

Looking at the paper, I'm not sure which representation you're talking about. I'm guessing Fig. 16, but I'm not sure. There's a note in the caption of Fig. 16 that's helpful: "(For interpretation of the references to color in this figure caption, the reader is referred to the web version of this article.)"
Possible answer: if you have a matrix of size A = (y_pixels,x_pixels,3), then you can display this as an RGB image via:
A = rand(100,100,3);
figure()
imshow(A)
Note that your matrix must be scaled in the range [0..1].
It seems easy to map your your PCA scores for each pixel onto such a matrix, and simply display that as RGB via imshow. Does that solve your problem?

Related

create the pixel size for Dicom_Picture in matlab

I have pictures in .dcm format. From Dicominfo I learned that the pixel spacing is [0.9,0.9] mm and the slice thickness is 1.98 mm.
My task: I should get the picture size in real (world) coordinates and then display the pictures in all three projections in matlab.
I had an idea that I would create a matrix in matlab, but it is difficult for me to create the pixel size spacing.
I mean that the pixel in the matrix is like a square and is 0.9mm * 0.9mm.
I don't know if my approach is correct and if there is an easy way to solve the problem.
Thank you very much for every answer
several plotting functions allow you to specify x/y/z positions of each pixel/voxel, including imagesc, pcolor, here is an example using imagesc.
% vol stores your dicom volume
vol=rand(40,50,30);
dx=[0.9,0.9,1.98];
imagesc((0:size(vol,1)-1)*dx(1), (0:size(vol,2)-1)*dx(2), vol(:,:,1))

Scramble the pixels of black and white images in Matlab

I have a series of black and white images (not greyscale, black and white; 2D matrices in Matlab), and I need to randomly scramble the pixels. I found this package in Mathworks File Exchange (https://it.mathworks.com/matlabcentral/fileexchange/66472-image-shuffle); one of the functions, imScrambleRand, does exactly what I need, but it works for RGB images (3D matrices). Is there a way to transform b&w images into 3D matrices so that I can use that function? Or can anyone suggest any other script that does what I need? Keep in mind that I'm not familiar with Matlab, but I'll do my best.
Thank you.
EDIT 1: When I import the BW image I get a 2D matrix of logic values (0 = black, 1 = white). I think the different data format (logic vs integer) is what yields errors when using the function for RGB images.
EDIT 2: I adapted the demo code from the aforementioned package and I used the suggestion by #Jonathan for transforming a 2D matrix into a 3D matrix, and added a loop to transform the logic values into RGB integer values, then use the imScrambleRand function. It works, but what I obtain is the following image: SCRAMBLED IMAGE. This is the BW picture I start with: BW IMAGE. So I checked the scrambled image, and the function from the FEX file actually scrambles within the RGB values, meaning that I found, for instance, a pixel with RGB 0,255,0. So I solved a problem but actually there's a problem within the function: it doesn't scramble pixels, it scrambles values generating colors that were not in the original picture.
EDIT 3: I used the code provided by #nhowe and I obtain exactly what I need, thanks!
EDIT 4: Ok, turns out it's not ok to scramble the pixels since it makes the image too scattered and different from the starting image (you don't say?), but I need to scramble BLOCKS OF PIXELS so that you can't really recognize the image but the black pixels are not too scattered. Is there a way to do that using the code provided by #nhowe?
EDIT 5: It should be ok with this function: https://it.mathworks.com/matlabcentral/fileexchange/56160-hio-been-hb-imagescramble
A simple way to scramble matrix M:
r = rand(size(M));
[~,ri] = sort(r(:));
M(ri) = M;
The simplest solution to go from grayscale to RGB might be this:
rgbImage = cat(3, grayImage, grayImage, grayImage);
Then apply your function from FEX and extract one color channel, assuming that the FEX function will yield three identical color channels.

abs function for fft2 is not working in MATLAB

i am trying to plot the figure of FFT magnitude of an image using the following code in the command window:
a= imread('lena','png')
figure,imshow(a)
ffta=fft2(a)
fftshift1=fftshift(ffta)
magnitude=abs(fftshift1)
figure,imshow(magnitude),title('magnitude')
However, the figure with the title magnitude shows nothing, even though MATLAB shows that it has computed abs() on fftshift. The figure is still empty, and there is no error. Also, why do we need to compute the phase shift before magnitude?
The reason why this is probably happening is because of the following things:
When you take the 2D fft of your image, it will produce a double valued result, even though your image is mostly unsigned 8-bit integer. MATLAB assumes that double formatted images have their intensities / colours between [0,1]. By doing imshow on just the magnitude itself, you will most likely get an entirely white image because I suspect a good majority of the FFT coefficients are bigger than 1. This is probably the blank figure that you're referring to.
Even if you rescale the magnitude so that it is between [0,1], the DC coefficient will be so large that if you try to display the image, you'll only see a white dot in the middle while every other component will be black.
As a side note, the reason why you are doing fftshift is because by default, MATLAB assumes that the origin of the FFT for 2D is located at the top left corner. Doing fftshift will allow the origin to be in the middle, which is what we would intuitively expect of the 2D FFT.
In order to remedy this situation, I would suggest doing a log transformation on the FFT coefficients so you can visually see the results. I would also normalize the coefficients once you log transform it so that they go between [0,1]. Do not actually modify the FFT coefficients as this would be improper. You need to leave them the same way that it is because if you intend to do any processing on the spectrum, you would start by working on the raw image. Doing filter design or anything of that sort will require the raw spectrum, as the final filter will depend on these coefficients untouched. Unless you actually want to do a log operation as part of your pipeline, then leave these coefficients as is. As such, this can be done through the following MATLAB code:
imshow(log(1 + magnitude), []);
I'm going to show an example, using your code that you have provided but using another image as you haven't provided one here. I'm going to use the cameraman.tif image that's part of the MATLAB system path. As such:
a= imread('cameraman.tif');
figure,imshow(a);
ffta=fft2(a);
fftshift1=fftshift(ffta);
magnitude=abs(fftshift1);
figure;
imshow(log(1 + magnitude), []); %// NEW
title('magnitude')
This is what I get:
As you can see, the magnitude is displayed more nicely. Also, the DC coefficient is in the middle of the spectrum thanks to fftshift.
If you want to apply this for colour images, fft2 should still work. It will apply the 2D fft to each colour plane by itself. However, if you want this to work, you'll not only need to take the log transform, but you'll also need to normalize each plane separately. You have to do this because if we tried doing the imshow command we did earlier, it would normalize it so that the greatest value in the spectrum of the colour image gets normalized to 1. This will inevitably produce that same small dot effect that we talked about earlier.
Let's try a colour image that's built-in to MATLAB: onion.png. We will use the same code that you used above, but we need an additional step of normalizing each colour plane by itself. As such:
a = imread('onion.png');
figure,imshow(a);
ffta=fft2(a);
fftshift1=fftshift(ffta);
magnitude=abs(fftshift1);
logMag = log(1 + magnitude); %// New
for c = 1 : size(a,3); %// New - normalize each plane
logMag(:,:,c) = mat2gray(logMag(:,:,c));
end
figure; imshow(logMag); title('magnitude');
Note that I had to loop through each colour plane and use mat2gray to normalize each plane to [0,1]. Also, I had to create a new variable called logMag because I have to modify each colour plane individually, and you can't do this with a single imshow call.
With this, these are the results I get:
What's different with this spectrum is that we are applying the FFT to each colour plane separately, and so you'll see a whole bunch of colour spatters because for each location in this image, we are visualizing a linear combination of components from the red, green and blue channels. For each location, we have a value in between [0,1] for each colour plane, and the combination of these give you a colour at this location. You could say that darker colours are for locations that have a relatively low magnitude for at least one of the colour channels, while locations that are brighter have a relatively high magnitude for at least one of the colour channels.
Hope this helps!
Can't be sure about your version of "lena.png", but if it's a color RGB picture, you need to convert it first to grayscale, or at least select which RGB plane you want to examine.
I.e., the following works for http://optipng.sourceforge.net/pngtech/img/lena.png (color png):
clear; close all;
a = imread('lena','png');
ag = rgb2gray(a);
ag = im2double(ag);
figure(1);
imshow(ag);
F = fftshift( fft2(ag) ); % also try fft2(ag, N, N) where N < image size. Say N=128.
magnitude=abs(F);
figure(2);
imshow(magnitude);

Image downsampling and upsampling using bilinear interpolation

I am trying to understand how exactly the upsampling and downsampling of a 2D image I have, would happen using Bilinear interpolation. Now I am aware of how bilinear interpolation works using a 2x2 neighbourhood values to interpolate the data point inside this 2x2 area using weights. But what I am not aware of, is asked below. My objectives and specific queries are -
1.To start with I have a 2D image of values(size MxN). The width(M) and height(N) of this image is not fixed, but will change from case to case. This 2D image needs to be down-sampled using bilinear interpolation to a grid of size PxQ (P and Q are to be configured as input parameters) e.g. lets take PxQ is 8x8. And assume input 2D array image is of size 200x100. i.e 200 columns, 100 rows.
Now how while performing downsampling using bilinear interpolation of this 200x100 image, should I first obtain a downsampled image of size 100x50 (downsampling by 2 in both dimensions using bilinear interpolation); then a 50x25 image(again by doing downsampling by 2 in both dimensions), then a 25x12 image, then a 12x12(this time doing downsampling by linear(not bilinear!) interpolation only along the rows, and finally drop some pixels to get 8x8.
Any pointers to exact algorithm or different ways to achieve this, are appreciated.
2.Above question raises another one - how to downsample using bilinear interpolation by a non-integer scale factor, e.g. how to go from a say 8x8 image array to a 6x2 image wherein resampling/scaling factors in both dimensions are not integers.
3.Then when I get a 8x8 sized image I need to upsample it by bilinear interpolation to the same original size I started with- MxN. If I need to go from 8x8 to say 20x20. How would it interpolate in between points in a row and would it interpolate a full row by some means. Again in case of non-integer scale factors how would bilinear interpolation for upsampling happen. Exact steps.
And finally I need to implement this in C.
I tried visualizing these particular questions by taking different examples, but not got a clear picture of how this bilinear interpolation would happen while downsampling and upsampling. All I have is plenty of paper sheets having'dots and crossed' pictures on my desk, but still no clear solution!
Any detailed reading material, books appreciated.

How to improve image quality in Matlab

I'm building an "Optical Character Recognition" system.
so far the system is capable to identify licence plates in good quality without any noise.
what I want in the next level is to be able to identify licence plates in poor quality beacuse of different reasons.
for example, let's look at the next plate:
as you see, the numbers are not look clearly, because of light returns or something else.
for my question: how can I improve the image quality, so when I move to binary image the numbers will not fade away?
thanks in advance.
We can try to correct for lighting effect by fitting a linear plane over the image intensities, which will approximate the average level across the image. By subtracting this shading plane from the original image, we can attempt to
normalize lighting conditions across the image.
For color RGB images, simply repeat the process on each channel separately,
or even apply it to a different colorspace (HSV, Lab*, etc...)
Here is a sample implementation:
function img = correctLighting(img, method)
if nargin<2, method='rgb'; end
switch lower(method)
case 'rgb'
%# process R,G,B channels separately
for i=1:size(img,3)
img(:,:,i) = LinearShading( img(:,:,i) );
end
case 'hsv'
%# process intensity component of HSV, then convert back to RGB
HSV = rgb2hsv(img);
HSV(:,:,3) = LinearShading( HSV(:,:,3) );
img = hsv2rgb(HSV);
case 'lab'
%# process luminosity layer of L*a*b*, then convert back to RGB
LAB = applycform(img, makecform('srgb2lab'));
LAB(:,:,1) = LinearShading( LAB(:,:,1) ./ 100 ) * 100;
img = applycform(LAB, makecform('lab2srgb'));
end
end
function I = LinearShading(I)
%# create X-/Y-coordinate values for each pixel
[h,w] = size(I);
[X Y] = meshgrid(1:w,1:h);
%# fit a linear plane over 3D points [X Y Z], Z is the pixel intensities
coeff = [X(:) Y(:) ones(w*h,1)] \ I(:);
%# compute shading plane
shading = coeff(1).*X + coeff(2).*Y + coeff(3);
%# subtract shading from image
I = I - shading;
%# normalize to the entire [0,1] range
I = ( I - min(I(:)) ) ./ range(I(:));
end
Now lets test it on the given image:
img = im2double( imread('http://i.stack.imgur.com/JmHKJ.jpg') );
subplot(411), imshow(img)
subplot(412), imshow( correctLighting(img,'rgb') )
subplot(413), imshow( correctLighting(img,'hsv') )
subplot(414), imshow( correctLighting(img,'lab') )
The difference is subtle, but it might improve the results of further image processing and OCR task.
EDIT: Here is some results I obtained by applying other contrast-enhancement techniques IMADJUST, HISTEQ, ADAPTHISTEQ on the different colorspaces in the same manner as above:
Remember you have to fine-tune any parameter to fit your image...
It looks like your question has been more or less answered already (see d00b's comment); however, here are a few basic image processing tips that might help you here.
First, you could try a simple imadjust. This simply maps the pixel intensities to a "better" value, which often increases the contrast (making it easier to view/read). I have had a lot of success with it in my work. It is easy to use too! I think its worth a shot.
Also, this looks promising if you simply want a higher resolution image.
Enjoy the "pleasure" of image-processing in MATLAB!
Good luck,
tylerthemiler
P.S. If you are flattening the image to binary tho, you are most likely ruining the image to start with, so don't do that if you can avoid it!
As you only want to find digits (of which there are only 10), you can use cross-correlation.
For this you would Fourier transform the picture of the plate. You also Fourier transform a pattern you want to match a good representation of a picture of the digit 1. Then you multiply in fourier space and inversely Fourier transform the result.
In the final cross-correlation, you will see pronounced peaks, where the pattern overlaps nicely with your image.
You do this 10 times and know where each digit is. Note that you must correct the tilt before you do the cross correlation.
This method has the advantage that you don't have to threshold your image.
There are certainly much more sophisticated algorithms in the literature for assigning number plates. One could for example use Bayes theory to estimate which digit would most likely occur (this helps a lot if you already have a databases of possible numbers).