Normalization of an image dataset after processing - matlab

Edited With More Clear Explanation
I am trying to normalize images in a dataset after processing them, but min, max, ranges change (for example one image is between the range [0.38,5.26] and another one is [-0.44, 3.65]) after the processing and normalizing them between [0,1] with the common normalization approach but it causes inconsistency between images.
imagesPath = '/home/berkanhoke/Datasets/Freiburg/Org/Night/';
outFolderPath = '/home/berkanhoke/Datasets/Freiburg/Maddern/Night';
imageSet = dir(strcat(imagesPath,'*.jpeg'));
imageCount = length(imageSet);
for i = 1:imageCount
fileName = imageSet(i).name;
filePath = strcat(imagesPath,fileName);
img = double(imread(filePath));
I_old = maddern(img,0.3975);
I_new = (I_old - min(I_old(:)))/(max(I_old(:)) - min(I_old(:)));
writePath = strcat(outFolderPath,fileName);
imwrite(I_new,writePath,'jpeg');
end
The function I use for processing is the following:
function [ ii_image ] = maddern( image, alpha )
ii_image = 0.5 + log(image(:,:,2)+1)...
- alpha * log(image(:,:,3)+1)...
- (1-alpha) * log(image(:,:,1)+1);
which is based on the paper: http://www.robots.ox.ac.uk/~mobile/Papers/2014ICRA_maddern.pdf
I tried normalized with respect to min/max of the whole dataset, but it did not work and I got weird results. How can I normalize the images by keeping the images consistent after processing?

The problem is that when you do min/max function in MATLAB, it only does it in one dimension. So if you have a 256x256 image, when you do min(image), you get a 1x256 vector. And when you divide this you are doing (256x256)/(1x256) = 256x1
To fix this, you'll want to do min(min(image))

Related

How do I write a 3D histogram code without the Matlab built in functions?

I want to creat a histogram code, knowing that it'll be counting the number of occurence of 3 values of a pixel.
The idea is I have 3 matrices (L1im, L2im, L3im) representing information extracted from an image, size of each of them is 256*226, and I want to compute how many times a combination of let's say (52,6,40) occurs (each number correspends to a matrix/component but they're all of the same pixel).
I have tried this, but it doesn’t produce the right result:
for i = 1 : 256
for j = 1 : 256
for k = 1 : 256
if (L1im == i) & (L2im == j) & (L3im == k)
myhist(i,j,k)= myhist(i,j,k)+1;
end
end
end
end
Colour Triplets Histogram
Keeping in mind doing an entire RGB triplet histogram is a large task since you can have 256 × 256 × 256 = 16,777,216 combinations of possible unique colours. A slightly more manageable task I believe is to compute the histogram for the unique RGB values in the image (since the rest will be zero anyways). This is still a fairly large task but might be reasonable if the image is fairly small. Below I believe a decent alternative to binning is to resize the image to a smaller number of pixels. This can be done by using the imresize function. I believe this will decrease fidelity of the image and almost act as a rounding function which can "kinda" simulate the behaviour of binning. In this example I convert the matrices string arrays an concatenate the channels, L1im, L2im and L3im of the image. Below is a demo where I use the image built into MATLAB named saturn.png. A Resize_Factor
of 1 will result in the highest amount of bins and the number of bins will decrease as the Resize_Factor increases. Keep in mind that the histogram might require scaling if the image is being resized with the Resize_Factor.
Resize_Factor = 200;
RGB_Image = imread("saturn.png");
[Image_Height,Image_Width,Number_Of_Colour_Channels] = size(RGB_Image);
Number_Of_Pixels = Image_Height*Image_Width;
RGB_Image = imresize(RGB_Image,[Image_Height/Resize_Factor Image_Width/Resize_Factor]);
L1im = RGB_Image(:,:,1);
L2im = RGB_Image(:,:,2);
L3im = RGB_Image(:,:,3);
L1im_String = string(L1im);
L2im_String = string(L2im);
L3im_String = string(L3im);
RGB_Triplets = L1im_String + "," + L2im_String + "," + L3im_String;
Unique_RGB_Triplets = unique(RGB_Triplets);
for Colour_Index = 1: length(Unique_RGB_Triplets)
RGB_Colour = Unique_RGB_Triplets(Colour_Index);
Unique_RGB_Triplets(Colour_Index,2) = nnz(RGB_Colour == RGB_Triplets);
end
Counts = str2double(Unique_RGB_Triplets(:,2));
Scaling_Factor = Number_Of_Pixels/sum(Counts);
Counts = Counts.*Scaling_Factor;
if sum(Counts) == Number_Of_Pixels
disp("Sum of histogram is equal to the number of pixels");
end
bar(Counts);
title("RGB Triplet Histogram");
xlabel("RGB Triplets"); ylabel("Counts");
Current_Axis = gca;
Scale = (1:length(Unique_RGB_Triplets));
set(Current_Axis,'xtick',Scale,'xticklabel',Unique_RGB_Triplets);
Angle = 90;
xtickangle(Current_Axis,Angle);

