Jump to content
Compvision.ru
Sign in to follow this  
mrgloom

kmeans и MNIST dataset

Recommended Posts

http://en.wikipedia.org/wiki/Principal_component_analysis#Relation_between_PCA_and_K-means_clustering

Relation between PCA and K-means clustering

It has been shown recently (2001,2004)[15][16] that the relaxed solution of K-means clustering, specified by the cluster indicators, is given by the PCA principal components, and the PCA subspace spanned by the principal directions is identical to the cluster centroid subspace specified by the between-class scatter matrix. Thus PCA automatically projects to the subspace where the global solution of K-means clustering lies, and thus facilitates K-means clustering to find near-optimal solutions.

если я правильно понял перевод, то результат один и тот же но k-means не всегда туда сходится.

void show_PCA(vector<Mat>& db)

{

    int total = db[0].rows * db[0].cols;


    // build matrix (column)

    Mat mat(total, db.size(), CV_32FC1);

    for(int i = 0; i < db.size(); i++) 

	{

        Mat X = mat.col(i);

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }


    // change to the number of principle components you want 

	//от чего должно зависеть их кол-во?

    int numPrincipalComponents = db.size() - 1;


    // do pca

	//http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html#PCA

    PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);


    // show mean vector

    namedWindow("avg", 1);

    //imshow("avg", pca.mean.reshape(1,db[0].rows));

    imshow("avg", pca.eigenvectors);

    waitKey(0);

}

я не понимаю эту строчку

int numPrincipalComponents = db.size() - 1;

на какое кол-во параметров проецировать в моем случае? что если numPrincipalComponents = кол-ву кластеров?

что можно сказать если посмотреть на pca.eigenvectors?

что я должен передавать в kmeans? спроецированные на этот новый базис изображения?(иих размер соответсвенно будет меньше)

Share this post


Link to post
Share on other sites

Обычно смотрят на значения собственных чисел, как правило берут те собственные векторы, которым соответствуют максимальные собственные значения.

Определить количество собственных векторов, можно либо произвольно (взять N векторов с максимальными собственными числами), либо по порогу, (собственные значения не менее X% от максимального).

Да, спроецированные на этот базис изображения, их размер будет равен количеству измерений нового базиса.

Share this post


Link to post
Share on other sites

попробовал уменьшение размерности и все равно размеры кластеров пишет 0,10000,0,... и т.д.

может что то делаю не так?

void cacl_PCA(vector<Mat>& images)

{

	int nEigens = 20/*images.size() - 1*/; //Number of Eigen Vectors.


	//Load the images into a Matrix

	Mat desc_mat(images.size(), images[0].rows * images[0].cols, CV_32FC1);

	for (int i=0; i<images.size(); i++) 

	  desc_mat.row(i) = images[i].reshape(1, 1);


	Mat average;

	PCA pca(desc_mat, average, CV_PCA_DATA_AS_ROW, nEigens);


	Mat data(desc_mat.rows, nEigens, CV_32FC1); //This Mat will contain all the Eigenfaces that will be used later


	//Project the images onto the PCA subspace

	for(int i=0; i<images.size(); i++) 

	{

	  Mat projectedMat(1, nEigens, CV_32FC1);

	  pca.project(desc_mat.row(i), projectedMat);


	  data.row(i) = projectedMat.row(0);

	}


	int clusterCount = 10;

	int attempts = 1;

	Mat centers;

	Mat labels;

	kmeans(data, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,

		0.0001, 10000),attempts, KMEANS_PP_CENTERS, centers );


	//определяем какие получились кластеры по размеру

	vector<int> cl_size(clusterCount);

	for(int i=0;i< labels.rows;++i)

	{

		cl_size[labels.at<int>(i,0)]+=1;

	}

}

Share this post


Link to post
Share on other sites

