Highlight sliding window in matlab - matlab

I have the following code which creates a sliding window over the image Final.
I created a copy of the original image:
ZwindowedMarked=Final;
I applied the sliding image to the original image
N = 32;
info = repmat(struct, ceil(size(Final, 1) / N), ceil(size(Final, 2) / N));
for row = 1:N:size(Final, 1)%loop through each pixel in the image matrix
for col = 1:N:size(Z, 2)
r = (row - 1) / N + 1;
c = (col - 1) / N + 1;
imgWindow = Final(row:min(end,row+N-1), col:min(end,col+N-1));
average = mean(imgWindow(:));
window(r, c).average=average;
display(window(r, c).average);
% if mean pixel intensity is greater than 200 then highlight the window
if average>180
ZWindowedMarked = insertShape(Z, 'rectangle', [col row 32 32]);
end
end
end
figure(2);
imshow(ZWindowedMarked)
However although there are lots of windows with average greater than 180 it is only displaying one rectangle on the image. Can anyone show me how to highlight all sliding windows with average greater than 180 on the same image??
Thanks

From the above code, can we assume that Final, Z, and ZWindowedMarked are all initially the same image (before the iterations)? You may want to make that clear in the code and just decide on using Z or Final but not both.
What you need to do to ensure that all rectangles are drawn on the windowed image (ZWindowedMarked) and pass that marked up image to the insertShape function
% if mean pixel average is greater than 180 then highlight the window
if average>180
ZWindowedMarked = insertShape(ZWindowedMarked, 'rectangle', [col row 32 32]);
end
rather than passing the original untouched Z to the above function. (Note the changes to the comments as well.)
Hope this helps!

Related

How to implement median filter with a kernel in MATLAB to smooth an image?

I don't know how to implement a median filter with a sliding window (kernel) in MATLAB. I need to know how the implementation looks like so I can try to implement a BSE algorithm (block smart erase), which is very similar to the median filter. I need that to erase some black and white pixels. I know that there's the medfilt2() function but I need to know how it is implemented.
The BSE algorithm works like this:
The BSE algorithm is based on median technology and takes the place of the extreme value (black or white) pixel by the median value of their surrounding pixels.
1) For an NxN window centered at the test pixel, where N would normally be and larger value should be suggested.
2) If f(i,j) = 0 or f(i,j) = 255, f(i,j) is an absolute extreme value pixel that must be estimated; go to step 3. Otherwise, the value of f(i,j) is not altered; go to step 4.
3) When an extreme value pixel is detected, its gray level is substituted by the median value of the window.
4) The procedure is repeated for the next window.
What I understood was that I need to implement the median filter with a condition to check if the current pixel value is 0 or 255. If it is, I change that value for the median value of its neighbourhood pixels.
I dont know if I was clear enough but I need some help with that:).
Current BSE algorithm:
function [outimg] = medianfilt(img,sz)
green = img(:,:,2);
[rows,cols] = size(green); % get size of grayscale image
pad = sz-1; % padding to be added
nimg = zeros(rows+pad,cols+pad); % padded image
nimg(pad/2+1:rows+pad/2, pad/2+1:cols+pad/2) = green;
outimg = zeros(rows,cols); % output / median filtered image
for x = pad/2 + 1 : cols + pad/2 % loop over columns
for y = pad/2 + 1 : rows + pad/2 % loop over rows
if nimg(y,x) == 0 || nimg(y,x) == 255
win = nimg(y-pad/2:y+pad/2, x-pad/2:x+pad/2); % get mxm window
outimg(y-pad/2,x-pad/2) = median(win(:)); % find median
else
outimg(y-pad/2,x-pad/2) = nimg(y,x);
end
win = nimg(y-pad/2:y+pad/2, x-pad/2:x+pad/2); % get mxm window
outimg(y-pad/2,x-pad/2) = median(win(:)); % find median
end
end
imshow(outimg);
end
you can implement median filter as below:
function [outimg] = medianfilt(img,sz)
[rows,cols] = size(img); % get size of grayscale image
pad = sz-1; % padding to be added
nimg = zeros(rows+pad,cols+pad); % padded image
nimg(pad/2+1:rows+pad/2, pad/2+1:cols+pad/2) = img;
outimg = zeros(rows,cols); % output / median filtered image
for x = pad/2 + 1 : cols + pad/2 % loop over columns
for y = pad/2 + 1 : rows + pad/2 % loop over rows
win = nimg(y-pad/2:y+pad/2, x-pad/2:x+pad/2); % get mxm window
outimg(y-pad/2,x-pad/2) = median(win(:)); % find median
end
end
end
you can check for BSE as below:
if nimg(y,x) == 0 || nimg(y,x) == 255
win = nimg(y-pad/2:y+pad/2, x-pad/2:x+pad/2); % get mxm window
outimg(y-pad/2,x-pad/2) = median(win(:)); % find median
else
outimg(y-pad/2,x-pad/2) = nimg(y,x);
end
As you noted, MATLAB has medfilt2. You can use this function to build your filter:
img = imread(...);
med = medfilt2(img);
mask = img==0 | img==255;
img(mask) = med(mask);
What the code above does is
compute the median filtered image med,
identify the pixels that need to be replaced (pixels with a value of 0 or 255), leading to a logical array mask that can be used for indexing, and finally
replace the given pixels in the input image with the corresponding pixels from the median-filtered image.

