I'm trying to do a vertical histogram of a binary image. I don't want to use MATLAB's functions. How to do it?
I have tried this code but I don't know if it's correct or not:
function H = histogram_binary(image)
[m,n] = size(image);
H = zeros(1,256);
for i = 1:m
for j = 1:n
H(1,image(i,j)) = H(1,image(i,j))+1;
end
end
The image is:
The result:
Why can't I see the value of black pixels in the histogram?
% Read the binary image...
img = imread('66He7.png');
% Count total, white and black pixels...
img_vec = img(:);
total = numel(img_vec);
white = sum(img_vec);
black = total - white;
% Plot the result in the form of an histogram...
bar([black white]);
set(gca(),'XTickLabel',{'Black' 'White'});
set(gca(),'YLim',[0 total]);
Output:
For what concerns your code, it is not counting black pixels since they have a value of 0 and your loop start from 1... rewrite it as follows:
function H = histogram_binary(img)
img_vec = img(:);
H = zeros(1,256);
for i = 0:255
H(i+1) = sum(img_vec == i);
end
end
But keep in mind that counting all the byte occurrences on a binary image (that can only contain 0 or 1 values) is kinda pointless and will make your histogram lack readability. On a side note, avoid using image as a variable name, since this would override an existing function.
As mentioned by #beaker in the comments above, vertical histogram in such cases generally refers to a vertical projection. Here is a way to do this :
I = imread('YcP1o.png'); % Read input image
I1 = rgb2gray(I); % convert image to grayscale
I2 = im2bw(I1); % convert grayscale to binary
I3 = ~I2; % invert the binary image
I4 = sum(I3,1); % project the inverted binary image vertically
I5 = (I4>1); % ceil the vector
plot([1:1:size(I,2)],I5); ylim([0 2])
You can further check for 0->1 transitions to count the number of characters using sum(diff(I5)>0) which gives 13 as answer in this case.
Related
I've been working on bilinear interpolation based on wiki example in matlab. I followed the example to the T, but when comparing the outputs from my function and the in-built matlab function, the results are vastly different and I can't figure out why or how that happens.
Using inbuilt matlab function:
Result of my function below:
function T = bilinear(X,h,w)
%pre-allocating the output size
T = uint8(zeros(h,w));
%padding the original image with 0 so i don't go out of bounds
X = padarray(X,[2,2],'both');
%calculating dimension ratios
hr = h/size(X,1);
wr = w/size(X,2);
for row = 3:h-3
for col = 3:w-3
%for calculating equivalent position on the original image
o_row = ceil(row/hr);
o_col = ceil(col/wr);
%getting the intensity values from horizontal neighbors
Q12=X(o_row+1,o_col-1);
Q22=X(o_row+1,o_col+1);
Q11=X(o_row-1,o_col-1);
Q21=X(o_row-1,o_col+1);
%calculating the relative positions to the enlarged image
y2=round((o_row-1)*hr);
y=round(o_row*hr);
y1=round((o_row+1)*hr);
x1=round((o_col-1)*wr);
x=round(o_col*wr);
x2=round((o_col+1)*wr);
%interpolating on 2 first axis and the result between them
R1=((x2-x)/(x2-x1))*Q11+((x-x1)/(x2-x1))*Q21;
R2=((x2-x)/(x2-x1))*Q12+((x-x1)/(x2-x1))*Q22;
P=round(((y2-y)/(y2-y1))*R1+((y-y1)/(y2-y1))*R2);
T(row,col) = P;
T = uint8(T);
end
end
end
The arguments passed to the function are step4 = bilinear(Igray,1668,1836); (scale factor of 3).
You are finding the pixel nearest to the point you want to interpolate, then find 4 of this pixel’s neighbors and interpolate between them:
o_row = ceil(row/hr);
o_col = ceil(col/wr);
Q12=X(o_row+1,o_col-1);
Q22=X(o_row+1,o_col+1);
Q11=X(o_row-1,o_col-1);
Q21=X(o_row-1,o_col+1);
Instead, find the 4 pixels nearest the point you want to interpolate:
o_row = ceil(row/hr);
o_col = ceil(col/wr);
Q12=X(o_row,o_col-1);
Q22=X(o_row,o_col);
Q11=X(o_row-1,o_col-1);
Q21=X(o_row-1,o_col);
The same pixel’s coordinates then need to be used when computing distances. The easiest way to do that is to separate out the floating-point coordinates of the output pixel ((row,col)) in the input image (o_row,o_col), and the location of the nearest pixel in the input image (fo_row,fo_col). Then, the distances are simply d_row = o_row - fo_row and 1-d_row, etc.
This is how I would write this function:
function T = bilinear(X,h,w)
% Pre-allocating the output size
T = zeros(h,w,'uint8'); % Create the matrix in the right type, rather than cast !!
% Calculating dimension ratios
hr = h/size(X,1); % Not with the padded sizes!!
wr = w/size(X,2);
% Padding the original image with 0 so I don't go out of bounds
pad = 2;
X = padarray(X,[pad,pad],'both');
% Loop
for col = 1:w % Looping over the row in the inner loop is faster!!
for row = 1:h
% For calculating equivalent position on the original image
o_row = row/hr;
o_col = col/wr;
fo_row = floor(o_row); % Code is simpler when using floor here !!
fo_col = floor(o_col);
% Getting the intensity values from horizontal neighbors
Q11 = double(X(fo_row +pad, fo_col +pad)); % Indexing taking padding into account !!
Q21 = double(X(fo_row+1+pad, fo_col +pad)); % Casting to double might not be necessary, but MATLAB does weird things with integer computation !!
Q12 = double(X(fo_row +pad, fo_col+1+pad));
Q22 = double(X(fo_row+1+pad, fo_col+1+pad));
% Calculating the relative positions to the enlarged image
d_row = o_row - fo_row;
d_col = o_col - fo_col;
% Interpolating on 2 first axis and the result between them
R1 = (1-d_row)*Q11 + d_row*Q21;
R2 = (1-d_row)*Q12 + d_row*Q22;
T(row,col) = round((1-d_col)*R1 + d_col*R2);
end
end
end
I trying to create my own nearest neighbor interpolation algorithm in Matlab to enlarge an image of 556×612 to 1668×1836.
This is homework!!!
I have attempted this already but encounter the error where the values inside M gets (not all but most) transformed to 255 (White Space), and I cannot get my head around why. Any help would be appreciated! The picture is a picture of a zebra.
%Take in image and convert to greyscale
I = imread('Zebra.jpg');
Igray = rgb2gray(I);
% Step-3: Resize the image to enlarged 1668x1836 by interpolation
% Step-3(a) : Using nearest neighbour
%First we will need to work out the dimension of the image
[j , k] = size(Igray);
%Now we need to set the size of the image we want
NewX = 1836;
NewY = 1668;
% Work out ratio of old to new
ScaleX = NewX./(j-1);
ScaleY = NewY./(k-1);
%Image Buffer
M = zeros(NewX, NewY);
%Create output image
for count1 = 1:NewX
for count2 = 1:NewY
M(count1,count2) = Igray(1+round(count1./ScaleX),1+round(count2./ScaleY));
end
end
%Show Images
imshow(M);
title('Scaled Image NN');
try imshow(M,[]). You created M without specifying type, which makes it double. double images are [0-1], so imshow by default makes white everything with higher value than 1.
Alternatively, create M to be uint8 as the original image
M = zeros(NewX, NewY,'uint8');
even better code would be:
M = zeros(NewX, NewY,class(Igray));
I have this MATLab code to count the number of objects in the image. There are two objects in the image I am choosing (a car and a cyclist). However, the program is returning a wrong output saying there are 0 objects. Can someone find the error in the code? Thanks.
The logic behind the code is:
1. Take two input images are given, one without objects and one with objects.
2. Convert the input images from RGB to Gray scale.
3. Compare the two images and find the difference.
4. Convert the image obtained to binary.
5. In the image, only open the blobs whose area is greater than 4000.
6. Display the count and density.
clc;
MV = imread('car.png'); %To read image
MV1 = imread('backgnd.png');
A = double(rgb2gray(MV)); %convert to gray
B= double(rgb2gray(MV1)); %convert 2nd image to gray
[height, width] = size(A); %image size?
h1 = figure(1);
%Foreground Detection
thresh=11;
fr_diff = abs(A-B);
for j = 1:width
for k = 1:height
if (fr_diff(k,j)>thresh)
fg(k,j) = A(k,j);
else
fg(k,j) = 0;
end
end
end
subplot(2,2,1) , imagesc(MV), title ({'Orignal Frame'});
subplot(2,2,2) , imshow(mat2gray(A)), title ('converted Frame');
subplot(2,2,3) , imshow(mat2gray(B)), title ('BACKGND Frame ');
sd=imadjust(fg); % adjust the image intensity values to the color map
level=graythresh(sd);
m=imnoise(sd,'gaussian',0,0.025); % apply Gaussian noise
k=wiener2(m,[5,5]); %filtering using Weiner filter
bw=im2bw(k,level);
bw2=imfill(bw,'holes');
bw3 = bwareaopen(bw2,5000);
labeled = bwlabel(bw3,8);
cc=bwconncomp(bw3);
Densityoftraffic = cc.NumObjects/(size(bw3,1)*size(bw3,2));
blobMeasurements = regionprops(labeled,'all');
numberofcars = size(blobMeasurements, 1);
subplot(2,2,4) , imagesc(labeled), title ({'Foreground'});
hold off;
disp(numberofcars); % display number of cars
disp(Densityoftraffic); %display number of vehicles
An empty image(of a road) with no objects(vehicles) in it
An image of the same road but with 2 objects(car and cyclist) in it
Try This it will help you in an optimize manner
clc
clear all
close all
im1 = imread('image1.png');
im2 = imread('image2.png');
gray1 = double(rgb2gray(im1));
gray2 = double(rgb2gray(im2));
absDif = mat2gray(abs(gray1 - gray2));
figure,imshow(absDif,[])
absDfbw = im2bw(absDif,0.9*graythresh(absDif));
figure,imshow(absDfbw,[])
absDfbw = bwareaopen(absDfbw,25);
absDfbw = imclose(absDfbw,strel('disk',5));
figure,imshow(absDfbw,[])
Results are:
Thank You
I'm currently using code:
i = imread('/usr/share/icons/matlab.png');
for k=1:1:m
for l=1:1:n
%a(k,l)=m*n;
a(k,l) = (.299*i(k,l,1))+(.587*i(k,l,2))+(.114*i(k,l,3));
end
end
imshow(a);
It shows only a white screen. Also the newly generated dimensions are n x m x 3 whereas it should be only m x n x 1.
If I use mat2gray it display the image like this
Since the image is a PNG, imread() is returning an integer image, with intensity values in the range [0 255] or equivalent, depending on the original bit depth. The conversion formula makes a a double image, which is expected to have intensities in the range [0 1]. Since all the pixel values in a are probably much greater than 1, they get clipped to 1 (white) by imshow().
The best option is to explicitly convert the image format before you start - this will take care of scaling things correctly:
i = imread('/usr/share/icons/matlab.png');
i = im2double(i);
a = .299*i(:,:,1) + .587*i(:,:,2) + .114*i(:,:,3); % no need for loops
imshow(a);
input=imread('test.jpg');
subplot(1,2,1), imshow(input), title('RGB Scale image');
[x,y,~] = size(input);
for i = 1:1:x
for j = 1:1:y
output(i,j) = 0.40*input(i,j,1) + 0.50*input(i,j,2) + 0.30*input(i,j,3);
end
end
subplot(1,2,2), imshow(output), title('Gray Scale image');
I posted another question about the Roberts operator, but I decided to post a new one since my code has changed significantly since that time.
My code runs, but it does not generate the correct image, instead the image becomes slightly brighter.
I have not found a mistake in the algorithm, but I know this is not the correct output. If I compare this program's output to edge(<image matrix>,'roberts',<threshold>);, or to images on wikipedia, it looks nothing like the effect of the roberts operator shown there.
code:
function [] = Robertize(filename)
Img = imread(filename);
NewImg = Img;
SI = size(Img);
I_W = SI(2)
I_H = SI(1)
Robertsx = [1,0;0,-1];
Robertsy = [0,-1;1,0];
M_W = 2; % do not need the + 1, I assume the for loop means while <less than or equal to>
% x and y are reversed...
for y=1 : I_H
for x=1 : I_W
S = 0;
for M_Y = 1 : M_W
for M_X = 1 : M_W
if (x + M_X - 1 < 1) || (x + M_X - 1 > I_W)
S = 0;
%disp('out of range, x');
continue
end
if (y + M_Y - 1 < 1) || (y + M_Y - 1 > I_H)
S = 0;
%disp('out of range, y');
continue
end
S = S + Img(y + M_Y - 1 , x + M_X - 1) * Robertsx(M_Y,M_X);
S = S + Img(y + M_Y - 1, x + M_X - 1) * Robertsy(M_Y,M_X);
% It is y + M_Y - 1 because you multiply Robertsx(1,1) *
% Img(y,x).
end
end
NewImg(y,x) = S;
end
end
imwrite(NewImg,'Roberts.bmp');
end
I think you may be misinterpreting how the Roberts Cross operator works. Use this page as a guide. Notice that it states that you convolve the original image separately with the X and Y operator. Then, you may calculate the final gradient (i.e. "total edge content") value by taking the square root of the sum of squares of the two (x and y) gradient values for a particular pixel. You're presently summing the x and y values into a single image, which will not give the correct results.
EDIT
I'll try to explain a bit better. The problem with summation instead of squaring/square root is that you can end up with negative values. Negative values are natural using this operator depending on the edge orientation. That may be why you think the image 'lightens' -- because when you display the image in MATLAB the negative values go to black, the zero values go to grey, and the positive values go to white. Here's the image I get when I run your code (with a few changes -- mostly setting NewImg to be zeros(size(Img)) so it's a double type instead of uint8. uint8 types don't allow negative values... Here's the image I get:.
You have to be very careful when trying to save files as well. Instead of calling imwrite, call imshow(NewImg,[]). That will automatically rescale the values in the double-valued image to show them correctly, with the most negative number being equal to black and most positive equal to white. Thus, in areas with little edge content (like the sky), we would expect grey and that's what we get!
I ran your code and got the effect you described. See how everything looks lighter:
Figure 1 - Original on the left, original roberts transformation on the right
The image on my system was actually saturated. My image was uint8 and the operations were pushing the image past 255 or under 0 (for the negative side) and everything became lighter.
By changing the line of code in the imread to convert to double as in
Img = double(rgb2gray( imread(filename)));
(note my image was color so I did an rgb conversion, too. You might use
Img = double(( imread(filename)));
I got the improved image:
Original on left, corrected code on right.
Note that I could also produce this result using 2d convolution rather than your loop:
Robertsx = [1,0;0,-1];
Robertsy = [0,-1;1,0];
dataR = conv2(data, Robertsx) + conv2(data, Robertsy);
figure(2);
imagesc(dataR);
colormap gray
axis image
For the following result:
Here is an example implementation. You could easily replace CONV2/IMFILTER with your own 2D convolution/correlation function:
%# convolve image with Roberts kernels
I = im2double(imread('lena512_gray.jpg')); %# double image, range [0,1]
hx = [+1 0;0 -1]; hy = [0 +1;-1 0];
%#Gx = conv2(I,hx);
%#Gy = conv2(I,hy);
Gx = imfilter(I,hx,'conv','same','replicate');
Gy = imfilter(I,hy,'conv','same','replicate');
%# gradient approximation
G = sqrt(Gx.^2+Gy.^2);
figure, imshow(G), colormap(gray), title('Gradient magnitude [0,1]')
%# direction of the gradient
Gdir = atan2(Gy,Gx);
figure, imshow(Gdir,[]), title('Gradient direction [-\pi,\pi]')
colormap(hot), colorbar%, caxis([-pi pi])
%# quiver plot
ySteps = 1:8:size(I,1);
xSteps = 1:8:size(I,2);
[X,Y] = meshgrid(xSteps,ySteps);
figure, imshow(G,[]), hold on
quiver(X, Y, Gx(ySteps,xSteps), Gy(ySteps,xSteps), 3)
axis image, hold off
%# binarize gradient, and compare against MATLAB EDGE function
BW = im2bw(G.^2, 6*mean(G(:).^2));
figure
subplot(121), imshow(BW)
subplot(122), imshow(edge(I,'roberts')) %# performs additional thinning step