Local thresholding in MATLAB - matlab

I am trying to implement local thresholding in MATLAB 7.7. This is what my original image looks like:
As seen the the word Test is covered in black. This image is a PNG image having dimensions 919x551. I want to apply local thresholding to this image so that I can get the word Test to be visible clearly.
I have implemented the following code that works by dividing the entire image into sub images of 60*60 blocks.
However, when I am doing so, I am not getting the desired output.
My code:
clc;
clear all;
close all;
im = imread('C:\samples\test100.png');
subplot(3,3,1);
imshow(im);
title('original image');
im = rgb2gray(im);
im = double(im);
subplot(3,3,2);
imshow(im);
title('gray scale image');
[row col] = size(im);
max_im = max(max(im));
h = zeros(1,max_im+1);
!1st block
for n = 1:1:60
for m = 1:1:60
a(n,m) = im(n,m);
end
end
a = a+1;
for n = 1:1:60
for m = 1:1:60
t = a(n,m);
h(t) = h(t)+1;
end
end
subplot(3,3,3);
bar(h)
[X,Y] = ginput(1);
for n = 1:1:60
for m = 1:1:60
if a(n,m)<X
a(n,m) = 0;
else
a(n,m) = 255;
end
end
end
subplot(3,3,4);
imshow(uint8(a))
title('1st block image');
!2nd block
for n = 1:1:60
for m = 61:1:60
b(n,m-60) = im(n,m)
end
end
b = b+1;
for n = 1:1:60
for m = 1:1:60
t = b(n,m);
h(t) = h(t)+1;
end
end
figure(2)
bar(h)
[X,Y] = ginput(1);
for n = 1:1:60
if b(n,m)<X
b(n,m) = 0;
else
b(n,m) = 255;
end
end
imshow(uint8(b))
!3rd block
for n = 61:1:120
for m = 1:1:60
c(n-60,m) = im(n,m);
end
end
c = c+1;
for n = 1:1:60
for m = 1:1:60
t = c(n,m);
h(t) = h(t)+1;
end
end
figure(3)
bar(h)
[X,Y] = ginput(1);
for n = 1:1:60
for m = 1:1:60
if c(n,m)< X
c(n,m) = 0;
else
c(n,m) = 255;
end
end
end
imshow(uint8(c))
!final block
for n = 1:1:row
for m = 61:1:col
d(n-60,m-60) = im(n,m);
end
end
d = d+1;
for n = 1:1:60
for m = 1:1:60
t = d(n,m);
h(t) = h(t)+1;
end
end
figure(4);
bar(h);
[X,Y] = ginput(1);
for n = 1:1:60
for m = 1:1:60
if d(n,m)<X
d(n,m) = 0;
else
d(n,m) = 255;
end
end
end
imshow(uint8(d))
s = [a b;c d];
figure(5);
imshow(uint(s))
When I try to run the entire code I get an error as:
??? Undefined function or method 'local' for input arguments of type 'char'
However, when I run only the code for the 1st block I get the following output.
How will I get the word Test visible by creating sub-images and then merging them together?

You can scan the greyscale image horizontally and then find the position of non-zero (or above the threshold) values and set that interval to be filled with white (256 or 1 if using im2double).
for j=1:551
row = im(:,j)
test = 0;
im2=zeros(size(im))
i=0;
%Left black area
while (test == 0 && i<919)
im2(i,j)=0;
if row(i)>threshold
test=1;
end;
i=i+1;
end;
%White inner area
while (test == 1 && i<919)
im2(i,j)=1
if row(i)>threshold
test=0;
end;
i=i+1;
end;
%Left black area
while (i<919)
im2(i,j)=0;
i=i+1;
end;
This doesn't work with letters that have an empty area (such as 'p'), but you can modify the code a little to do that.

Related

Use a variable outside the function in matlab

