I have a 2D image (matrix). I have found the local maxima of this image. Now I want to define the boundaries around each local maxima in such a way that I want all the pixels around the local maxima that have a value above 85% of the maximum.
Here is my existing code:
function [location]= Mfind_peak_2D( Image,varargin )
p = inputParser;
addParamValue(p,'max_n_loc_max',5);
addParamValue(p,'nb_size',3);
addParamValue(p,'thre',0);
addParamValue(p,'drop',0.15);
parse(p,varargin{:});
p=p.Results;
if sum(isnan(Image(:)))>0
Image(isnan(Image))=0;
end
hLocalMax = vision.LocalMaximaFinder;
hLocalMax.MaximumNumLocalMaxima = p.max_n_loc_max;
hLocalMax.NeighborhoodSize = [p.nb_size p.nb_size];
end
This should do the job (the code is full of comments and should be pretty self-explanatory but if you have doubts feel free to ask for more details):
% Load the image...
img = imread('peppers.png');
img = rgb2gray(img);
% Find the local maxima...
mask = ones(3);
mask(5) = 0;
img_dil = imdilate(img,mask);
lm = img > img_dil;
% Find the neighboring pixels of the local maxima...
img_size = size(img);
img_h = img_size(1);
img_w = img_size(2);
res = cell(sum(sum(lm)),3);
res_off = 1;
for i = 1:img_h
for j = 1:img_w
if (~lm(i,j))
continue;
end
value = img(i,j);
value_thr = value * 0.85;
% Retrieve the neighboring column and row offsets...
c = bsxfun(#plus,j,[-1 0 1 -1 1 -1 0 1]);
r = bsxfun(#plus,i,[-1 -1 -1 0 0 1 1 1]);
% Filter the invalid positions...
idx = (c > 0) & (c <= img_w) & (r > 0) & (r <= img_h);
% Transform the valid positions into linear indices...
idx = (((idx .* c) - 1) .* img_h) + (idx .* r);
idx = reshape(idx.',1,numel(idx));
idx = idx(idx > 0);
% Retrieve the neighbors and filter them based on te threshold...
neighbors = img(idx);
neighbors = neighbors(neighbors > value_thr);
% Update the final result...
res(res_off,:) = {sub2ind(img_size,i,j) value neighbors};
res_off = res_off + 1;
end
end
res = sortrows(res,1);
The variable res will be a cell matrix with three columns: the first one contain the linear indices to the local maxima of the image, the second one contains the values of the local maxima and the third one a vector with the pixels around the local maxima that fall within the specified threshold.
Related
I'm trying to write an image compression script in MATLAB using multilayer 3D DWT(color image). along the way, I want to apply thresholding on coefficient matrices, both global and local thresholds.
I like to use the formula below to calculate my local threshold:
where sigma is variance and N is the number of elements.
Global thresholding works fine; but my problem is that the calculated local threshold is (most often!) greater than the maximum band coefficient, therefore no thresholding is applied.
Everything else works fine and I get a result too, but I suspect the local threshold is miscalculated. Also, the resulting image is larger than the original!
I'd appreciate any help on the correct way to calculate the local threshold, or if there's a pre-set MATLAB function.
here's an example output:
here's my code:
clear;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% COMPRESSION %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% read base image
% dwt 3/5-L on base images
% quantize coeffs (local/global)
% count zero value-ed coeffs
% calculate mse/psnr
% save and show result
% read images
base = imread('circ.jpg');
fam = 'haar'; % wavelet family
lvl = 3; % wavelet depth
% set to 1 to apply global thr
thr_type = 0;
% global threshold value
gthr = 180;
% convert base to grayscale
%base = rgb2gray(base);
% apply dwt on base image
dc = wavedec3(base, lvl, fam);
% extract coeffs
ll_base = dc.dec{1};
lh_base = dc.dec{2};
hl_base = dc.dec{3};
hh_base = dc.dec{4};
ll_var = var(ll_base, 0);
lh_var = var(lh_base, 0);
hl_var = var(hl_base, 0);
hh_var = var(hh_base, 0);
% count number of elements
ll_n = numel(ll_base);
lh_n = numel(lh_base);
hl_n = numel(hl_base);
hh_n = numel(hh_base);
% find local threshold
ll_t = ll_var * (sqrt(2 * log2(ll_n)));
lh_t = lh_var * (sqrt(2 * log2(lh_n)));
hl_t = hl_var * (sqrt(2 * log2(hl_n)));
hh_t = hh_var * (sqrt(2 * log2(hh_n)));
% global
if thr_type == 1
ll_t = gthr; lh_t = gthr; hl_t = gthr; hh_t = gthr;
end
% count zero values in bands
ll_size = size(ll_base);
lh_size = size(lh_base);
hl_size = size(hl_base);
hh_size = size(hh_base);
% count zero values in new band matrices
ll_zeros = sum(ll_base==0,'all');
lh_zeros = sum(lh_base==0,'all');
hl_zeros = sum(hl_base==0,'all');
hh_zeros = sum(hh_base==0,'all');
% initiate new matrices
ll_new = zeros(ll_size);
lh_new = zeros(lh_size);
hl_new = zeros(lh_size);
hh_new = zeros(lh_size);
% apply thresholding on bands
% if new value < thr => 0
% otherwise, keep the previous value
for id=1:ll_size(1)
for idx=1:ll_size(2)
if ll_base(id,idx) < ll_t
ll_new(id,idx) = 0;
else
ll_new(id,idx) = ll_base(id,idx);
end
end
end
for id=1:lh_size(1)
for idx=1:lh_size(2)
if lh_base(id,idx) < lh_t
lh_new(id,idx) = 0;
else
lh_new(id,idx) = lh_base(id,idx);
end
end
end
for id=1:hl_size(1)
for idx=1:hl_size(2)
if hl_base(id,idx) < hl_t
hl_new(id,idx) = 0;
else
hl_new(id,idx) = hl_base(id,idx);
end
end
end
for id=1:hh_size(1)
for idx=1:hh_size(2)
if hh_base(id,idx) < hh_t
hh_new(id,idx) = 0;
else
hh_new(id,idx) = hh_base(id,idx);
end
end
end
% count zeros of the new matrices
ll_new_size = size(ll_new);
lh_new_size = size(lh_new);
hl_new_size = size(hl_new);
hh_new_size = size(hh_new);
% count number of zeros among new values
ll_new_zeros = sum(ll_new==0,'all');
lh_new_zeros = sum(lh_new==0,'all');
hl_new_zeros = sum(hl_new==0,'all');
hh_new_zeros = sum(hh_new==0,'all');
% set new band matrices
dc.dec{1} = ll_new;
dc.dec{2} = lh_new;
dc.dec{3} = hl_new;
dc.dec{4} = hh_new;
% count how many coeff. were thresholded
ll_zeros_diff = ll_new_zeros - ll_zeros;
lh_zeros_diff = lh_zeros - lh_new_zeros;
hl_zeros_diff = hl_zeros - hl_new_zeros;
hh_zeros_diff = hh_zeros - hh_new_zeros;
% show coeff. matrices vs. thresholded version
figure
colormap(gray);
subplot(2,4,1); imagesc(ll_base); title('LL');
subplot(2,4,2); imagesc(lh_base); title('LH');
subplot(2,4,3); imagesc(hl_base); title('HL');
subplot(2,4,4); imagesc(hh_base); title('HH');
subplot(2,4,5); imagesc(ll_new); title({'LL thr';ll_zeros_diff});
subplot(2,4,6); imagesc(lh_new); title({'LH thr';lh_zeros_diff});
subplot(2,4,7); imagesc(hl_new); title({'HL thr';hl_zeros_diff});
subplot(2,4,8); imagesc(hh_new); title({'HH thr';hh_zeros_diff});
% idwt to reconstruct compressed image
cmp = waverec3(dc);
cmp = uint8(cmp);
% calculate mse/psnr
D = abs(cmp - base) .^2;
mse = sum(D(:))/numel(base);
psnr = 10*log10(255*255/mse);
% show images and mse/psnr
figure
subplot(1,2,1);
imshow(base); title("Original"); axis square;
subplot(1,2,2);
imshow(cmp); colormap(gray); axis square;
msg = strcat("MSE: ", num2str(mse), " | PSNR: ", num2str(psnr));
title({"Compressed";msg});
% save image locally
imwrite(cmp, 'compressed.png');
I solved the question.
the sigma in the local threshold formula is not variance, it's the standard deviation. I applied these steps:
used stdfilt() std2() to find standard deviation of my coeff. matrices (thanks to #Rotem for pointing this out)
used numel() to count the number of elements in coeff. matrices
this is a summary of the process. it's the same for other bands (LH, HL, HH))
[c, s] = wavedec2(image, wname, level); %apply dwt
ll = appcoeff2(c, s, wname); %find LL
ll_std = std2(ll); %find standard deviation
ll_n = numel(ll); %find number of coeffs in LL
ll_t = ll_std * (sqrt(2 * log2(ll_n))); %local the formula
ll_new = ll .* double(ll > ll_t); %thresholding
replace the LL values in c in a for loop
reconstruct by applying IDWT using waverec2
this is a sample output:
I have a 2D matrix of zeros and ones, where the ones indicate a convex figure
I now want to divide this figure (that is the elements of value 1) in nonoverlapping patches of equally the same size, as in this figure
Do you have any suggestion? I could go for mat2cell and have just rectangles, and keep the rectangles with at least one value 1 in them, but I would prefer a more equal division.
For similar problems, I often use a method called 'orthogonal recursive bisection'.
An example of what it does with your circle is in the picture.
As the name suggests, the method divides subdomains into two smaller subdomains,
until the total number of subdomains is the desired value.
My implementation for your case is
function array = ORB(array,nparts)
%
% array = ORB(array,nparts)
%
% Divide the nonzeros of array into nparts equally large,
% approximately square parts.
%
% convert true/false array into 0/1:
ar = array; array = zeros(size(ar)); array(ar) = 1;
% initialize subdivision-admin
istart = 1; iend = nparts; values = 1;
last_value = max(values);
% Divide up the parts that need dividing up
while length(values) < nparts
new_istart = []; new_iend = []; new_values = [];
for i = 1:length(values)
if iend(i) > istart(i)
disp(sprintf('Current values %d should eventually be split into domains %d-%d',values(i),istart(i),iend(i)))
last_value = last_value + 1;
new_istart = [new_istart, istart(i), istart(i) + floor((iend(i)-istart(i)+1)/2)];
new_iend = [new_iend, istart(i) + floor((iend(i)-istart(i)+1)/2)-1, iend(i)];
new_values = [new_values, values(i), last_value];
n = length(new_values);
disp(sprintf('Current values %d should now be split into domains %d and %d, in ratio %d:%d\n', ...
values(i), new_values(n-1:n),new_iend(n-1:n)-new_istart(n-1:n)+1));
array = Split(array,new_values(n-1:n),new_iend(n-1:n)-new_istart(n-1:n)+1);
else
disp(sprintf('Domain %d is done\n',values(i)))
new_istart = [new_istart, istart(i)];
new_iend = [new_iend, iend(i)];
new_values = [new_values, values(i)];
end
end
iend = new_iend; istart = new_istart; values = new_values;
end
for i = 1:nparts
disp(sprintf('Part %d has %d points',i,length(find(array==i))))
end
close all
pcolor(array)
which needs the function Split:
function array = Split(array,parts,sizes)
%
% array = Split(array,parts,sizes)
%
% Change some of the values of array which are now equal to parts(1) into the value parts(2).
% At the end, the ratio
% length(find(array==parts(1))) : length(find(array==parts(2)))
% should be
% sizes(1) : sizes(2)
%
% Calculate sizes of each patch
[i,j] = find(array==parts(1));
npoints = size(i,1); sizes = npoints * sizes/(sizes(1)+sizes(2));
imin = min(i); imax = max(i); jmin = min(j); jmax = max(j);
nmin = 0; nmax = npoints;
if jmax-jmin>imax-imin
% divide domain in (j < jmid) and (jmid <= j)
while jmax > jmin + 1
jmid = (jmax + jmin)/2; n_this = size(find(j<jmid));
if n_this < sizes(1)
jmin = jmid; nmin = n_this;
else
jmax = jmid; nmax = n_this;
end
end
i = i(j>=jmid); j = j(j>=jmid);
else
% divide domain in (i < imid) and (imid <= i)
while imax > imin + 1
imid = (imax + imin)/2; n_this = size(find(i<imid));
if n_this < sizes(1)
imin = imid; nmin = n_this;
else
imax = imid; nmax = n_this;
end
end
j = j(i>=imid); i = i(i>=imid);
end
% Change the values in array
array(sub2ind(size(array),i,j)) = parts(2);
I have used the following code from the matlab central website in my project to perform seeded region growing. This works perfectly but I am struggling to understand exactly what the code is doing in some places. I have contacted the author but have had no reply. Would anyone be able to provide me with some explanations ?
function Phi = segCroissRegion(tolerance,Igray,x,y)
if(x == 0 || y == 0)
imshow(Igray,[0 255]);
[x,y] = ginput(1);
end
Phi = false(size(Igray,1),size(Igray,2));
ref = true(size(Igray,1),size(Igray,2));
PhiOld = Phi;
Phi(uint8(x),uint8(y)) = 1;
while(sum(Phi(:)) ~= sum(PhiOld(:)))
PhiOld = Phi;
segm_val = Igray(Phi);
meanSeg = mean(segm_val);
posVoisinsPhi = imdilate(Phi,strel('disk',1,0)) - Phi;
voisins = find(posVoisinsPhi);
valeursVoisins = Igray(voisins);
Phi(voisins(valeursVoisins > meanSeg - tolerance & valeursVoisins < meanSeg + tolerance)) = 1;
end
Thanks
I've added some comments in your code :
function Phi = segCroissRegion(tolerance,Igray,x,y)
% If there's no point, select one from image
if(x == 0 || y == 0)
imshow(Igray,[0 255]);
[x,y] = ginput(1);
end
%Create seed with by adding point in black image
Phi = false(size(Igray,1),size(Igray,2));
ref = true(size(Igray,1),size(Igray,2));
PhiOld = Phi;
Phi(uint8(x),uint8(y)) = 1;
while(sum(Phi(:)) ~= sum(PhiOld(:)))
PhiOld = Phi;
% Evaluate image intensity at seed/line points
segm_val = Igray(Phi);
% Calculate mean intensity at seed/line points
meanSeg = mean(segm_val);
% Grow seed 1 pixel, and remove previous seed (so you'll get only new pixel perimeter)
posVoisinsPhi = imdilate(Phi,strel('disk',1,0)) - Phi;
% Evaluate image intensity over the new perimeter
voisins = find(posVoisinsPhi);
valeursVoisins = Igray(voisins);
% If image intensity over new perimeter is greater than the mean intensity of previous perimeter (minus tolerance), than this perimeter is part of the segmented object
Phi(voisins(valeursVoisins > meanSeg - tolerance & valeursVoisins < meanSeg + tolerance)) = 1;
% Repeat while there's new pixel in seed, stop if no new pixel were added
end
I am working on rotating image manually in Matlab. Each time I run my code with a different image the previous images which are rotated are shown in the Figure. I couldn't figure it out. Any help would be appreciable.
The code is here:
[screenshot]
im1 = imread('gradient.jpg');
[h, w, p] = size(im1);
theta = pi/12;
hh = round( h*cos(theta) + w*abs(sin(theta))); %Round to nearest integer
ww = round( w*cos(theta) + h*abs(sin(theta))); %Round to nearest integer
R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
T = [w/2; h/2];
RT = [inv(R) T; 0 0 1];
for z = 1:p
for x = 1:ww
for y = 1:hh
% Using matrix multiplication
i = zeros(3,1);
i = RT*[x-ww/2; y-hh/2; 1];
%% Nearest Neighbour
i = round(i);
if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
im2(y,x,z) = im1(i(2),i(1),z);
end
end
end
end
x=1:ww;
y=1:hh;
[X, Y] = meshgrid(x,y); % Generate X and Y arrays for 3-D plots
orig_pos = [X(:)' ; Y(:)' ; ones(1,numel(X))]; % Number of elements in array or subscripted array expression
orig_pos_2 = [X(:)'-(ww/2) ; Y(:)'-(hh/2) ; ones(1,numel(X))];
new_pos = round(RT*orig_pos_2); % Round to nearest neighbour
% Check if new positions fall from map:
valid_pos = new_pos(1,:)>=1 & new_pos(1,:)<=w & new_pos(2,:)>=1 & new_pos(2,:)<=h;
orig_pos = orig_pos(:,valid_pos);
new_pos = new_pos(:,valid_pos);
siz = size(im1);
siz2 = size(im2);
% Expand the 2D indices to include the third dimension.
ind_orig_pos = sub2ind(siz2,orig_pos(2*ones(p,1),:),orig_pos(ones(p,1),:), (1:p)'*ones(1,length(orig_pos)));
ind_new_pos = sub2ind(siz, new_pos(2*ones(p,1),:), new_pos(ones(p,1),:), (1:p)'*ones(1,length(new_pos)));
im2(ind_orig_pos) = im1(ind_new_pos);
imshow(im2);
There is a problem with the initialization of im2, or rather, the lack of it. im2 is created in the section shown below:
if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
im2(y,x,z) = im1(i(2),i(1),z);
end
If im2 exists before this code is run and its width or height is larger than the image you are generating the new image will only overwrite the top left corner of your existing im2. Try initializing im2 by adding adding
im2 = zeros(hh, ww, p);
before
for z = 1:p
for x = 1:ww
for y = 1:hh
...
As a bonus it might make your code a little faster since Matlab won't have to resize im2 as it grows in the loop.
I am a total beginner in Matlab and trying to write some Machine Learning Algorithms in Matlab. I would really appreciate it if someone can help me in debugging this code.
function y = KNNpredict(trX,trY,K,X)
% trX is NxD, trY is Nx1, K is 1x1 and X is 1xD
% we return a single value 'y' which is the predicted class
% TODO: write this function
% int[] distance = new int[N];
distances = zeroes(N, 1);
examples = zeroes(K, D+2);
i = 0;
% for(every row in trX) { // taking ONE example
for row=1:N,
examples(row,:) = trX(row,:);
%sum = 0.0;
%for(every col in this example) { // taking every feature of this example
for col=1:D,
% diff = compute squared difference between these points - (trX[row][col]-X[col])^2
diff =(trX(row,col)-X(col))^2;
sum += diff;
end % for
distances(row) = sqrt(sum);
examples(i:D+1) = distances(row);
examples(i:D+2) = trY(row:1);
end % for
% sort the examples based on their distances thus calculated
sortrows(examples, D+1);
% for(int i = 0; i < K; K++) {
% These are the nearest neighbors
pos = 0;
neg = 0;
res = 0;
for row=1:K,
if(examples(row,D+2 == -1))
neg = neg + 1;
else
pos = pos + 1;
%disp(distances(row));
end
end % for
if(pos > neg)
y = 1;
return;
else
y = -1;
return;
end
end
end
Thanks so much
When working with matrices in MATLAB, it is usually better to avoid excessive loops and instead use vectorized operations whenever possible. This will usually produce faster and shorter code.
In your case, the k-nearest neighbors algorithm is simple enough and can be well vectorized. Consider the following implementation:
function y = KNNpredict(trX, trY, K, x)
%# euclidean distance between instance x and every training instance
dist = sqrt( sum( bsxfun(#minus, trX, x).^2 , 2) );
%# sorting indices from smaller to larger distances
[~,ord] = sort(dist, 'ascend');
%# get the labels of the K nearest neighbors
kTrY = trY( ord(1:min(K,end)) );
%# majority class vote
y = mode(kTrY);
end
Here is an example to test it using the Fisher-Iris dataset:
%# load dataset (data + labels)
load fisheriris
X = meas;
Y = grp2idx(species);
%# partition the data into training/testing
c = cvpartition(Y, 'holdout',1/3);
trX = X(c.training,:);
trY = Y(c.training);
tsX = X(c.test,:);
tsY = Y(c.test);
%# prediction
K = 10;
pred = zeros(c.TestSize,1);
for i=1:c.TestSize
pred(i) = KNNpredict(trX, trY, K, tsX(i,:));
end
%# validation
C = confusionmat(tsY, pred)
The confusion matrix of the kNN prediction with K=10:
C =
17 0 0
0 16 0
0 1 16