MATLAB - Histogram Matching of Two Images - matlab

I need to write a function which will match the histogram of image2 to the image that will be remapped, let's call it image1. But I am not allowed to use histeq. Could you please help me with the code?
ps: Also I am wondering how would I do that operation if I were allowed to use histeq? What should I do after extracting red-green and blue channels? (I could not use histeq(R2,R1)?)
image1 = imread('color1.jpeg');
image2 = imread('color2.jpeg');
R1 = image1(:, :, 1);
G1 = image1(:, :, 2);
B1 = image1(:, :, 3);
R2 = image2(:, :, 1);
G2 = image2(:, :, 2);
B2 = image2(:, :, 3);
Regards,
Amadeus

I don't think the question is specific enough. One way to solve this is to convert the three channels to a grayscale image (rgb2gray), compute the two histograms (hist) and then find a desired mapping between the histograms and apply it to each channel of the original image.
The conversion to grayscale is not necessary, you can perform this algorithm on each channel and then join the channels together later.
Check this question, which uses histq.

Histogram Matching algorithm consist of 3 stage:
1-compute Normalize CDF of first image(T(r)).
2-compute Normalize CDF of second image(G(z)).
3-calculate G^-1(T(r)) and transform intensity value of first image to desired one.

Related

How do I calculate the bending of filtration in matlab?

