mrgloom 242 Жалоба Опубликовано May 5, 2012 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? спроецированные на этот новый базис изображения?(иих размер соответсвенно будет меньше) Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 5, 2012 Обычно смотрят на значения собственных чисел, как правило берут те собственные векторы, которым соответствуют максимальные собственные значения. Определить количество собственных векторов, можно либо произвольно (взять N векторов с максимальными собственными числами), либо по порогу, (собственные значения не менее X% от максимального). Да, спроецированные на этот базис изображения, их размер будет равен количеству измерений нового базиса. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 22, 2012 попробовал уменьшение размерности и все равно размеры кластеров пишет 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; } } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 22, 2012 Так там же 10 цифр, а не 20, а собственных векторов 9 должно быть ( http://www.cognotics.com/opencv/servo_2007_series/part_5/page_4.html ). ЗЫ: Может сначала на каком-нибудь датасете поменьше размером и размерностью отладить? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 22, 2012 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; } но не очень понятно как трактовать результаты Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 22, 2012 Как собственные векторы. Во всяком случае визуально похоже. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 22, 2012 Так там же 10 цифр, а не 20, а собственных векторов 9 должно быть ( http://www.cognotics.com/opencv/servo_2007_series/part_5/page_4.html ). ЗЫ: Может сначала на каком-нибудь датасете поменьше размером и размерностью отладить? хмм ну я думал что кол-во векторов определяется размеров входного вектора признаков ,а не кол-вом различных сущностей в выборке. впрочем вот для 9-ти то же самое. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 22, 2012 Это правильно, ограничение по количеству классов, вероятно удобнее для классификации. Для каждой цифры надо (после получения собственных векторов) найти координаты в этих новых осях (коэффициенты), и эти коэффициенты подавать уже на 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] Можно попробовать построить первые две координаты (с наибольшими собственными числами) на плоскости, чтобы визуально проверить что там с кластерами выходит. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 23, 2012 забавно, но похоже проблема в том, что изображения не правильно читаются. первые шесть нормально, а остальные как черные. читал так 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]); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 23, 2012 Ну да, вроде все верно 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 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 23, 2012 нашел набор из 10к изображений, попробую их в такой форме загрузить. Может это поковырять интересно будет: https://sites.google...l-network-class ну там все на матлабе. вот нашел еще про PCA и какие то другие методы. http://www.inb.uni-luebeck.de/publikationen/pdfs/LaBaMa08c.pdf Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 23, 2012 У меня этот вариант норм загружает и считает собственные векторы, плюс проецирует картинку на полученные собственные векторы и восстанавливает картинку по заданным проекциям на собственные векторы. #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] 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 24, 2012 ошибка была в ifstream::binary, но очень странно как в таком случае прочитались первые 6 цифр. PCAProject у меня не находит, но это наверно можно сделать и через pca.project. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 24, 2012 Да нет, не странно, просто он дошел до символа конца файла. 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 24, 2012 ну вообще попробовал кластеризовать как есть получились такие вот центры кластеров. в целом разброд внутри кластера наблюдается сильный, но алгоритм вроде бы работает правильно. пробовал переписать этот кусок / --------------------------------------------------- // Спроецируем 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 ,а на выходе большие. возможно там где то опять надо сконвертировать. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 24, 2012 попробовал перед выводом Mat normalize(const Mat& src) { Mat srcnorm; normalize(src, srcnorm, 0, 255, NORM_MINMAX, CV_8UC1); return srcnorm; } получаю нечто расплывчатое похожее на собственные вектора Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 24, 2012 У меня result в пределах +-1000 примерно были, думаю это нормально. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано May 24, 2012 нет у меня по несколько милионов) 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)); } } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 24, 2012 Мне думается в этом куске портятся собственные векторы (temp - действительно ссылка). minMaxLoc(temp,&m,&M); if((M-m)!=0) { temp-=m; temp/=(M-m); temp*=255.0; } [/code] Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 4, 2012 всё таки, что то не то. либо операция проекции не полностью обратимая. читаю 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); в итоге имею Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 4, 2012 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 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 5, 2012 результаты кластеризации, если использовать тупо вектор пикселей центры кластеров. состав кластеров - одна строка один кластер если попробовать использовать 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; } } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 5, 2012 вроде бы заставил его работать. непонятно только какую размерность пространства выбирать, т.к. ответ от неё зависит. во всяком случае и с 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); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 5, 2012 да еще вопрос, есть ли смысл использовать фильтры Габора для выделения вектора фич? есть ли смысл как то размывать\ уменьшать изображения и добавлять эту инфу в общий вектор? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано June 5, 2012 Я думаю, что кластеризацией здесь большего не добиться, ведь программу никто цифрам не учил. А по изображениям он и так неплохо справился (ведь 9 чисто геометрически очень смахивает на 4 или на 0, да и на 8 тоже). И вообще, кто его поймет в пространстве такой размерности Если нужно научить его понимать эти цифры как их понимают люди, то учить нужно с учителем (регрессия, обратное распространение, SVM, boost и т.п.). Тогда программа будет искать различия между заданными классами. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах