how do i mask labeled object based on some specified threshold value for each objects area,majoraxis and minoraxis? - matlab

i am currently using bwconnomp to label each connected object and regionpropsto find area, majoraxis, minoraxis of each labeled object respectively. i am also displaying each labeled object its area,majoraxis and minoraxis. now i want to set some threshold for area,majoraxis and minoraxis and if the value of area,majoraxis and minoraxis is above specified threshold then that object has to be masked.how this can be done??
here is my code
clc
clear all
close all
Index = 1;
scrsz = get(0,'ScreenSize');
%read an image
while Index ~= 0
% Open a dialog and select an image file
[FileName,FilePath,Index] = uigetfile('*.png', 'Open Imagefile ');
if Index == 0
disp('Procedure Done')
break;
end
inimage = imread([num2str(FilePath) FileName]);
D=inimage;
A=inimage;
subplot(2,3,1);
imshow(inimage);
title('original image');
%labeling algorithm
B=im2bw(inimage);
C=imfill(B,'holes');
label=bwlabel(C);
max(max(label))
CC = bwconncomp(B);
data = regionprops(CC,'all');
for j=1:max(max(label))
[row, col] = find(label==j);
len=max(row)-min(row)+2;
breadth=max(col)-min(col)+2;
target=uint8(zeros([len breadth] ));
sy=min(col)-1;
sx=min(row)-1;
for i=1:size(row,1)
x=row(i,1)-sx;
y=col(i,1)-sy;
target(x,y)=A(row(i,1),col(i,1));
end
mytitle=strcat('Object Number:' ,num2str(j),'area:', num2str(data(j).Area),'MajorAxis: ',num2str(data(j).MajorAxisLength),'MinorAxis: ',num2str(data(j).MinorAxisLength));
figure,imshow(target);title(mytitle);
a=size(target);
ax=a(1);
ay=a(2);
pos=[1,1,ay,ax];
rectangle('Position',pos,'EdgeColo','r')
end
next = input('next image? press Enter: ');
if next == 0
channelactivity = 0;
break
else
close all
disp('==================================')
pause(0.2)
continue
end
end

Here is a way to do it. The code is commented so easy to follow; the important line is the following:
AboveAreaIndices = find(vertcat(data.Area) > SomeValue)
In which you store the indices of the objects whose area is larger than SomeValue. In the example I color them red but you can do whatever you want with them or remove them altogether from the data structure.
You can also use logical operators to combine multiple conditions for example using the MinorAxis and MajorAxis properties. Note that I used AllArea as anew variable to store the concatenated areas to make things clearer, but you can keep them as vertcat(data.Area).
AboveIndices = find(vertcat(data.Area) > SomeValue & vertcat(data. MinorAxis) > SomeValue & Bla bla bla...);
Whole code:
clear
clc
close all
%// Read and clean up sample image
A = imread('rice.png');
A = im2bw(A,.5);
A = bwareaopen(A,50);
CC = bwconncomp(A);
%// Same as you.
data = regionprops(CC,'all');
%// Concatenate all the areas into an array.
AllArea = vertcat(data.Area);
%//========================================
%//==== Apply threshold on area here \\====
AboveAreaIndices = find(AllArea > 150);
%// If you wish to remove the entries from the data structure
% data(AllArea>150) = [];
%//========================================
%// Same for centroids...for display purposes
AllCentroids = vertcat(data.Centroid);
%// Display original and thresholded objects. Use the indices calculated
%// above to "mask" large areas if you want
imshow(A);
hold on
scatter(AllCentroids(:,1),AllCentroids(:,2),40,'b','filled')
scatter(AllCentroids(AboveAreaIndices,1),AllCentroids(AboveAreaIndices,2),40,'r','filled')
And sample output:

Related

For Loop and indexing

