Недавно на хабре появилось несколько интересных статей про голографическое кодирование и декодирование информации — Эксперимент с голографическим кодированием и декодированием информации и я, разумеется, сразу же захотел реализовать это дело под OpenCV :)
Алгоритм производит действия, аналогичные процессу получения голограммы:
В определённой области пространства (каждом пикселе изображения) складывают две волны: одна из них идёт непосредственно от источника (опорная волна — постоянное значение: 127.5), а другая отражается от объекта записи (объектная волна — суммарное значение весов всех пикселей исходной картинки). В этой же области размещают фотопластинку (или иной регистрирующий материал — пустая картинка), в результате на этой пластинке возникает сложная картина полос потемнения, которые соответствуют картине интерференции в этой области пространства. Если теперь эту пластинку осветить волной, близкой к опорной, то она преобразует эту волну в волну, близкую к объектной. Таким образом, мы будем видеть (с той или иной степенью точности) такой же свет, какой отражался бы от объекта записи.
Реализацию алгоритма на php смотрите в первой статье, а на паскале во второй(ссылки внизу), вот же что получилось у меня:
//
// голографическое кодирование и декодирование информации
//
// на основе статьи: Эксперимент с голографическим кодированием и декодированием информации
// http://habrahabr.ru/blogs/algorithm/120051/
// http://habrahabr.ru/blogs/algorithm/122318/
//
// Сложность алгоритма оценивается как O(n^2)
// поэтому экспериментировать стоит только на маленьких картинках ;)
//
// http://robocraft.ru
//
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string>
// получить голограмму изображения
// src - исходное изображение
// wave_length - длина волны
// base_light - опорный свет
IplImage* cvImageHologram(const IplImage* src, float wave_length, float base_light = 127.5 );
// получить изображение по голограмме
IplImage* cvImageDehologram(const IplImage* src, float wave_length);
int main(int argc, char* argv[])
{
IplImage *image = 0, *dst = 0, *dst2 = 0;
char img_name[] = "Image0.jpg";
// имя картинки задаётся первым параметром
char* image_filename = argc >= 2 ? argv[1] : img_name;
// получаем картинку
image = cvLoadImage(image_filename, 1);
printf("[i] image: %s\n", image_filename);
if(!image){
printf("[!] Error: cant load image: %s\n", image_filename);
return -1;
}
// покажем изображение
cvNamedWindow( "image");
cvShowImage( "image", image );
//for(int i=1; i<1000; i++){
//float wave_len = 2; //0.01*i;
char* tmp_ptr=0;
float wave_len = argc >= 3 ? (float)strtod(argv[2], &tmp_ptr) : 0.0001;
printf("%f\n", wave_len);
#if 1
// получить голограмму
dst = cvImageHologram(image, wave_len);
// раскодируем полученную голограмму
dst2 = cvImageDehologram(dst, wave_len);
#else
// декодирование голограммы
dst = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvConvertImage(image, dst, CV_BGR2GRAY);
dst2 = cvImageDehologram(dst, wave_len);
#endif
// покажем результат
cvNamedWindow( "Hol");
cvShowImage( "Hol", dst );
cvNamedWindow( "deHol");
cvShowImage( "deHol", dst2 );
#if 1
// сохраняем результат
std::string dst_file_name = image_filename;
dst_file_name += "-hol.png";
cvSaveImage(dst_file_name.c_str(), dst);
dst_file_name = image_filename;
dst_file_name += "-dehol.png";
cvSaveImage(dst_file_name.c_str(), dst2);
#endif
#if 1
// увеличенные картинки для отображения результатов
int resW = image->width * 3;
int resH = image->height * 3;
IplImage* dst3 = cvCreateImage( cvSize(resW, resH), IPL_DEPTH_8U, 3);
IplImage* dst4 = cvCreateImage( cvSize(resW, resH), IPL_DEPTH_8U, 1);
// показываем картинки
cvNamedWindow( "obj");
cvResize(image, dst3, CV_INTER_NN);
cvShowImage( "obj", dst3 );
cvNamedWindow( "Hologram");
cvResize(dst, dst4, CV_INTER_NN);
cvShowImage( "Hologram", dst4 );
cvNamedWindow( "deHologram");
cvResize(dst2, dst3, CV_INTER_NN);
cvShowImage( "deHologram", dst3 );
cvReleaseImage(&dst3);
cvReleaseImage(&dst4);
#endif
// ждём нажатия клавиши
cvWaitKey(0);
// освобождаем ресурсы
cvReleaseImage(&image);
cvReleaseImage(&dst);
cvReleaseImage(&dst2);
//}
// удаляем окна
cvDestroyAllWindows();
return 0;
}
// получить голограмму изображения
// src - исходное изображение
// wave_length - длина волны
// base_light - опорный свет
IplImage* cvImageHologram(const IplImage* src, float wave_length, float base_light)
{
if(!src){
return 0;
}
float resize = 1;
float W = wave_length; //длина волны источника света
if(W<=0){
return 0;
}
IplImage* dst = cvCreateImage(cvSize(src->width*resize, src->height*resize), IPL_DEPTH_32F, 1);
if(!dst){
return 0;
}
cvZero(dst);
printf("[i] Start...\n");
// пробегаемся по всем пикселям получаемого изображения
for( int y1=0; y1<dst->height; y1++ ) {
float* ptr_dst = (float*) (dst->imageData + y1 * dst->widthStep);
for( int x1=0; x1<dst->width; x1++ ) {
// яркость каждой точки искомого изображения -
// равна сумме света пришедшего ОТО ВСЕХ точек исходного изображения
// пробегаемся по всем пикселям исходного изображения
for( int y0=0; y0<src->height; y0++ ) {
uchar* ptr_src = (uchar*) (src->imageData + y0 * src->widthStep);
for( int x0=0; x0<src->width; x0++ ) {
// расстояние от точки (x0;y0) до точки (x1;y1) считаем что везде z=1, плоская голограмма
float D = sqrt( 1.0f + (x0*resize-x1)*(x0*resize-x1) + (y0*resize-y1)*(y0*resize-y1) );
// Фаза волны достигшей этой точки
float Phase = D/W;
// доля света от очередной точки объекта:
// суммируем свет от очередной точки
// (в соответствии с фазой световой волны пришедшей от этой точки)
// на выходе имеем - интенсивность света в точке (x1;y1)
// 3 канала
ptr_dst[x1] += ptr_src[3*x0]*cos(Phase) + // B - синий
ptr_src[3*x0+1]*cos(Phase) + // G - зелёный
ptr_src[3*x0+2]*cos(Phase); // R - красный
}
}
}
}
printf("[i] Done.\n");
// находим максимальное значение
float max = 0;
for( int y1=0; y1<dst->height; y1++ ) {
float* ptr_dst = (float*) (dst->imageData + y1 * dst->widthStep);
for( int x1=0; x1<dst->width; x1++ ) {
if(ptr_dst[x1]>max){
max = ptr_dst[x1];
}
}
}
printf("[i] max: %f \n", max);
// результирующее изображение
IplImage* temp = cvCreateImage(cvSize(src->width*resize, src->height*resize), src->depth, 1);
// пробегаемся по всем пикселям получаемого изображения
for( int y1=0; y1<dst->height; y1++ ) {
float* ptr_dst = (float*) (dst->imageData + y1 * dst->widthStep);
uchar* ptr_temp = (uchar*) (temp->imageData + y1 * temp->widthStep);
for( int x1=0; x1<dst->width; x1++ ) {
float val = ptr_dst[x1];
if(max!=0){
// добавляем опорный свет
val = abs( pow( (ptr_dst[x1]/max)*127.5 + base_light, 2 )/255 );
}
if(val>255.0){
val = 255;
}
ptr_temp[x1] = (uchar)val;
}
}
cvReleaseImage(&dst);
return temp;
}
// получить изображение по голограмме
// src - исходное изображение голограммы
// wave_length - длина волны
IplImage* cvImageDehologram(const IplImage* src, float wave_length)
{
if(!src){
return 0;
}
float resize = 1;
IplImage* dst = cvCreateImage(cvSize(src->width*resize, src->height*resize), IPL_DEPTH_32F, 3);
if(!dst){
return 0;
}
cvZero(dst);
float W = wave_length; //длина волны источника света
if(W<=0){
W=0.1;
}
printf("[i] Start...\n");
// пробегаемся по всем пикселям получаемого изображения
for( int y1=0; y1<dst->height; y1++ ) {
float* ptr_dst = (float*) (dst->imageData + y1 * dst->widthStep);
for( int x1=0; x1<dst->width; x1++ ) {
// пробегаемся по всем пикселям исходного изображения
for( int y0=0; y0<src->height; y0++ ) {
uchar* ptr_src = (uchar*) (src->imageData + y0 * src->widthStep);
for( int x0=0; x0<src->width; x0++ ) {
// расстояние от точки (x0;y0) до точки (x1;y1) считаем что везде z=1, плоская голограмма
float D = sqrt( 1.0f + (x0*resize-x1)*(x0*resize-x1) + (y0*resize-y1)*(y0*resize-y1) );
// Фаза волны достигшей этой точки
float Phase = D/W;
// суммируем свет от очередной точки
// (в соответствии с фазой световой волны пришедшей от этой точки)
//на выходе имеем - интенсивность света в точке (x1;y1)
float val = ptr_src[x0]*cos(Phase);
// 3 канала
ptr_dst[3*x1] += val; // B - синий
ptr_dst[3*x1+1] += val; // G - зелёный
ptr_dst[3*x1+2] += val; // R - красный
}
}
ptr_dst[3*x1] = pow(ptr_dst[3*x1], 2);
ptr_dst[3*x1+1] = pow(ptr_dst[3*x1+1], 2);
ptr_dst[3*x1+2] = pow(ptr_dst[3*x1+2], 2);
}
}
printf("[i] Done.\n");
// находим максимальное значение
float maxR = 0, maxG=0, maxB=0;
for( int y1=0; y1<dst->height; y1++ ) {
float* ptr_dst = (float*) (dst->imageData + y1 * dst->widthStep);
for( int x1=0; x1<dst->width; x1++ ) {
if(ptr_dst[3*x1]>maxB){
maxB = ptr_dst[3*x1];
}
if(ptr_dst[3*x1+1]>maxG){
maxG = ptr_dst[3*x1+1];
}
if(ptr_dst[3*x1+2]>maxR){
maxR = ptr_dst[3*x1+2];
}
}
}
printf("[i] max: %f %f %f \n", maxR, maxG, maxB);
IplImage* temp = cvCreateImage(cvSize(src->width*resize, src->height*resize), IPL_DEPTH_8U, 3);
// пробегаемся по всем пикселям изображения
for( int y1=0; y1<dst->height; y1++ ) {
float* ptr_dst = (float*) (dst->imageData + y1 * dst->widthStep);
uchar* ptr_temp = (uchar*) (temp->imageData + y1 * temp->widthStep);
for( int x1=0; x1<dst->width; x1++ ) {
ptr_temp[3*x1] = ptr_dst[3*x1]*255/maxB;
ptr_temp[3*x1+1] = ptr_dst[3*x1+1]*255/maxG;
ptr_temp[3*x1+2] = ptr_dst[3*x1+2]*255/maxR;
}
}
cvReleaseImage(&dst);
return temp;
}
Голограммы можно использовать не только для хранения информации (кстати, есть мнение, что мозг запоминает информацию не напрямую, а Фурье-образами, т.е. голограммами), но и для эффективного распознавания. Это должно быть очень хорошо описано в книге «Распознавание образов с помощью оптической пространственной фильтрации». Автор Ритц или как-то вроде этого. Точно не помню. Когда делал курсовую, не смог найти эту книгу ни в бумажном, ни в электронном виде.
Комментарии (1)
RSS свернуть / развернутьProgrammerForever
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.