I need to create a GUI in Matlab. It requires me to identify the spots for two images, and calculate the distance between them.
I have obtained the code for finding and encircling a single spot. It is as follows:
function [meanx,meany] = centroid(pic)
[x,y,z] = size(pic);
if(z==1)
;
else
pic = rgb2gray(pic);
end
% N=2;
% image = interp2(double(pic),N,'spline');
image = sort(sort(pic,1),2);
image =reshape(image,1,numel(image));
i=0;
while(i<3)
if(image(end)==image(end-1))
image(end)=[];
else
image(end)=[];
i=i+1;
end
end
threshold = image(end);
pic2 =(pic>=threshold);
pic=(pic-threshold).*uint8(pic2);
% % image=(pic-threshold+1).*uint8(image); %minus threshold
[rows,cols] = size(pic);
x = ones(rows,1)*[1:cols];
y = [1:rows]'*ones(1,cols);
area = sum(sum(pic));
if area ~= 0
meanx = sum(sum(double(pic).*x))/area;
meany = sum(sum(double(pic).*y))/area;
else
meanx = cols/2;
meany = rows/2;
end
However, I need it to work for multiple spots as shown below :
http://imgur.com/oEe0mRV,UAnbH5y#0
http://imgur.com/oEe0mRV,UAnbH5y#1
So far, I have come up with this, but it only circles separate spots and not all together.
PLEASE HELP - I need to encircle at least 10X10 spots and store their values, and do this for two images as shown above, and find the distance between them!
img1 = imread('r0.bmp');
centroidmat=zeros(10,10,2);
for numx=1:2
for numy=1:2
single_spot=img1((numx*220+780):((numx+1)*220+780),(numy*220+1272):((numy+1)*220+1272),:);
figure
imshow(single_spot);
figure
[cx,cy] = centroid(single_spot);
centroidmat(numx,numy,1)=cx;
centroidmat(numx,numy,2)=cy;
imshow(single_spot);
hold on;
plot(cx,cy,'og')
end
end
Please HELP GUYS! Any help is appreciated!
Would this work ? -
centroidmat=zeros(10,10,2);
for numx=1:2
for numy=1:2
single_spot=img1((numx*220+780):((numx+1)*220+780),(numy*220+1272):((numy+1)*220+1272),:);
[cx,cy] = centroid(single_spot);
centroidmat(numx,numy,1)=cx;
centroidmat(numx,numy,2)=cy;
figure,
imshow(single_spot);
hold on;
plot(cx,cy,'og')
end
end
I have only removed the redundant figure and imshow(single_spot); at the start of the loop, as they appear again later on inside the same loop.
Related
I am attending a class on image processing with Matlab and I found a problem on the internet and I tried to solve it but it is hard, because I am new to this subject.
The problem has to be solved with Matlab and it is new for me as well.
Problem:
'Think of RGB and HSV spaces as 3-dimensional spaces. Define a
neighborhood distance (we can use ecludien distance) and set to 0 all
the pixels whose value in RGB or HSV space is far (in the sense of
this distance) from your reference value. See if you can easily
achieve the same type of segmentation in both cases. Try for example
to segment only the helmets of the warriors of the image
bilibinWar.jpg.'
I tried to code it but i don't know if the result is good.
%%
% 4) 8 - Segmentatiion dans l’’espace HSV et RVB..
clear all; close all;
ImagebilibinWar = imread("bilibinWar.jpg");
[lin, col, pla] = size(ImagebilibinWar);
figure(1);imshow(ImagebilibinWar);
Image_bilibinWar_HSV= rgb2hsv(ImagebilibinWar);
[lo,co] = ginput(1);
lo = round(lo);
co = round(co);
RIOH = Image_bilibinWar_HSV(lo,co,1);
%%
% Im going to use this first section so ican isolate the helmets inside a circle ARROUND THE HELMETS and get rid of REST background Circle_Image_bilibinWar_HSV = Image_bilibinWar_HSV;
for i= 1:lin
for j = 1:col
d(i,j) = ((i-lo)^2 + (j-co)^2)^0.5;
if d(i,j,:) > 90
Circle_Image_bilibinWar_HSV(i,j,:) = 0;
end
end
end
Circle_Image_bilibinWar_RGB = hsv2rgb(Circle_Image_bilibinWar_HSV);
figure(2);imshow(Circle_Image_bilibinWar_RGB); % i have isolated the circle
%% here im going to isolate the helmets inside the circle
figure(3); imshow(Circle_Image_bilibinWar_HSV); % as u can see here i will try to isolate the helmets from the rest
New_Circle_Image_bilibinWar_HSV = Circle_Image_bilibinWar_HSV % assinging a new image so as i can work on it seperatly;
valueH = New_Circle_Image_bilibinWar_HSV(lo,co,1);
for i=1:lin
for j=1:col
if (New_Circle_Image_bilibinWar_HSV(i,j,1) > valueH + 0.19)
New_Circle_Image_bilibinWar_HSV(i,j,:) = 0;
end
end
end
Circle_Image_bilibinWar_HSV = Circle_Image_bilibinWar_HSV - New_Circle_Image_bilibinWar_HSV;
NEW_Image_bilibinWar_RGB = hsv2rgb(Circle_Image_bilibinWar_HSV);
figure(4); subplot(1,2,1);imshow(ImagebilibinWar);
subplot(1,2,2);imshow(NEW_Image_bilibinWar_RGB);
So can some one help me with it? i don't know if its good and if not how can i make it good ?
I don't think there is anything wrong with your code. The answer is that segmenting using euclidean distance in colors simply does not work for RGB or HSV spaces. The entire purpose of the L*a*b color space was indeed this, creating a color space where similar colors would have the little euclidean distance.
Here a less cluttered version of it:
clear all; close all;
ImagebilibinWar = imread("https://i.stack.imgur.com/wnBDu.jpg");
[lin, col, pla] = size(ImagebilibinWar);
figure;imshow(ImagebilibinWar);
ImagebilibinWarHSV= rgb2hsv(ImagebilibinWar);
[lo,co] = ginput(1);
lo = round(lo);
co = round(co);
RIOH = ImagebilibinWarHSV(lo,co,1);
RIOS = ImagebilibinWarHSV(lo,co,2);
RIOV = ImagebilibinWarHSV(lo,co,3);
%reference value that i have to choose
for a=0:0.05:1
d = ((ImagebilibinWarHSV(:,:,1)-RIOH).^2 + (ImagebilibinWarHSV(:,:,2)-RIOS).^2+(ImagebilibinWarHSV(:,:,3)-RIOV).^2).^0.5;
ImagebilibinWarRGB = hsv2rgb(ImagebilibinWarHSV.*double(d<a));
figure;imshow(ImagebilibinWarRGB);
end
I'm working on this function which gets axis handler and data, and is supposed to plot it correctly in the axis. The function is called in for loop. It's supposed to draw the multiple data in one figure. My resulted figure is shown below.
There are only two correctly plotted graphs (those with four colors). Others miss areas plotted before the final area (red area is the last plotted area in each graph). But the script is same for every axis. So where can be the mistake? The whole function is written below.
function [] = powerSpectrumSmooth(axis,signal,fs)
N= length(signal);
samplesPer1Hz = N/fs;
delta = int16(3.5*samplesPer1Hz); %last sample of delta frequncies
theta = int16(7.5*samplesPer1Hz); %last sample of theta frequncies
alpha = int16(13*samplesPer1Hz); %last sample of alpha frequncies
beta = int16(30*samplesPer1Hz); %last sample of beta frequncies
x=fft(double(signal));
powerSpectrum = 20*log10(abs(real(x)));
smoothPS=smooth(powerSpectrum,51);
PSmin=min(powerSpectrum(1:beta));
y1=[(smoothPS(1:delta)); zeros(beta-delta,1)+PSmin];
y2=[zeros(delta-1,1)+PSmin; (smoothPS(delta:theta)); zeros(beta-theta,1)+PSmin];
y3=[zeros(theta-1,1)+PSmin; (smoothPS(theta:alpha)); zeros(beta-alpha,1)+PSmin];
y4=[zeros(alpha-1,1)+PSmin; (smoothPS(alpha:beta))];
a1=area(axis,1:beta,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axis,1:beta,y2);
set(a2,'FaceColor','blue')
a3=area(axis,1:beta,y3);
set(a3,'FaceColor','green')
a4=area(axis,1:beta,y4);
set(a4,'FaceColor','red')
ADDED
And here is the function which calls the function above.
function [] = drawPowerSpectrum(axesContainer,dataContainer,fs)
size = length(axesContainer);
for l=1:size
powerSpectrumSmooth(axesContainer{l},dataContainer{l},fs)
set(axesContainer{l},'XTickLabel','')
set(axesContainer{l},'YTickLabel','')
uistack(axesContainer{l}, 'top');
end
ADDED 29th July
Here is a script which reproduces the error, so you can run it in your computer. Before running it again you might need to clear variables.
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
a1=area(axes,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axes,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axes,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axes,1:N,y4);
set(a4,'FaceColor','red')
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
My result of this script is plotted below:
Again only one picture contains all areas.
It looks like that every call to plot(axes,data) deletes whatever was written in axes.
Important note: Do not use a variable name the same as a function. Do not call something sin ,plot or axes!! I changed it to axs.
To solve the problem I just used the classic subplot instead of creating the axes as you did:
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axs=subplot(3,3,l);
a1=area(axs,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axs,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axs,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axs,1:N,y4);
set(a4,'FaceColor','red')
set(axs,'XTickLabel','')
set(axs,'YTickLabel','')
axis tight % this is to beautify it.
end
As far as I know, you can still save the axs variable in an axescontainer and then modify the properties you want (like location).
I found out how to do what I needed.
len = 8;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
Y=[y1',y2',y3',y4'];
a=area(axes,Y);
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
The area is supposed to work with matrices like this. The tricky part is, that the signal in every next column is not plotted absolutely, but relatively to the data in previous column. That means, if at time 1 the data in first column has value 1 and data in second column has value 4, the second column data is ploted at value 5. Source: http://www.mathworks.com/help/matlab/ref/area.html
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:
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
I am on a project thumb recognition system on matlab. I implemented Kmean Algorithm and I got results as well. Actually now I want to plot the results like here they done. I am trying but couldn't be able to do so. I am using the following code.
load training.mat; % loaded just to get trainingData variable
labelData = zeros(200,1);
labelData(1:100,:) = 0;
labelData(101:200,:) = 1;
k=2;
[trainCtr, traina] = kmeans(trainingData,k);
trainingResult1=[];
for i=1:k
trainingResult1 = [trainingResult1 sum(trainCtr(1:100)==i)];
end
trainingResult2=[];
for i=1:k
trainingResult2 = [trainingResult2 sum(trainCtr(101:200)==i)];
end
load testing.mat; % loaded just to get testingData variable
c1 = zeros(k,1054);
c1 = traina;
cluster = zeros(200,1);
for j=1:200
testTemp = repmat(testingData(j,1:1054),k,1);
difference = sum((c1 - testTemp).^2, 2);
[value index] = min(difference);
cluster(j,1) = index;
end
testingResult1 = [];
for i=1:k
testingResult1 = [testingResult1 sum(cluster(1:100)==i)];
end
testingResult2 = [];
for i=1:k
testingResult2 = [testingResult2 sum(cluster(101:200)==i)];
end
in above code trainingData is matrix of 200 X 1054 in which 200 are images of thumbs and 1054 are columns. actually each image is of 25 X 42. I reshaped each image in to row matrix (1 X 1050) and 4 other (some features) columns so total of 1054 columns are in each image. Similarly testingData I made it in the similar manner as I made testingData It is also the order of 200 X 1054. Now my Problem is just to plot the results as they did in here.
After selecting 2 features, you can just follow the example. Start a figure, use hold on, and use plot or scatter to plot the centroids and the data points. E.g.
selectedFeatures = [42,43];
plot(trainingData(trainCtr==1,selectedFeatures(1)),
trainingData(trainCtr==1,selectedFeatures(2)),
'r.','MarkerSize',12)
Would plot the selected feature values of the data points in cluster 1.