Finding the closest centroids in a k means clustering - machine-learning

With
X = [1.8421 4.6076;
5.6586 4.8;
6.3526 3.2909;
2.904 4.6122;
3.232 4.9399;
1.2479 4.9327]
And
centroids = [3 3;
6 2;
8 5]
I'm trying to find the nearest centroid to each point in x.
I'm coding in Octave and here's my code
K = size(centroids, 1);
idx = zeros(size(X,1), 1); %idx is the vector storing the index of the closest centroid
for e = 1: size(X,1)
difference(1, :) = X(e,:) - centroids(1,:);
min_distance = sum(difference(1,:).^2);
for j = 2:K
difference(j, :) = X(e,:) - centroids(j,:);
distance = sum(difference.^2);
if distance<min_distance
min_distance = distance;
idx(e) = centroids(j);
endif
endfor
endfor
The code works, but I only get
idx = 0 0 0
for the first three entries of x

You need to be consistent in the size of your operand when you are calculating
the distance and properly set idx:
K = size(centroids, 1);
difference=zeros(size(centroids));
idx = zeros(size(X,1), 1); %idx is the vector storing the index of the closest centroid
for e = 1: size(X,1)
difference(1, :) = X(e,:) - centroids(1,:);
min_distance = sum(difference(1,:).^2);
idx(e)=1;
for j = 2:K
difference(j, :) = X(e,:) - centroids(j,:);
distance = sum(difference(j,:).^2);
if (distance<min_distance)
min_distance = distance;
idx(e) = j;
endif
endfor
endfor
idx
with this change the output is:
idx =
1
3
2
1
1
1

You may find the min function useful, when using Octave ;)
[minimum_values, minimum_index] = min(k);
You would use the minimum_index value for idx, for example:
idx(i) = minimum_index;
You could therefore reduce this further to:
[minimum_values, idx(i)] = min(k);

Related

Why my cost function is giving wrong answer?

I have written a code for the cost function and it is giving incorrect answer.
I have read the code many times but I cannot find the mistake.
Here is my code:-
function J = computeCost(X, y, theta)
m = length(y); % number of training examples
s = 0;
h = 0;
sq = 0;
J = 0;
for i = 1:m
h = theta' * X(i, :)';
sq = (h - y(i))^2;
s = s + sq;
end
J = (1/2*m) * s;
end
Example:-
computeCost( [1 2; 1 3; 1 4; 1 5], [7;6;5;4], [0.1;0.2] )
ans = 11.9450
Here the answer should be 11.9450 but my code is giving me this:-
ans = 191.12
I have checked the the matrix multiplication and the code is calculating it right.
It seems you misunderstood the operator evaluation order. In fact
1/2*m ~= 1/(2*m)
With this in mind it seems you're computing an average. Instead of reinventing the wheel it is usually a good idea to use the built in functions to do the job which results in a much clearer (and less error prone) implementation:
function J = computeCost(X, y, theta)
h = X * theta;
sq = (h - y).^2;
J = 1/2 * mean(sq);
end
computeCost( [1,2;1,3;1,4;1,5], [7;6;5;4], [0.1;0.2] )
% ans = 11.9450
Try it online!

decomposeProjectionMatrix gives unexpected result