I've written the following function:
% This function plots the contours of likelihood values on the scatter plot of a 2 dimensional data.
function [xgrid,ygrid,Z,xy_matrix] = biVariateContourPlotsGMMCopula(givenData,gmmObject,~,numMeshPoints,x_dim,y_dim)
%INPUT: givenData (MxN, M=number of points, N=Dimension)
% : plo = binary variable (1 plot contour plot, 0 do not plot)
%OUTPUT: xgrid,ygrid,Z ( Z contains the likelihood values of the points defined by xgrid and ygrid)
%load general_info;
d = 2;
if nargin < 5
x_dim = 1;
y_dim = 2;
end
if x_dim == y_dim
hist(givenData(:,x_dim),10);
return;
end
numMeshPoints = min(numMeshPoints,256);
givenData = givenData(:,[x_dim y_dim]);
alpha = gmmObject.alpha;
mu = gmmObject.mu(:,[x_dim y_dim]);
sigma = gmmObject.sigma([x_dim y_dim],[x_dim y_dim],:) + 0.005*repmat(eye(d),[1 1 numel(alpha)]);
gmmObject = gmdistribution(mu,sigma,alpha);
bin_num = 256;
for j = 1:2
l_limit = min(gmmObject.mu(:,j))-3*(max(gmmObject.Sigma(j,j,:))^0.5);
u_limit = max(gmmObject.mu(:,j))+3*(max(gmmObject.Sigma(j,j,:))^0.5);
xmesh_inverse_space{j} = (l_limit:(u_limit-l_limit)/(bin_num-1):u_limit);
end
%if isempty(xmesh)||isempty(pdensity)||isempty(cdensity)
% Following for loop does the non-parameteric estimation of marginal % densities if not provided
for i = 1:d
currentVar = givenData(:,i);
[~,pdensity{i},xmesh{i}]=kde(currentVar,numMeshPoints);
pdensity{i}(pdensity{i}<0) = 0;
cdensity{i} = cumsum(pdensity{i});
cdensity{i} = (cdensity{i}-min(cdensity{i}))/(max(cdensity{i})-min(cdensity{i})); % scaling the cdensity value to be between [0 1]
end
[xgrid,ygrid] = meshgrid(xmesh{1}(2:end-1),xmesh{2}(2:end-1));
for k = 1:d
marginalLogLikelihood_grid{k} = log(pdensity{k}(2:end-1)+eps);
marginalCDFValues_grid{k} = cdensity{k}(2:end-1);
end
[marg1,marg2] = meshgrid(marginalLogLikelihood_grid{1},marginalLogLikelihood_grid{2});
[xg,yg] = meshgrid(marginalCDFValues_grid{1},marginalCDFValues_grid{2});
inputMatrix = [reshape(xg,numel(xg),1) reshape(yg,numel(yg),1)];
clear xg yg;
copulaLogLikelihoodVals = gmmCopulaPDF(inputMatrix,gmmObject,xmesh_inverse_space);
Z = reshape(copulaLogLikelihoodVals,size(marg1,1),size(marg1,2));
Z = Z+marg1+marg2;
Z = exp(Z);
% Getting the likelihood value from the log-likelihood
plot(givenData(:,1),givenData(:,2),'b.','MarkerSize',5);hold
[~,h] = contour(xgrid,ygrid,Z,[4e-6,4e-6]);
% Extract the (x, y) coordinates of the contour and concatenate them along the first dimension
xy_matrix = [];
for i = 1:length(h)
xy = get(h(i), 'XData');
x = xy(1, :);
y = xy(2, :);
xy_matrix = [xy_matrix, [x; y]];
end
% Print the concatenated matrix
disp(xy_matrix);
%title_string = ['GMCM fit (Log-Likelihood = ',num2str(logLikelihoodVal), ')'];
%title(title_string,'FontSize',12,'FontWeight','demi');
axis tight
however xy_matrix is not shown on the workspace.
How do I return the variable xy_matrix so that I can use it in another function?
Function call is inside a for loop as in below:
for i = 1:d
for j = 1:d
subplot(d,d,count); count = count+1;
[xgrid,ygrid,Z,xy_matrix] = biVariateContourPlotsGMMCopula(power_curve_reference_build_T2,gmcObject_bestfit,0,256,i,j);
end
end
So, when I'm including xy_matrix as a params in the function call, it generates the following error:
Have I missed anything here?
When you're calling the function with i==j==1 as parameters x_dim and y_dim, the function ends in the following if:
if x_dim == y_dim
hist(givenData(:,x_dim),10);
return;
end
The return values aren't defined at that point. If you define them in the beginning of the function, you won't get the error message.
function [xgrid,ygrid,Z,xy_matrix] = biVariateContourPlotsGMMCopula(givenData,gmmObject,~,numMeshPoints,x_dim,y_dim)
%INPUT: givenData (MxN, M=number of points, N=Dimension)
% : plo = binary variable (1 plot contour plot, 0 do not plot)
%OUTPUT: xgrid,ygrid,Z ( Z contains the likelihood values of the points defined by xgrid and ygrid)
%load general_info;
xgrid=0;
ygrid=0;
Z=0;
xy_matrix=0;
d = 2;
if nargin < 5
x_dim = 1;
y_dim = 2;
end
Below is a suggestion of some changes of your function call. The return values are saved in cells so that you don't overwrite them in the next iteration. The function is also not called when i==j==x_dim==y_dim.
xgrids={};
ygrids={};
Zs={};
xy_matrices={};
for i = 1:d
for j = 1:d
if i~=j
subplot(d,d,count); count = count+1;
[xgrids{i,j},ygrids{i,j},Zs{i,j},xy_matrices{i,j}] = biVariateContourPlotsGMMCopula(power_curve_reference_build_T2,gmcObject_bestfit,0,256,i,j);
end
end
end