Так там же 10 цифр, а не 20, а собственных векторов 9 должно быть ( http://www.cognotics.com/opencv/servo_2007_series/part_5/page_4.html ).

ЗЫ: Может сначала на каком-нибудь датасете поменьше размером и размерностью отладить?

Share this post


Link to post
Share on other sites

http://bytefish.de/blog/pca_in_opencv#simple_example

попробовал еще от сюда

void cacl_PCA2(vector<Mat>& db)

{

	int total = db[0].rows * db[0].cols;


    // build matrix (column)

    Mat mat(total, db.size(), CV_32FC1);

    for(int i = 0; i < db.size(); i++)

	{

        Mat X = mat.col(i);

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }


    // change to the number of principal components you want

    int numPrincipalComponents = 12;


    // do pca

    PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);


	Mat out_mat(pca.mean.reshape(1, db[0].rows));

	for(int i=0;i<numPrincipalComponents;++i)

	{

		std::ostringstream out;

		out << "pca_test_" << i <<".png";

		std::string str = out.str();

		Mat temp= normalize(pca.eigenvectors.row(i)).reshape(1, db[0].rows);

		imwrite(str, temp);

	}


	int f=0;

}

но не очень понятно как трактовать результаты

post-701-0-26269900-1337696093_thumb.png

Share this post


Link to post
Share on other sites

Как собственные векторы. Во всяком случае визуально похоже.

Share this post


Link to post
Share on other sites

Так там же 10 цифр, а не 20, а собственных векторов 9 должно быть ( http://www.cognotics.com/opencv/servo_2007_series/part_5/page_4.html ).

ЗЫ: Может сначала на каком-нибудь датасете поменьше размером и размерностью отладить?

хмм ну я думал что кол-во векторов определяется размеров входного вектора признаков ,а не кол-вом различных сущностей в выборке.

впрочем вот для 9-ти то же самое.

post-701-0-80497100-1337696553_thumb.png

Share this post


Link to post
Share on other sites

Это правильно, ограничение по количеству классов, вероятно удобнее для классификации.

Для каждой цифры надо (после получения собственных векторов) найти координаты в этих новых осях (коэффициенты), и эти коэффициенты подавать уже на k-means.

Это как раз и есть нахождение этих коэффициентов

//Project the images onto the PCA subspace
for(int i=0; i<images.size(); i++)
{
Mat projectedMat(1, nEigens, CV_32FC1);
pca.project(desc_mat.row(i), projectedMat);

data.row(i) = projectedMat.row(0);
}[/code]

Можно попробовать построить первые две координаты (с наибольшими собственными числами) на плоскости, чтобы визуально проверить что там с кластерами выходит.

Share this post


Link to post
Share on other sites

забавно, но похоже проблема в том, что изображения не правильно читаются.

первые шесть нормально, а остальные как черные.

читал так

vector<Mat> read_mnist(/*string full_path*/)

{

	vector<Mat> vec_img;

	ifstream file (/*full_path*/"C:/MNIST/10k_images.bin");

	if (file.is_open())

	{

		int magic_number=0;

		int number_of_images=0;

		int n_rows=0;

		int n_cols=0;

		file.read((char*)&magic_number,sizeof(magic_number)); //если перевернуть то будет 2051

		magic_number= reverseInt(magic_number);

		file.read((char*)&number_of_images,sizeof(number_of_images));//если перевернуть будет 10к

		number_of_images= reverseInt(number_of_images);

		file.read((char*)&n_rows,sizeof(n_rows));

		n_rows= reverseInt(n_rows);

		file.read((char*)&n_cols,sizeof(n_cols));

		n_cols= reverseInt(n_cols);

		for(int i=0;i<number_of_images;++i)

		{

			Mat temp(n_rows,n_cols,CV_8UC1);

			for(int r=0;r<n_rows;++r)

			{

				for(int c=0;c<n_cols;++c)

				{

					unsigned char t_ch=0;

					file.read((char*)&t_ch,sizeof(t_ch));

					//тут идет запись матрицы 28х28 в вектор

					temp.at<unsigned char>(r,c)= t_ch; //возможно можно как то быстрее копировать построчно?

				}

			}

			vec_img.push_back(temp);

		}

	}

	return vec_img;

}

сохранял так
for (int i=0; i<images.size(); ++i) 

	{

		std::ostringstream out;

		out <<"digits/"<< i <<".png";

		std::string str = out.str();

		imwrite(str,images[i]);

	}

Share this post


Link to post
Share on other sites

Ну да, вроде все верно

TRAINING SET LABEL FILE (train-labels-idx1-ubyte):

[offset] [type] [value] [description]

0000 32 bit integer 0x00000801(2049) magic number (MSB first)

0004 32 bit integer 60000 number of items

0008 unsigned byte ?? label

0009 unsigned byte ?? label

........

xxxx unsigned byte ?? label

The labels values are 0 to 9.

TRAINING SET IMAGE FILE (train-images-idx3-ubyte):

[offset] [type] [value] [description]

0000 32 bit integer 0x00000803(2051) magic number

0004 32 bit integer 60000 number of images

0008 32 bit integer 28 number of rows

0012 32 bit integer 28 number of columns

0016 unsigned byte ?? pixel

0017 unsigned byte ?? pixel

........

xxxx unsigned byte ?? pixel

Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).