I have 2 variables:
Image which contain original image.
FilteredImage which is filtered image.
Both are RGB images. I know how to calculate the bending for 2-D images
Image = unread('C:\Users\klass\Pictures\man.jpeg');
NoiseImage = minimise(Image,'gaussian');
ImageFiltered = NoiseImage;
for c = 1 : 3
ImageFiltered (:, :, c) = medfilt2(NoiseImage(:, :, c) [3, 3]
end
Bending = norm(im2double(Image - FilteredImage))/norm(im2double(FilteredImage)) * 100;
When I try to use this formula to my figures I get this error:
Error using norm
Input must be 2-D.
I tried pass 3-D images to norm() function. The work around is convert each image to 2-D by rgb2gray()function.
Therefore I evacuate banding with formula:
Bending = norm(im2double(rgb2gray(Image) - rgb2gray(FilteredImage)) / norm(im2double(rgb2gray(Image))) * 100

What's the difference between HSV and grayscale intensities?

I'm doing some research on image processing using MATLAB and I've created grayscale intensity images in two different ways using rgb2gray and rgb2hsv like so:
read_image = imread(handles.myImage);
bc_gambar2 = imresize(read_image,[280 540]);
g = rgb2gray(bc_gambar2); % First intensity image
g2 = rgb2hsv(bc_gambar2);
g = g2(:,:,3); % Second intensity image
The result seems better using rgb2hsv and indexing than using rgb2gray. Can anybody tell me what the difference is and why it's happening?
Here's a sample image I'm using (if needed):
The calculation used by rgb2hsv to compute the value (i.e. lightness) channel is different than that used by rgb2gray to compute the grayscale intensity. They are described by the second and fourth bullet points here, respectively. Briefly:
The computation for the value channel (rgb2hsv) is:
g = max(bc_gambar2, [], 3);
The computation for the grayscale intensity (rgb2gray) is:
g = 0.299.*bc_gambar2(:, :, 1) + ...
0.587.*bc_gambar2(:, :, 2) + ...
0.114.*bc_gambar2(:, :, 3);
More information about different color spaces can be found here.

Matlab: Create 3D cube RGB and show it

I'll try to be precise and short.
I have a volume (128x128x128) and a mask (same size with [0|1|2] values)
I want to make the 3D volume matrix a 3D image with RGB, and store in each channel (red,green,blue) the points marked in the mask.
This is to use a 2D representation by taking a slice of that 3D cube, and not compute it over and over to make things way more faster (very important in my project), so actually, the 3D volume + rgb would be like a store for 128 2D images.
The question is, what steps and how do I have to make all this:
- Create a volume 128x128x128x3 ?
- Define a new colormap (original is gray) ?
- Join each channel ?
- How do I use imagesc/whatever to show one slice of that cube with the points in the color as marked in the mask (ex: imageRGB(:,:,64)) ?
That's just my guess, but I don't even know how to do it properly...I'm a bit lost, I hope you can help me, this is a piece of code that may be wrong but may help you out
% Create the matrix 4D
ovImg = zeros(size(volImg,1),size(volImg,2),size(volImg,3),3); % 128x128x128x3
% Store in each channel the points marked as groups
ovImg(:,:,:,1) = volImg .* (mask==1);
ovImg(:,:,:,2) = volImg .* (mask==2);
ovImg(:,:,:,3) = volImg .* (mask==3);
many many thanks!!
UPDATE:
I'm having some trouble with transparency and the colormap, this is what I did.
% Create the matrix 4D
ovImg = zeros(size(volImg,1),size(volImg,2),size(volImg,3),3);
% Store in each channel the points marked as groups
ovImg(:,:,:,1) = imaNorm.*(mask==1);
ovImg(:,:,:,2) = imaNorm.*(mask==2);
ovImg(:,:,:,3) = imaNorm.*(mask==3);
[X,Y,Z] = meshgrid(1:128,1:128,1:128);
imaNorm = volImg - min(volImg(:));
maxval = max(imaNorm(:));
ovImg = imaNorm + mask * maxval;
N= ceil(maxval);
c = [linspace(0,1,N)' zeros(N,2)];
my_colormap = [c(:,[1 2 3]) ; c(:,[3 1 2]) ; c(:,[2 3 1])];
figure;
imshow(squeeze(ovImg(:,:,64)),my_colormap);
figure;
imagesc(squeeze(mask(:,:,64)));
Result (Overlayed image / mask)
Any ideas? Thanks again, everybody
FINAL UPDATE:
With the other approach that Gunther Struyf suggested, I had exactly what I wanted.
Thanks mate, I really appreciate it, hope this helps other people too.
You can use imshow with a colormap to 'fake' an RGB image from a grayscale image (which you have). For the scale I'd not multiply it, but add an offset to the value, so each mask is a different range in the colormap.
For plotting a slice of the 3d matrix, you can just index it and then squeeze it to remove the resulting singleton dimension:
Example:
[X,Y,Z]=meshgrid(1:128,1:128,1:128);
volImg =5*sin(X/3)+13*cos(Y/5)+8*sin(Z/10);
volImg=volImg-min(volImg(:));
mask = repmat(floor(linspace(0,3-2*eps,128))',[1 128 128]);
maxval=max(volImg(:));
ovImg=volImg+mask*maxval;
imshow(squeeze(ovImg(:,:,1)),jet(ceil(max(ovImg(:)))));
Unmasked, original image (imshow(squeeze(volImg(:,:,1)),jet(ceil(maxval))))
Resulting with mask (code block above):
For different colormaps, see here, or create your own colormap. Eg you're mask has three values, so let's match those with R,G and B:
N = ceil(maxval);
c = [linspace(0,1,N)' zeros(N,2)];
my_colormap = [c(:,[1 2 3]) ; c(:,[3 1 2]) ; c(:,[2 3 1])];
figure
imshow(squeeze(ovImg(:,:,1)),my_colormap);
which gives:
Other approach:
Now I understand your question, I see you got it quite right from the beginning, you only need rescale the variable to a value between 0 and 1, since from imshow:
Color intensity can be specified on the interval 0.0 to 1.0.
which you can do using:
minval=min(volImg(:));
maxval=max(volImg(:));
volImg=(volImg-minval)/(maxval-minval);
next up is your code:
ovImg = zeros([size(volImg),3]);
ovImg(:,:,:,1) = volImg .* (mask==1);
ovImg(:,:,:,2) = volImg .* (mask==2);
ovImg(:,:,:,3) = volImg .* (mask==3);
You just have to plot it now:
imshow(squeeze(ovImg(:,:,64,:)))

Histogram matching of two colored images in matlab

Anyone knows how to perform RGB histogram matching on two colored images?
for example this is an image to be re-mapped:
and this is a target image
Then the RGB remapped image look like this
here is what I did so far, in this code I took two color images im1 and im2
I took the im1 which is the one that has to be remapped then broke it up into
its colors then I took each color of im1 and used histeq to match their histograms to
each color in im2.
I don't know how to reconstruct the re-mapped image from the colors I matched, any help please that would be nice??:
im1 = imread('Atlas-Mer.png');
im2 = imread('techno-trs.png');
Red1 = im1(:, :, 1);
Green1 = im1(:, :, 2);
Blue1 = im1(:, :, 3);
.
.
.
Red2 = im2(:, :, 1);
Green2 = im2(:, :, 2);
Blue2 = im2(:, :, 3);
red2n = histeq(Red2,HnRed1);
green2n = histeq(Green2,HnGreen1);
blue2n = histeq(Blue2,HnBlue1);
Well it's been months since the original question was posted but I think everyone can use an alternative approach to what was suggested: the following code puts the three color channels into one RGB image:
rgb_out = cat(3, red2n, green2n, blue2n);
You can just do:
im2(:, :, 1) = red2n;
etc.
Matlab now has a built-in function in the Image Processing Toolbox to do this:
http://www.mathworks.com/help/images/ref/imhistmatch.html
But if you have an older version of Matlab (I have 2010b and it does not include imhistmatch.m), this is function that does classic histogram matching:
https://www.mathworks.com/matlabcentral/fileexchange/27396-matchhistograms

Creating "holey" median filter in Matlab

What I need to do is to create a "special" kind of median filter for image processing in Matlab - the "holey" median filter. This is a filter that excludes the element at the center of the area.
For standard median filter I use the medfilt2 function, but I can't pass the mask (kernel) for it as a matrix (it's not a linear transform).
For example, using standard averaging filter 3x3 I create the mask (kernel) as:
h = ones(3,3)/9;
And for "holey" averaging filter:
h = ones(3,3)/8;
h(2,2) = 0;
How to do the same thing with median filter? Is there any way to modify the medfilt2 or do I need to implement a running median on my own?
What about using the underlying function ordfilt2 and defining your own domain there?
https://www.mathworks.com/help/images/ref/ordfilt2.html
Using #Doug's idea, the following is an example that handles all cases:
hole position in even/odd mask size
median position in even/odd number of elements
Example:
%%# mask size: N-by-N
N = 3;
assert(N>=3);
%%# read image and add noise
I = im2double( imread('eight.tif') );
I = imnoise(I, 'salt & pepper',0.05);
%%# build mask with hole in center
h = true(N,N);
if mod(N,2) == 0
%# hole is a 2-by-2 square
h([N/2 N/2+1],[N/2 N/2+1]) = false(2);
else
%# hole is one point
h((N+1)/2,(N+1)/2) = false;
end
%%# compute median filter with hole
num = sum(h(:));
if mod(num,2) == 0
%# even case: average from using the two elements in the middle
I1 = ordfilt2(I, num/2, h, 'symmetric');
I2 = ordfilt2(I, num/2+1, h, 'symmetric');
J = imdivide( imadd(I1,I2), 2 );
else
%# odd case: note this is never reached
J = ordfilt2(I, (num+1)/2, h, 'symmetric');
end
%%# plot and compare against normal median filter
subplot(121), imshow(J)
subplot(122), imshow( medfilt2(I,[N N],'symmetric') );
My guess is that it does not exist, and that you would need to implement one yourself. You can write one as a matlab function or if speed is an issue, write one in C.
Another way to approach your problem is to use a rank filter. It is not the same as what you are asking for, but might be another way to achieve what you want.