Determining black pixels as white in matlab - 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));

Related

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 display the connected component through a specific pixel coordinate

I have a gray scale image add1, however there are only two pixel intensities in it (0 for Black and 255 for White). I am able to track the coordinate of my pixel of consideration i.e. add1(i,j). now I want to display the connected component of which this pixel is part of. I have tried it with the regionprop using 'PixelIdxList' and 'PixelList' unsuccesfully.
Can someone help please.Thanks in advance.
As much i understand you want this:
clc
clear all
close all
im = imread('labelProb.png');
im = im2bw(im);
labelIm = bwlabel(im);
rg = regionprops(im,'PixelIdxList','Centroid');
figure,imshow(labelIm,[]),hold on
for i = 1:length(rg)
cc = rg(i).Centroid;
text(cc(1),cc(2),['label: ',num2str(i)],'Color','b','FontSize',9)
end
f = getframe();
lab = frame2im(f);
hold off
% suppose you want label number 3 only.
cc = rg(3).Centroid; % this is your pixel index;
% Extract label number through this index.
cc = round(cc);
labelNumber = labelIm(cc(2),cc(1));
% create a new blank image.
blankImage = false(size(im));
for i = 1:length(rg)
if i == labelNumber
blankImage(rg(i).PixelIdxList) = true;
end
end
figure,imshow(blankImage,[])
And result of above execution are:
If I understand your question, what you want is: given a specific coordinates (i,j) what is the label, and mask of the connected component that (i,j) is part of.
add = bwlabel( add1 ); %// convert to label mask
lij = add(i,j); %// get the label to which i,j belongs to
figure;
imshow( add == lij, [] ); %// select only the relevant label

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.

How to calculate center of gravity of pixels in an image?

This is my homework question:
Write HW3_func.m as follows:
function [cogR, cogC] = HW3_func ( f, i )
f: input grayscale image
i : intensity level to check
Function should find all the pixels in f with intensity of i. Then, return the center of gravity of those pixels as [cogR, cogC]. Center of gravity is computed as the average of the row and average of column. If no pixel == i, then return [0,0]
I don't understand how to calculate center of gravity. What I have done is:
Declare a matrix X with the same dimension as the image. Initialize it with all zeros
Find the position of the pixels with the given intensity in the input image and replace those positions in X with 1.
Am I on the right path?
This is what I have right now:
function [ cogR,cogC ] = HW3_func(f,i)
[r,c] = size(f)
X = zeros(r,c)
for k = 1:r
for j = 1:c
if f(k,j)==i
X(k,j)=1;
end
end
end
%disp(X)
cogR=centroid(X);
cogC=centroid(X,2);
disp(cogR)
disp(cogC)
end
You probably just want to use find(), e.g.
[row_indices, col_indices, values] = find(f==i)
The CoG coordinates are then, as you said, just the average of the row and column indices, which you now have in two vectors. See mean().

Model division of cancer cells on a grid

