2014-05-01 2 views
-1

Мне нужно найти способ сгруппировать двоичные векторы с помощью OPENCV для Android.Кластеризация двоичных векторов в OpenCV для Android

Я использую модель словесной модели, до сих пор я работал на своем компьютере с помощью java и использовал просеивание. Проблема в том, что это не файл OPENCV для Android, поэтому я решил попробовать использовать ORB, но это двоичный дескриптор. Так что мне нужно найти способ сгруппировать двоичные векторы, используя opencv на android.

+0

Вы можете реализовать свой собственный алгоритм просеять (Notic: SIFT является несвободным алгоритмом) – Hadi

+0

Вопросов просят нас, чтобы рекомендовать или найти инструмент, ** библиотеки или любимые вне сайта ресурсов являются вне темы ** для Stack Overflow, поскольку они склонны привлекать упрямые ответы и спам. Вместо этого опишите проблему и то, что было сделано до сих пор, чтобы ее решить. –

ответ

0

Прежде всего, вы можете попробовать использовать JFeatureLib, javasift (здесь вы найдете javasift in android application).

В бинарной кластеризации вы можете посмотреть Епископ «Распознавание образов и машинное обучение» см. На страницах 461-465 главы «Смеси распределений Бернулли». У меня есть реализация (см. Код ниже), но все комментарии на русском языке (я слишком ленив, чтобы перевести его). This video показывает, как он работает для двоичных изображений рукописных цифр (бинаризованный MNIST). Он нашел центры кластеров.