I have the following projection matrix P:
-375 0 2000 262500
-375 2000 0 262500
-1 0 0 700
This projection matrix projects 3D points in mm on a detector in px (with 1px equals to 0.5mm) and is built from the intrinsic matrix K and the extrinsic matrix [R|t] (where R is a rotation matrix and t a translation vector) according the relation P = K [R|t].
2000 0 375 0 0 1 0
K = 0 2000 375 R = 0 1 0 t = 0
0 0 1 -1 0 0 700
For some reasons I need to decompose P back into these matrices. When I use decomposeProjectionMatrix I get this as a rotation matrix:
0 0 0
0 0 0
-1 0 0
Which doesn't look like a rotation matrix to me.
Moreover when I build back the projection matrix from the Open CV decomposition I get this matrix:
-375 0 0 262500
-375 0 0 262500
-1 0 0 700
Looks similar but it is not the same.
I'm wondering if I'm doing something wrong or if I'm unlucky and that was one of the rare cases where this function fails.
Note that I did the decomposition by myself and I get coherent results but I would rather use Open CV functions as much as possible.
The problem seems to be in the RQ decomposition used by decomposeProjectionMatrix.
Even though the first square of the matrix P is non singular, the RQDecomp3x3 function gives incorrect results:
0 0 375 0 0 0
R = 0 0 375 Q = 0 0 0
0 0 1 -1 0 0
So a work around is to use a homemade function (here written in Python) based on the section 2.2 of Peter Sturm's lectures:
def decomposeP(P):
import numpy as np
M = P[0:3,0:3]
Q = np.eye(3)[::-1]
P_b = Q # M # M.T # Q
K_h = Q # np.linalg.cholesky(P_b) # Q
K = K_h / K_h[2,2]
A = np.linalg.inv(K) # M
l = (1/np.linalg.det(A)) ** (1/3)
R = l * A
t = l * np.linalg.inv(K) # P[0:3,3]
return K, R, t
I use the anti-identity matrix Q to build the non conventional Cholesky decomposition U U* where U is upper triangular.
This method differs slightly from the Peter Sturm's one as we use the relation P = K[R|t] while in Peter Sturm's lectures the relation used is P = K[R|-Rt].
A C++ implementation using only Open CV is trickier as they don't really expose a function for Cholesky decompostion:
void chol(cv::Mat const& S, cv::Mat& L)
{
L = cv::Mat::zeros(S.rows, S.rows, cv::DataType<double>::type);
for (int i = 0; i < S.rows; ++i) {
for (int j = 0; j <= i ; ++j) {
double sum = 0;
for (int k = 0; k < j; ++k)
sum += L.at<double>(i,k) * L.at<double>(j,k);
L.at<double>(i,j) = (i == j) ? sqrt(S.at<double>(i,i) - sum) : (S.at<double>(i,j) - sum) / L.at<double>(j,j);
}
}
}
void decomposeP(cv::Mat const& P, cv::Mat& K, cv::Mat& R, cv::Mat& t)
{
cv::Mat M(3, 3, cv::DataType<double>::type);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
M.at<double>(i, j) = P.at<double>(i ,j);
cv::Mat Q = cv::Mat::zeros(3, 3, cv::DataType<double>::type);
Q.at<double>(0, 2) = 1.0;
Q.at<double>(1, 1) = 1.0;
Q.at<double>(2, 0) = 1.0;
cv::Mat O = Q * M * M.t() * Q;
cv::Mat C;
chol(O, C);
cv::Mat B = Q * C * Q;
K = B / B.at<double>(2,2);
cv::Mat A = K.inv() * M;
double l = std::pow((1 / cv::determinant(A)), 1/3);
R = l * A;
cv::Mat p(3, 1, cv::DataType<double>::type);
for (int i = 0; i < 3; ++i)
p.at<double>(i, 0) = P.at<double>(i ,3);
t = l * K.inv() * p;
}

Converting from pixel coordinates to meter coordinates

I would like to convert pixel coordinates to meter coordinates. My camera has radial distortion, and I already have camera parameters, I use cvUndistort function of Opencv to get Undistort image, then use these 2 formulas:
(u0, v0 are principal points coordinates(in pixel). px, py are focal lengths(in pixel))
x = (u-u0)/px
y = (v-v0)/py
I finally want to calculate moments in metric coordinates.
my code:
CvMat* camera_matrix;
CvMat* distortion_coeffs;
camera_matrix = cvCreateMat(3, 3, CV_32FC1 );
distortion_coeffs = cvCreateMat(1, 5, CV_32FC1 );
double k1 = -0.33060;
double k2 = 0.11170;
double k3 = 0;
double k4 = 0;
double k5 = 0;
double fx = 195.0507;
double fy = 195.0992;
double cx = 162.4085;
double cy = 127.1973;
CV_MAT_ELEM(*(camera_matrix),float,0, 0 ) = (float)fx;
CV_MAT_ELEM(*(camera_matrix),float,0, 1 ) = 0;
CV_MAT_ELEM(*(camera_matrix),float,0, 2 ) = (float)cx;
CV_MAT_ELEM(*(camera_matrix),float,1, 0 ) = 0;
CV_MAT_ELEM(*(camera_matrix),float,1, 1 ) = (float)fy;
CV_MAT_ELEM(*(camera_matrix),float,1, 2 ) = (float)cy;
CV_MAT_ELEM(*(camera_matrix),float,2, 0 ) = 0;
CV_MAT_ELEM(*(camera_matrix),float,2, 1 ) = 0;
CV_MAT_ELEM(*(camera_matrix),float,2, 2 ) = 1;
CV_MAT_ELEM(*(distortion_coeffs),float,0, 0 ) = (float)k1;
CV_MAT_ELEM(*(distortion_coeffs),float,0, 1 ) = (float)k2;
CV_MAT_ELEM(*(distortion_coeffs),float,0, 2 ) = (float)k3;
CV_MAT_ELEM(*(distortion_coeffs),float,0, 3 ) = (float)k4;
CV_MAT_ELEM(*(distortion_coeffs),float,0, 4 ) = (float)k5;
cvUndistort2( image, Undistort_img, camera_matrix,distortion_coeffs );
//**********************************************************************
//Threshold image
//**********************************************************************
cvSmooth( Undistort_img, smoothed_image,CV_BLUR,3,3,0,0);
for(int i = 0; i < smoothed_image->height; i++)
{
for(int j = 0; j < smoothed_image->width; j++)
{
s = cvGet2D(smoothed_image,i,j);
if (((float)s.val[0]) >= 210)
cvSet2D(tr_img, i, j, white_value);
else
cvSet2D(tr_img, i, j, black_value);
}
}
//*************************************************************
//moment calculation in metric coordinates
//*************************************************************
for(int i = 0;i < tr_img->height; i++)
{
for(int j = 0; j < tr_img->width; j++)
{
if(CV_MAT_ELEM(*(tr_img),float,i,j) != 0)
{
x = (i-u0)/px;
y = (j-v0)/py;
kern1[0][0] = 1 + kern1[0][0];
kern1[1][0] = x * 1 + kern1[1][0];
kern1[0][1] = y * 1 + kern1[0][1];
kern1[2][0] = x * x * 1 + kern1[2][0];
kern1[0][2] = y * y * 1 + kern1[0][2];
kern1[1][1] = x * y * 1 + kern1[1][1];
}
}
}
moments->m00 = (float)kern1[0][0];
moments->m10 = (float)kern1[0][1];
moments->m01 = (float)kern1[1][0];
moments->m11 = (float)kern1[1][1];
moments->m20 = (float)kern1[0][2];
moments->m02 = (float)kern1[2][0];
as we know, normalizing centers of mass are calculated based on:(Z_star and m00_star are the values in initial point):
xn = xg * an = (m10/m00)* Z_star*sqrt(m00_star/m00)
yn = yg * an = (m01/m00)* Z_star*sqrt(m00_star/m00)
these two values should not change when camera just has transmission along optical axis(z axis). but my values change considerably, would you please help me?