Following is my code :
function marks(my_numbers)
handle = zeros(5,1)
x = 10 ;
y = 10:20:100 ;
for i = 1
for j = 1:5 ;
handle(j,i) = rectangle('position',[x(i),y(j),20 10],'facecolor','r')
end
end
end
now lets say input argument my_numbers = 2
so i have written the code :
set(handle(j(my_numbers),1),'facecolor','g')
With this command, rectangle with lower left corner at (30,10) should have turned green. But MATLAB gives an error of index exceeds matrix dimensions
This is more an illustrated comment than an answer, but as #hagubear mentioned your i index is pointless so you could remove it altogether.
Using set(handle(my_numbers,1),'facecolor','g') will remove the error, because you were trying to access handles(j(2),1) and that was not possible because j is a scalar.
Anyhow using this line after your plot works fine:
set(handle(my_numbers,1),'facecolor','g')
According to your comment below, here is a way to call the function multiple times and add green rectangles as you go along. There are 2 files for the purpose of demonstration, the function per se and a script to call the function multiple times and generate an animated gif:
1) The function:
function marks(my_numbers)
%// Get green and red rectangles to access their properties.
GreenRect = findobj('Type','rectangle','FaceColor','g');
RedRect = findobj('Type','rectangle');
%// If 1st call to the function, create your plot
if isempty(RedRect)
handle = zeros(5,1);
x = 10 ;
y = 10:20:100 ;
for j = 1:5 ;
handle(j) = rectangle('position',[x,y(j),20 10],'facecolor','r');
end
set(handle(my_numbers,1),'facecolor','g')
%// If not 1st call, fetch existing green rectangles and color them green. Then color the appropriate rectangle given by my_numbers.
else
RedRect = flipud(RedRect); %// Flip them to maintain correct order
if numel(GreenRect) > 0
hold on
for k = numel(GreenRect)
set(GreenRect(k),'facecolor','g')
set(RedRect(my_numbers,1),'facecolor','g')
end
end
end
2) The script:
clear
clc
%// Shuffle order for appearance of green rectangles.
iter = randperm(5);
filename = 'MyGifFile.gif';
for k = iter
marks(k)
pause(1)
frame = getframe(1);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if k == iter(1)
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
Here is the animated gif of the output:

Take a text line in an image file to create a new image file MATLAB