TEST SET LABEL FILE (t10k-labels-idx1-ubyte):

[offset] [type] [value] [description]

0000 32 bit integer 0x00000801(2049) magic number (MSB first)

0004 32 bit integer 10000 number of items

0008 unsigned byte ?? label

0009 unsigned byte ?? label

........

xxxx unsigned byte ?? label

The labels values are 0 to 9.

TEST SET IMAGE FILE (t10k-images-idx3-ubyte):

[offset] [type] [value] [description]

0000 32 bit integer 0x00000803(2051) magic number

0004 32 bit integer 10000 number of images

0008 32 bit integer 28 number of rows

0012 32 bit integer 28 number of columns

0016 unsigned byte ?? pixel

0017 unsigned byte ?? pixel

........

xxxx unsigned byte ?? pixel

Может это поковырять интересно будет: https://sites.google.com/site/mihailsirotenko/projects/convolutional-neural-network-class

Share this post


Link to post
Share on other sites

нашел набор из 10к изображений, попробую их в такой форме загрузить.

Может это поковырять интересно будет: https://sites.google...l-network-class

ну там все на матлабе.

вот нашел еще про PCA и какие то другие методы.

http://www.inb.uni-luebeck.de/publikationen/pdfs/LaBaMa08c.pdf

Share this post


Link to post
Share on other sites

У меня этот вариант норм загружает и считает собственные векторы, плюс проецирует картинку на полученные собственные векторы и восстанавливает картинку по заданным проекциям на собственные векторы.

post-1-0-80471700-1337792982_thumb.png

post-1-0-10348200-1337803830_thumb.png


#include <iostream>
#include <vector>
#include <stdio.h>
#include "opencv2/core/core.hpp"
#include "opencv2/core/gpumat.hpp"
#include "opencv2/core/opengl_interop.hpp"
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "fstream"
#include "iostream"
using namespace std;
using namespace cv;

inline void endian_swap(unsigned short& x)
{
x = (x>>8) |
(x<<8);
}

inline void endian_swap(unsigned int& x)
{
x = (x>>24) |
((x<<8) & 0x00FF0000) |
((x>>8) & 0x0000FF00) |
(x<<24);
}

// __int64 for MSVC, "long long" for gcc
inline void endian_swap(unsigned __int64& x)
{
x = (x>>56) |
((x<<40) & 0x00FF000000000000) |
((x<<24) & 0x0000FF0000000000) |
((x<<8) & 0x000000FF00000000) |
((x>>8) & 0x00000000FF000000) |
((x>>24) & 0x0000000000FF0000) |
((x>>40) & 0x000000000000FF00) |
(x<<56);
}