Gini Impurity, growing random trees in opencv

Goal: To add offset-impurity to the split decision of growing trees in openCV.
Currently in opencv random trees, the split is made as following:
if( !priors )
{
int L = 0, R = n1;
for( i = 0; i < m; i++ )
rsum2 += (double)rc[i]*rc[i];
for( i = 0; i < n1 - 1; i++ )
{
int idx = responses[sorted_indices[i]];
int lv, rv;
L++; R--;
lv = lc[idx]; rv = rc[idx];
lsum2 += lv*2 + 1;
rsum2 -= rv*2 - 1;
lc[idx] = lv + 1; rc[idx] = rv - 1;
if( values[i] + epsilon < values[i+1] )
{
double val = (lsum2*R + rsum2*L)/((double)L*R);
if( best_val < val )
{
best_val = val;
best_i = i;
}
}
}
}
Its using the gini impurity.
Anyone who can explain how the code accomplish this, from what i get it: initially it puts all class counts in the right node, and while moving one instance from right to left and update lsum2 and rsum2 it find the best solution. What i dont get is how p_j^2 is related to lv*2 +1 or rv*2-1.
The real question, if having offsets available and would like to add a split based on the impurity of simularity of offsets. (offsets are direction and distance from center to the current node.
What i have come up with is something like this, and if anyone can point out any flaws it would be good, because atm its not giving good results and im not sure where to start debugging.
//Compute mean
for(i = 0; i<n1;++i)
{
float* point = (float*)(points.data + rstep*sample_idx_src[sorted_indices[i]]);
meanx[responses[sorted_indices[i]]] += point[0];
meany[responses[sorted_indices[i]]] += point[1];
}
for(i = 0;i<m;++i)
{
meanx[i] /= rc0[i];
meany[i] /= rc0[i];
}
if(!priors)
{
int L = 0, R = n1;
for(i=0;i<n1;i++)
{
float* point = (float*)(points.data + rstep*sample_idx_src[sorted_indices[i]]);
double tmp = point[0] - meanx[responses[sorted_indices[i]]];
rsum2 += tmp*tmp;
tmp = point[1] -meany[responses[sorted_indices[i]]];
rsum2 += tmp*tmp;
}
double minDist = DBL_MAX;
for(i=0;i<n1;++i)
{
float* point = (float*)(points.data + rstep*sample_idx_src[sorted_indices[i]]);
++L; --R;
double tmp = point[0] - meanx[responses[sorted_indices[i]]];
lsum2 += tmp*tmp;
tmp = point[1] -meany[responses[sorted_indices[i]]];
lsum2 += tmp*tmp;
tmp = point[0] - meanx[responses[sorted_indices[i]]];
rsum2 -= tmp*tmp;
tmp = point[1] -meany[responses[sorted_indices[i]]];
rsum2 -= tmp*tmp;
if( values[i] + epsilon < values[i+1] )
{
double val = (lsum2 + rsum2)/((double)L*R);
if(val < minDist )
{
minDist = val;
best_val = -val;
best_i = i;
}
}
}
Ok, the Gini coefficient in this case is simple because there are only two groups, left and right. So instead of a large sum 1-sum(pj*pj) we have 1-pl*pl-pr*pr. The proportion of items on the left pl is the number of items on the left lv divided by the total.
Now as we shift the split, pl*pl and pr*pr change, but not because the total number of items changes. So instead of optimizing pr and pl (which are floating-point numbers) we optimize lv and rv (which are simple counts).
Next, the question why 2*lv+1. That's simple: we're increasing lv = lv=1 to optimize lv*lv. Now (lv+1)*(lv+1) - (lv*lv) (the increase) happens to be 2*lv+1 if you write out all the terms. And the decrease (rv-1)*(rv-1) - (rv*rv) happens to be -2*rv+1 or -(r*rv+1).

Search for lines with a small range of angles in OpenCV

I'm using the Hough transform in OpenCV to detect lines. However, I know in advance that I only need lines within a very limited range of angles (about 10 degrees or so). I'm doing this in a very performance sensitive setting, so I'd like to avoid the extra work spent detecting lines at other angles, lines I know in advance I don't care about.
I could extract the Hough source from OpenCV and just hack it to take min_rho and max_rho parameters, but I'd like a less fragile approach (have to manually update my code w/ each OpenCV update, etc.).
What's the best approach here?
Well, i've modified the icvHoughlines function to go for a certain range of angles. I'm sure there's cleaner ways that plays with memory allocation as well, but I got a speed gain going from 100ms to 33ms for a range of angle going from 180deg to 60deg, so i'm happy with that.
Note that this code also outputs the accumulator value. Also, I only output 1 line because that fit my purposes but there was no gain really there.
static void
icvHoughLinesStandard2( const CvMat* img, float rho, float theta,
int threshold, CvSeq *lines, int linesMax )
{
cv::AutoBuffer<int> _accum, _sort_buf;
cv::AutoBuffer<float> _tabSin, _tabCos;
const uchar* image;
int step, width, height;
int numangle, numrho;
int total = 0;
float ang;
int r, n;
int i, j;
float irho = 1 / rho;
double scale;
CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
image = img->data.ptr;
step = img->step;
width = img->cols;
height = img->rows;
numangle = cvRound(CV_PI / theta);
numrho = cvRound(((width + height) * 2 + 1) / rho);
_accum.allocate((numangle+2) * (numrho+2));
_sort_buf.allocate(numangle * numrho);
_tabSin.allocate(numangle);
_tabCos.allocate(numangle);
int *accum = _accum, *sort_buf = _sort_buf;
float *tabSin = _tabSin, *tabCos = _tabCos;
memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
// find n and ang limits (in our case we want 60 to 120
float limit_min = 60.0/180.0*PI;
float limit_max = 120.0/180.0*PI;
//num_steps = (limit_max - limit_min)/theta;
int start_n = floor(limit_min/theta);
int stop_n = floor(limit_max/theta);
for( ang = limit_min, n = start_n; n < stop_n; ang += theta, n++ )
{
tabSin[n] = (float)(sin(ang) * irho);
tabCos[n] = (float)(cos(ang) * irho);
}
// stage 1. fill accumulator
for( i = 0; i < height; i++ )
for( j = 0; j < width; j++ )
{
if( image[i * step + j] != 0 )
//
for( n = start_n; n < stop_n; n++ )
{
r = cvRound( j * tabCos[n] + i * tabSin[n] );
r += (numrho - 1) / 2;
accum[(n+1) * (numrho+2) + r+1]++;
}
}
int max_accum = 0;
int max_ind = 0;
for( r = 0; r < numrho; r++ )
{
for( n = start_n; n < stop_n; n++ )
{
int base = (n+1) * (numrho+2) + r+1;
if (accum[base] > max_accum)
{
max_accum = accum[base];
max_ind = base;
}
}
}
CvLinePolar2 line;
scale = 1./(numrho+2);
int idx = max_ind;
n = cvFloor(idx*scale) - 1;
r = idx - (n+1)*(numrho+2) - 1;
line.rho = (r - (numrho - 1)*0.5f) * rho;
line.angle = n * theta;
line.votes = accum[idx];
cvSeqPush( lines, &line );
}
If you use the Probabilistic Hough transform then the output is in the form of a cvPoint each for lines[0] and lines[1] parameters. We can get x and y co-ordinated for each of the two points by pt1.x, pt1.y and pt2.x and pt2.y.
Then use the simple formula for finding slope of a line - (y2-y1)/(x2-x1). Taking arctan (tan inverse) of that will yield that angle in radians. Then simply filter out desired angles from the values for each hough line obtained.
I think it's more natural to use standart HoughLines(...) function, which gives collection of lines directly in rho and theta terms and select nessessary angle range from it, rather than recalculate angle from segment end points.

Resources