I have a 5000x5000 grid, and I'm trying to implement a simple model of cancer division in MATLAB. Initially, it picks a random point (x,y) and makes that cell a cancer cell. On the first iteration, it divides - the parent cell stays in it's place, the daughter cell is randomly assigned to any neighbouring cell.
Easy so far.
My problem is this: on successive iterations, a daughter cell will often be assigned to a cell that already has a cancer cell. In this case, I want the daughter cell to take its place and "bump" the cell already there to an adjacent cell. If that adjacent cell is empty, it is filled and the process stops. If not, the cell already in that place is bumped and so on until the last cell finds an empty space and the process stops.
This should be simple, but I have no idea how to code it up and what kind of loops to use.
I'm a physical scientists rather than a programmer, so please treat me like a simpleton!
Here is a function I hacked together that roughly meets the specs you provided.
I does slow down as the number of cancerous cells gets large.
Basically I have a few variables, the NxN matrix that represents the grid of cell locations (i call this a plate as grid is the name of an existing matlab function)
A vector of points that I can iterate through quickly. I pick a seed location and then run a while loop until the grid is full.
On each loop iteration I perform the following for each cell:
Generate a random number to determine if that cell should divide
Generate a random direction to divide
Find the first open plate position in that direction
Populate that position
I haven't tested it extensively but it appears to work.
function simulateCancer(plateSize, pDivide)
plate = zeros(plateSize, plateSize);
nCells = 1;
cellLocations = zeros(plateSize*plateSize,2);
initX = randi(plateSize);
initY = randi(plateSize);
cellLocations(nCells,:) = [initX, initY];
plate(initX, initY) = 1;
f = figure;
a = axes('Parent', f);
im = imagesc(plate, 'Parent', a);
while(nCells < (plateSize * plateSize))
currentGeneration = currentGeneration+1;
for i = 1:nCells
divide = rand();
if divide <= pDivide
divideLocation = cellLocations(i,:);
divideDir = randi(4);
[x, y, v] = findNewLocation(divideLocation(1), divideLocation(2), plate, divideDir);
if (v==1)
nCells = nCells+1;
plate(x,y) = 1;
cellLocations(nCells,:) = [x,y];
end
end
end
set(im,'CData', plate);
pause(.1);
end
end
function [x,y, valid] = findNewLocation(xin, yin, plate, direction)
x = xin;
y = yin;
valid = 1;
% keep looking for new spot if current spot is occupied
while( plate(x, y) == 1)
switch direction
case 1 % divide up
y = y-1;
case 2 % divide down
y = y+1;
case 3 % divide left
x = x-1;
case 4 % divide down
x = x+1;
otherwise
warning('Invalid direction')
x = xin;
y = yin;
return;
end
%if there has been a collision with a wall then just quit
if y==0 || y==size(plate,2)+1 || x==0 || x==size(plate,1)+1 % hit the top
x = xin; %return original values to say no division happend
y = yin;
valid = 0;
return;
end
end
end
Note: Instead of thinking of pushing cells, I coded this in a way that leaves cells where they currently are and creates the new cell at the end of the row/column. Semantically its different but logically it has the same end result, as long as you don't care about the generations.
Inspired by an another question, I though of using image processing techniques to implement this simulation. Specifically we can use morphological dilation to spread the cancerous cells.
The idea is to dilate each pixel using a structuring element that looks like:
1 0 0
0 1 0
0 0 0
where the center is fixed, and the other 1 is placed at random at one of the other eight remaining positions. This would effectively extend the pixel in that direction.
The way the dilation is performed is by created a blank image, with only one pixel set, then accumulating all the results using a simple OR operation.
To speed things up, we don't need to consider every pixel, only those on the perimeter of the current blocks formed by the clusters of cancerous cells. The pixels on the inside are already surrounded by cancer cells, and would have no effect if dilated.
To speed even further, we perform the dilation on all pixels that are chosen to be extended in the same direction in one call. Thus every iteration, we perform at most 8 dilation operations.
This made the code relatively fast (I tested up to 1000x1000 grid). Also it maintains the same timing across all iterations (will not slow down as the grid starts to fill up).
Here is my implementation:
%# initial grid
img = false(500,500);
%# pick 10 random cells, and set them as cancerous
img(randi(numel(img),[10 1])) = true;
%# show initial image
hImg = imshow(img, 'Border','tight', 'InitialMag',100);
%# build all possible structing elements
%# each one dilates in one of the 8 possible directions
SE = repmat([0 0 0; 0 1 0; 0 0 0],[1 1 8]);
SE([1:4 6:9] + 9*(0:7)) = 1;
%# run simulation until all cells have cancer
BW = false(size(img));
while ~all(img(:)) && ishandle(hImg)
%# find pixels on the perimeter of all "blocks"
on = find(bwperim(img,8));
%# percentage chance of division
on = on( rand(size(on)) > 0.5 ); %# 50% probability of cell division
if isempty(on), continue; end
%# decide on a direction for each pixel
d = randi(size(SE,3),[numel(on) 1]);
%# group pixels according to direction chosen
dd = accumarray(d, on, [8 1], #(x){x});
%# dilate each group of pixels in the chosen directions
%# to speed up, we perform one dilation for all pixels with same direction
for i=1:8
%# start with an image with only those pixels set
BW(:) = false;
BW(dd{i}) = true;
%# dilate in the specified direction
BW = imdilate(BW, SE(:,:,i));
%# add results to final image
img = img | BW;
end
%# show new image
set(hImg, 'CData',img)
drawnow
end
I also created an animation of the simulation on a 500x500 grid, with 10 random initial cancer cells (warning: the .gif image is approximately 1MB in size, so may take some time to load depending on your connection)