How to get max rectangle basing inside an object [duplicate]

I'm making an image processing project and I have stuck in one the project's steps. Here is the situation;
This is my mask:
and I want to detect the maximum-sized rectangle that can fit into this mask like this.
I'm using MATLAB for my project. Do you know any fast way to accomplish this aim. Any code sample, approach or technique would be great.
EDIT 1 : The two algorithms below are works with lot's of the cases. But both of them give wrong results in some difficult cases. I'am using both of them in my project.
This approach starts with the entire image and shrinks each border in turn pixel-by-pixel until it finds an acceptable rectangle.
It takes ~0.02 seconds to run on the example image, so it's reasonably fast.
EDIT: I should clarify that this isn't meant to be a universal solution. This algorithm relies on the rectangle being centered and having roughly the same aspect ratio as the image itself. However, in the cases where it is appropriate, it is fast. #DanielHsH offered a solution which they claim works in all cases.
The code:
clear; clc;
tic;
%% // read image
imrgb= imread('box.png');
im = im2bw(rgb2gray(imrgb)); %// binarize image
im = 1-im; %// convert "empty" regions to 0 intensity
[rows,cols] = size(im);
%% // set up initial parameters
ULrow = 1; %// upper-left row (param #1)
ULcol = 1; %// upper-left column (param #2)
BRrow = rows; %// bottom-right row (param #3)
BRcol = cols; %// bottom-right column (param #4)
parameters = 1:4; %// parameters left to be updated
pidx = 0; %// index of parameter currently being updated
%% // shrink region until acceptable
while ~isempty(parameters); %// update until all parameters reach bounds
%// 1. update parameter number
pidx = pidx+1;
pidx = mod( pidx-1, length(parameters) ) + 1;
p = parameters(pidx); %// current parameter number
%// 2. update current parameter
if p==1; ULrow = ULrow+1; end;
if p==2; ULcol = ULcol+1; end;
if p==3; BRrow = BRrow-1; end;
if p==4; BRcol = BRcol-1; end;
%// 3. grab newest part of region (row or column)
if p==1; region = im(ULrow,ULcol:BRcol); end;
if p==2; region = im(ULrow:BRrow,ULcol); end;
if p==3; region = im(BRrow,ULcol:BRcol); end;
if p==4; region = im(ULrow:BRrow,BRcol); end;
%// 4. if the new region has only zeros, stop shrinking the current parameter
if isempty(find(region,1))
parameters(pidx) = [];
end
end
toc;
params = [ULrow ULcol BRrow BRcol]
area = (BRrow-ULrow)*(BRcol-ULcol)
The results for this image:
Elapsed time is 0.027032 seconds.
params =
10 25 457 471
area =
199362
Code to visualize results:
imrgb(params(1):params(3),params(2):params(4),1) = 0;
imrgb(params(1):params(3),params(2):params(4),2) = 255;
imrgb(params(1):params(3),params(2):params(4),3) = 255;
imshow(imrgb);
Another example image:
Here is a correct answer.
You must use dynamic programming! Other methods of direct calculation (like cutting 1 pixel from each edge) might produce sub-optimal results. My method guarantees that it selects the largest possible rectangle that fits in the mask. I assume that the mask has 1 big convex white blob of any shape with black background around it.
I wrote 2 methods. findRect() which finds the best possible square (starting on x,y with length l). The second method LargestInscribedImage() is an example of how to find any rectangle (of any aspect ratio). The trick is to resize the mask image, find a square and resize it back.
In my example the method finds the larges rectangle that can be fit in the mask having the same aspect ration as the mask image. For example if the mask image is of size 100x200 pixels than the algorithm will find the largest rectangle having aspect ratio 1:2.
% ----------------------------------------------------------
function LargestInscribedImage()
% ----------------------------------------------------------
close all
im = double(imread('aa.bmp')); % Balck and white image of your mask
im = im(:,:,1); % If it is colored RGB take only one of the channels
b = imresize(im,[size(im,1) size(im,1)]); Make the mask square by resizing it by its aspect ratio.
SC = 1; % Put 2..4 to scale down the image an speed up the algorithm
[x1,y1,l1] = findRect(b,SC); % Lunch the dyn prog algorithm
[x2,y2,l2] = findRect(rot90(b),SC); % rotate the image by 90deg and solve
% Rotate back: x2,y2 according to rot90
tmp = x2;
x2 = size(im,1)/SC-y2-l2;
y2 = tmp;
% Select the best solution of the above (for the original image and for the rotated by 90degrees
if (l1>=l2)
corn = sqCorn(x1,y1,l1);
else
corn = sqCorn(x2,y2,l2);
end
b = imresize(b,1/SC);
figure;imshow(b>0); hold on;
plot(corn(1,:),corn(2,:),'O')
corn = corn*SC;
corn(1,:) = corn(1,:)*size(im,2)/size(im,1);
figure;imshow(im); hold on;
plot(corn(1,:),corn(2,:),'O')
end
function corn = sqCorn(x,y,l)
corn = [x,y;x,y+l;x+l,y;x+l,y+l]';
end
% ----------------------------------------------------------
function [x,y,l] = findRect(b,SC)
b = imresize(b,1/SC);
res = zeros(size(b,1),size(b,2),3);
% initialize first col
for i = 1:1:size(b,1)
if (b(i,1) > 0)
res(i,1,:) = [i,1,0];
end
end
% initialize first row
for i = 1:1:size(b,2)
if (b(1,i) > 0)
res(1,i,:) = [1,i,0];
end
end
% DynProg
for i = 2:1:size(b,1)
for j = 2:1:size(b,2)
isWhite = b(i,j) > 0;
if (~isWhite)
res(i,j,:)=res(i-1,j-1,:); % copy
else
if (b(i-1,j-1)>0) % continuous line
lineBeg = [res(i-1,j-1,1),res(i-1,j-1,2)];
lineLenght = res(i-1,j-1,3);
if ((b(lineBeg(1),j)>0)&&(b(i,lineBeg(2))>0)) % if second diag is good
res(i,j,:) = [lineBeg,lineLenght+1];
else
res(i,j,:)=res(i-1,j-1,:); % copy since line has ended
end
else
res(i,j,:) = [i,j,0]; % Line start
end
end
end
end
% check last col
[maxValCol,WhereCol] = max(res(:,end,3));
% check last row
[maxValRow,WhereRow] = max(res(end,:,3));
% Find max
x= 0; y = 0; l = 0;
if (maxValCol>maxValRow)
y = res(WhereCol,end,1);
x = res(WhereCol,end,2);
l = maxValCol;
else
y = res(end,WhereRow,1);
x = res(end,WhereRow,2);
l = maxValRow;
end
corn = [x,y;x,y+l;x+l,y;x+l,y+l]';
% figure;imshow(b>0); hold on;
% plot(corn(1,:),corn(2,:),'O')
return;
end
The black boundaries in your image are curved and not closed. For example, in the top right corner, the black boundaries won't meet and form a closed contour. Therefore, a simple strategy in one of my comments will not work.
I am now providing you with a skeleton of a code which you can play with and add conditions as per your need. My idea is as follows:
To find left-side x-coordinate of the rectangle, first count the white pixels each column of the image contains:
%I assume that the image has already been converted to binary.
whitePixels=sum(img,1);
Then find the rate of change:
diffWhitePixels=diff(whitePixels);
If you see the bar plot of diffWhitePixels then you will observe various large entries (which indicate that the white region is still not in a straight line, and it is not a proper place to put the rectangles left vertical edge). Small entries (in your image, less than 5) indicate you can put the rectangle edge there.
You can do similar things to determine right, top and bottom edge positions of the rectangles.
Discussion:
First of all, the problem is ill-posed in my opinion. What do you mean by maximum-sized rectangle? Is it maximum area or length of side? In all possible cases, I don't think above method can get the correct answer. I can think of two or three cases right now where above method would fail, but it will at least give you the right answer on images similar to the given image, provided you adjust the values.
You can put some constraints once you know how your images are going to look. For example, if the black boundary curves inside, you can say that you don't want a column such as [0;0;...0;1;1;...0;0;...;0;1;1;...;1] i.e. zeros surrounded by ones. Another constraint could be how many black pixels do you want to allow? You can also crop the image till to remove extra black pixels. In your image, you can crop the image (programmatically) from the left and the bottom edge. Cropping an image is probably necessary, and definitely the better thing to do.

Matlab- put border around sliding window

Hi I have code which puts a sliding window over an image in Matlab. If the pixels within the sliding window meet certain conditions then I need to highlight that sliding window on the original image by putting a rectangle around it.
Can anyone explain to me how to do this?
Thanks.
if average>200
N2=8;
info2 = repmat(struct, ceil(size(Z, 1) / N2), ceil(size(Z, 2) / N2));
for row1 = 1:N2:size(Z, 1)%loop through each pixel in the 8x8 window
for col1 = 1:N2:size(Z, 2)
x = (row1 - 1) / N2 + 1;
y = (col1 - 1) / N2 + 1;
imgWindow2 = Z(row1:min(end,row1+N2-1), col1:min(end,col1+N2-1));
average2 = mean(imgWindow2(:)); %calculate mean intensity of pixels
window2(x,y).average=average2;
% display(window2(x,y).average);
% if the intensity of the 8x8 window is greater than
% 210 then considered suspicious-
if average2>210
%%%% THEN HIGHLIGH THIS WINDOW ON THE ORG IMAGE (Z)
end
end
end
If you want to display this in a figure, you can use the imrect function. If you want to draw the rectangle into the image itself, and you have the Computer Vision System Toolbox, you can use insertShape or insertObjectAnnotation functions.

Matlab create window on image

I need to create A 16X16 window to scan over an entire image in matlab and record the position and grey level value of pixel with largest grey level in window.
Can anyone guide me on how to do this? Cant find any help on creating windows on images.
Thanks
Just for fun, here is another way of achieving this: store the intensity and the position of the maximum in your window as the real and imaginary parts of a complex number. You can then use the nfilter function to perform the moving filtering:
fun = #(x) complex(double(max(x(:))),double(find(x==max(x(:)), 1, 'first')));
B = nlfilter(YourImage,[16 16],fun);
You can then access the maximum and its position from the complex map. Here is an example of the results when applied to one of the images given in this post:
Max intensity in the neighborhood (imagesc(real(B))):
Position of the maximum (imagesc(img(B))):
Old school for-Loop method -
%%// Outputs that you are interested in are - img, x1 and y1
img = rgb2gray(input_image); %%// Gray level values
x1 = zeros(size(img)); %%// Row values for the maximum pixel in the 16x16 window
y1 = zeros(size(img)); %%// Column values for the maximum pixel in the 16x16 window
for k1= 1:size(img,1)-15
for k2= 1:size(img,2)-15
img1 = img(k1:k1+15,k2:k2+15);
[val,ind1] = max(img1(:));
img(k1+8,k2+8)=val; %%// Store the max grey value into the image
[x1(k1,k2),y1(k1,k2)] = ind2sub([16 16],ind1);
end
end
Edit 1: For calculating mean across this sliding window, use this -
window_size = 16; %%// Edit this to your window size
wsz = window_size-1;
mp = round(window_size/2);
%%// Outputs that you are interested in are - img, x1 and y1
img = rgb2gray(input_image); %%// Gray level values
x1 = zeros(size(img)); %%// Row values for the maximum pixel in the 16x16 window
y1 = zeros(size(img)); %%// Column values for the maximum pixel in the 16x16 window
img1 = img;
for k1= 1:size(img,1)-wsz
for k2= 1:size(img,2)-wsz
window_data = img(k1:k1+wsz,k2:k2+wsz);
val = round(mean(window_data(:)));
img1(k1+mp,k2+mp)=val; %%// Store the mean grey value into the image
end
end
figure,imshow(img1)
Edit 2:
img1 = Z;
for k1= 1:size(Z,1)-wsz
for k2= 1:size(Z,2)-wsz
window_data = Z(k1:k1+wsz,k2:k2+wsz);
val = mean(window_data(:))
if (val~=0)
keyboard;
error('Look, there is a non-zero mean value!');
end
% img1(k1+mp,k2+mp)=val; %%// Store the mean grey value into the image
display(val);
end
end
You could do it like this:
% img = [matrix representing your image]
N = 16;
window = repmat(struct, ceil(size(img, 1) / N), ceil(size(img, 2) / N));
for row = 1:N:size(img, 1)
for col = 1:N:size(img, 2)
r = (row - 1) / N + 1;
c = (col - 1) / N + 1;
imgWindow = img(row:min(end,row+N-1), col:min(end,col+N-1));
largest = max(imgWindow(:));
[rLarg, cLarg] = find(imgWindow == largest, 1, 'first');
window(r, c).largest = largest;
window(r, c).row = rLarg + row - 1;
window(r, c).col = cLarg + col - 1;
end
end
You'll have a matrix called window where window(r,c) contains information about window (r,c), with the fields:
window(r,c).largest: gray level of the largest pixel
window(r,c).row, window(r,c).col: position of the largest pixel on the original image
The key step you need is to extract a sub image the given scanning window (i.e. rectangle area). If the scanning winow, say roi is in format [x, y, width, height], you can simply call imcrop:
subImage = imcrop(Image, roi);
Then you can find the max gray level in the sub image, like this
[value, location] = max(subImage(:));
Of course, you need to update the scanning window i.e. roi in order to scan over the whole image.

Roberts Operator just makes the image brighter

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