Перейти к содержимому
Compvision.ru
Smorodov

Нормализация изображения (приведение к форме, удобной для классификаторов)

Recommended Posts

Написал кусок кода по мотивам:

http://ufldl.stanford.edu/wiki/index.php/Implementing_PCA/Whitening

http://ufldl.stanford.edu/wiki/index.php/Exercise:PCA_and_Whitening

но это не совсем то, там берутся кусочки вытягиваются в векторы проводится PCA всего набора этих кусочков.

У меня проводится SVD центрированного (вычел среднее) всего изображения и дальше по формуле ZCA по ссылке выше.

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

Вот что программа делает с изображениями:

post-1-0-34539200-1345817626_thumb.jpg

post-1-0-98450800-1345817641_thumb.jpg


#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/legacy/legacy.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <iostream>

using namespace std;
using namespace cv;
double epsilon=1.0;
//----------------------------------------------------------
// Точка входа
//----------------------------------------------------------
int main(int argc, char* argv[])
{
setlocale(LC_ALL, "Russian");
// Матрица изображения
Mat img;
Mat result;
//---------------------------------------------
//
//---------------------------------------------
namedWindow("Исходное изображение");

namedWindow("Результат");
// Грузим изображение
img=imread("C:\\ImagesForTest\\head.ppm",0);
img.convertTo(img,CV_32FC1,1.0/255.0);
// Среднее
double mean=cv::mean(img)[0];
// создаем SVD вычислятор
cv::SVD s;
// память под результат разложения
Mat w,u,vt;
// вычисляем
Mat ZeroCentered=(img-mean);
s.compute(ZeroCentered,w,u,vt);
// собираем матрицу Sigma (по-диагонали собственные числа, остальное нули)
// так как функция вернула нам их в виде вектора, а нам нужна диагональная матрица
Mat W=Mat::zeros(w.rows,w.rows,CV_32FC1);
for(int i=0;i<w.rows;i++)
{
W.at<float>(i,i)=1.0/(sqrt(w.at<float>(i)+epsilon));
}
// Собираем изображение обратно
result=u*W*u.t()*ZeroCentered;
cv::normalize(result,result,0,1,cv::NORM_MINMAX);
//result+=mean;
//---------------------------------------------
//
//---------------------------------------------
imshow("Исходное изображение", img);
imshow("Результат", result);
cvWaitKey(0);
return 0;
}
[/code]

ЗЫ: Реализовал для генерации "корма" для Sparse autoencoder Сам автоэнкодер реализовал пока что в матлабе.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Соорудил Whitening filter через FFT (результат похож на то что применяется при обучении разреженным признакам (sparse features)).

post-1-0-31678800-1346062429_thumb.jpg

Формулу взял отсюда: http://redwood.psych.cornell.edu/papers/olshausen_field_nature_1996.pdf