How to count the number of occurrences of pixel intensities in an image without using for loop?

I am to writing a script for histogram equalisation and I need to work on each RGB plane separately. In the first step I count the number of occurrences of each intensity value in the range 0-255. As far as I know, using for loops makes MATLAB code super slow. This is what I came up with :
org_image = imread('image.jpg')
tot_pixel = size(org_image,1) * size(org_image,2)
R = org_image(:,:,1);
G = org_image(:,:,2);
B = org_image(:,:,3);
[R_val_ocurr,R_unique_val] = histcounts(R);
[G_val_ocurr,G_unique_val] = histcounts(G);
[B_val_ocurr,B_unique_val] = histcounts(B);
Now to have an array of size 256,with each index holding number of pixels corresponding to it what should my next step be? I'm trying to write down my logic :
for i = 0 to 255
if i is in R_unique_val
hist[i] = R_val_ocurr[i]
else
hist[i] = 0
How to correctly and efficiently write this in MATLAB?
after you have separete the channel you can use imhist to get the histogram of each channel:
[NumberOfPixelR, intensity] = imhist(R);
[NumberOfPixelG, intensity] = imhist(G);
[NumberOfPixelB, intensity] = imhist(B);

connected component analysis error

I'm trying to do connected component analysis.but I'm getting error. I need the vertebral body ;but I'm getting some other objects.
Image is:
Result is:
im= imread('im.bmp');
figure,imshow(im);
K1=imadjust(im);
figure, imshow(K1), title('After Adjustment Image')
threshold = graythresh(K1);
originalImage = im2bw(K1, threshold);
originalImage = bwareaopen(originalImage,100);
se = strel('disk', 2); %# structuring element
closeBW = imclose(originalImage,se);
figure,imshow(closeBW);
CC = bwconncomp(closeBW);
L = labelmatrix(CC);
L2 = bwlabel(K1);
figure, imshow(label2rgb(L));
Segmentation isn't my area, so I'm not sure what the best approach is. Here are a couple heuristic ideas I came up with:
Discard regions that are too big or too small.
It looks like you can expect a certain size from the vertebra.
regionIdxs = unique(L(:));
regionSizes = accumarray(L(:)+1,1);
If we look at regionSizes, we see the region sizes in pixels:
213360
919
887
810
601
695
14551
684
1515
414
749
128
173
26658
The regions you want (rows 2-6) are on the range 500-1000. We can probably safely discard regions that are <200 or >2000 in size.
goodRegionIdx = (regionSizes>200) & (regionSizes<2000);
regionIdxs = regionIdxs(goodRegionIdx);
regionSizes = regionSizes(goodRegionIdx);
Look at the image moments of the desired regions.
The eigenvalues of the covariance matrix of a distribution characterize its size in its widest direction and its size perpendicular to that direction. We are looking for fat disk-shapes, so we can expect a big eigenvalue and a medium-sized eigenvalue.
[X,Y] = meshgrid(1:size(L,2),1:size(L,1));
for i = 1:length(regionIdxs)
idx = regionIdxs(i);
region = L==idx;
totalmass = sum(region(:));
Ex(i) = sum( X(1,:).*sum(region,1) ) / totalmass;
Ey(i) = sum( Y(:,1).*sum(region,2)) / totalmass;
Exy(i) = sum(sum( X.*Y.*region )) / totalmass;
Exx(i) = sum(sum( X.*X.*region )) / totalmass;
Eyy(i) = sum(sum( Y.*Y.*region )) / totalmass;
Varx(i) = Exx(i) - Ex(i)^2;
Vary(i) = Eyy(i) - Ey(i)^2;
Varxy(i) = Exy(i) - Ex(i)*Ey(i);
Cov = [Varx(i) Varxy(i); Varxy(i) Vary(i)];
eig(i,:) = eigs(Cov);
end
If we look at the eigenvalues eig:
177.6943 30.8029
142.4484 35.9089
164.6374 26.2081
112.6501 22.7570
138.1674 24.1569
89.8082 58.8964
284.2280 96.9304
83.3226 15.9994
113.3122 33.7410
We are only interested in rows 1-5, which have eigenvalues on the range 100-200 for the largest and below 50 the the second. If we discard these, get the following regions:
goodRegionIdx = (eig(:,1)>100) & (eig(:,1)<200) & (eig(:,2)<50);
regionIdxs = regionIdxs(goodRegionIdx);
We can plot the regions by using logical OR |.
finalImage = false(size(L));
for i = 1:length(regionIdxs)
finalImage = finalImage | (L==regionIdxs(i) );
end
We seem to get one false positive. Looking at the ratio of the eigenvalues eig(:,1)./eig(:,2) is one idea but that seem to be a little problematic too.
You could try some sort of outlier detection like RANSAC to try and eliminate the region you don't want, since true vertebra tend to be spatially aligned along a line or curve.
I'm not sure what else to suggest. You may have to look into more advanced segmentation methods like machine learning if you can't find another way to discriminate the good from the bad. Having a stricter preprocessing method might be one thing to try.
Hope that helps.