#include <iostream> 
#include <vector> 
#include <stdio.h> 
#include <opencv2/opencv.hpp> 
#include <numeric> 
#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); 
} 
//----------------------------------------------------------------------------------------------------- 
// 
//----------------------------------------------------------------------------------------------------- 
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); 
} 
//----------------------------------------------------------------------------------------------------- 
// Чтение меток NMIST (здесь не используется) 
//----------------------------------------------------------------------------------------------------- 
void read_mnist_labels(string fname,vector<unsigned char>& vec_lbl) 
{ 
    ifstream file; 
    file.open(fname,ifstream::in | ifstream::binary); 
    if (file.is_open()) 
    { 
     unsigned int magic_number=0; 
     unsigned int number_of_labels=0; 
     file.read((char*)&magic_number,sizeof(magic_number)); //если перевернуть то будет 2051 
     endian_swap(magic_number); 
     file.read((char*)&number_of_labels,sizeof(number_of_labels));//если перевернуть будет 10к 
     endian_swap(number_of_labels); 

     cout << "magic_number=" << magic_number << endl; 
     cout << "number_of_labels=" << number_of_labels << endl; 

     for(int i=0;i<number_of_labels;++i) 
     { 
      unsigned char t_ch=0; 
      file.read((char*)&t_ch,sizeof(t_ch)); 
      vec_lbl.push_back(t_ch); 
     } 
    } 
} 
//----------------------------------------------------------------------------------------------------- 
// Чтение изображений MNIST, на выходе вектор матриц с изображениями цифр 
//----------------------------------------------------------------------------------------------------- 
void read_mnist(string fname,vector<Mat>& vec_img) 
{ 
    ifstream file; 
    file.open(fname,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 << endl; 
     cout << "Высота изображений=" << n_rows << endl; 
     cout << "Ширина изображений=" << n_cols << endl; 
     cout << "Количество изображений=" << 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); 
     } 
    } 

} 
//----------------------------------------------------------------------------------------------------- 
// Считаем правдоподобие выборки данных x для распределения Бернулли с параметром mu 
//----------------------------------------------------------------------------------------------------- 
double Likelihood(Mat& x,Mat& mu) 
{ 
    double P=1; 
    int n_rows=x.rows; 
    int n_cols=x.cols; 
    for(int r=0;r<n_rows;++r) 
    { 
     for(int c=0;c<n_cols;++c) 
     { 
      // Распределение бинарное, поэтому можем позволить себе такое безобразие. 
      if(x.at<double>(r,c)>0.5) 
      { 
       P*=mu.at<double>(r,c); // Если выпала единица 
      } 
      else 
      { 
       P*=1.0-mu.at<double>(r,c); // если выпал ноль 
      } 
     } 
    } 
    return P; 
} 
//----------------------------------------------------------------------------------------------------- 
// E - шаг 
// Вычисляем значения скрытых переменных. 
// Постериорная вероятность принадлежности X к кластеру K 
//----------------------------------------------------------------------------------------------------- 
RNG rng; 
void getGamma(vector<Mat>& vecX, vector<Mat>& vecMu,vector<double>& vecPi,Mat& Gamma) 
{ 
    int N=vecX.size(); 
    int K=vecPi.size(); 
    for(int n=0;n<N;n++) 
    { 
     // Вычислим знаменатель (Маргинальная вероятность по классу) 
     double denom=0; 
     for(int j=0;j<K;j++) 
     { 
      denom+=Likelihood(vecX[n],vecMu[j]); 
     } 

     for(int k=0;k<K;k++) 
     { 
      double p=Likelihood(vecX[n],vecMu[k]); 

      // Некоторая моя вычислительная алхимия 
      double tmp; 
      if(fabs(denom)>(2*DBL_MIN)) 
      { 
       tmp=p/denom; 
      }else 
      { 
       tmp=rng.gaussian(1/(K*sqrt(3.0)))+1.0/K; // пошумим чуть-чуть 
      } 
      // ------------------------------------ 
      Gamma.at<double>(n,k)=vecPi[k]*tmp; 
      // Для каждого X сумма вероятностей принадлежности ко всем кластерам равна 1 
      // (К какому нибудь кластеру он точно принадлежит.) 
      normalize(Gamma.row(n),Gamma.row(n),1,0,cv::NORM_L1); 
     } 

    } 
    // Проконтролируем на всякий случай границы (вероятность не может иметь значения вне диапазона [0;1]) 
    normalize(Gamma,Gamma,0,1,cv::NORM_MINMAX); 
} 
//----------------------------------------------------------------------------------------------------- 
// M - шаг. Теперь по полному набору переменных (наблюдаемые и скрытые) находим следующее приближение параметров распределения. 
//----------------------------------------------------------------------------------------------------- 
void getMuAndPi(vector<Mat>& vecX,Mat& Gamma,vector<Mat>& vecMu,vector<double>& vecPi) 
{ 
    int N=vecX.size(); 
    int K=vecPi.size(); 

    for(int k=0;k<K;k++) 
    { 
     double Nk=0; 
     for(int n=0;n<N;n++) 
     { 
      Nk+=Gamma.at<double>(n,k); 
     } 

     // Эффективное количество элементов, принадлежащих K-тому кластеру 
     cout << "N[" << k << "]=" << Nk << endl; 

     vecMu[k]=0; 
     for(int n=0;n<N;n++) 
     { 
      vecMu[k]+=(vecX[n].mul(Gamma.at<double>(n,k))); 
     } 
     vecMu[k]/=Nk; // Находим приближение центров кластеров 
     vecPi[k]=Nk/(double)N; // Находим приближение коэффициентов смеси 
    } 

    // Отмасштабируем коэффициенты смеси, чтобы сумма их была равна 1 
    double sumPi=0; 
    sumPi=std::accumulate(vecPi.begin(),vecPi.end(), 0.0); 
    transform(vecPi.begin(), vecPi.end(), vecPi.begin(), std::bind2nd(std::divides<double>(),sumPi)); 
} 
//----------------------------------------------------------------------------------------------------- 
// Инициализация параметров 
//----------------------------------------------------------------------------------------------------- 
void InitParameters(int N,int K,vector<Mat>& MNIST,vector<Mat>& vecX,Mat& Gamma,vector<Mat>& vecMu,vector<double>& vecPi) 
{ 
    Gamma=Mat::zeros(N,K,CV_64FC1); 
    Mat tmp; 
    int h=MNIST[0].cols; 
    int w=MNIST[0].rows; 

    vecX.resize(N); 
    // Это делается чтобы можно было задать объем обрабатываемых данных (через N) 
    for(int i=0;i<N;i++) 
    {  
     threshold(MNIST[i],tmp,128,1,CV_8UC1); 
     tmp.convertTo(vecX[i],CV_64FC1); 
    } 
    // инициализация центров кластеров 
    for(int k=0;k<K;k++) 
    { 
     Mat r(MNIST[0].size(),CV_64FC1); 
     randu(r,0,1); 
     normalize(r,r,MNIST[0].rows*MNIST[0].cols,0,cv::NORM_L1); 
     r*=0.5; 
     r+=0.25; 
     // Центры кластеров (все пиксели имеют яркость в около 0.5) 
     vecMu.push_back(r); 
     // коэффициенты смеси инициализируются так, чтобы их сумма была равна единице 
     vecPi.push_back(1.0/K); 
    } 
} 
//----------------------------------------------------------------------------------------------------- 
// Отрисовка центров кластеров в один ряд на одном изображении 
//----------------------------------------------------------------------------------------------------- 
void DrawMu(Mat& dst, vector<Mat>& vecMu) 
{ 
    int rows=vecMu[0].rows; 
    int cols=vecMu[0].cols; 
    dst=Mat::zeros(rows, vecMu.size()*cols, CV_64FC1); 
    for(int i=0;i<vecMu.size();i++) 
    { 
     vecMu[i].copyTo(dst(Rect(i*cols,0,cols,rows))); 
    } 
    cv::normalize(dst,dst,0,1,cv::NORM_MINMAX); 
} 
//----------------------------------------------------------------------------------------------------- 
// Bishop страницы 461-465 глава "Mixtures of Bernoulli distributions" 
//----------------------------------------------------------------------------------------------------- 
int main(int argc, char** argv) 
{ 
    // Количество кластеров, которое хотим получить 
    int N_clusters=10; 
    // Количество итераций EM - алгоритма. 
    int N_iter=50; 

    setlocale(LC_ALL, "Russian"); 
    vector<Mat> MNIST; 
    // читаем изображения 
    cout << "Загрузка изображений." << endl; 
    read_mnist("D:/MNIST/t10k-images.idx3-ubyte",MNIST); 
    cout << "Загрузка изображений выполнена." << endl; 
    // создаем окно 
    namedWindow("result"); 
    // размеры одного изображения 
    int rows=MNIST[0].rows; 
    int cols=MNIST[0].cols; 

    vector<Mat>  vecX; // Входные векторы 
    Mat    Gamma; // Мера ответственности K-того кластера за N-ный входной вектор 
    vector<Mat>  vecMu; // Центры кластеров 
    vector<double> vecPi; // Коэффициенты смеси распределений 

    // Создаем и заполняем необходимые переменные 
    cout << "Инициализация параметров." << endl; 
    InitParameters(10000,N_clusters,MNIST,vecX,Gamma,vecMu,vecPi); 
    cout << "Инициализация параметров выполнена." << endl; 

    // Запишем все в видеофайл 
    VideoWriter vw=VideoWriter::VideoWriter("output.mpeg", CV_FOURCC('P','I','M','1'), 20, Size(cols*vecMu.size(),rows)); 
    // собственно сам EM-алгоритм 
    // Критерием сходимости таких алгоритмов обычно является стабилизация значений центров кластеров 
    // но мне лень это делать, поэтому поставлю фиксированное количество итераций. 
    for(int iter=0;iter<N_iter;iter++) 
    { 
     cout << "Итерация №" << iter << endl; 
     getGamma(vecX,vecMu,vecPi,Gamma); // E - Шаг (расчет матожиданий коэффициентов) 
     cout << "E - шаг выполнен." << endl; 
     getMuAndPi(vecX,Gamma,vecMu,vecPi); // M - шаг (уточнение параметров распределения методом максимизации правдоподобия) 
     cout << "M - шаг выполнен." << endl; 

     // Отрисовка центров кластеров, чтобы не скучно было :) 
     Mat MuImg; 
     DrawMu(MuImg,vecMu); 
     imshow("result",MuImg); 
     MuImg.convertTo(MuImg,CV_8UC1,255); 
     cvtColor(MuImg,MuImg,cv::COLOR_GRAY2BGR); 
     //resize(MuImg,MuImg,Size(MuImg.cols*4,MuImg.rows*4)); 
     vw<<MuImg; // Запись кадра в видеофайл 

     waitKey(30); 
     MuImg.release(); 

    } 
    // Освободим видеофайл 
    vw.release(); 
    // Закончили, ждем нажатия клавиши 
    waitKey(0); 
    destroyAllWindows(); 
    return 0; 
} 
+0

Двоичное изображение - двоичный вектор, а двоичный дескриптор - также двоичный вектор. В чем разница? –

Смежные вопросы