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

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);

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);

copying an NxN matrix into page of NxNxN matrix

Ridiculously simple question, but I'd like to get it right: Working in MATLAB, I'm trying to take an NxN matrix and copy it N times to fill an NxNxN matrix. My code executes, but the variable "threeD" is left unchanged after the loop finishes. Also, I'm imagining a loop is not the best way to do this, although I have nothing against it in principle. Thanks in advance!
reps = 64;
gradient = (1:reps);
pattern = repmat(gradient,reps,1);
threeD = zeros(reps,reps,reps);
for c = reps
threeD(:,:,c) = pattern;
end
Method 1: Using Loops
The for-loop needed to loop from 1 to reps which is indicated by 1:reps.
reps = 64;
gradient = (1:reps);
pattern = repmat(gradient,reps,1);
threeD = zeros(reps,reps,reps);
for Layer = 1: reps
threeD(:,:,Layer) = pattern;
end
Method 2: Using Repmat to Replicate Along the Third Dimension
The second argument in repmat(), the array [1 1 reps] indicates how mnay times to replicate the array along the [row column layer]/[x y z] dimensions.
reps = 64;
gradient = (1:reps);
pattern = repmat(gradient,reps,1);
threeD = repmat(pattern,[1 1 reps]);
Using MATLAB version: R2019b

Downsizing and rescaling an image using for loops

I'm relatively new to Matlab, and trying to understand why a piece of code isn't working.
I have a 512x512 image that needs to be downsized to 256, and then resized back up to 512.
How I understand the mathematics, is that I would need to mean the pixels in the image to get the 256, and then sum them back to get the 512. Is that correct ? Following is the code that I'm looking at, and if someone can explain me whats wrong(its giving a blank white image), I would appreciate it:
w = double(imread('walkbridge.tif'));
%read the image
w = w(:,:,1);
for x = 1:256
for y = 1:256
s256(x,y) = (w(2*x,2*y)+ w(2*x,(2*y)-1) + w((2*x)-1,2*y)+ w((2*x)-1,(2*y)-1))/4;
end
end
for x = 1 : 256
for y = 1 : 256
for x1 = 0:1
for y1 = 0:1
R1((2*x)-x1,((2*y)-y1)) = s256(x,y);
end
end
end
end
imshow(R1)
I got your code to work, so you might have some bad values in your image data. Namely, if your image has values in range 0..127 or something similar, it will most likely show as all white. By default, imshow expects color channels to be in range 0..1.
You might also want to simplify your code a bit by indexing the original array instead of accessing individual elements. That way the code is even easy to change:
half_size = 256;
w = magic(2*half_size);
w = w / max(w(:));
figure()
imshow(w)
s = zeros(half_size);
for x = 1:half_size
for y = 1:half_size
ix = w(2*x-1:2*x, 2*y-1:2*y);
s(x,y) = sum(ix(:))/4;
end
end
for x = 1:half_size
for y = 1:half_size
R1(2*x-1:2*x, 2*y-1:2*y) = s(x,y);
end
end
figure()
imshow(R1)
I imagine the calculations could even be vectorised in some way instead of looping, but I didn't bother.

Normalization of an image dataset after processing

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))

Oblique stripes resulting from bilinear interpolation

I'm trying to write a function in GNU Octave that does bilinear interpolation on a PGM image. The result isn't that great: I keep getting oblique stripes of different shades all over the image. Also, the rows and columns that are added during interpolation are darker than they should. Could someone help me by pointing out the problem, please?
function bilinear(img)
data = imread(img);
for n = 1 : 2 : (rows(data) - 1) * 2
average = average_vector(data(n, 1:end), data(n+1:1:end));
data = [data(1:n, 1:end); average; data(n+1:rows(data), 1:end)];
end
for n = 1 : 2 : (columns(data) - 1) * 2
average = average_vector(data(1:rows(data), n), data(1:rows(data), n+1));
data = [data(1:rows(data), 1:n) average data(1:rows(data), n+1:end)];
end
imwrite(data, strcat("out_bilinear_", img));
end
function res = average_vector(a, b)
res = zeros(size(a));
for n = 1 : length(a)
res(n) = (a(n) + b(n)) / 2;
end
end
Here's an image showing the problem:
You're iterating through the input image row-by-row (or column-by-column), but inserting new rows (or columns) as you go. I'm pretty sure this will screw your indexing up.
I would suggest creating a new output matrix, rather than modifying the original. This will be considerably faster, too.
Incidentally, your average_vector function can be written simply as res = (a + b) / 2;.