Combine convolve filter in matlab

Is there a way to take the low pass and high pass filters in the following code and combine them into a single kernel and apply one conv2() function?
note: length(lfilter) = 21, length(hfilter) = 81.
what we are basically doing in the last step is saying to remove the large objects from the image (after already removing the very small objects with a Gaussian blur).
properties (Constant)
minStar = 2; % min star radius
maxStar = 8; % max star radius
threshold = 12;
end
function filter2(this)
normalize = #(x) x/sum(x);
lfilter = normalize(exp(-((-ceil(5*this.minStar):ceil(5*this.minStar))/(2*this.minStar)).^2));
hfilter = normalize(exp(-((-ceil(5*this.maxStar):ceil(5*this.maxStar))/(2*this.maxStar)).^2));
this.low = conv2(lfilter',lfilter,this.raw,'same');
this.high = conv2(hfilter',hfilter,this.raw,'same');
this.filtered = this.low - this.high;
this.foreground = this.filtered > this.threshold;
end
Since the convolution operator is associative:
conv( a, conv(b,c) ) == conv( conv(a,b), c )
you should be able to combine the two kernels into one just by convolving them with each other.
In your case something like this should work:
new_kernel = conv2(lfilter',lfilter, conv2(hfilter',hfilter), 'same');
Convolution is commutative as well so the order in which you perform the convolutions shouldn't matter.
EDIT: as I explain in the comment below, the asker's method of performing four 1D convolutions ends up being faster than a single 2D convolution.
I just got the answer in the matlab forums. http://www.mathworks.com/matlabcentral/answers/169713-combine-convolution-filters-bandpass-into-a-single-kernel
The gist is that you have to use padding to fill in both sides of the shorter filter, and then you can just combine the vectors.
Convolution is a linear operation so yes, you can combine the two filtering operations into one. Just make the filters the same size and add/subtract them. For example:
lfilter = normalize(exp(-((-ceil(5*minStar):ceil(5*minmax))/(2*this.minStar)).^2));
hfilter = normalize(exp(-((-ceil(5*maxStar):ceil(5*minmax))/(2*this.maxStar)).^2));
padlength = (length(hfilter) - length(lfilter))/2;
lfilter = padarray(lfilter, [0 padlength]);
lhfilter = lfilter - hfilter;
this.filtered = conv2(lhfilter',lhfilter,this.raw,'same');

sum of absolute differences of two images

I want to find how similar a picture is to some samples that I have (black and white).
I use the sum of absolute difference code, but because I'm new to MATLAB I didn't find out how to use it. How does this algorithm work? Does it give a measure of how similar the pics are?
I= imread('img1.jpg');
image2= imread('img2.jpg');
% J = uint8(filter2(fspecial('gaussian'), I));
K = imabsdiff(I,image2);
figure, imshow(K,[])
Well I think you pretty much answered your question yourself. It is the sum of the absolute difference. So let say you have img1 and img2 which are the same size and type.
To find the difference, do subtraction
img1-img2
To find the absolute difference, use the absolute value function abs
abs(img1-img2)
To find the sum, use the sum function. Note that you will need to do this for each "dimension" your image has. If you are not sure, type size(img1) and see if there are 2 or 3 numbers that show up, this corresponds to how many sum(...) you need to use.
For a color image (3 dimensions):
sum(sum(sum(abs(img1-img2))))
^^ Is the sum of the absolute differences. Whichever has the smallest sum can be considered the closest image.
If you have different sized images, you need to use the normxcorr2 function. This function will return a matrix of the same size with how well the template (small) image fits into the big image at each different point. Find the maximum value of that matrix and that is how well that image fits.
For instance:
correlation = normxcorr2(smallImg, bigImg);
compareMe = max(correlation(:))
It is best practice to use MATLAB's build-in function imabsdiff. In contrast to the other suggested answers, it takes care of the range boundaries if your image is formatted as uint8. Consider:
img1 = uint8(10);
img2 = uint8(20);
sum(abs(img1(:)-img2(:)))
gives you 0, whereas
imabsdiff(img1(:),img2(:))
correctly gives 10.
You should use the command im2col in MATLAB you will be able to do so in Vectorized manner.
Just arrange each neighborhood in columns (For each frame).
Put them in 3D Matrix and apply you operation on the 3rd dimension.
Code Snippet
I used Wikipedia's definition of "Sum of Absolute Differences".
The demo script:
```
% Sum of Absolute Differences Demo
numRows = 10;
numCols = 10;
refBlockRadius = 1;
refBlockLength = (2 * refBlockRadius) + 1;
mImgSrc = randi([0, 255], [numRows, numCols]);
mRefBlock = randi([0, 255], [refBlockLength, refBlockLength]);
mSumAbsDiff = SumAbsoluteDifferences(mImgSrc, mRefBlock);
```
The Function SumAbsoluteDifferences:
```
function [ mSumAbsDiff ] = SumAbsoluteDifferences( mInputImage, mRefBlock )
%UNTITLED2 Summary of this function goes here
% Detailed explanation goes here
numRows = size(mInputImage, 1);
numCols = size(mInputImage, 2);
blockLength = size(mRefBlock, 1);
blockRadius = (blockLength - 1) / 2;
mInputImagePadded = padarray(mInputImage, [blockRadius, blockRadius], 'replicate', 'both');
mBlockCol = im2col(mInputImagePadded, [blockLength, blockLength], 'sliding');
mSumAbsDiff = sum(abs(bsxfun(#minus, mBlockCol, mRefBlock(:))));
mSumAbsDiff = col2im(mSumAbsDiff, [blockLength, blockLength], [(numRows + blockLength - 1), (numCols + blockLength - 1)]);
end
```
Enjoy...