#include <iostream>
#include <vector>
#include <stdio.h>
#include "opencv2/core/core.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;
const double E=2.7182818284590452353602874713527;
//----------------------------------------------------------
// Функция для перестановки четвертей изображения местамии
// так, чтобы ноль спектра находился в центре изображения.
//----------------------------------------------------------
void Recomb(Mat &src,Mat &dst)
{
int cx = src.cols>>1;
int cy = src.rows>>1;
Mat tmp;
tmp.create(src.size(),src.type());
src(Rect(0, 0, cx, cy)).copyTo(tmp(Rect(cx, cy, cx, cy)));
src(Rect(cx, cy, cx, cy)).copyTo(tmp(Rect(0, 0, cx, cy)));
src(Rect(cx, 0, cx, cy)).copyTo(tmp(Rect(0, cy, cx, cy)));
src(Rect(0, cy, cx, cy)).copyTo(tmp(Rect(cx, 0, cx, cy)));
dst=tmp;
}
//----------------------------------------------------------
// По заданному изображению рассчитывает
// действительную и мнимую части спектра Фурье
//----------------------------------------------------------
void ForwardFFT(Mat &Src, Mat *FImg)
{
int M = getOptimalDFTSize( Src.rows );
int N = getOptimalDFTSize( Src.cols );
Mat padded;
copyMakeBorder(Src, padded, 0, M - Src.rows, 0, N - Src.cols, BORDER_CONSTANT, Scalar::all(0));
// Создаем комплексное представление изображения
// planes[0] содержит само изображение, planes[1] его мнимую часть (заполнено нулями)
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexImg;
merge(planes, 2, complexImg);
dft(complexImg, complexImg);
// После преобразования результат так-же состоит из действительной и мнимой части
split(complexImg, planes);

// обрежем спектр, если у него нечетное количество строк или столбцов
planes[0] = planes[0](Rect(0, 0, planes[0].cols & -2, planes[0].rows & -2));
planes[1] = planes[1](Rect(0, 0, planes[1].cols & -2, planes[1].rows & -2));

Recomb(planes[0],planes[0]);
Recomb(planes[1],planes[1]);
// Нормализуем спектр
planes[0]/=float(M*N);
planes[1]/=float(M*N);
FImg[0]=planes[0].clone();
FImg[1]=planes[1].clone();
}
//----------------------------------------------------------
// По заданным действительной и мнимой части
// спектра Фурье восстанавливает изображение
//----------------------------------------------------------
void InverseFFT(Mat *FImg,Mat &Dst)
{
Recomb(FImg[0],FImg[0]);
Recomb(FImg[1],FImg[1]);
Mat complexImg;
merge(FImg, 2, complexImg);
// Производим обратное преобразование Фурье
idft(complexImg, complexImg);
split(complexImg, FImg);
normalize(FImg[0], Dst, 0, 1, CV_MINMAX);
}
//----------------------------------------------------------
// Раскладывает изображение на амплитуду и фазу спектра Фурье
//----------------------------------------------------------
void ForwardFFT_Mag_Phase(Mat &src, Mat &Mag,Mat &Phase)
{
Mat planes[2];
ForwardFFT(src,planes);
Mag.zeros(planes[0].rows,planes[0].cols,CV_32F);
Phase.zeros(planes[0].rows,planes[0].cols,CV_32F);
cv::cartToPolar(planes[0],planes[1],Mag,Phase);
}
//----------------------------------------------------------
// По заданным амплитуде и фазе
// спектра Фурье восстанавливает изображение
//----------------------------------------------------------
void InverseFFT_Mag_Phase(Mat &Mag,Mat &Phase, Mat &dst)
{
Mat planes[2];
planes[0].create(Mag.rows,Mag.cols,CV_32F);
planes[1].create(Mag.rows,Mag.cols,CV_32F);
cv::polarToCart(Mag,Phase,planes[0],planes[1]);
InverseFFT(planes,dst);
}
//----------------------------------------------------------
// Whiten image
//----------------------------------------------------------
void whiten(Mat& src,Mat &dst)
{
double f0=200;
//----------------------------------------------------------
// Производим свертку
//----------------------------------------------------------
// Раскладываем изображение в спектр
// Ампльтуда спектра
Mat Mag;
// Фаза спектра
Mat Phase;
ForwardFFT_Mag_Phase(src,Mag,Phase);
//----------------------------------------------------------
// Создаем частотный фильтр (можно создать 1 раз и использовать повторно)
//----------------------------------------------------------
Mat filter;
filter=Mat::zeros(Mag.rows,Mag.cols,CV_32F);
for(int i=0;i<src.rows;i++)
{
double I=(float)i-((float)src.rows-1)/2.0;
float* F = filter.ptr<float>(i);
for(int j=0;j<src.cols;j++)
{
double J=(float)j-((float)src.cols-1)/2.0;
double f=sqrtl(I*I+J*J);
F[j]=f*powf(E,-powf((f/f0),4.0));
}
}


cv::multiply(Mag,filter,Mag);
//cv::multiply(Phase,filter,Phase);
//----------------------------------------------------------
// Обратное преобразование
//----------------------------------------------------------
InverseFFT_Mag_Phase(Mag,Phase,dst);
dst=dst(Range(0,src.rows),Range(0,src.cols));
}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
namedWindow("Result");
Mat I=imread("C:\\ImagesForTest\\lena.jpg",0);
I.convertTo(I,CV_32FC1,1.0/255.0);
Mat res;
whiten(I,res);
imshow("Result",res);
waitKey(0);
return 0;
}[/code]

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Еще один whitening.

По работе: Enhanced Local Texture Feature Sets for Face Recognition Under Difficult Lighting Conditions.

Результат работы:

post-1-0-46600800-1388255879_thumb.png

Исходник:

main.cpp

Тот-же исходник что и в архиве:

#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdarg.h>
#include <set>
#include "opencv2/opencv.hpp"
#include "fstream"
#include "iostream"
using namespace std;
using namespace cv;


#include <windows.h>

int main(int argc, char* argv[])
{
namedWindow("result");
Mat img=imread("D:\\ImagesForTest\\lena.jpg",0);
img.convertTo(img,CV_32FC1,1.0/255.0);

double alpha=0.1;
double tau=12.0;
double gamma=0.2;

Mat I_pow;
Mat I=img.clone();

// Гамма-коррекция
cv::pow(I,gamma,I);

// DoG фильтр
Mat g1,g2;
cv::GaussianBlur(I,g1,Size(7,7),1.0);
cv::GaussianBlur(I,g2,Size(7,7),2.0);
I=(g1-g2);

// Выравнивание контраста
cv::pow(I,alpha,I_pow);
I=I/pow(mean(I_pow)[0],1.0/alpha);

Mat Ithr;
threshold(I,Ithr,tau,1.0,cv::THRESH_TOZERO);
cv::add(Ithr,tau,Ithr,(Ithr==0));

cv::pow(Ithr,alpha,Ithr);
I=I/pow(mean(Ithr)[0],1.0/alpha);

// Сигмоида (сжимаем диапазон яркостей в интеравал (0,1) )
Mat exp_I;
cv::exp(-I,exp_I);
I=1.0/(1+exp_I);

imshow("result",I);

cv::waitKey(0);
}[/code]

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×