void read_mnist(vector<Mat>& vec_img)
{
//vector<Mat> vec_img;
ifstream file;

//file.open("C:/MNIST/train-images.idx3-ubyte",ifstream::in | ifstream::binary);
file.open("C:/MNIST/t10k-images.idx3-ubyte",ifstream::in | ifstream::binary);
if (file.is_open())
{
unsigned int magic_number=0;
unsigned int number_of_images=0;
unsigned int n_rows=0;
unsigned int n_cols=0;
file.read((char*)&magic_number,sizeof(magic_number)); //если перевернуть то будет 2051
endian_swap(magic_number);
file.read((char*)&number_of_images,sizeof(number_of_images));//если перевернуть будет 10к
endian_swap(number_of_images);
file.read((char*)&n_rows,sizeof(n_rows));
endian_swap(n_rows);
file.read((char*)&n_cols,sizeof(n_cols));
endian_swap(n_cols);
cout << "magic_number=" << magic_number << endl;
cout << "n_rows=" << n_rows << endl;
cout << "n_cols=" << n_cols << endl;
cout << "number_of_images=" << number_of_images << endl;

for(int i=0;i<number_of_images;++i)
{
Mat temp(n_rows,n_cols,CV_8UC1);
for(int r=0;r<n_rows;++r)
{
for(int c=0;c<n_cols;++c)
{
unsigned char t_ch=0;
file.read((char*)&t_ch,sizeof(t_ch));
//тут идет запись матрицы 28х28 в вектор
temp.at<unsigned char>(r,c)= t_ch; //возможно можно как то быстрее копировать построчно?
}
}
vec_img.push_back(temp);
}
}

}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
void calc_PCA(vector<Mat>& db,int numPrincipalComponents,Mat& EigVec,Mat& Mean)
{
int total = db[0].rows * db[0].cols;

int rows=db[0].rows;
int cols=db[0].cols;

Mat mat(total, db.size(), CV_32FC1);

for(int i = 0; i < db.size(); i++)
{
Mat X = mat.col(i);
db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);
}

EigVec=Mat(numPrincipalComponents,total,CV_32FC1);
// do pca
PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);

Mat imgDst;
imgDst.create( rows, cols*numPrincipalComponents, CV_32FC1 );
imgDst=0;

pca.mean.copyTo(Mean);

for(int i=0;i<numPrincipalComponents;++i)
{
Mat temp=(pca.eigenvectors.row(i));
normalize(temp,temp); // Это и есть собственный вектор
temp.copyTo(EigVec.row(i));
// ---------------------------------------------------
// Этот кусок нужен для того, чтобы были видны картинки
// ---------------------------------------------------
double m,M;
minMaxLoc(temp,&m,&M);
if((M-m)!=0)
{
temp-=m;
temp/=(M-m);
temp*=255.0;
}
temp=temp.reshape(1, rows);
temp.copyTo(imgDst(Rect(i*cols,0,cols,rows)));
// ---------------------------------------------------
}
imwrite("result.png", imgDst);
int f=0;
}


//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
const int NumVectors=20;
vector<Mat> MNIST;
read_mnist(MNIST);
int rows=MNIST[0].rows;
int cols=MNIST[0].cols;
// ---------------------------------------------------
// Составили картинку из 100 первых изображений
// ---------------------------------------------------
Mat imgDst;
imgDst.create( 10*rows, 10*cols, CV_8UC1 );
imgDst=0;
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
MNIST[i+j*10].copyTo(imgDst(Rect(i*cols,j*rows,cols,rows)));
}
}
imshow("result",imgDst);
// ---------------------------------------------------
// Посчитаем собственные векторы возьмем NumVectors с
// максимальными собственными числами
// ---------------------------------------------------
Mat EigVec,mean,result,repared;
calc_PCA(MNIST,NumVectors,EigVec,mean);
// ---------------------------------------------------
// Спроецируем 10 первых цифр на собственные векторы
// получаем координаты этих цифр в NumVectors мерном пространстве
// а затем восстановим их по этим проекциям.
// ---------------------------------------------------
for(int i=0; i<10; i++)
{
// Спроецируем на собственные векторы
cv::PCAProject(MNIST[i].reshape(1, rows*cols),mean,EigVec,result);
cout << result << endl;

// Восстановим по их NumVectors проекциям на собственные оси.
cv::PCABackProject(result,mean,EigVec,repared);

// переведем обратно в прямоугольный вид
// и выведем в файл
repared=repared.reshape(1, rows);
char str[100];
sprintf(str,"repared_%d.png",i);
imwrite(str,repared);

}

