Split histogram into different regions in Matlab - matlab

I have an Image histogram using imhist and it contains 3 different regions like the attached image shows, I want to get the borders or the interval of the largest continuous area of the histogram, in this case, the second region is the one that I am looking for and the borders would be 43 and 225

You can find the begin and end bins for each region like this
[counts,binLocations] = imhist(I);
der = diff([false; counts>0; false]);
upedge = find(der == 1);
downedge = find(der == -1) - 1;
regions = [binLocations(upedge) binLocations(downedge)];
If the values are not exactly zero, but very close to zero then you can replace 0 with some threshold value in the above code.
Example
im = uint8(zeros(300,400));
im(1:100,:) = uint8(randi([0,40],[100,400]));
im(101:200,:) = uint8(randi([90,100],[100,400]));
im(201:300,:) = uint8(randi([140,240],[100,400]));
[counts,binLocations] = imhist(im);
der = diff([false; counts>0; false]);
upedge = find(der == 1);
downedge = find(der == -1) - 1;
regions = [binLocations(upedge) binLocations(downedge)];
results in
regions =
0 40
90 100
140 240

I will use the answer to this question to find regions of consecutive non zero elements in an array.
lets assume we have this array (histogram):
h = [0,0,0,1,2,3,44,77,5,656,0,0,0,0,0,0,2,99,7,34];
now we want to know were each region of consecutive non-zero elements starts and ends, in this example we want
startIndex = [4,17]
endIndex = [10,20]
lengths = [7,4]
to get this result we use the code from the question as follows:
dsig = diff([1,h(:)'==0,1]);
startIndex = find(dsig < 0);
endIndex = find(dsig > 0)-1;
duration = endIndex-startIndex+1;
and to get longest region use:
[~,maxLengthIndex] = max(lengths);
maxStartIndex = startIndex(maxLengthIndex);
maxEndIndex = endIndex(maxLengthIndex);

Related

My Decision Tree predict() method returns the same label for every test example

My Decision tree Classifier returns the same class label for every prediction "setosa" when minParentSize is set to 1 and in other cases returns a prediction accuracy of only 5%. I have spent days trying to fix this and assume it is something wrong with my buildTree method as my predict method is very simple and just loops through the nodes checking if the currentNode cutPoint is lower than the current feature value in test_examples.
Here is my buildTree() and findBestCutPoint()
function bestCut = findBestCutPoint(obj,node)%find the best cut point for the current node
bestCut.CutPoint = 0;
bestCut.CutPredictorIndex = 0;
bestCut.CutIndex = 0;
bestCut.ShouldCut = true;
bestGDI = Inf;
parentLabels = obj.Y(node.StartIndex:node.EndIndex, 1);
parentProbability = node.Size/length(obj.X);
parentGDI = weightedGDI(parentLabels, obj.Y);
parentSplitVal = parentProbability * parentGDI;
for i = 1:size(obj.X,2)% Loop through all the features
values = unique(obj.X(node.StartIndex:node.EndIndex, i));% Loop through all the unique values of the feature
values = sort(values);
for j = 1:length(values) % Calculate the weighted impurity of the two cuts
leftLabels = obj.Y(node.StartIndex:node.EndIndex, 1);
rightLabels = obj.Y(node.StartIndex:node.EndIndex, 1);
leftProb = obj.X(node.StartIndex:node.EndIndex, i) < values(j);
rightProb = obj.X(node.StartIndex:node.EndIndex, i) >= values(j);
leftLabels = leftLabels(obj.X(node.StartIndex:node.EndIndex, i) < values(j));
rightLabels = rightLabels(obj.X(node.StartIndex:node.EndIndex, i) >= values(j));
leftProbability = length(leftProb)/length(obj.X);
rightProbability = length(rightProb)/length(obj.X);
leftGDI = weightedGDI(leftLabels, obj.Y);
rightGDI = weightedGDI(rightLabels, obj.Y);
cutGDI = ((leftProbability * leftGDI) + (rightProbability * rightGDI));% Calculate the weighted impurity of the split
if cutGDI < bestGDI % Update the best split if the current split has a lower GDI
bestGDI = cutGDI;
value = (values(j) + values(j-1))/2;%added
bestCut.CutPoint = value; %swapped values(j)
bestCut.CutPredictorIndex = i;
bestCut.CutIndex = find(obj.X(:, i) == values(j), 1, 'first');
end
end
end
if parentSplitVal <= bestGDI
bestCut.ShouldCut = false;
return
end
end
% the fitting phase:
function treenode = buildTree(obj,node)
CutPoint = findBestCutPoint(obj,node);
if node.Size <= obj.MinParentSize || obj.CurrentNumSplits >= obj.MaxNumSplits || CutPoint.ShouldCut == false
node.Leaf = true;% Mark the node as a leaf node
labels = obj.Y(node.StartIndex:node.EndIndex); %gather all the labels for the data in the nodes range
node.NodeClass = mode(labels);%find the most frequent label and classify the node as such
obj.Nodes{end+1} = node;%add the node to the Nodes cell array
obj.Leaves{end+1} = node;
treenode = node;%return the node so it can be added as a child
return;
end
leftChild = Node(node.StartIndex, CutPoint.CutIndex - 1);%create a node called left child with the same start index as the original node and end index as the last one before the cut index
rightChild = Node(CutPoint.CutIndex, node.EndIndex);% create the right child node with the cut index as sindex and the same eindex as the original node
obj.CurrentNumSplits = obj.CurrentNumSplits + 1;%update the number of splits
node.CutPoint = CutPoint.CutPoint;%save the cutpoint
node.CutPredictorIndex = CutPoint.CutPredictorIndex;%save the cutpredictor index
%labels = obj.Y(node.StartIndex:node.EndIndex); %gather all the labels for the data in the nodes range
%node.NodeClass = mode(labels); %find the most frequent label and classify the node as such
node.Left = buildTree(obj,leftChild);%recusively build the tree from the left child and save it as the original nodes left child changed from CHILDREN{1}
node.Right = buildTree(obj,rightChild);%recusively build the tree from the right child and save it as the original nodes right child
treenode = node;%return the node
obj.Nodes{end+1} = treenode;%add the node to the nodes cell array
end
And here is my predict()
function predictions = predict(obj, test_examples)
% get ready to store our predicted class labels:
predictions = categorical;
for i = 1:length(test_examples)
thisNode = obj.Root;
while thisNode.Leaf == false
if test_examples(i,thisNode.CutPredictorIndex) < thisNode.CutPoint
k = findNodeIndex(obj,thisNode.Left);
thisNode = obj.Nodes{k};
disp('Left Child')
disp(thisNode)
else
k = findNodeIndex(obj,thisNode.Right);
thisNode = obj.Nodes{k};
disp('Right Child')
disp(thisNode)
end
end
predictions(i,1) = thisNode.NodeClass;
disp('leaf')
disp(thisNode)
end
end
The data set I'm using is set out as a 90x2 array for training examples with 2 features and a 90x1 for the
training labels.
Testing data is 60x2 for the examples and 60x1 for the labels.
I am trying to train a decision tree based off the training data and labels to predict what labels the testing data has.
The testing data was predicted to be all the same label "setosa"

Dot indexing is not supported for variables of this type for filtering particle tracking (imageJ)

When I ran the code below, it gave me this error. Any thoughts?
Unable to perform assignment because dot indexing is not supported for variables of this type.
The fundamental basis of this piece of is to filter or parse through a series of tracking data (generated via ImageJ/Fiji), one named Spots and one named Tracks, to remove undesired particle tracks - those that do not share a starting time of 0 and have different durations.
Batch Process Control
%batch parse TrackMate V.7 output to individual x y and t .csv files
clear all; clc;
%specify directory
directory = '/Volumes/GoogleDrive/Shared drives/Jessica_Michael/Data/matlab/20220715_noise_floor/';
addpath(directory)
%find and store all imgs in the directory to cell array
dirspots = dir([directory '*Spots_statistics.csv']);
dirtracks = dir([directory '*Tracks_statistics.csv']);
spotsfnames = {};
tracksfnames = {};
numfiles = length(dirspots);
[spotsfnames{1:numfiles}] = dirspots(:).name;
[tracksfnames{1:numfiles}] = dirtracks(:).name;
for fnum = 1:numfiles
spots_file = spotsfnames{fnum};
tracks_file = tracksfnames{fnum};
[x_temp, y_temp, t_temp] = parse_file(tracks_file,spots_file);
x_filtered{fnum}=x_temp;
y_filtered{fnum}=y_temp;
t_filtered{fnum}=t_temp;
end
%% read track statistics
function [x_filtered,y_filtered,t_filtered]=parse_file(tracks_file,spots_file)
trackStatistics = readtable(tracks_file);
lengthTrack = length(trackStatistics.TRACK_START); %returns number of rows/tracks
trackStatistics_filtered = [];
spotsStatistics_filtered = [];
x_filtered = [];
y_filtered = [];
t_filtered = [];
spotsStatistics = readtable(spots_file);
lengthSpots = length(spotsStatistics.ID); %returns number of rows/spots
max_frame = max(spotsStatistics.FRAME)+1; %TrackMate frame number starts from 0
max_timelapse = max(trackStatistics.TRACK_DURATION);
for i = 1 : lengthTrack
if trackStatistics.TRACK_START(i) == 0 && trackStatistics.TRACK_DURATION(i) == max_timelapse
trackStatistics_filtered(end+1) = trackStatistics.TRACK_ID(i);
end
end
lengthStatistics_filtered = length(trackStatistics_filtered);
for j = 1 : lengthStatistics_filtered
for i = 1 : lengthSpots
if spotsStatistics.TRACK_ID(i) == trackStatistics_filtered(j)
% if there is a trackID equal to one in the filtered list,
% append that spotsStatistics to the *END* of the row
spotsStatistics_filtered = [spotsStatistics_filtered; spotsStatistics(i,:)];
end
end
% at the end of each x_, y_, and t_filtered, append spotsStatistics.
% x_filtered, y_filtered and t_filtered will grow in size till for loop
% ends.
x_filtered = [x_filtered spotsStatistics_filtered.POSITION_X(end-max_frame+1:end)];
y_filtered = [y_filtered spotsStatistics_filtered.POSITION_Y(end-max_frame+1:end)];
t_filtered = [t_filtered spotsStatistics_filtered.POSITION_T(end-max_frame+1:end)];
end
end
Any recommendations?

Spheroids detction from Images

I need to find the blobs from the below image.
The major problem is background. background doesn't have uniform intensity. I tried couple of things like thresholding and edge detection in MATLAB but couldn't able to find a better ways to segment out all spheroids. I need to extract the blobs and I need to find the area of each blobs. Does anyone know how to work-around with this kind of background?
Edit (07/02/17):
As suggested by Spektre I tried Following things in MATLAB.
Method 1:
img_original = imread('~/my_image.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
g = fspecial('gaussian',200,100); %Kernel matrix to make the img blurr
con_img = conv2(img_ch,g,'same'); %2D convolution, this wil make the img blurr
sub_img = (con_img - img_ch); %Simple matrix subtraction
sub_img(sub_img <= 10) = 0; %Thresholding
sub_img(sub_img ~= 0) = 1;
fil_sub = imfill(sub_img,'holes'); %Fill the regions
imgfilt = imfilter(fil_sub, ones(3)); %run filter using 3by3 matrx
imgfilt(imgfilt < 8) = 0; %Reduce noisy pixels by thresholding
mfilt_img = (medfilt2(imgfilt)); %reduce unwanted pixels
img = img_ch;
img(mfilt_img ~= 0) = 255;
img2 = img_ch;
img2(img2 < 70) = 0; %Threshold for darker pixels which are left out from above methode.
img(img2 ==0) = 255;
disp_img = img_original(:,:,1);
disp_img(img ==255) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
I got the segments but still not good enough I think. This method gave good segments in the high intensity background, Even if I reduce the threshold value segments are not clear in the darker background and brightest pixels in the blobs are excluded.
Method 2:
img_original = imread('~/cancer_cells/Snap-10234.jpg'); %Read image
img_ch = single(img_original(:,:,2)); %Pick one channel( here its green)
clear new_matcel cur_img matcel avg_matrx
s=3; % Set size of the square window
mat_img = img_ch; % Working image channel
% resize the working matrix so that the dimensions matches
resize_img = resizem(mat_img,round(size(mat_img)/s)*s);
% convert matrix into small s x s matrix and save each in cells
window_c = ones(1,size(resize_img,1)/s) * s;
window_r = ones(1,size(resize_img,2)/s) * s;
mat_cel = mat2cell(resize_img,window_c,window_r);
new_matcel = cell(size(mat_cel)); % initialize new variable
% get the average value for each window and replace the actual by avg value
for i = 1:size(mat_cel,1)
for j = 1:size(mat_cel,2)
cur_img = mat_cel{i,j};
avg_value = mean(mean(cur_img));
new_matcel{i,j} = ones(s) * avg_value;
end
end
avg_matrx = cell2mat(new_matcel); % convert cells to matrix
image_sub = (abs(resize_img - avg_matrx)); % take the absolute difference
image_sub(image_sub < 7) = 0; % thresholding
image_sub(image_sub~=0) = 1;
image_sub = bwmorph(image_sub,'bridge');% fill gaps
image_sub = imfill(image_sub,'holes'); % fill the bounded regioons
% image_sub(image_sub == 1) = 255;
image_sub = resizem(image_sub,size(img_ch)); % resize to original size
disp_img = img_original(:,:,1);
disp_img(image_sub == 1) = 255;
img_original(:,:,1) = disp_img;
figure, imshow(img_original)
Much better segmented image:
even brighter pixels are included in the segment. Thanks to Spektre.
Is there a way to improve the above code? or any other idea to get more precise segments?
Thanks.

Background subtraction And foreground detection using Kalman Filter

I need to separate the background from the foreground in a video using Kalman filter. Can somebody give me some resources or code examples to follow.
Update: i've found a good example here Traffic detection.It worked excellent for Traffic detection but i want to re-adapt it for people extraction. I've found some variables that's need to be adapted for example:
1. alpha = learning constant
2. K= #of guassians in the mixture
3. T = min. portion of background
4. initVariance = initial variance
5. pixelThresh = threshold condition for computing adaptive process on pixel
Here is an overview of the main file (In case just you want an overview)
function foregroundEstimation(movie)
%Load video into memory and prepare output video for writing
v = VideoReader(movie);
numFrames = 150;
foregroundVideo = VideoWriter('foreground.avi');
open(foregroundVideo);
%video constants
initFrame = read(v,1);
global height;
global width;
height = size(initFrame,1);
width = size(initFrame,2);
%initialize GMM parameters: (based upon Stauffer notation)
%http://www.ai.mit.edu/projects/vsam/Publications/stauffer_cvpr98_track.pdf
% alpha = learning constant
% K= #of guassians in the mixture
% T = min. portion of background
% initVariance = initial variance
% pixelThresh = threshold condition for computing adaptive process on pixel
alpha=0.05; % 0.05
K=5; % 5
global T; % T = 0.8
T=0.8;
global initVariance;
initVariance=75; % 75
pixelThresh=45; % 45
referenceDistance = 40; % 40 %shortcut to speed up processing time. Compare current pixel to pixel referenceDistance frames back and skip adaptive process if similar. Downside is doesn't collect background evidence as well.
sideWeight = (K-1)/(1-T);
global matchThres;
matchThres = sqrt(3);
global ccThreshold;
ccThreshold = 9000; % 5000
global deltaT;
deltaT = 1;
global numParticles;
numParticles = 100;
trackingOn = 0; % will superimpose tracking color marker on detected vehicles in output video. tackingOn should equal 1 or 0
prevCentSize = 0;
%structures to pass information between frames for detection purposes.
field = 'f';
filterValue = {[];[];};
prevFilter = struct(field,filterValue);
modelValue = {[];prevFilter};
prevModel = struct(field,modelValue);
%initiailze video process components
initColorBoxes();
foreFrame = zeros(height,width,3);
backFrame = zeros(height,width,3);
%map represents pixels at a given frame to perform adaptive process
pixThreshMap = ones(height,width);
%individual pixel process components
pixel = zeros(3,1);
pixMean = zeros(3,1,K);
pixVar = ones(1,K);
pixWeight = zeros(1,K);
%global pixel process components
globalWeight = (ones(height,width,K)/sideWeight);
globalWeight(:,:,1) = T;
%globalWeight = (ones(height,width,K)/K);
globalMean = zeros(height,width,3,K);
globalVar = ones(height,width,K);
%=====================================================
%Extract Foreground and Background by K-mixture model
%=====================================================
%initialize g-mixture model
globalVar = globalVar*initVariance;
for k=1:K
globalMean(:,:,1,k)=initFrame(:,:,1);
globalMean(:,:,2,k)=initFrame(:,:,2);
globalMean(:,:,3,k)=initFrame(:,:,3);
end;
distVec = zeros(numFrames,1);
%adaptive g-mixture background segmentation
for frameIndex=2:numFrames
%get current frame and the refernece frame
%tic;
frameIndex
currentFrame = double(read(v,frameIndex));
if (frameIndex<=referenceDistance)
referenceFrame= double(read(v,1));
else
referenceFrame= double(read(v,frameIndex-referenceDistance));
end;
frameDifference = abs(currentFrame - referenceFrame);
%creates map of pixel locations where we will perform adaptive process. Based
%upon threshold that detects low change regions based on previous frame in
%order to save computation.
pixThreshMap = min(sum(+(frameDifference(:,:,:)>pixelThresh),3),1);
for index=1:3
backFrame(:,:,index)=(+(pixThreshMap(:,:)==0)).*currentFrame(:,:,index);
end;
%extract the parts considered "stable background" from current frame
%reset foreground frame
foreFrame = ones(height,width,3)*255;
%gaussian mixture matching & model updating
[i,j]=find(pixThreshMap(:,:)==1);
%loop through every pixel location where adaptive process should be performed
for k = 1:size(i,1)
pixel = reshape(currentFrame(i(k),j(k),:),3,1);
pixMean = reshape(globalMean(i(k),j(k),:,:),3,1,K);
pixVar = reshape(globalVar(i(k),j(k),:,:),1,K);
pixWeight=reshape(globalWeight(i(k),j(k),:),1,K);
%update gaussian mixture according to new pix value
match=matchingCriterion(pixMean,pixVar,pixel);
matchWeight = 0;
if(match>0)
%match found so update weights/normalize
pixWeight = (1-alpha)*pixWeight;
pixWeight(match)= pixWeight(match) + alpha;
pixWeight = pixWeight/sum(pixWeight);
matchWeight = pixWeight(1,match);
%NOTE ALPHA SHOULD BE REPACED WITH SOME KIND OF RHO EVENTUALLY
%WHERE RHO IS PRODUCT OF ALPHA AND CONDITIONAL PROBABILITY MEASURE
%update variance
pixVar(:,match) = (1-alpha)*pixVar(:,match) + ...
alpha*(pixel - pixMean(:,:,match))'*(pixel-pixMean(:,:,match));
%update mean
pixMean(:,:,match) = (1-alpha)*pixMean(:,:,match) + alpha*pixel;
else
%no match currently found.
%replace one with lowest sigma value
rankVector = pixWeight./sqrt(pixVar(1,:));
[mini minIndex] = min(rankVector);
pixMean(:,:,minIndex) = pixel;
pixVar(:,minIndex) = initVariance;
end
%rerank all pixel components
rankCriterionVector = pixWeight./sqrt(pixVar(1,1,:));
[rankSort rankIndex] = sort(rankCriterionVector);
pixMean = pixMean(rankIndex);
pixVar = pixVar(rankIndex);
pixWeight = pixWeight(rankIndex);
%repopulate global structures with updated values
globalWeight(i(k),j(k),:) = pixWeight(:,1);
globalMean(i(k),j(k),:,:) = pixMean(:,1,:);
globalVar(i(k),j(k),:,:) = pixVar(:,:,:);
%now need to perform the background segmentation based upon weight
%threshold
bgIndex = segmentBackground(pixWeight);
if(ismember(matchWeight, pixWeight))
matchIndex = find(pixWeight == matchWeight,1);
else
matchIndex = 0;
end
if((matchIndex>=bgIndex) || (matchIndex == 0))
%also check against initFrame for match
%NOTE CHANGE
if(initMatch(initFrame(i(k),j(k),:),pixel) == 0)
foreFrame(i(k),j(k),:) = pixel;
end
end
end
%Now write foreground frame to foreground estimation video
contrastFrame = foreFrame/max(abs(foreFrame(:)));
%remove all connected components associated with foreground objects that are smaller than what we expect a vehicle should be.
[cleanFrame centroids]= connectedComponentCleanup(contrastFrame);
if(trackingOn == 1)
if(size(centroids,1) > prevCentSize)
prevModel = addModel(prevModel, centroids, height, width);
elseif (size(centroids,1) < prevCentSize)
prevModel = removeModel(prevModel, centroids, height, width);
end
if(size(centroids,1) > 0)
%implies there is a car in frame for tracking
[curModel orderedCentroids] = vehicleTracking(centroids, prevModel);
prevModel = curModel;
trackFrame = colorBox(cleanFrame, curModel,orderedCentroids, height, width);
else
trackFrame = cleanFrame;
end
else
trackFrame = cleanFrame;
end
writeVideo(foregroundVideo,trackFrame);
prevCentSize = size(centroids,1);
end
Thanks.
Basically this is not task for kalman filter, look at background subtraction in opencv.
Kalman filter could be used after that to track objects between frames, you could look for example here
http://studentdavestutorials.weebly.com/kalman-filter-with-matlab-code.html

Grouping of points using Triangulation

Language : MATLAB
Problem Defenition:
I have a set of 2D points in space. I would like to group the points based on their euclidean distance. My data has a property that two groups are always separated by at least R units. Hence for a given point, all points that are closer than 50 units can be considered to be its neighbors. Combining points having common neighbors would result in the groups (that is the idea at least).
Proposed Method:
Use delaunay triangulation in matlab and get list of edges of the resulting triangles. Remove all edges that are greater than R units. Each group of points left are the groups I am looking for. Remaining unconnected points can be ignored.
Attempt:
I tried to implement the above in MATLAB, but I am making a mistake in grouping the left over points. I am attaching my code.
DT = delaunayTriangulation(double(frame(:,1:2)));
edgeList = edges(DT);
edgeVertex1 = frame(edgeList(:,1),:);
edgeVertex2 = frame(edgeList(:,2),:);
dVec = edgeVertex1 - edgeVertex2;
edgeLengths = sqrt(sum(abs(dVec).^2,2));
requiredEdges = edgeLengths < NEIGH_RADIUS;
edgeLengthsFiltered = edgeLengths(requiredEdges);
edgeListFiltered = edgeList(requiredEdges,:);
% Clustering
edgeOrigins = edgeListFiltered(:,1);
edgeEndings = edgeListFiltered(:,2);
nodeList = unique(edgeOrigins);
if isempty(nodeList)
Result = struct([]);
super_struct(i).result = Result;
else
groups = cell(10,1);
groups{1} = nodeList(1);
groupLength = 2;
flag = 0;
% grouping
for j = 1:1:length(nodeList);
neighbourList = [nodeList(j); edgeEndings(edgeOrigins==nodeList(j))];
% add current node as part of neighbourList
for k = 1:1:groupLength-1
te = ismembc(groups{k}, neighbourList);
if sum(te) ~=0
temp = sort([groups{k}; neighbourList]);
groups{k} = temp([true;diff(temp(:))>0]);
flag = 1;
break;
end
end
if ~flag
groups{groupLength} = neighbourList;
groupLength = groupLength + 1;
end
flag = 0;
end
largeGroups = cell(1,1);
largeGroups_c = 1;
for j = 1:1:groupLength -1;
if ~ isempty(groups{j})
for k = j+1:1:groupLength - 1
te = ismembc(groups{j}, groups{k});
if sum(te) ~= 0
temp = sort([groups{j}; groups{k}]);
groups{j} = temp([true;diff(temp(:))>0]);
groups{k} =[];
end
end
% ignore small groups
if length(groups{j}) > MIN_PTS_IN_GROUP
largeGroups{largeGroups_c} = groups{j};
largeGroups_c = largeGroups_c+1;
end
end
end
in the above code, frame is the variable that has the list of points. The constants NEIGH_RADIUS represents R from the question. The other constant MIN_PTS_IN_GROUP is user defined to select the minimum no of points needed to consider it a cluster of interest.
When I run the above code, there are still instances where a single group of points are still represented as multiple groups.
The red lines border a single group as identified by the code above. Clearly there are intersecting groups which is wrong.
Question 1
Can someone suggest a better (and correct) way of grouping?
Question 2
Any other alternate methods of obtaining the groups faster than Triangulation would also be great!
Thank you in advance
If you know the number of group you search for, you can use kmeans function in matlab statistic toolbox or you can find other implentation on matlab exchange (kmeans clustering)