generate a matrix image after having all the balck pixel's coordinates with MatLab

I have an Image, converted into binary, i got all the black pixel's coordinates.
The 'matrix' contains the x and y coordinates arranged by columns.
Now i Need to make a Simulation, to see if my Programme works.
I have to generate an Matrix Image with my results.
im=imread('square.jpg');
imshow(im); c=im2bw(im); figure; imshow(c);
dim = size(c) % size of the image
x = [];
y = [];
xdif = [];
newx = [];
matrix = [];
for i = 1:dim(1)
for j = 1:dim(2)
if c(i,j)==0;
x = [x i];
y = [y j];
end
end
end
% show black pixel's coordinates
p = [x;y];
%number of pixels
nr = length(x)
dimp = size(p);
xval = p(1,:);
yval = p(2,:);
j=1;
i=1;
for z = 1:dimp(2)-1
xdif = xval(z+1)-xval(z);
ff=find(xdif > 0);
if ff == 1
i = 1;
else
i=i+1;
end
newx(i,j)= xval(z);
newy(i,j)= yval(z);
if ff == 1
j= j+1;
end
end
xsize = size(newx);
ysize = size(newy);
matrix_size = xsize(2)+ysize(2)
xinc = 1;
yinc = 1;
x=1;
for ct = 1:1:matrix_size/2
x;
matrix(:,x) = newx(:,xinc);
matrix(:,x+1) = newy(:,yinc);
matrix;
xinc = xinc+1;
yinc = yinc+1;
x=x+3;
end
matrix
this is my Programme, now i need to make a simulation, by generating an image with my coordinates.
how can i do that?
thank's

matlab, user inputs a matrix into variable

I have this code for matlab to multiply matrixes how di i make the user add the matrixes and then use the matrixes in the code?
eg [n,m] = input(user inputs matrix here)
[n,m] = size(A);
[p,q] = size(B);
C = zeros(n,p);
if p~=m
error('Inner Matrix Dimensions Must Agree.')
end
for k = 1:n
for j = 1:q
temp=0;
for i = 1:p
temp = temp+(A(k,i)*B(i,j));
end
C(k,j) = temp;
end
end
You can use in the script:
A = input('input array A ');
B = input('input array B ');
[n,m] = size(A);
[p,q] = size(B);
C = zeros(n,p);
if p~=m
error('Inner Matrix Dimensions Must Agree.')
end
for k = 1:n
for j = 1:q
temp=0;
for i = 1:p
temp = temp+(A(k,i)*B(i,j));
end
C(k,j) = temp;
end
end
or you can write the above as a function:
function C = matrixmultiply(A,B)
[n,m] = size(A);
[p,q] = size(B);
C = zeros(n,p);
if p~=m
error('Inner Matrix Dimensions Must Agree.')
end
for k = 1:n
for j = 1:q
temp=0;
for i = 1:p
temp = temp+(A(k,i)*B(i,j));
end
C(k,j) = temp;
end
end
end

Changing the order in for-loop