waitKey(0);
return 0;
}
[/code]

  • Like 1

Share this post


Link to post
Share on other sites

ошибка была в ifstream::binary, но очень странно как в таком случае прочитались первые 6 цифр.

PCAProject у меня не находит, но это наверно можно сделать и через pca.project.

Share this post


Link to post
Share on other sites

Да нет, не странно, просто он дошел до символа конца файла.

  • Like 1

Share this post


Link to post
Share on other sites

ну вообще попробовал кластеризовать как есть

получились такие вот центры кластеров.

post-701-0-52380700-1337865756_thumb.png

в целом разброд внутри кластера наблюдается сильный, но алгоритм вроде бы работает правильно.

пробовал переписать этот кусок

/ ---------------------------------------------------

        // Спроецируем 10 первых цифр на собственные векторы

        // получаем координаты этих цифр в NumVectors мерном пространстве

        // а затем восстановим их по этим проекциям.

        // ---------------------------------------------------

        for(int i=0; i<10; i++) 

        {

                // Спроецируем на собственные векторы

                cv::PCAProject(MNIST[i].reshape(1, rows*cols),mean,EigVec,result);

                cout << result << endl;


                // Восстановим по их NumVectors проекциям на собственные оси.

                cv::PCABackProject(result,mean,EigVec,repared);


                // переведем обратно в прямоугольный вид

                // и выведем в файл

                repared=repared.reshape(1, rows);

                char str[100];

                sprintf(str,"repared_%d.png",i);

                imwrite(str,repared);


        }
как
Mat result,repared;

	for(int i=0; i<10; i++) 

        {

                // Спроецируем на собственные векторы

		pca.project(db[i].reshape(1, rows*cols),result);

                cout << result << endl;


                // Восстановим по их NumVectors проекциям на собственные оси.

		pca.backProject(result,repared);


                // переведем обратно в прямоугольный вид

                // и выведем в файл

                repared=repared.reshape(1, rows);

                char str[100];

                sprintf(str,"repared_%d.png",i);

                imwrite(str,repared);

        }

похоже что работает не верно, в result получаются какие то большие числа, хотя возможно так и должно быть.

на входе получаются числа от 0-255 ,а на выходе большие. возможно там где то опять надо сконвертировать.

Share this post


Link to post
Share on other sites

попробовал перед выводом

Mat normalize(const Mat& src) 

{

    Mat srcnorm;

    normalize(src, srcnorm, 0, 255, NORM_MINMAX, CV_8UC1);

    return srcnorm;

}

получаю нечто расплывчатое похожее на собственные вектора

Share this post


Link to post
Share on other sites

У меня result в пределах +-1000 примерно были, думаю это нормально.

Share this post


Link to post
Share on other sites

нет у меня по несколько милионов)

void calc_PCA(vector<Mat>& db)

