Matlab create window on image - matlab

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.

Related

Select pixel position for image segmentation based on threshold value

I am writing a function to segment an image in MATLAB. I want to do a simple segmentation where I first sum up elements along columns and select pixel position which is greater than threshold and display only those pixels from the original[![enter image description here] image. I have written a function below where it can sum pixel intensities, I need help in selecting pixel position where intensity is greater than threshold and display only that part of image.
function S = image_segment(im)
% im is the image to segment
nrofsegments = 5; % there is 5 fragments for this image
S = cell(1,nrofsegments);
m = size(im,1);
n = size(im,2);
for kk = 1:nrofsegments
S_sum=sum(im); %sum the intensity along column
S_position = ... % get pixel position where the pixel intensity is greater than 128
S{kk} = ... % im(S_position), only part of image with this pixel position
end
This code should work for your image. Please find the explanations inline.
% Read your test image from the web
im = imread('https://i.stack.imgur.com/qg5gx.jpg');
% Get sum of intensities along the columns
colSum = sum(im);
% Set a proper threshold (128 was not working for me)
thresh = 300;
% Get an 1-D logical array indicating which columns have letters
hasLetter = colSum > thresh;
% Get the difference of consecutive values in hasLetter
hasLetterDiff = diff( hasLetter ) ;
% If this is greater than 0, we have the start of a letter.
% The find gets the indices where this is true.
% Then, we add one to compensate for the offset introduced by diff.
letterStartPos = find( hasLetterDiff > 0 ) + 1;
% Use a similar approach to find the letter end position
% Here, we search for differences smaller than 0.
letterEndPos = find( hasLetterDiff < 0 ) + 1;
% Cut out image from start and end positions
numSegments = 5;
S = cell(1, numSegments );
for k = 1 : numel(S)
S{k} = im( :, letterStartPos(k) : letterEndPos(k));
end
You should consider furthermore to add some code to make it fail-safe for cases where there are less than 5 segments. Moreover, I would recommend to do some low-pass or median filtering on colSum.
Alternative: Instead of deriving the start and stop positions, it would also be possible to use splitapply (introduced in R2015) directly on hasLetterDiff as follows:
S = splitapply( #(X) { im(:,X) }, 1 : numel( hasLetter), [1 cumsum( abs( hasLetterDiff))] + 1);
S = S(2:2:end);

Why is my bilinear interpolation vastly different from the in-built matlab function?

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

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.

Determining black pixels as white in matlab

I have the black-white image. When I view particular coordinate (x,y) of this image in Image Viewer I could see that it has value 0. However, when I want to obtain value from (x,y) in my script I get 255. Code looks as following:
bw = imread('my_map.png');
imshow(bw);
hold on
% find corners of obstacles
corners = detectHarrisFeatures(bw);
plot(corners.selectStrongest(50));
cornerPoints = corners.selectStrongest(50);
hold on
% determine line's equation for two particular corners
m = cornerPoints.Location(4,2)-cornerPoints.Location(3,2);
n = cornerPoints.Location(4,1)-cornerPoints.Location(3,1);
k = (m)/(n);
b = cornerPoints.Location(3,2) - k*cornerPoints.Location(3,1);
%determine if this line intersects any obstacle
black = 0;
white = 0;
for y=cornerPoints.Location(3,2):1:cornerPoints.Location(4,2)
x = (y-b)/k;
if (int16(x) == 0)
x = cornerPoints.Location(3,1);
end
plot(int16(x),int16(y),'r*')
hold on
c = bw(int16(x), int16(y));
if (c==255)
white=white+1;
else
black=black+1;
end
end
if (white == 0)
display('valid')
else if (black <= 2)
display('valid')
else
display('invalid')
end
The image is this
.
What might be the problem?
In Matlab, the first coordinate of a matrix represents a row index, and the second one represents a column index.
Therefore, in order to access to point (x,y) of a matrix M, i.e. with row index y and column index x, you need to write:
M(y,x)
In your case, you should write:
c = bw(int16(y), int16(x));
instead of:
c = bw(int16(x), int16(y));

Highlight sliding window in 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!