I have a matrix (with the size of A and B; suppose 100x100) and want to fill in with smaller matrix (or block) with the size of a and b (suppose 12x12).
As it is clear, the loop starts from "j" and then goes to the next row. Actually I want to use the same loop, by adding another variable to impose that it first complete the columns. Any idea that how I should define this new variable in the following loop to control the completion direction.
M = zeros(100,100);
for j = 1:12:100-12+1
for i = 1:12:100-12+1
block = rand(12,12);
M(i:i+11, j:j+11) = block;
imagesc(M); axis equal tight xy
pause(.1)
end;
end;
Why not just do
M = zeros(100,100);
for j = 1:12:100-12+1
for i = 1:12:100-12+1
block = rand(12,12);
M(i:i+11, j:j+11) = block;
imagesc(M); axis equal tight xy
pause(.1)
end;
end;
Now you will iterate over the i's first.
Incidentally, I recommend not using i and j as loop variables - they shadow the built in sqrt(-1) imaginary number...
update based on your comment, it seems you want to leave the order of i and j in the outer loop, and add "another parameter" to change the direction. The following code does all that. Is this what you are after?
M = zeros(100,100);
rowFirst = true; % set to false for "column first"
for i = 1:12:100-12+1
for j = 1:12:100-12+1
block = rand(12,12);
if rowFirst
M((0:11) + i, (0:11) + j) = block;
else
M((0:11) + j, (0:11) + i) = block;
end
imagesc(M); axis equal tight xy
pause(.1)
end
end
update 2 and now "even for non square matrix" (not tested, late at night):
M = zeros(100, 120);
rowFirst = true;
sz = size(M);
blockSize = 12;
v = 1:blockSize;
nrc = floor(sz / blockSize);
if rowFirst
nrc = reverse(nrc);
end
for ii = blockSize * (0:nrc(1)-1)
for jj = blockSize * (0:nrc(2)-1)
block = rand(blockSize*[1 1]);
if ~rowFirst
block = block';
end if
M(v + ii, v+jj) = block;
if rowFirst
imagesc(M);
else
imagesc(M');
end
axis equal tight xy
pause(0.1)
end
end
LAST TIME if you insist that the outer loop iterates over j and the inner loop over i, yet that in some instances j is the "faster moving" variable, you can do the following.
P = 120;
Q = 180;
M = zeros(P, Q); % not a square matrix
rowFirst = true; % a switch you can flip
blockSize = 15; % size of block
sz = floor(size(M)/blockSize); % number of iterations in j, i
nr = sz(1); nc = sz(2);
vv = 1:blockSize;
for jj = 0: (nc-1)
for ii = 0: (nr-1)
if(rowFirst)
kk = ii * blockSize;
ll = jj * blockSize;
else
nn = jj * nr + ii;
ll = mod(nn, nc);
kk = floor(nn / nc);
%ll = (nn - kk * nc);
fprintf(1, 'ii, jj, nn = [%d, %d, %d]: [kk, ll] = %d, %d\n', ii, jj, nn, kk, ll)
ll = ll * blockSize; kk = kk * blockSize;
% mod(nn, P);
end
M(kk+vv, ll+vv) = rand(blockSize*[1 1]);
imagesc(M);
axis tight equal xy;
pause(0.1);
end
end

Average filter in matlab

I'm trying to compute the average of every pixel with just the left and right neighbors but at the end of my processing I get only a white image, I can't find where my error. Here's my code
imageIn = imread('Prueba.jpg');
imageIn = rgb2gray(imageIn);
imageOut = zeros(size(imageIn));
ny = size(imageIn, 1);
nx = size(imageIn, 2);
imshow(imageIn);
u = [];
v = [];
tic
for i = 1:ny
u = imageIn(i,:);
v = zeros(1, ny);
for k = 2:ny-1
v(k) = (uint32(u(k-1))+uint32(u(k))+uint32(u(k+1)))/3;
end
%Special cases first and last pixel
v(1) = (uint32(u(2))+uint32(u(1))+uint32(u(2)))/3;
v(ny) = (uint32(u(ny-1))+uint32(u(ny))+uint32(u(ny-1)))/3;
imageOut(i,:) = v;
end
toc
imshow(imageOut);
Any ideas?
Change the last line of your code to imagesc(imageOut) and you'll see that the image is not in fact white.
Your code is fine; the reason the image appears white using the imshow() function is because after applying your local average the range of pixel intensities is considerably smaller and the default scaling used by imshow() is insufficient to bring out the contrast of the image.
Read about the difference b/t imshow() and imagesc() and you'll see the confusion.
Why not just create a 2nd matrix which is a clone of the first, shift it over and then averate the two matrices?
imIn = imread('Prueba.jpg');
nx = size(d,1);
ny = size(d,2);
% Create temporary matrices padded with nan
tmp1 = [nan(ny,2), d];
tmp2 = [d, nan(ny,2)];
imOut = tmp1;
imOut(:,:,2) = tmp2;
% use nanmean so the mean is just the value of the 1 column
imOut = nanmean(imOut,3);
out = imOut(2:end-1,:);
Try to use this
imageIn = imread('Prueba.jpg');
imageIn = rgb2gray(imageIn);
imageOut = zeros(size(imageIn));
ny = size(imageIn, 1);
nx = size(imageIn, 2);
imshow(imageIn);
u = [];
v = [];
tic
for i = 1:ny
u = imageIn(i,:);
v = zeros(1, ny);
for k = 2:ny-1
v(k) = (uint32(u(k-1))+uint32(u(k))+uint32(u(k+1)))/3;
end
%Special cases first and last pixel
v(1) = (uint32(u(2))+uint32(u(1))+uint32(u(2)))/3;
v(ny) = (uint32(u(ny-1))+uint32(u(ny))+uint32(u(ny-1)))/3;
imageOut(i,:) = v;
end
toc
imshow(imageOut);