{

    int numPrincipalComponents=10;

    int total = db[0].rows * db[0].cols;


    int rows=db[0].rows;

    int cols=db[0].cols;


    Mat mat(total, db.size(), CV_32FC1);


    for(int i = 0; i < db.size(); i++)

    {

        Mat X = mat.col(i);

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }


    // do pca

    PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);


    Mat imgDst(rows,cols*numPrincipalComponents,CV_32FC1);


    //тут выводим собсвенные векторы

    for(int i=0;i<numPrincipalComponents;++i)

    {

            Mat temp=pca.eigenvectors.row(i);

            normalize(temp,temp); // Это и есть собственный вектор

            // ---------------------------------------------------

            // Этот кусок нужен для того, чтобы были видны картинки

            // ---------------------------------------------------

            double m,M;

            minMaxLoc(temp,&m,&M);

            if((M-m)!=0)

            {

                    temp-=m;

                    temp/=(M-m);

                    temp*=255.0;

            }

            temp=temp.reshape(1, rows);

            temp.copyTo(imgDst(Rect(i*cols,0,cols,rows)));

            // ---------------------------------------------------

    }

    imwrite("result.png", imgDst);



    //пробуем спроэцировать и получить обратно исходные данные

    Mat result,repared;

    for(int i=0; i<10; i++)//первые 10

    {

        // Спроецируем на собственные векторы

		//var1

		Mat t;

		db[i].reshape(1, rows*cols).convertTo(t,CV_32FC1,1./255);

		pca.project(t,result);

		cout <<db[i].reshape(1, rows*cols)<< endl;

		cout <<t<< endl;

		//var2

		/*pca.project(db[i].reshape(1, rows*cols),result);

		cout <<db[i].reshape(1, rows*cols)<< endl;*/


        cout << result << endl;


        // Восстановим по их NumVectors проекциям на собственные оси.

		pca.backProject(result,repared);

		cout << repared << endl;


        // переведем обратно в прямоугольный вид

        // и выведем в файл

        repared=repared.reshape(1, rows);

        char str[100];

        sprintf(str,"repared_%d.png",i);

        imwrite(str,normalize(repared));

    }

}

Share this post


Link to post
Share on other sites

Мне думается в этом куске портятся собственные векторы (temp - действительно ссылка).


minMaxLoc(temp,&m,&M);
if((M-m)!=0)
{
temp-=m;
temp/=(M-m);
temp*=255.0;
}
[/code]

Share this post


Link to post
Share on other sites

всё таки, что то не то. либо операция проекции не полностью обратимая.

читаю

void read_mnist(vector<Mat>& vec_img)

{

        //vector<Mat> vec_img;

        ifstream file;


        //file.open("C:/MNIST/train-images.idx3-ubyte",ifstream::in | ifstream::binary);

        file.open("C:/ICP/MNIST/10k_images.bin",ifstream::in | ifstream::binary);

        if (file.is_open())

        {

                unsigned  int magic_number=0;

                unsigned  int number_of_images=0;

                unsigned  int n_rows=0;

                unsigned  int n_cols=0;

                file.read((char*)&magic_number,sizeof(magic_number)); //если перевернуть то будет 2051

                endian_swap(magic_number);

                file.read((char*)&number_of_images,sizeof(number_of_images));//если перевернуть будет 10к

                endian_swap(number_of_images);

                file.read((char*)&n_rows,sizeof(n_rows));

                endian_swap(n_rows);

                file.read((char*)&n_cols,sizeof(n_cols));

                endian_swap(n_cols);

               /* cout << "magic_number=" << magic_number << endl;

                cout << "n_rows=" << n_rows << endl;

                cout << "n_cols=" << n_cols << endl;

                cout << "number_of_images=" << number_of_images << endl;*/


                for(int i=0;i<number_of_images;++i)

                {

                        Mat temp(n_rows,n_cols,CV_8U);

                        for(int r=0;r<n_rows;++r)

                        {

                                for(int c=0;c<n_cols;++c)

                                {

                                        unsigned char t_ch=0;

                                        file.read((char*)&t_ch,sizeof(t_ch));

                                        //тут идет запись матрицы 28х28 в вектор

                                        temp.at<unsigned char>(r,c)= t_ch; //возможно можно как то быстрее копировать построчно?

                                }

                        }

                        vec_img.push_back(temp);

						/*imwrite("test_im.png",temp);

						cout <<temp<< endl;

						int g=0;*/

                }

        }

}
void mnist_to_img()