I need to take each line of text from an image file and create a new separate image for each of the lines. i already have a way to count how many lines are in the image file.
if anybody has any suggestions it would be a huge help because i'm not too good with images. im not allowed to use the image processing toolbox.
This is the code:
function out = countLines( imgFile )
% count the number of lines in the image file
im = imread(imgFile);
im = 255 - im;
imbw = uint8(0.33*im(:,:,1) + 0.34*im(:,:,2) + 0.33*im(:,:,3)) > 127;
imwrite(imbw, 'temp.jpg');
rvec = sum(imbw');
rvec1 = [0 rvec 0];
svec = [rvec 0 0];
out = sum(rvec1 == 0 & svec ~= 0);
I tried this method on a test image I found on the internet and it seemed to work alright provided the text is straight. Basically you look for entries in your rvec vector whose neighbouring entries are both smaller than them. That is to say you look for the local maximum entries (first image). After that you group the clusters of lines together to decide where to split the image (second image).
clear; clc;
im = imread('text.png'); % load the image
[Nrows,Ncols,~] = size(im); % get the size
imgray = rgb2gray(im); % convert to grayscale
vec = mean(imgray,2); % average intensities of each row
localMax=[]; % list of local maximum entries
for i = 2:Nrows-1 % accept local max rows that do not have text
hasText = sum( imgray(i,:)<100 )>0;
if vec(i)>vec(i-1) && vec(i)>vec(i+1) && ~hasText
localMax = [localMax;i];
end
end
numMax = length(localMax);
% get distances between local max rows
distances = localMax(2:end) - localMax(1:end-1);
thresh = mean(distances); % the average distance will be our threshold
splitRows = []; % rows where we will split the image
cluster = localMax(1); % start a cluster with the first local max row
for i = 1:numMax-1;
if distances(i) < thresh % if rows are close together, keep them in a cluster
cluster = [cluster;localMax(i+1)];
else % average the cluster to get the row where we split the image
newSplit = round(mean(cluster));
splitRows = [ splitRows ; newSplit ];
cluster = localMax(i+1);
end
end
newSplit = round(mean(cluster)); % add the last cluster as well
splitRows = [ splitRows ; newSplit ];

Matlab get vector of specific pixels

I am pretty new to Matlab and encountered a problem when working with images.
I want to get a pixel that is in a specific colour (blue) in the following image:
image
My current code looks something like this:
function p = mark(image)
%// display image I in figure
imshow(image);
%// first detect all blue values higher 60
high_blue = find(image(:,:,3)>60);
%cross elements is needed as an array later on, have to initialize it with 0
cross_elements = 0;
%// in this iteration the marked values are reduced to the ones
%where the statement R+G < B+70 applies
for i = 1:length(high_blue)
%// my image has the size 1024*768, so to access the red/green/blue values
%// i have to call the i-th, i+1024*768-th or i+1024*768*2-th position of the "array"
if ((image(high_blue(i))+image(high_blue(i)+768*1024))<...
image(high_blue(i)+2*768*1024)+70)
%add it to the array
cross_elements(end+1) = high_blue(i);
end
end
%// delete the zero element, it was only needed as a filler
cross_elements = cross_elements(cross_elements~=0);
high_vector = zeros(length(cross_elements),2);
for i = 1:length(cross_elements)
high_vector(i,1) = ceil(cross_elements(i)/768);
high_vector(i,2) = mod(cross_elements(i), 768);
end
black = zeros(768 ,1024);
for i = 1:length(high_vector)
black(high_vector(i,2), high_vector(i,1)) = 1;
end
cc = bwconncomp(black);
a = regionprops(cc, 'Centroid');
p = cat(1, a.Centroid);
%// considering the detection of the crosses:
%// RGB with B>100, R+G < 100 for B<150
%// consider detection in HSV?
%// close the figure
%// find(I(:,:,3)>150)
close;
end
but it is not optimized for Matlab, obviously.
So i was wondering if there was a way to search for pixels with specific values,
where the blue value is larger than 60 (not hard with the find command,
but at the same time the values in the red and green area not too high.
Is there a command I am missing?
Since English isn't my native language, it might even help if you gave me some suitable keywords for googling ;)
Thanks in advance
Based on your question at the end of the code, you could get what you want in a single line:
NewImage = OldImage(:,:,1) < SomeValue & OldImage(:,:,2) < SomeValue & OldImage(:,:,3) > 60;
imshow(NewImage);
for example, where as you see you provide a restriction for each channel using logical operators, that you can customize of course (eg. using | as logical OR). Is this what you are looking for? According to your code you seem to be looking for specific regions in the image like crosses or coins is that the case? Please provide more details if the code I gave you is completely off the track :)
Simple example:
A = imread('peppers.png');
B = A(:,:,3)>60 & A(:,:,2)<150 & A(:,:,1) < 100;
figure;
subplot(1,2,1);
imshow(A);
subplot(1,2,2)
imshow(B);
Giving this:

MATLAB Array Iteration & Fieldname

I'm really struggling to do what I want with this so any help will be greatly appreciated.
I'm looping through an array X number of times, displaying an array of images in a randomised manner. What I want to do is retrieve the name of each image that is being currently displayed in the random order, and the array it belongs to, as each image is displayed in the loop, and store the two in separate variables.
images.blue = imread('blue.bmp');
images.red = imread('red.bmp');
images.green = imread('green.bmp');
images.yellow = imread('yellow.bmp');
colours = {images.blue, images.red, images.green, images.yellow}
cata = {images.blue, images.red}
catb = {images.green, images.yellow}
So for example if images.blue is being displayed on the screen while the loop is iterating through the array, I want the name blue to be saved in variable CurrentFieldname.
for count = 1;
names = (fieldnames(images));
while count <= 5
for n = randperm(length(colours));
d =(colours{n});
imshow(d);
pause(1)
CurrentFieldName = (names {n});
end
count = count+1;
end
break
end
What happens with the above code is that after all the images have been displayed, every iteration up till the condition is satisfied, the field name of the last displayed image is stored in CurrentFieldname.
The above is not what I want. After every time an image is displayed in the iterating loop, I want the field CurrentFieldname, to contain the name of the image that is being displayed. Then, during each interation through the loop, I would like to compare the CurrentFieldName with cata and catb, to see which array CurrentFieldName belongs to. Then, record this into a separate variable, CurrCat. E.g.
if CurrentFieldname == cata
CurrCat = a;
I would just like to have both of these variables, CurrentFieldName and CurrCat, contain the relevant information at the end of every iteration. Then they would both be overwritten by the information corresponding to the next image that is randomly displayed and so forth.
I hope this all makes sense.
Thanks
Lets try:
colors = {'red', 'green', 'blue', 'yellow' }; % existing colors, assuming for each color there is a .bmp image
NC = numel( colors ); % number of colors
% read the images once
for ci=1:NC
img.(colors{ci}) = imread( [colors{ci}, '.bmp' ] );
end
NumIters = 1; % number of iterations over all colors
% reapeat as many times
for itr = 1:NumIters
ord = randperm( NC ); % permutation for this iteration
for ci = ord(:)', %'
CurrentFieldName = colors{ci};
imshow( img.(colors{ci}) ); % display the current color image
title( colors{ci} );
tic;
% your code here processing img.(colors{ci})
Response = myFun( img.(colors{ci}) );
ResponseTime = toc; % record timing of processing
save( sprintf('data_for_itr%03d_color%02d.mat', itr, ci ),...
'CurrentFieldName', 'Response', 'ResponseTime' );
end
end

Rolling window for averaging using MATLAB

I have the following code, pasted below. I would like to change it to only average the 10 most recently filtered images and not the entire group of filtered images. The line I think I need to change is: Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;, but how do I do it?
j=1;
K = 1:3600;
window = zeros(1,10);
Yout = zeros(10,column,row);
figure;
y = 0; %# Preallocate memory for output
%Load one image
for i = 1:length(K)
disp(i)
str = int2str(i);
str1 = strcat(str,'.mat');
load(str1);
D{i}(:,:) = A(:,:);
%Go through the columns and rows
for p = 1:column
for q = 1:row
if(mean2(D{i}(p,q))==0)
x = 0;
else
if(i == 1)
meanvalue = mean2(D{i}(p,q));
end
%Calculate the temporal mean value based on previous ones.
meanvalue = (meanvalue+D{i}(p,q))/2;
x = double(D{i}(p,q)/meanvalue);
end
%Filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
end
end
end
% for k = 2:10
% subplot(5,2,k)
% subimage(Yout(k)*5000, [0 100]);
% colormap jet
% end
% pause(0.01);
end
disp('Done Loading...')
The best way to do this (in my opinion) would be to use a circular-buffer to store your images. In a circular-, or ring-buffer, the oldest data element in the array is overwritten by the newest element pushed in to the array. The basics of making such a structure are described in the short Mathworks video Implementing a simple circular buffer.
For each iteration of you main loop that deals with a single image, just load a new image into the circular-buffer and then use MATLAB's built in mean function to take the average efficiently.
If you need to apply a window function to the data, then make a temporary copy of the frames multiplied by the window function and take the average of the copy at each iteration of the loop.
The line
Yout(k,p,q) = (Yout(k,p,q) + (y.^2))/2;
calculates a kind of Moving Average for each of the 10 bands over all your images.
This line calculates a moving average of meanvalue over your images:
meanvalue=(meanvalue+D{i}(p,q))/2;
For both you will want to add a buffer structure that keeps only the last 10 images.
To simplify it, you can also just keep all in memory. Here is an example for Yout:
Change this line: (Add one dimension)
Yout = zeros(3600,10,column,row);
And change this:
for q = 1:row
[...]
%filtering for 10 bands, based on the previous state
for k = 1:10
[y, ZState{k}] = filter(bCoeff{k},aCoeff{k},x,ZState{k});
Yout(i,k,p,q) = y.^2;
end
YoutAvg = zeros(10,column,row);
start = max(0, i-10+1);
for avgImg = start:i
YoutAvg(k,p,q) = (YoutAvg(k,p,q) + Yout(avgImg,k,p,q))/2;
end
end
Then to display use
subimage(Yout(k)*5000, [0 100]);
You would do sth. similar for meanvalue