{

    //---------------------------------------------------

    // Составили картинку из изображений для теста

    // ---------------------------------------------------

	int sz_=100;

	Mat imgDst;

	imgDst.create( sz_*rows, sz_*cols, CV_8U);

    imgDst=0;

    for(int i=0;i<sz_;i++)

    {

        for(int j=0;j<sz_;j++)

        {

			MNIST[i+j*sz_].copyTo(imgDst(Rect(i*cols,j*rows,cols,rows)));

        }

    }

	imwrite("all_imgs.png",imgDst);

}
пробую проекцию
//пробуем спроецировать и получить обратно исходные данные

	const int n_samples= 10000;

	Mat imgOut(100*rows,100*cols,CV_8U); 

	Mat result,repared;

	for(int i=0; i<n_samples; i++)

    {

        // Спроецируем на собственные векторы

		//var1

		Mat t;

		db[i].reshape(1, rows*cols).convertTo(t,CV_32FC1,1./255);//переводим опять во флоат

		pca.project(t,result);

		//cout <<db[i].reshape(1, rows*cols)<< endl; //нужен разделитель

		//cout <<t<< endl;


        //cout << result << endl;


        // Восстановим по их NumVectors проекциям на собственные оси.

		pca.backProject(result,repared);

		//cout << repared << endl;


		//переведем опять в 0-255

		Mat res;

		repared.convertTo(res,CV_8U,255);

		//cout << res << endl;


		int c= i%100;

		int r= i/100;

		res.reshape(1, rows).copyTo(imgOut(Rect(c*cols,r*rows,cols,rows)));

    }

	imwrite("repared.png",imgOut);

в итоге имею

post-701-0-11045200-1338810417_thumb.png

post-701-0-02123800-1338810518_thumb.png

Share this post


Link to post
Share on other sites
Of course, unless all the principal components have been retained, the reconstructed vectors will be different from the originals, but typically the difference will be small is if the number of components is large enough (but still much smaller than the original vector dimensionality) - that’s why PCA is used after all.

только я что то не понял из-за чего?

я проецировал на 10, т.к. 10 цифр или это всё-таки не принципиально?

UPD: попробовал спроецировать на cols*rows компонент и вроде ответ получается идентичный начальному, всё таки результат восстановления зависит от кол-ва компонент.

только тут они почему то генерили для каждого набора свой вектор.

хмм и самое смешное, что если посмотреть график зависимости точности от кол-ва собственных значений ,то оно достигается при максимальном значении(что как бы немного странно для меня)

http://individual.utoronto.ca/gauravjain/ECE462-HandwritingRecognition.pdf

Share this post


Link to post
Share on other sites

результаты кластеризации, если использовать тупо вектор пикселей

центры кластеров.

post-701-0-29955800-1338895873_thumb.png

состав кластеров - одна строка один кластер

image.png

если попробовать использовать PCA, то всё тупо сваливается в 1 кластер.(даже если поставить максимальное число компонент)

подозреваю, что что то не так.

void calc_PCA(vector<Mat>& db)

{

    int total = db[0].rows * db[0].cols;

	int numPrincipalComponents=/*10*/total;


    int rows=db[0].rows;

    int cols=db[0].cols;


    Mat mat(total, db.size(), CV_32FC1);


	//составляем всё в общию матрицу

    for(int i = 0; i < db.size(); i++)

    {

        Mat X = mat.col(i);

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }


    // do pca

    PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);


	//cout<<pca.eigenvalues; // важны ли их относительные значения? и скорость убывания?

	//теперь должны спроецировать наши входные данные на наш новый базис и засунуть в алгоритм кластеризации

	//проецируем

	Mat data(db.size(), numPrincipalComponents, CV_32FC1);

	for(int i=0;i<db.size();++i)

	{

		Mat temp;

		Mat res;

		db[i].reshape(1, rows*cols).convertTo(temp,CV_32FC1,1./255);//переводим опять во флоат

		pca.project(temp,res);

		res.copyTo(data(Rect(0,i,numPrincipalComponents,1)));

	}

	//кластеризуем

	int clusterCount = 10;

    int attempts = 1;

    Mat centers;

    Mat labels;

    kmeans(data, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,

            0.0001, 10000),attempts, KMEANS_PP_CENTERS, centers );



	//определяем какие получились кластеры по размеру

    vector<int> cl_size(clusterCount);

    for(int i=0;i< labels.rows;++i)

    {

		cl_size[labels.at<int>(i,0)]+=1;

    }

}

Share this post


Link to post
Share on other sites

вроде бы заставил его работать.

непонятно только какую размерность пространства выбирать, т.к. ответ от неё зависит.

во всяком случае и с PCA результат далёк от правды.

то ли дело в самом алгоритме, то ли в выделяемых признаках.

во всяком случае есть ли какой либо от этого толк можно проверить только, если проверять по известным лейблам, потом попробую с k-nearest.

void calc_PCA(vector<Mat>& db)

{

    int total = db[0].rows * db[0].cols;

	int numPrincipalComponents=10/*total*/;


    int rows=db[0].rows;

    int cols=db[0].cols;


    Mat mat(total, db.size(), CV_32FC1);


	//составляем всё в общию матрицу

    for(int i = 0; i < db.size(); i++)

    {

        Mat X = mat.col(i); //тут получается приравнивание только лишь установка указателя

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }


    // do pca

    PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);


	//теперь должны спроецировать наши входные данные на наш новый базис и засунуть в алгоритм кластеризации

	//проецируем

	Mat data(db.size(), numPrincipalComponents, CV_32FC1);

	Mat test(db.size(), numPrincipalComponents, CV_8U);

	for(int i=0;i<db.size();++i)

	{

		Mat temp;

		Mat res;

		db[i].reshape(1, rows*cols).convertTo(temp,CV_32FC1,1./255);//переводим опять во флоат

		pca.project(temp,res);

		//возможно нужно нормировать сразу потом всё а не каждый в отдельности?

		//нужна ли нормализация?

		//Mat t= normalize_f(res);//нужно не нормирование а растянуть динамический диапазон?

		Mat tr= /*t*/res.t();

		tr.copyTo(data(Rect(0,i,numPrincipalComponents,1)));

	}


	//кластеризуем

	int clusterCount = 10;

    int attempts = 1;

    Mat centers;

    Mat labels;


	//правильно ли поданы данные?

    kmeans(data, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,

            0.0001, 10000),attempts, KMEANS_PP_CENTERS, centers );



	//определяем какие получились кластеры по размеру

    vector<int> cl_size(clusterCount);

    for(int i=0;i< labels.rows;++i)

    {

		cl_size[labels.at<int>(i,0)]+=1;

    }

	int f=0;


	//допустим напишем функцию которая сохранит в виде одна строчка один кластер

	int n_max=0;

	for(int i=0;i<cl_size.size();++i)

	{

		if(cl_size[i]>n_max)

			n_max=cl_size[i];

	}

	Mat clasters(cl_size.size()*rows, n_max*cols, CV_8U);


	//имеем лэйблы от PCA и просто копируем исходные данные для отображения

	vector<int> c_vec(cl_size.size());

	for(int i=0;i<labels.rows;++i)

	{

		int n= labels.at<int>(i,0); //в какую строку пойдёт

		Mat t;

		db[i].copyTo(t);


		t.copyTo(clasters(Rect(c_vec[n]*cols,n*rows,cols,rows)));

		++c_vec[n];//увеличиваем счётчик

	}

	imwrite("clusters.png",clasters);

}

Share this post


Link to post
Share on other sites

да еще вопрос, есть ли смысл использовать фильтры Габора для выделения вектора фич?

есть ли смысл как то размывать\ уменьшать изображения и добавлять эту инфу в общий вектор?

Share this post


Link to post
Share on other sites

Я думаю, что кластеризацией здесь большего не добиться, ведь программу никто цифрам не учил.

А по изображениям он и так неплохо справился (ведь 9 чисто геометрически очень смахивает на 4 или на 0, да и на 8 тоже). И вообще, кто его поймет в пространстве такой размерности :)

Если нужно научить его понимать эти цифры как их понимают люди, то учить нужно с учителем (регрессия, обратное распространение, SVM, boost и т.п.). Тогда программа будет искать различия между заданными классами.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×