mirror of
https://github.com/eddyem/fitsview-hartmann.git
synced 2025-12-06 10:45:21 +03:00
ported to git
This commit is contained in:
parent
0fb1222d34
commit
35a1e70547
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.hg*
|
||||
*~
|
||||
*.bak
|
||||
24
CMakeLists.txt
Normal file
24
CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
set(PROJ fitsview)
|
||||
project(${PROJ})
|
||||
set(CMAKE_COLOR_MAKEFILE ON)
|
||||
set(DEBUG 1) # ÚÁËÏÍÍÅÎÔÉÒÏ×ÁÔØ ÜÔÕ ÓÔÒÏËÕ ÐÏ ÏËÏÎÞÁÎÉÉ "ÒÁÚÒÁÂÏÔËÉ"
|
||||
if(NOT DEFINED NO_CUDA)
|
||||
message("Try to use CUDA")
|
||||
find_package(CUDA)
|
||||
if(CUDA_FOUND)
|
||||
add_definitions(-DCUDA_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT DEFINED PROCESSOR_COUNT)
|
||||
set(PROCESSOR_COUNT 2) # by default 2 cores
|
||||
set(cpuinfo_file "/proc/cpuinfo")
|
||||
if(EXISTS "${cpuinfo_file}")
|
||||
file(STRINGS "${cpuinfo_file}" procs REGEX "^processor.: [0-9]+$")
|
||||
list(LENGTH procs PROCESSOR_COUNT)
|
||||
endif()
|
||||
endif()
|
||||
add_definitions(-DTHREAD_NUMBER=${PROCESSOR_COUNT})
|
||||
message("In multithreaded operations will use ${PROCESSOR_COUNT} threads")
|
||||
subdirs(src)
|
||||
|
||||
99
ChangeLog
Normal file
99
ChangeLog
Normal file
@ -0,0 +1,99 @@
|
||||
01.12.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* Изменена функция определения изолиний. Теперь медлненно, но надежно. Планирую ускорить
|
||||
- обнаружены ошибки при открывании файла сразу в 3D
|
||||
- неверно отображаются изолинии на 3D при выборе части изображения
|
||||
|
||||
|
||||
06.09.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* добавлен поиск изолиний (с различными типами шкалы высот)
|
||||
- АЛГОРИТМ ЖУТКО ГЛЮЧИТ
|
||||
- сегфолт на экспоненциальной шкале высот
|
||||
- почему-то некоторые контуры получаются разорванными, контуры выходят за пределы рисунка
|
||||
|
||||
|
||||
29.08.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* добавлен медианный фильтр
|
||||
|
||||
|
||||
22.08.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* убран сегфолт при попытке открыть битую симв. ссылку
|
||||
* начал добавлять фильтры
|
||||
|
||||
|
||||
14.08.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* перешел на mercurial
|
||||
|
||||
|
||||
18.07.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
- исправить глюки с гистограммами и Хафом
|
||||
- переписать функции рассчета вершин и нормалей на CUDA
|
||||
- сделать нормальные пределы на гистограмме (а не [0, 1])
|
||||
- скорректировать линейки на графическом окне
|
||||
|
||||
|
||||
30.05.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* исправлена ошибка с чтением шапок фитс-файлов
|
||||
* разделены операции обнаружения пятен и распознавания гартманограммы
|
||||
* автоматическое распознавание пред- и зафокальных гартманограмм
|
||||
* сохранение списка координат обнаруженных пятен
|
||||
|
||||
|
||||
10.04.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
-+частично реализовано сохранение FITSов (и шапок)
|
||||
-+частично реализовано вращение 3D мышью
|
||||
|
||||
|
||||
04.04.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* пункт меню "открыть" в окне 3D (без навигации pgUp/pgDwn)
|
||||
* прокрутка в редактировании/просмотре шапки фитсов
|
||||
* пункты меню "открыть в новом окне" и "открыть в 3D"
|
||||
|
||||
|
||||
31.03.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
* навигация по файлам в текущей директории
|
||||
|
||||
|
||||
31.03.2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
|
||||
Пре-альфа версия, на ближайшее время реализовать:
|
||||
- отображение имени файла в строке состояния (а то непонятно, что за файл открыт)
|
||||
- глюк: "увеличение рамкой" не отменяется
|
||||
- исправить глюки при открывании нового файла (остаются старые режимы, spots и т.п.)
|
||||
- предлагать на выбор методы определения центров тяжести (аппр. гауссом, параболой по логарифму, "тупой", параболой по макушке, "тупой" с порогами/весами, аппр. параболоидом...)
|
||||
- отображать отмеченные треки, границы на гистограмме и т.п.
|
||||
- редактировать границы треков
|
||||
- разбор аргументов командной строки
|
||||
- batch-режим
|
||||
- вращение 3D мышью
|
||||
- сохранение FITSов (и шапок) преобразованного изображения
|
||||
- интерактивный Хаф
|
||||
- распознавание окружностей
|
||||
- расчет поверхности зеркала по гартманограммам (случай 1 и пары снимков)
|
||||
- фильтрация изображений (свертки/Фурье, вейвлеты)
|
||||
- корреляционный анализ
|
||||
- визуальное сравнение двух изображений (верхнее - полупрозрачное)
|
||||
- добавить в 3D NURBS'ы
|
||||
- "лупа", копипаст, редактирование (с сохранением)
|
||||
- полная статистика
|
||||
- вычисление экв. ширины линии на срезе
|
||||
- отождествление кривых (например, сп. порядков или теллур. линий) и "выпрямление" изображения
|
||||
- арифметические операции над изображениями
|
||||
- отображение комплексных изображений (варианты: амплитуда, фаза, Re, Im) и комплексные операции (Фурье, арифм., Фурье-фильтры, градиентные фильтры и т.п.)
|
||||
- глючит редактирование (где-то лишнее free, не снимается выделение с ячеек)
|
||||
- сохранение FITSов (и шапок)
|
||||
- вращение 3D мышью
|
||||
- исправить глюки с гистограммами и Хафом
|
||||
- переписать функции рассчета вершин и нормалей на CUDA
|
||||
- сделать нормальные пределы на гистограмме (а не [0, 1])
|
||||
- скорректировать линейки на графическом окне
|
||||
- при открывании нового изображения старое не удаляется из памяти - УТЕЧКА
|
||||
6
README
Normal file
6
README
Normal file
@ -0,0 +1,6 @@
|
||||
Ключи cmake:
|
||||
DEBUG=1 - отладочный режим
|
||||
NO_CUDA=1 - не использовать CUDA, даже если она поддерживается системой
|
||||
PROCESSOR_COUNT=X - в многопоточных задачах использовать X потоков
|
||||
NO_LEPTONICA=1 - не использовать лептонику, даже если она есть в системе
|
||||
NO_GSL=1 - не использовать GSL, даже если она есть в системе
|
||||
88
src/CMakeLists.txt
Normal file
88
src/CMakeLists.txt
Normal file
@ -0,0 +1,88 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
if(DEFINED DEBUG)
|
||||
add_definitions(-DEBUG)
|
||||
endif()
|
||||
set(SRC ${CMAKE_SOURCE_DIR}/src)
|
||||
aux_source_directory(${SRC} SOURCES)
|
||||
set(NOCUFILE ${SRC}/NOCUDA.c)
|
||||
set(CUFILE ${SRC}/CUDA.cu)
|
||||
set(CFLAGS -O3 -Wall -Werror -W -std=c99)
|
||||
set(LCPATH ${SRC}/locale/ru)
|
||||
set(PO_FILE ${LCPATH}/messages.po)
|
||||
set(MO_FILE ${LCPATH}/LC_MESSAGES/${PROJ}.mo)
|
||||
set(RU_FILE ${LCPATH}/ru.po)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GTK2 REQUIRED)
|
||||
pkg_check_modules(${PROJ} REQUIRED
|
||||
#glib-2.0>=2.10
|
||||
gtkglext-1.0>=0.7.0
|
||||
gtkglext-x11-1.0>=0.7.0
|
||||
#gtk+-2.0>=2.6.0
|
||||
cfitsio>=3.0
|
||||
fftw3>=3.2.0
|
||||
)
|
||||
include(FindOpenMP)
|
||||
if(OPENMP_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lfftw3_threads")
|
||||
if(NOT DEFINED NO_LEPTONICA)
|
||||
pkg_check_modules(LIBLEPT liblept)
|
||||
endif()
|
||||
if(NOT DEFINED NO_GSL)
|
||||
pkg_check_modules(GSL gsl)
|
||||
endif()
|
||||
if(NOT DEFINED GSL_VERSION)
|
||||
message("GSL not found, some mathematics functions wouldn't be avialable")
|
||||
else()
|
||||
add_definitions(-DGSL_FOUND)
|
||||
endif()
|
||||
if(NOT DEFINED LIBLEPT_VERSION)
|
||||
message("Leptonica library not found, some functions wouldn't be avialable")
|
||||
else()
|
||||
add_definitions(-DLEPTONICA_FOUND)
|
||||
endif()
|
||||
if(CUDA_FOUND)
|
||||
list(REMOVE_ITEM SOURCES ${NOCUFILE})
|
||||
list(APPEND CUDA_NVCC_FLAGS --use_fast_math)
|
||||
cuda_include_directories(include)
|
||||
cuda_add_executable(${PROJ} ${SOURCES} ${CUFILE} ${PO_FILE} ${MO_FILE} ui.h)
|
||||
target_link_libraries( ${PROJ} ${${PROJ}_LIBRARIES}
|
||||
${GSL_LIBRARIES} ${LIBLEPT_LIBRARIES}
|
||||
${CUDA_CUFFT_LIBRARIES} -lcuda)
|
||||
else(CUDA_FOUND)
|
||||
find_package(Threads)
|
||||
add_executable(${PROJ} ${SOURCES} ${PO_FILE} ${MO_FILE} ui.h)
|
||||
target_link_libraries( ${PROJ} ${${PROJ}_LIBRARIES}
|
||||
${GSL_LIBRARIES} ${LIBLEPT_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
endif(CUDA_FOUND)
|
||||
include_directories(${SRC}/include ${${PROJ}_INCLUDE_DIRS} ${GSL_INCLUDE_DIRS} ${LIBLEPT_INCLUDE_DIRS})
|
||||
link_directories(${${PROJ}_LIBRARY_DIRS} ${GSL_LIBRARY_DIRS} ${LIBLEPT_LIBRARY_DIRS})
|
||||
add_definitions(-DPACKAGE_VERSION=\"0.0.1\" -DGETTEXT_PACKAGE=\"${PROJ}\"
|
||||
-DLOCALEDIR=\"~/.local/share/locale\" ${CFLAGS})
|
||||
|
||||
#if(DEFINED DEBUG)
|
||||
find_package(Gettext REQUIRED)
|
||||
find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
|
||||
if(NOT GETTEXT_XGETTEXT_EXECUTABLE )
|
||||
message(FATAL_ERROR "xgettext not found")
|
||||
endif(NOT GETTEXT_XGETTEXT_EXECUTABLE )
|
||||
add_custom_command(
|
||||
OUTPUT ${PO_FILE}
|
||||
COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} --from-code=koi8-r ${SOURCES} ${SRC}/${PROJ}.glade -k_ -kN_ -o ${PO_FILE}
|
||||
DEPENDS ${SOURCES})
|
||||
add_custom_command(
|
||||
OUTPUT ${MO_FILE}
|
||||
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ${RU_FILE} -o ${MO_FILE}
|
||||
DEPENDS ${RU_FILE})
|
||||
add_custom_command(
|
||||
OUTPUT ui.h
|
||||
COMMAND gtk-builder-convert ${SRC}/${PROJ}.glade ${PROJ}.ui
|
||||
COMMAND ${SRC}/scripts/genh ${PROJ}.ui
|
||||
DEPENDS ${PROJ}.glade)
|
||||
#endif(DEFINED DEBUG)
|
||||
693
src/CUDA.cu
Normal file
693
src/CUDA.cu
Normal file
@ -0,0 +1,693 @@
|
||||
/*
|
||||
* CUDA.cu - subroutines for GPU
|
||||
*
|
||||
* Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
#define _CUDA_CU_
|
||||
#include "include/CUtools.h"
|
||||
|
||||
#include <cuda.h>
|
||||
#include <cufft.h>
|
||||
//#include <cuda_runtime_api.h>
|
||||
//#include <crt/device_runtime.h>
|
||||
//#include <device_functions.h>
|
||||
|
||||
const int SHMEMSZ = 16383; // default constants, changed runtime
|
||||
const int QBLKSZ = 16; // QBLKSZ = sqrt(LBLKSZ)
|
||||
const int LBLKSZ = 512;
|
||||
|
||||
// static arrays for sines & cosines values
|
||||
static float *Sin_d = NULL, *Cos_d = NULL;
|
||||
// array size
|
||||
static int sincosize = 0;
|
||||
|
||||
cudaError_t CUerr;
|
||||
inline int CUERROR(char *str){
|
||||
if(CUerr != cudaSuccess){
|
||||
fprintf(stderr, "%s, %s\n", str, cudaGetErrorString(CUerr));
|
||||
return 1;
|
||||
}else return 0;
|
||||
}
|
||||
// error macro (by default - nothing)
|
||||
#define RETMACRO return
|
||||
// memory macros
|
||||
#define CUALLOC(var, size) do{ \
|
||||
CUerr = cudaMalloc((void**)&var, size); \
|
||||
if(CUERROR("CUDA: can't allocate memory")){ \
|
||||
RETMACRO; \
|
||||
}}while(0)
|
||||
#define CUMOV2DEV(dest, src, size) do{ \
|
||||
CUerr = cudaMemcpy(dest, src, size, \
|
||||
cudaMemcpyHostToDevice); \
|
||||
if(CUERROR("CUDA: can't copy data to device")){\
|
||||
RETMACRO;} \
|
||||
}while(0)
|
||||
#define CUMOV2HOST(dest, src, size) do{ \
|
||||
CUerr = cudaMemcpy(dest, src, size, \
|
||||
cudaMemcpyDeviceToHost); \
|
||||
if(CUERROR("CUDA: can't copy data to host")){\
|
||||
RETMACRO;} \
|
||||
}while(0)
|
||||
#define CUFREE(var) do{cudaFree(var); var = NULL; }while(0)
|
||||
#define CUFFTCALL(fn) do{ \
|
||||
cufftResult fres = fn; \
|
||||
if(CUFFT_SUCCESS != fres){ \
|
||||
fprintf(stderr, "CUDA fft error %d\n", fres);\
|
||||
RETMACRO;} \
|
||||
}while(0)
|
||||
|
||||
#ifdef EBUG
|
||||
#define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__)
|
||||
#define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n");} while(0)
|
||||
#else
|
||||
#define FNAME() do{}while(0)
|
||||
#define DBG(...) do{}while(0)
|
||||
#endif //EBUG
|
||||
|
||||
// getting the videocard parameters
|
||||
extern "C" void getprops(){
|
||||
cudaDeviceProp dP;
|
||||
CUdevice dev; CUcontext ctx;
|
||||
cudaGetDeviceProperties(&dP, 0);
|
||||
cuDeviceGet(&dev,0);
|
||||
cuCtxCreate(&ctx, 0, dev);
|
||||
printf("\nDevice: %s, totalMem=%zd, memPerBlk=%zd,\n", dP.name, dP.totalGlobalMem, dP.sharedMemPerBlock);
|
||||
printf("warpSZ=%d, TPB=%d, TBDim=%dx%dx%d\n", dP.warpSize, dP.maxThreadsPerBlock,
|
||||
dP.maxThreadsDim[0],dP.maxThreadsDim[1],dP.maxThreadsDim[2]);
|
||||
printf("GridSz=%dx%dx%d, MemovrLap=%d, GPUs=%d\n", dP.maxGridSize[0],
|
||||
dP.maxGridSize[1],dP.maxGridSize[2],
|
||||
dP.deviceOverlap, dP.multiProcessorCount);
|
||||
printf("canMAPhostMEM=%d\n", dP.canMapHostMemory);
|
||||
printf("compute capability %d.%d.\n\n", dP.major, dP.minor);
|
||||
if(dP.major > 1){
|
||||
// SHMEMSZ = 49151; QBLKSZ = 32; LBLKSZ = 1024;
|
||||
}
|
||||
size_t theFree, theTotal;
|
||||
CUresult aaa = cuMemGetInfo( &theFree, &theTotal );
|
||||
printf("CARD returns(err=%d): free mem:%zd, total mem:%zd\n", aaa, theFree, theTotal);
|
||||
cuCtxDetach(ctx);
|
||||
}
|
||||
|
||||
// normalisation of array arr with size arrsize
|
||||
__global__ void normalize_vec(float *arr, int arrsize){
|
||||
__shared__ float max[LBLKSZ];
|
||||
int idx = threadIdx.x;
|
||||
int blksize = (arrsize + blockDim.x - 1) / blockDim.x;
|
||||
int b_beg = idx * blksize;
|
||||
if(b_beg >= arrsize) return;
|
||||
int b_end = b_beg + blksize;
|
||||
if(b_end > arrsize) b_end = arrsize;
|
||||
int i; float *ptr = &arr[b_beg];
|
||||
float mm = *ptr++;
|
||||
for(i = b_beg +1 ; i < b_end; i++, ptr++)
|
||||
if(mm < *ptr) mm = *ptr;
|
||||
max[idx] = mm;
|
||||
__syncthreads();
|
||||
if(idx == 0){
|
||||
mm = max[0];
|
||||
for(i = 1; i < LBLKSZ; i++)
|
||||
if(mm < max[i]) mm = max[i];
|
||||
max[0] = mm;
|
||||
}
|
||||
__syncthreads();
|
||||
ptr = &arr[b_beg];
|
||||
mm = max[0];
|
||||
if(mm != 0.f)
|
||||
for(i = b_beg ; i < b_end; i++, ptr++) *ptr /= mm;
|
||||
}
|
||||
/*
|
||||
__global__ void fill_zeros(float *arr, int arrsize, int W, int H){
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if(x > W || y > H) return;
|
||||
arr[x + y*W] = 0.f;
|
||||
}*/
|
||||
|
||||
// kernel of function for sin/cos array initialisation
|
||||
__global__ void fill_sincos(int angles,
|
||||
float *Sin_d, float *Cos_d,
|
||||
float anglestep, float conv){
|
||||
int k = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if(k >= angles) return;
|
||||
float theta = ((float)k / anglestep - 90.f) * conv;
|
||||
sincosf(theta, &Sin_d[k], &Cos_d[k]);
|
||||
}
|
||||
|
||||
// initialisation of sin/cos arrays
|
||||
extern "C" int init_sincos(int angles){
|
||||
#undef RETMACRO
|
||||
#define RETMACRO return 0
|
||||
// the value reciprocal for angle step
|
||||
float anglestep = (float)angles / 270.f;
|
||||
float conv = M_PI / 180.f;
|
||||
int blks = (angles + QBLKSZ - 1) / QBLKSZ;
|
||||
int threads = LBLKSZ;
|
||||
// first time we initialize arrays
|
||||
if(!Sin_d || !Cos_d || angles != sincosize){
|
||||
CUFREE(Cos_d);
|
||||
CUFREE(Sin_d);
|
||||
CUALLOC(Sin_d, angles*sizeof(float));
|
||||
CUALLOC(Cos_d, angles*sizeof(float));
|
||||
fill_sincos<<<blks, threads>>>(angles, Sin_d, Cos_d, anglestep, conv);
|
||||
sincosize = angles;
|
||||
}
|
||||
cudaThreadSynchronize();
|
||||
return 1;
|
||||
#undef RETMACRO
|
||||
#define RETMACRO return
|
||||
}
|
||||
|
||||
/*
|
||||
* Lines Hough transform kernel
|
||||
* ima_d - device array with the image
|
||||
* imW, imH, min, max - width, height of the image and extreme values of its histogram
|
||||
* Sin_d, Cos_d - device array with sines and cosines of angles (-90..180degr increments 270/angles)
|
||||
* Rmax - the maximum range for the desired lines
|
||||
* angles - the number of angles in the range -90 .. 180
|
||||
* treshold - lower threshold of intensity (in relative units: I=tres*(max-min)+min) for inclusion of point into array
|
||||
* hough_d - output array with Hough transform
|
||||
*/
|
||||
__global__ void fill_lin_hough_array(float *ima_d,
|
||||
int imW, int imH,
|
||||
float min, float max,
|
||||
float *Sin_d, float *Cos_d,
|
||||
int Rmax, int angles, float treshold,
|
||||
float *hough_d){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
int i = xi + imW * yi;
|
||||
float x = (float)xi;
|
||||
float y = (float)yi;
|
||||
int k, R;
|
||||
if(xi >= imW || yi >= imH) return;
|
||||
float wd = max-min; if(wd == 0.f) wd = 1.f;
|
||||
float ima = (ima_d[i]-min)/wd;
|
||||
if(ima > treshold){
|
||||
for(k = 0; k < angles; k++){
|
||||
// R = x*cos(theta) + y*sin(theta)
|
||||
R = (int)(0.5f + x * Cos_d[k] + y * Sin_d[k]);
|
||||
// THIS IS VERY BAD, BUT atomicAdd doesn't work in old devices
|
||||
if(R > 0 && R < Rmax) hough_d[R + Rmax*k] += ima;
|
||||
//if(R > 0 && R < Rmax) atomicAdd(&hough_d[R + Rmax*k], ima);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build Hough transform to find lines
|
||||
* Input:
|
||||
* ima - the image data
|
||||
* min, max - range of the data in it
|
||||
* imW, imH - image width and height
|
||||
* Rmax - the maximum value of R
|
||||
* Angles - the array size of angles (the angle of pitch is 180/angles degrees)
|
||||
* Output:
|
||||
* hough - array initialized by an external function,
|
||||
* in which the Hough transform will be
|
||||
* !!! array must be initialized with zeros before calling this function
|
||||
* Output array is normalized to unity
|
||||
*/
|
||||
extern "C" int fill_hough_lines(float *ima, float min, float max, int imW, int imH,
|
||||
int Rmax, int angles, float *hough){
|
||||
#undef RETMACRO
|
||||
#define RETMACRO do{ ret = 0; goto free_all; }while(0)
|
||||
int sz, ret = 1;
|
||||
int lblksz = LBLKSZ;
|
||||
float *ima_d = NULL, *hough_d = NULL;
|
||||
float treshold = 0.1f;
|
||||
sz = imW * imH;
|
||||
getprops();
|
||||
dim3 blkdim(QBLKSZ, QBLKSZ);
|
||||
dim3 griddim((imW+QBLKSZ-1)/QBLKSZ, (imH+QBLKSZ-1)/QBLKSZ);
|
||||
// dim3 hgriddim((Rmax+QBLKSZ-1)/QBLKSZ, (angles+QBLKSZ-1)/QBLKSZ);
|
||||
if(!init_sincos(angles)) RETMACRO;
|
||||
CUALLOC(ima_d, sz*sizeof(float));
|
||||
CUMOV2DEV(ima_d, ima, sz*sizeof(float));
|
||||
sz = Rmax * angles;
|
||||
CUALLOC(hough_d, sz*sizeof(float));
|
||||
cudaMemset(hough_d, 0, sz*sizeof(float));
|
||||
// fill_zeros<<<hgriddim, blkdim>>>(hough_d, sz, Rmax, angles);
|
||||
cudaThreadSynchronize();
|
||||
CUMOV2DEV(hough_d, hough, sz*sizeof(float));
|
||||
fill_lin_hough_array<<<griddim, blkdim>>>(ima_d, imW,imH, min,max, Sin_d,Cos_d,
|
||||
Rmax, angles, treshold, hough_d);
|
||||
cudaThreadSynchronize();
|
||||
normalize_vec<<<1, lblksz>>>(hough_d, sz);
|
||||
cudaThreadSynchronize();
|
||||
CUMOV2HOST(hough, hough_d, sz*sizeof(float));
|
||||
free_all:
|
||||
CUFREE(hough_d);
|
||||
CUFREE(ima_d);
|
||||
return ret;
|
||||
#undef RETMACRO
|
||||
#define RETMACRO return
|
||||
}
|
||||
|
||||
/*
|
||||
* Kernels of the threshold filtering
|
||||
* in, out - in and out
|
||||
* stepfn - a pointer to a function of conversion
|
||||
* sizex, sizey - image size
|
||||
* min - the minimum intensity
|
||||
* wd - range of the data
|
||||
* step - a step for stepfn
|
||||
*/
|
||||
// uniform intensity distribution
|
||||
__global__ void Funiform(float *in, int sizex, int sizey, float min, float step){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
int i = xi + yi*sizex;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
in[i] = floor((in[i]-min)/step);
|
||||
}
|
||||
// logarithm distribution
|
||||
__global__ void Flog(float *in, int sizex, int sizey, float min, float step){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
int i = xi + yi*sizex;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
in[i] = floor(logf(in[i]-min+1.f)/step);
|
||||
}
|
||||
// exponential distribution
|
||||
__global__ void Fexp(float *in, int sizex, int sizey, float min, float wd, float step){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
int i = xi + yi*sizex;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
in[i] = floor(expf((in[i]-min)/wd)/step);
|
||||
}
|
||||
// distribution of a square root
|
||||
__global__ void Fsqrt(float *in, int sizex, int sizey, float min, float step){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
int i = xi + yi*sizex;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
in[i] = floor(sqrtf(in[i]-min)/step);
|
||||
}
|
||||
// distribution of a x^2
|
||||
__global__ void Fpow(float *in, int sizex, int sizey, float min, float step){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
int i = xi + yi*sizex;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
in[i] = floor((in[i]-min)*(in[i]-min)/step);
|
||||
}
|
||||
|
||||
// functions for calculation of output scale
|
||||
float Suniform(float in, float min, float wd, float step){
|
||||
return step*in + min;
|
||||
}
|
||||
float Slog(float in, float min, float wd, float step){
|
||||
return expf(in*step) + min - 1.f;
|
||||
}
|
||||
float Sexp(float in, float min, float wd, float step){
|
||||
return wd*logf(in*step) + min;
|
||||
}
|
||||
float Ssqrt(float in, float min, float wd, float step){
|
||||
return in*in*step*step + min;
|
||||
}
|
||||
float Spow(float in, float min, float wd, float step){
|
||||
return sqrtf(in*step) + min;
|
||||
}
|
||||
|
||||
/*
|
||||
* Threshold filtering ("posterization")
|
||||
* Input:
|
||||
* ima - picture (free() must be executed in the caller)
|
||||
* f - filter:
|
||||
* f-> w - number of levels of posterization, [2.255]
|
||||
* f-> h - type of posterization (0 - uniform)
|
||||
* sizex, sizey - image size
|
||||
* min, max - minimum and maximum intensity of the image
|
||||
* Output:
|
||||
* result - filtered image, the memory is allocated in this procedure
|
||||
* scale - the scale of intensities, the memory is allocated here (if the scale!=NULL)
|
||||
*
|
||||
* TODO: save the result in the char, not float; learn display function
|
||||
*/
|
||||
extern "C" int StepFilter(float *ima, float **result,
|
||||
Filter *f, int sizex, int sizey,
|
||||
float min, float max, float **scale){
|
||||
#undef RETMACRO
|
||||
#define RETMACRO do{ ret = 0; goto free_all; }while(0)
|
||||
int ret = 1;
|
||||
float wd = max - min;
|
||||
int y;
|
||||
float Nsteps = (float)f->w; // number of intervals
|
||||
float step;
|
||||
float *in=NULL; // image and result array
|
||||
int sz = sizex*sizey*sizeof(float);
|
||||
dim3 blkdim(QBLKSZ, QBLKSZ);
|
||||
dim3 griddim((sizex+QBLKSZ-1)/QBLKSZ, (sizey+QBLKSZ-1)/QBLKSZ);
|
||||
*result = (float*)malloc(sz);
|
||||
if(!result) RETMACRO;
|
||||
float (*scalefn)(float,float,float,float);
|
||||
if(f->w < 2 || f->w > 255) return 0;
|
||||
if(wd == 0.f) return 0;
|
||||
CUALLOC(in, sz);
|
||||
CUMOV2DEV(in, ima, sz);
|
||||
switch(f->h){ // filter type
|
||||
case LOG: // logarithm
|
||||
scalefn = Slog;
|
||||
step = logf(max-min+1.f)/Nsteps;
|
||||
Flog<<<griddim, blkdim>>>(in, sizex, sizey, min, step);
|
||||
break;
|
||||
case EXP: // exponential
|
||||
scalefn = Sexp;
|
||||
step = expf(1.f)/Nsteps;
|
||||
Fexp<<<griddim, blkdim>>>(in, sizex, sizey, min, wd, step);
|
||||
break;
|
||||
case SQRT: // square root
|
||||
scalefn = Ssqrt;
|
||||
step = sqrtf(wd)/Nsteps;
|
||||
Fsqrt<<<griddim, blkdim>>>(in, sizex, sizey, min, step);
|
||||
break;
|
||||
case POW: // power of two
|
||||
scalefn = Spow;
|
||||
step = wd*wd/Nsteps;
|
||||
Fpow<<<griddim, blkdim>>>(in, sizex, sizey, min, step);
|
||||
break;
|
||||
default: // uniform
|
||||
scalefn = Suniform;
|
||||
step = wd/Nsteps;
|
||||
Funiform<<<griddim, blkdim>>>(in, sizex, sizey, min, step);
|
||||
}
|
||||
cudaThreadSynchronize();
|
||||
CUMOV2HOST(*result, in, sz);
|
||||
if(scale){
|
||||
int M = f->w;
|
||||
*scale = (float*)calloc(M, sizeof(float));
|
||||
if(*scale) for(y = 0; y < M; y++){
|
||||
(*scale)[y] = scalefn(y+1,min,wd,step);
|
||||
}
|
||||
}
|
||||
free_all:
|
||||
CUFREE(in);
|
||||
return ret;
|
||||
#undef RETMACRO
|
||||
#define RETMACRO return
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A set of functions for constructing differential filters
|
||||
*/
|
||||
int p2oi(int i){
|
||||
unsigned int v = (unsigned int)i - 1;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return (int) v;
|
||||
}
|
||||
int nextpow2(int i, int j){
|
||||
int p1 = p2oi(i), p2 = p2oi(j);
|
||||
return (p1 > p2)? p1 : p2;
|
||||
}
|
||||
// multiplication of two complex matrices with size x size
|
||||
// result in the entry of the first matrix
|
||||
__global__ void ComplexMul(cufftComplex *inout, cufftComplex *in, int size){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if(xi >= size || yi >= size) return;
|
||||
int i = xi + yi*size;
|
||||
cufftComplex a = inout[i], b = in[i];
|
||||
inout[i].x = a.x * b.x - a.y * b.y;
|
||||
inout[i].y = a.x * b.y + a.y * b.x;
|
||||
}
|
||||
|
||||
// restore coordinates of the Fourier transform
|
||||
__global__ void fftshift(int size, float *m){
|
||||
int h = size/2;
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if(xi >= h || yi >= h) return;
|
||||
// k - point in left upper quadrant, k1 - in right upper
|
||||
int k = yi * size+xi, k1 = k + h;
|
||||
// p - point in right lower quadrant, p1 - in left lower
|
||||
int p = k + (size+1)*h, p1 = k1 + (size-1)*h;
|
||||
float tmp;
|
||||
tmp = m[k]; m[k] = m[p]; m[p] = tmp;
|
||||
tmp = m[k1]; m[k1] = m[p1]; m[p1] = tmp;
|
||||
}
|
||||
// data copying float->cufftReal (need because different sizes of picture and Fourier image)
|
||||
__global__ void f2r(cufftReal *out, float *in, int sizex, int sizey, int size2){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
out[xi+yi*size2] = (cufftReal) in[xi+yi*sizex];
|
||||
}
|
||||
// data copying cufftReal->float
|
||||
__global__ void r2f(float *out, cufftReal *in, int sizex, int sizey, int size2){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if(xi >= sizex || yi >= sizey) return;
|
||||
out[xi+yi*sizex] = (float) in[xi+yi*size2];
|
||||
}
|
||||
|
||||
/*
|
||||
* The kernel of the Laplacian of Gaussian
|
||||
* Output:
|
||||
* mask - the filled array
|
||||
* Input:
|
||||
* size - array size (size x size)
|
||||
* x0, x1 - array bounds on x: [x0, x1) (outside this array filled by zeros)
|
||||
* y0, y1 - -//- on y
|
||||
* half - half the size of the array
|
||||
* ss - normalizing factor
|
||||
* sx2, sy2 - the variance of the filter in x and y
|
||||
*/
|
||||
__global__ void LGf_kernel(cufftReal *mask, int size, int x0, int x1,
|
||||
int y0, int y1, float half, float ss,
|
||||
float sx2, float sy2){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x + x0;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y + y0;
|
||||
if(xi >= x1 || yi >= y1) return;
|
||||
int i = xi + yi*size;
|
||||
float x2 = (float)xi + half;
|
||||
float y2 = (float)yi + half;
|
||||
x2 = x2*x2 / sx2; y2 = y2*y2 / sy2;
|
||||
mask[i] = (cufftReal)(ss * ((x2-1.f)/sx2+(y2-1.f)/sy2)*expf(-(x2+y2)/2.f));
|
||||
}
|
||||
// The kernel of Gaussian filter
|
||||
__global__ void Gf_kernel(cufftReal *mask, int size, int x0, int x1,
|
||||
int y0, int y1, float half, float ss,
|
||||
float sx2, float sy2){
|
||||
int xi = blockIdx.x * blockDim.x + threadIdx.x + x0;
|
||||
int yi = blockIdx.y * blockDim.y + threadIdx.y + y0;
|
||||
if(xi >= x1 || yi >= y1) return;
|
||||
int i = xi + yi*size;
|
||||
float x2 = (float)xi + half;
|
||||
float y2 = (float)yi + half;
|
||||
x2 = x2*x2 / sx2; y2 = y2*y2 / sy2;
|
||||
mask[i] = (cufftReal)(ss * expf(-(x2+y2)/2.f));
|
||||
}
|
||||
/*
|
||||
* Building mask of Gaussian or Laplasian of Gaussian
|
||||
* Output:
|
||||
* mask - filter array
|
||||
* Input:
|
||||
* size - mask size (size x size)
|
||||
* f - filter parameters
|
||||
*/
|
||||
void build_GLG_filter(cufftReal *mask, int size, Filter *f){
|
||||
int y0=0,y1=size, x0=0, x1=size;
|
||||
float sx2 = f->sx * f->sx, sy2 = f->sy * f->sy;
|
||||
float half;
|
||||
dim3 blkdim(QBLKSZ, QBLKSZ);
|
||||
dim3 griddim((size+QBLKSZ-1)/QBLKSZ, (size+QBLKSZ-1)/QBLKSZ);
|
||||
if(f->w < size && f->w > 0){
|
||||
x0 = (size - f->w + 1) / 2;
|
||||
x1 = x0 + f->w;
|
||||
}
|
||||
if(f->h < size && f->h > 0){
|
||||
y0 = (size - f->h + 1) / 2;
|
||||
y1 = y0 + f->h;
|
||||
}
|
||||
half = -(float)size / 2.f;
|
||||
float ss = 3.f / half / half / sqrt(-half);
|
||||
switch(f->FilterType){
|
||||
case LAPGAUSS:
|
||||
LGf_kernel<<<griddim, blkdim>>>(mask, size, x0,x1, y0,y1, half, ss, sx2, sy2);
|
||||
break;
|
||||
case GAUSS:
|
||||
Gf_kernel<<<griddim, blkdim>>>(mask, size, x0,x1, y0,y1, half, ss, sx2, sy2);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: bad filter\n");
|
||||
}
|
||||
cudaThreadSynchronize();
|
||||
DBG("size=%d, x0=%d,x1=%d, y0=%d,y1=%d, half=%g, ss=%g, sx2=%g, sy2=%g",
|
||||
size, x0,x1, y0,y1, half, ss, sx2, sy2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Building of elementary filter mask
|
||||
* Output:
|
||||
* mask - filter array
|
||||
* Input:
|
||||
* size - mask size (size x size)
|
||||
* f - filter parameters
|
||||
*/
|
||||
void build_S_filter(cufftReal *mask, int size, Filter *f){
|
||||
int y, a0, a1;
|
||||
float hh, Y, pt = 0.f;
|
||||
a0 = (size - 2) / 2;
|
||||
a1 = a0 + 3;
|
||||
hh = -(float)(size / 2);
|
||||
float ss = 1.f / (M_PI*2.f) / hh / hh / sqrtf(-hh);
|
||||
Y = -1.f;
|
||||
for(y = a0; y < a1; y++, Y+=1.f){
|
||||
float X = -1.f;
|
||||
int str, x;
|
||||
str = y * size;
|
||||
for(x = a0; x < a1; x++, X+=1.f){
|
||||
switch(f->FilterType){
|
||||
case SOBELH:
|
||||
pt = -X*(2.f-fabs(Y));
|
||||
break;
|
||||
case SOBELV:
|
||||
pt = -Y*(2.f-fabs(X));
|
||||
break;
|
||||
case PREWITTH:
|
||||
pt = X;
|
||||
break;
|
||||
case PREWITTV:
|
||||
pt = Y;
|
||||
break;
|
||||
}
|
||||
cufftReal tmppar = (cufftReal)ss*pt;
|
||||
cudaMemcpy(&mask[str + x], &tmppar, sizeof(cufftReal), cudaMemcpyHostToDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Convolution filtering (convolution by FFT)
|
||||
* Input:
|
||||
* ima - picture, that need to be filtering
|
||||
* f - filter parameters
|
||||
* Output:
|
||||
* result - memory area, allocated by this function,
|
||||
* where the filtered picture to be store
|
||||
* return: TRUE if the filtering succeed
|
||||
*/
|
||||
extern "C" int DiffFilter(float *ima, float **result,
|
||||
Filter *f, int sizex, int sizey){
|
||||
#undef RETMACRO
|
||||
#define RETMACRO do{ ret = 0; goto free_all; }while(0)
|
||||
int ssize, ret = 0, size2;
|
||||
float *tmp;
|
||||
size2 = nextpow2(sizex, sizey);
|
||||
ssize = size2 * size2; // Fourier image size
|
||||
dim3 blkdim(QBLKSZ, QBLKSZ);
|
||||
dim3 griddim((size2+QBLKSZ-1)/QBLKSZ, (size2+QBLKSZ-1)/QBLKSZ);
|
||||
dim3 halfgriddim((size2/2+QBLKSZ-1)/QBLKSZ, (size2/2+QBLKSZ-1)/QBLKSZ);
|
||||
dim3 imgriddim((sizex+QBLKSZ-1)/QBLKSZ, (sizey+QBLKSZ-1)/QBLKSZ);
|
||||
if(!result || !*result || !ima || !f){
|
||||
fprintf(stderr, "DiffFilter: bad parameters\n");
|
||||
return 0;
|
||||
}
|
||||
cufftHandle plan;
|
||||
cufftComplex *Fmask=NULL, *Fimg=NULL;
|
||||
cufftReal *mask=NULL, *img=NULL, *resm=NULL;
|
||||
#ifdef EBUG
|
||||
getprops();
|
||||
#endif
|
||||
// Allocate memory for new objects
|
||||
DBG("allocate");
|
||||
CUALLOC(img, ssize*sizeof(cufftReal));
|
||||
// fill it zeros
|
||||
cudaMemset(img, 0, ssize*sizeof(cufftReal));
|
||||
// copy ima -> img
|
||||
DBG("copy image to dev");
|
||||
CUALLOC(tmp, sizex*sizey*sizeof(float));
|
||||
CUMOV2DEV(tmp, ima, sizex*sizey*sizeof(float));
|
||||
f2r<<<imgriddim, blkdim>>>(img, tmp, sizex, sizey, size2);
|
||||
cudaThreadSynchronize();
|
||||
CUFREE(tmp);
|
||||
CUALLOC(Fimg, ssize*sizeof(cufftComplex));
|
||||
// make FFT
|
||||
DBG("doing image FFT");
|
||||
CUFFTCALL(cufftPlan2d(&plan, size2, size2, CUFFT_R2C));
|
||||
CUFFTCALL(cufftExecR2C(plan, img, Fimg));
|
||||
CUFREE(img);
|
||||
DBG("allocate");
|
||||
CUALLOC(mask, ssize*sizeof(cufftReal));
|
||||
cudaMemset(mask, 0, ssize*sizeof(cufftReal));
|
||||
CUALLOC(Fmask, ssize*sizeof(cufftComplex));
|
||||
switch(f->FilterType){
|
||||
case LAPGAUSS:
|
||||
case GAUSS:
|
||||
build_GLG_filter(mask, size2, f);
|
||||
break;
|
||||
case SOBELH:
|
||||
case SOBELV:
|
||||
case PREWITTH:
|
||||
case PREWITTV:
|
||||
build_S_filter(mask, size2, f);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: bad filter\n");
|
||||
RETMACRO;
|
||||
}
|
||||
// swap filter quadrants
|
||||
fftshift<<<halfgriddim, blkdim>>>(size2, mask);
|
||||
cudaThreadSynchronize();
|
||||
// make FFT
|
||||
DBG("doing filter FFT");
|
||||
CUFFTCALL(cufftExecR2C(plan, mask, Fmask));
|
||||
CUFFTCALL(cufftDestroy(plan));
|
||||
CUFREE(mask);
|
||||
// make convolution in Fourier space
|
||||
DBG("multiplication");
|
||||
ComplexMul<<<griddim, blkdim>>>(Fimg, Fmask, size2);
|
||||
cudaThreadSynchronize();
|
||||
CUFREE(Fmask);
|
||||
// Inverse FFT
|
||||
DBG("doing inverse FFT");
|
||||
CUALLOC(resm, ssize*sizeof(cufftReal));
|
||||
CUFFTCALL(cufftPlan2d(&plan, size2, size2, CUFFT_C2R));
|
||||
CUFFTCALL(cufftExecC2R(plan, Fimg, resm));
|
||||
CUFFTCALL(cufftDestroy(plan));
|
||||
CUFREE(Fimg);
|
||||
DBG("allocate");
|
||||
CUALLOC(tmp, ssize*sizeof(float));
|
||||
*result = (float*)calloc(sizex*sizey, sizeof(float));
|
||||
if(!*result) RETMACRO;
|
||||
// copy iFFT -> res
|
||||
DBG("copy to host");
|
||||
r2f<<<imgriddim, blkdim>>>(tmp, resm, sizex, sizey, size2);
|
||||
cudaThreadSynchronize();
|
||||
CUMOV2HOST(*result, tmp, sizex*sizey*sizeof(float));
|
||||
ret = 1;
|
||||
free_all:
|
||||
CUFREE(Fmask); CUFREE(Fimg); CUFREE(img);
|
||||
CUFREE(mask); CUFREE(resm); CUFREE(tmp);
|
||||
#ifdef EBUG
|
||||
getprops();
|
||||
#endif
|
||||
return ret;
|
||||
#undef RETMACRO
|
||||
#define RETMACRO return
|
||||
}
|
||||
extern "C" int MedFilter(float *ima, float **result, Filter *f, int sizex, int sizey){return 0;}
|
||||
extern "C" int GradFilterSimple(float *ima, float **result, Filter *f, int sizex, int sizey){return 0;}
|
||||
816
src/NOCUDA.c
Normal file
816
src/NOCUDA.c
Normal file
@ -0,0 +1,816 @@
|
||||
// NOCUDA.c - CPU-variants when there's no CUDA
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
#include "CUtools.h"
|
||||
#include <pthread.h>
|
||||
#include <fftw3.h>
|
||||
|
||||
static float *Sin_d = NULL, *Cos_d = NULL;
|
||||
static int sincosize = 0;
|
||||
|
||||
#ifndef THREAD_NUMBER
|
||||
#define THREAD_NUMBER 2 // default - 2 threads
|
||||
#endif
|
||||
|
||||
typedef struct{
|
||||
float *image;
|
||||
float min;
|
||||
float max;
|
||||
float *hough;
|
||||
int w;
|
||||
int Y0;
|
||||
int Y1;
|
||||
int Rmax;
|
||||
int angles;
|
||||
pthread_mutex_t *mutex;
|
||||
}Hough_kernel_args;
|
||||
|
||||
// sin/cos ini, [-90,+180)
|
||||
void init_sincos(int angles){
|
||||
float anglestep = (float)angles / 270.; // step by an angle
|
||||
float conv = M_PI / 180.;
|
||||
float *cp, *sp;
|
||||
int k;
|
||||
if(!Sin_d || !Cos_d || angles != sincosize){ // first time initialize arrays
|
||||
free(Sin_d);
|
||||
free(Cos_d);
|
||||
Sin_d = malloc(angles * sizeof(float));
|
||||
Cos_d = malloc(angles * sizeof(float));
|
||||
cp = Cos_d; sp = Sin_d;
|
||||
for(k = 0; k < angles; k++){ // fill arrays from -90 to +90 degr in radians
|
||||
float theta = ((float)k / anglestep - 90.) * conv;
|
||||
*sp++ = sinf(theta);
|
||||
*cp++ = cosf(theta);
|
||||
//sincosf(theta, sp++, cp++);
|
||||
}
|
||||
sincosize = angles;
|
||||
}
|
||||
}
|
||||
|
||||
// Line Hough transform kernel
|
||||
void *fill_lin_hough_array(void *data){
|
||||
Hough_kernel_args *HD = (Hough_kernel_args*) data;
|
||||
float *ima = HD->image, *hough = HD->hough;
|
||||
float min = HD->min, wd = HD->max - min;
|
||||
pthread_mutex_t *mutex = HD->mutex;
|
||||
int Y0 = HD->Y0, Y1 = HD->Y1, imW = HD->w, Rmax = HD->Rmax, angles = HD->angles;
|
||||
int i, j, k, Y, R;
|
||||
for(j = Y0; j < Y1; j++){
|
||||
for(i = 0.; i < imW; i++, ima++){
|
||||
float imdata = (*ima - min) / wd;
|
||||
if(imdata > 0.1){
|
||||
Y = 0;
|
||||
pthread_mutex_lock(mutex);
|
||||
for(k = 0; k < angles; k++, Y+=Rmax){
|
||||
// R = x*cos(theta) + y*sin(theta)
|
||||
R = (int)(0.5 + i*Cos_d[k] + j*Sin_d[k]);
|
||||
if(R > 0 && R < Rmax) hough[R + Y] += imdata;
|
||||
}
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Build of a Hough transform to find lines
|
||||
* Input:
|
||||
* ima - the image data
|
||||
* min, max - range of the data in it
|
||||
* imW, imH - image width and height
|
||||
* Rmax - the maximum value of R
|
||||
* angles - the array size of angles (the angle step is 180/angles degrees)
|
||||
* Output:
|
||||
* hough - initialized by an external function array for Hough transform
|
||||
* !!! array must be initialized with zeros before calling this function !!!
|
||||
* Output array is normalized to unity
|
||||
*/
|
||||
int fill_hough_lines(float *ima, float min, float max, int imW, int imH, int Rmax, int angles, float *hough){
|
||||
int i, Y0, Y1, dY;
|
||||
float *hptr = hough, hmax;
|
||||
Hough_kernel_args HD[THREAD_NUMBER];
|
||||
pthread_t threads[THREAD_NUMBER];
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
init_sincos(angles);
|
||||
dY = (imH + THREAD_NUMBER/2) / THREAD_NUMBER;
|
||||
Y0 = 0; Y1 = dY;
|
||||
for(i = 0; i < THREAD_NUMBER; i++, Y0+=dY, Y1+=dY){
|
||||
if(Y0 >= imW) break;
|
||||
if(Y1 > imW) Y1 = imW;
|
||||
HD[i].min = min; HD[i].max = max;
|
||||
HD[i].image = ima; HD[i].hough = hough;
|
||||
HD[i].Y0 = Y0; HD[i].Y1 = Y1; HD[i].w = imW;
|
||||
HD[i].Rmax = Rmax; HD[i].angles = angles;
|
||||
HD[i].mutex = &mutex;
|
||||
pthread_create(&threads[i], NULL, fill_lin_hough_array, &HD[i]);
|
||||
}
|
||||
for(i = 0; i < THREAD_NUMBER; i++)
|
||||
pthread_join(threads[i], NULL);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
hmax = *hough++;
|
||||
Y1 = Rmax * angles;
|
||||
for(i = 1; i < Y1; i++, hough++)
|
||||
if(*hough > hmax) hmax = *hough;
|
||||
hough = hptr;
|
||||
for(i = 0; i < Y1; i++, hough++)
|
||||
*hough /= hmax;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// from http://graphics.stanford.edu/%7Eseander/bithacks.html#RoundUpPowerOf2
|
||||
int nextpow2(int i, int j){
|
||||
inline int p2oi(int i){
|
||||
unsigned int v = (unsigned int)i - 1;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return (int) v;
|
||||
}
|
||||
int p1 = p2oi(i), p2 = p2oi(j);
|
||||
return MAX(p1, p2);
|
||||
}
|
||||
|
||||
// FFT
|
||||
fftw_plan fftimg, fftmask, ifft;
|
||||
// FFT buffrers for image & filter
|
||||
fftw_complex *Fmask = NULL, // FFT of a filter
|
||||
*Fimg = NULL; // picture FFT
|
||||
static double *mask = NULL, // filter mask
|
||||
*img = NULL, // picture
|
||||
*resm = NULL;
|
||||
|
||||
void fftshift(int size, double *m){
|
||||
int h = size/2, ss, ss1, i, j, k, l, p;
|
||||
double tmp;
|
||||
ss = (2*h+1)*h;
|
||||
ss1 = (2*h-1)*h;
|
||||
for(j = 0; j < h; j++){
|
||||
k = j * size;
|
||||
l = k + h;
|
||||
for(i = 0; i < h; i++, k++, l++){
|
||||
p = k + ss;
|
||||
tmp = m[k]; m[k] = m[p]; m[p] = tmp;
|
||||
p = l + ss1;
|
||||
tmp = m[l]; m[l] = m[p]; m[p] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lapgauss mask building
|
||||
void build_LG_filter(int size, Filter *f){
|
||||
int y, y0=0,y1=size, x0=0, x1=size;
|
||||
double sx2 = f->sx * f->sx, sy2 = f->sy * f->sy;
|
||||
double hw, hh;
|
||||
#ifdef EBUG
|
||||
double t0=dtime();
|
||||
#endif
|
||||
if(f->w < size && f->w > 0){
|
||||
x0 = (size - f->w + 1) / 2;
|
||||
x1 = x0 + f->w;
|
||||
}
|
||||
if(f->h < size && f->h > 0){
|
||||
y0 = (size - f->h + 1) / 2;
|
||||
y1 = y0 + f->h;
|
||||
}
|
||||
hh = -(double)size / 2.;
|
||||
hw = -(double)size / 2.+(double)x0;
|
||||
DBG("y0=%d, y1=%d, hw=%g, hh=%g",y0,y1,hw,hh);
|
||||
double ss = 3. / hh / hh / sqrt(-hh);
|
||||
// double ss = 1./sqrt(2*M_PI*f->sx*f->sy);
|
||||
#pragma omp parallel for
|
||||
for(y = y0; y < y1; y++){
|
||||
double X, Y, y2, x2, R;
|
||||
int str, x;
|
||||
X = hw;
|
||||
str = y * size;
|
||||
Y = ((double)y) + hh;
|
||||
y2 = Y*Y/sy2;
|
||||
for(x = x0; x < x1; x++, X+=1.){
|
||||
x2 = X*X/sx2;
|
||||
R = x2 + y2;
|
||||
mask[str + x] =ss * ((x2-1.)/sx2+(y2-1.)/sy2)*exp(-R/2.);
|
||||
}
|
||||
}
|
||||
DBG("time=%f\n", dtime()-t0);
|
||||
}
|
||||
|
||||
// Gaussian mask building/
|
||||
void build_G_filter(int size, Filter *f){
|
||||
int y, y0=0,y1=size, x0=0, x1=size;
|
||||
double sx2 = f->sx * f->sx, sy2 = f->sy * f->sy;
|
||||
double hw, hh;
|
||||
#ifdef EBUG
|
||||
double t0=dtime();
|
||||
#endif
|
||||
if(f->w < size && f->w > 0){
|
||||
x0 = (size - f->w + 1) / 2;
|
||||
x1 = x0 + f->w;
|
||||
}
|
||||
if(f->h < size && f->h > 0){
|
||||
y0 = (size - f->h + 1) / 2;
|
||||
y1 = y0 + f->h;
|
||||
}
|
||||
hh = -(double)size / 2.;
|
||||
hw = -(double)size / 2.+(double)x0;
|
||||
DBG("y0=%d, y1=%d, hw=%g, hh=%g",y0,y1,hw,hh);
|
||||
double ss = 1. / (M_PI*2.) / sx2 / sy2 / hh / hh;
|
||||
#pragma omp parallel for
|
||||
for(y = y0; y < y1; y++){
|
||||
double X, Y, y2, x2, R;
|
||||
int str, x;
|
||||
X = hw;
|
||||
str = y * size;
|
||||
Y = ((double)y) + hh;
|
||||
y2 = Y*Y/sy2;
|
||||
for(x = x0; x < x1; x++, X+=1.){
|
||||
x2 = X*X/sx2;
|
||||
R = x2 + y2;
|
||||
mask[str + x] =ss * exp(-R/2.);
|
||||
}
|
||||
}
|
||||
DBG("time=%f\n", dtime()-t0);
|
||||
}
|
||||
|
||||
// Elementary filter mask building
|
||||
void build_S_filter(int size, Filter *f){
|
||||
int y, a0, a1;
|
||||
double hh, Y, pt = 0.;
|
||||
a0 = (size - 2) / 2;
|
||||
a1 = a0 + 3;
|
||||
hh = -(double)(size / 2);
|
||||
double ss = 1. / (M_PI*2.) / hh / hh / sqrt(-hh);
|
||||
Y = -1.;
|
||||
for(y = a0; y < a1; y++, Y+=1.){
|
||||
double X = -1.;
|
||||
int str, x;
|
||||
str = y * size;
|
||||
for(x = a0; x < a1; x++, X+=1.){
|
||||
switch(f->FilterType){
|
||||
case SOBELH:
|
||||
pt = -X*(2.-fabs(Y));
|
||||
break;
|
||||
case SOBELV:
|
||||
pt = -Y*(2.-fabs(X));
|
||||
break;
|
||||
case PREWITTH:
|
||||
pt = X;
|
||||
break;
|
||||
case PREWITTV:
|
||||
pt = Y;
|
||||
break;
|
||||
/* case :
|
||||
pt =
|
||||
break;
|
||||
case :
|
||||
pt =
|
||||
break;
|
||||
case :
|
||||
pt =
|
||||
break;
|
||||
case :
|
||||
pt =
|
||||
break;
|
||||
case :
|
||||
pt =
|
||||
break;*/
|
||||
}
|
||||
mask[str + x] = ss*pt;
|
||||
}
|
||||
}
|
||||
//mask[size*size/2]=0.;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filtering by convolution with a filter
|
||||
* Input:
|
||||
* ima - a pointer to picture data, which should be filtered
|
||||
* f - filter parameters
|
||||
* Output:
|
||||
* result - allocated by this function memory area where
|
||||
* the filtered image is placed
|
||||
* Returns TRUE, if the filter succeeded
|
||||
*/
|
||||
int DiffFilter(float *ima,
|
||||
float **result,
|
||||
Filter *f,
|
||||
int sizex,
|
||||
int sizey
|
||||
){
|
||||
int ssize, i, j, k, l;
|
||||
static int fftw_ini = 0;
|
||||
int size2;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
size2 = nextpow2(sizex, sizey);
|
||||
ssize = size2 * size2; // FFT image size
|
||||
if(!fftw_ini)
|
||||
if(!(fftw_ini = fftw_init_threads())){
|
||||
//g_err(_("FFTW error");
|
||||
return FALSE;
|
||||
}
|
||||
void free_all(){
|
||||
_FREE(mask); _FREE(Fmask); _FREE(img);
|
||||
_FREE(Fimg); _FREE(resm);
|
||||
}
|
||||
free_all();
|
||||
DBG("img (%d x %d) -> (%d x %d), time=%f\n", sizex,sizey, size2,size2, dtime()-t0);
|
||||
// allocate memory for objects
|
||||
img = (double*)calloc(ssize, sizeof(double));
|
||||
Fimg = (fftw_complex*)calloc(ssize, sizeof(fftw_complex));
|
||||
if(!img || !Fimg){free_all(); return FALSE;}
|
||||
// define direct FFT
|
||||
fftw_plan_with_nthreads(THREAD_NUMBER);
|
||||
fftimg = fftw_plan_dft_r2c_2d(size2, size2, img, Fimg, FFTW_ESTIMATE);
|
||||
// copy ima -> img
|
||||
for(j = 0; j < sizey; j++){
|
||||
k = j * size2;
|
||||
l = j * sizex;
|
||||
for(i = 0; i < sizex; i++, k++, l++)
|
||||
img[k] = ima[l];
|
||||
}
|
||||
fftw_execute(fftimg);
|
||||
_FREE(img);
|
||||
// build filter
|
||||
DBG("build filter, time=%f\n", dtime()-t0);
|
||||
mask = (double*)calloc(ssize, sizeof(double));
|
||||
Fmask = (fftw_complex*)calloc(ssize, sizeof(fftw_complex));
|
||||
if(!mask || !Fmask){free_all(); return FALSE;}
|
||||
switch(f->FilterType){
|
||||
case LAPGAUSS:
|
||||
build_LG_filter(size2, f);
|
||||
break;
|
||||
case GAUSS:
|
||||
build_G_filter(size2, f);
|
||||
break;
|
||||
case SOBELH:
|
||||
case SOBELV:
|
||||
case PREWITTH:
|
||||
case PREWITTV:
|
||||
build_S_filter(size2, f);
|
||||
break;
|
||||
}
|
||||
// define filter FFT
|
||||
fftw_plan_with_nthreads(THREAD_NUMBER);
|
||||
fftmask = fftw_plan_dft_r2c_2d(size2, size2, mask, Fmask, FFTW_ESTIMATE);
|
||||
fftw_execute(fftmask);
|
||||
_FREE(mask);
|
||||
// filtered picture:
|
||||
DBG("filter image, time=%f\n", dtime()-t0);
|
||||
resm = (double*)calloc(ssize, sizeof(double));
|
||||
if(!resm){free_all(); return FALSE;}
|
||||
// define inverse FFT
|
||||
fftw_plan_with_nthreads(THREAD_NUMBER);
|
||||
ifft = fftw_plan_dft_c2r_2d(size2, size2, Fimg, resm, FFTW_ESTIMATE);
|
||||
// DON'T PARALLEL THIS, it will be slower
|
||||
for(i=0; i<ssize; i++){ // convolution by multiplication in Fourier space
|
||||
/**/
|
||||
double a,b,c,d;
|
||||
a=Fimg[i][0]; c=Fmask[i][0];
|
||||
b=Fimg[i][1]; d=Fmask[i][1];
|
||||
Fimg[i][0] = a*c - b*d;
|
||||
Fimg[i][1] = b*c + a*d;
|
||||
/**
|
||||
Fimg[i][0] = Fmask[i][0];
|
||||
Fimg[i][1] = Fmask[i][1];
|
||||
**/
|
||||
}
|
||||
_FREE(Fmask);
|
||||
fftw_execute(ifft);
|
||||
_FREE(Fimg);
|
||||
fftshift(size2, resm);
|
||||
*result = calloc(ssize, sizeof(float));
|
||||
if(!*result){free_all(); return FALSE;}
|
||||
float *tmp = *result;
|
||||
// copy inv FFT -> result
|
||||
for(j = 0; j < sizey; j++){
|
||||
k = j * size2;
|
||||
l = j * sizex;
|
||||
for(i = 0; i < sizex; i++, k++, l++)
|
||||
tmp[l] = resm[k];
|
||||
}
|
||||
_FREE(resm);
|
||||
fftw_destroy_plan(fftimg);
|
||||
fftw_destroy_plan(ifft);
|
||||
fftw_destroy_plan(fftmask);
|
||||
fftw_cleanup_threads();
|
||||
DBG("time=%f\n", dtime()-t0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple gradient filter based on two Sobel filters
|
||||
* output = sqrt(SobelH(input)^2+SobelV(input)^2)
|
||||
*/
|
||||
int GradFilterSimple(float *ima, float **result, Filter *f, int w, int h){
|
||||
float *dst1, *dst2;
|
||||
int res = FALSE, y;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
f->FilterType = SOBELH;
|
||||
res = DiffFilter(ima, &dst1, f, w, h);
|
||||
if(!res) return FALSE;
|
||||
f->FilterType = SOBELV;
|
||||
res = DiffFilter(ima, &dst2, f, w, h);
|
||||
if(!res){free(dst1); return FALSE;}
|
||||
*result = dst1;
|
||||
#pragma omp parallel for
|
||||
for(y = 0; y < h; y++){
|
||||
int x;
|
||||
float *in, *out;
|
||||
in = dst2 + y*w;
|
||||
out = dst1 + y*w;
|
||||
for(x = 0; x < w; x++, in++, out++)
|
||||
*out = sqrtf((*in)*(*in) + (*out)*(*out));
|
||||
}
|
||||
free(dst2);
|
||||
DBG("time=%f\n", dtime()-t0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick median functions stolen from
|
||||
*
|
||||
* Fast median search: an ANSI C implementation
|
||||
* Nicolas Devillard - ndevilla AT free DOT fr
|
||||
* July 1998
|
||||
*/
|
||||
#define PIX_SORT(a,b) { if ((*a)>(*b)) ELEM_SWAP((a),(b)); }
|
||||
#define ELEM_SWAP(a,b) { register float *t=(a);(a)=(b);(b)=t; }
|
||||
float opt_med3(float **p, int n __attribute__((unused))){
|
||||
PIX_SORT(p[0],p[1]) ; PIX_SORT(p[1],p[2]) ; PIX_SORT(p[0],p[1]) ;
|
||||
return(*p[1]) ;
|
||||
}float opt_med5(float **p, int n __attribute__((unused))){
|
||||
PIX_SORT(p[0],p[1]) ; PIX_SORT(p[3],p[4]) ; PIX_SORT(p[0],p[3]) ;
|
||||
PIX_SORT(p[1],p[4]) ; PIX_SORT(p[1],p[2]) ; PIX_SORT(p[2],p[3]) ;
|
||||
PIX_SORT(p[1],p[2]) ; return(*p[2]) ;
|
||||
}float opt_med7(float **p, int n __attribute__((unused))){
|
||||
PIX_SORT(p[0], p[5]) ; PIX_SORT(p[0], p[3]) ; PIX_SORT(p[1], p[6]) ;
|
||||
PIX_SORT(p[2], p[4]) ; PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[5]) ;
|
||||
PIX_SORT(p[2], p[6]) ; PIX_SORT(p[2], p[3]) ; PIX_SORT(p[3], p[6]) ;
|
||||
PIX_SORT(p[4], p[5]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[1], p[3]) ;
|
||||
PIX_SORT(p[3], p[4]) ; return (*p[3]) ;
|
||||
}float opt_med9(float **p, int n __attribute__((unused))){
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ;
|
||||
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ;
|
||||
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ;
|
||||
PIX_SORT(p[4], p[2]) ; return(*p[4]) ;
|
||||
} float opt_med25(float **p, int n __attribute__((unused))){
|
||||
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[2], p[4]) ;
|
||||
PIX_SORT(p[2], p[3]) ; PIX_SORT(p[6], p[7]) ; PIX_SORT(p[5], p[7]) ;
|
||||
PIX_SORT(p[5], p[6]) ; PIX_SORT(p[9], p[10]) ; PIX_SORT(p[8], p[10]) ;
|
||||
PIX_SORT(p[8], p[9]) ; PIX_SORT(p[12], p[13]); PIX_SORT(p[11], p[13]) ;
|
||||
PIX_SORT(p[11], p[12]); PIX_SORT(p[15], p[16]); PIX_SORT(p[14], p[16]) ;
|
||||
PIX_SORT(p[14], p[15]); PIX_SORT(p[18], p[19]); PIX_SORT(p[17], p[19]) ;
|
||||
PIX_SORT(p[17], p[18]); PIX_SORT(p[21], p[22]); PIX_SORT(p[20], p[22]) ;
|
||||
PIX_SORT(p[20], p[21]); PIX_SORT(p[23], p[24]); PIX_SORT(p[2], p[5]) ;
|
||||
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[0], p[6]) ; PIX_SORT(p[0], p[3]) ;
|
||||
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[1], p[7]) ; PIX_SORT(p[1], p[4]) ;
|
||||
PIX_SORT(p[11], p[14]); PIX_SORT(p[8], p[14]) ; PIX_SORT(p[8], p[11]) ;
|
||||
PIX_SORT(p[12], p[15]); PIX_SORT(p[9], p[15]) ; PIX_SORT(p[9], p[12]) ;
|
||||
PIX_SORT(p[13], p[16]); PIX_SORT(p[10], p[16]); PIX_SORT(p[10], p[13]) ;
|
||||
PIX_SORT(p[20], p[23]); PIX_SORT(p[17], p[23]); PIX_SORT(p[17], p[20]) ;
|
||||
PIX_SORT(p[21], p[24]); PIX_SORT(p[18], p[24]); PIX_SORT(p[18], p[21]) ;
|
||||
PIX_SORT(p[19], p[22]); PIX_SORT(p[8], p[17]) ; PIX_SORT(p[9], p[18]) ;
|
||||
PIX_SORT(p[0], p[18]) ; PIX_SORT(p[0], p[9]) ; PIX_SORT(p[10], p[19]) ;
|
||||
PIX_SORT(p[1], p[19]) ; PIX_SORT(p[1], p[10]) ; PIX_SORT(p[11], p[20]) ;
|
||||
PIX_SORT(p[2], p[20]) ; PIX_SORT(p[2], p[11]) ; PIX_SORT(p[12], p[21]) ;
|
||||
PIX_SORT(p[3], p[21]) ; PIX_SORT(p[3], p[12]) ; PIX_SORT(p[13], p[22]) ;
|
||||
PIX_SORT(p[4], p[22]) ; PIX_SORT(p[4], p[13]) ; PIX_SORT(p[14], p[23]) ;
|
||||
PIX_SORT(p[5], p[23]) ; PIX_SORT(p[5], p[14]) ; PIX_SORT(p[15], p[24]) ;
|
||||
PIX_SORT(p[6], p[24]) ; PIX_SORT(p[6], p[15]) ; PIX_SORT(p[7], p[16]) ;
|
||||
PIX_SORT(p[7], p[19]) ; PIX_SORT(p[13], p[21]); PIX_SORT(p[15], p[23]) ;
|
||||
PIX_SORT(p[7], p[13]) ; PIX_SORT(p[7], p[15]) ; PIX_SORT(p[1], p[9]) ;
|
||||
PIX_SORT(p[3], p[11]) ; PIX_SORT(p[5], p[17]) ; PIX_SORT(p[11], p[17]) ;
|
||||
PIX_SORT(p[9], p[17]) ; PIX_SORT(p[4], p[10]) ; PIX_SORT(p[6], p[12]) ;
|
||||
PIX_SORT(p[7], p[14]) ; PIX_SORT(p[4], p[6]) ; PIX_SORT(p[4], p[7]) ;
|
||||
PIX_SORT(p[12], p[14]); PIX_SORT(p[10], p[14]); PIX_SORT(p[6], p[7]) ;
|
||||
PIX_SORT(p[10], p[12]); PIX_SORT(p[6], p[10]) ; PIX_SORT(p[6], p[17]) ;
|
||||
PIX_SORT(p[12], p[17]); PIX_SORT(p[7], p[17]) ; PIX_SORT(p[7], p[10]) ;
|
||||
PIX_SORT(p[12], p[18]); PIX_SORT(p[7], p[12]) ; PIX_SORT(p[10], p[18]) ;
|
||||
PIX_SORT(p[12], p[20]); PIX_SORT(p[10], p[20]); PIX_SORT(p[10], p[12]) ;
|
||||
return (*p[12]);
|
||||
}
|
||||
float quick_select(float **arr, int n){
|
||||
int low, high;
|
||||
int median;
|
||||
int middle, ll, hh;
|
||||
float ret;
|
||||
low = 0 ; high = n-1 ; median = (low + high) / 2;
|
||||
for(;;){
|
||||
if(high <= low) /* One element only */
|
||||
break;
|
||||
if(high == low + 1){ /* Two elements only */
|
||||
PIX_SORT(arr[low], arr[high]) ;
|
||||
break;
|
||||
}
|
||||
/* Find median of low, middle and high items; swap into position low */
|
||||
middle = (low + high) / 2;
|
||||
PIX_SORT(arr[middle], arr[high]) ;
|
||||
PIX_SORT(arr[low], arr[high]) ;
|
||||
PIX_SORT(arr[middle], arr[low]) ;
|
||||
/* Swap low item (now in position middle) into position (low+1) */
|
||||
ELEM_SWAP(arr[middle], arr[low+1]) ;
|
||||
/* Nibble from each end towards middle, swapping items when stuck */
|
||||
ll = low + 1;
|
||||
hh = high;
|
||||
for(;;){
|
||||
do ll++; while (*arr[low] > *arr[ll]);
|
||||
do hh--; while (*arr[hh] > *arr[low]);
|
||||
if(hh < ll) break;
|
||||
ELEM_SWAP(arr[ll], arr[hh]) ;
|
||||
}
|
||||
/* Swap middle item (in position low) back into correct position */
|
||||
ELEM_SWAP(arr[low], arr[hh]) ;
|
||||
/* Re-set active partition */
|
||||
if (hh <= median) low = ll;
|
||||
if (hh >= median) high = hh - 1;
|
||||
}
|
||||
ret = *arr[median];
|
||||
return ret;
|
||||
}
|
||||
#undef PIX_SORT
|
||||
#undef ELEM_SWAP
|
||||
|
||||
/*
|
||||
#define _0(x) (x & 0x7FF) // lower 11 bits
|
||||
#define _1(x) (x >> 11 & 0x7FF) // middle 11 bits
|
||||
#define _2(x) (x >> 22 ) // upper 10 bits
|
||||
float hist_select(float **arr, int n){
|
||||
inline uint32_t FloatFlip(uint32_t f){
|
||||
uint32_t mask = -((int32_t)(f >> 31)) | 0x80000000;
|
||||
return f ^ mask;
|
||||
}
|
||||
inline uint32_t IFloatFlip(uint32_t f){
|
||||
uint32_t mask = ((f >> 31) - 1) | 0x80000000;
|
||||
return f ^ mask;
|
||||
}
|
||||
uint32_t b0
|
||||
}
|
||||
#undef _0
|
||||
#undef _1
|
||||
#undef _2
|
||||
*/
|
||||
|
||||
/*
|
||||
* Median filtering
|
||||
* Input:
|
||||
* ima - picture (free() should be in a caller)
|
||||
* f - filter
|
||||
* sizex, sizey - picture size
|
||||
* Output:
|
||||
* result - filtered picture, memory allocates in this routine.
|
||||
* Image borders that didn't pass through the filter (+- 1/2 of filter size)
|
||||
* filled zeros
|
||||
*/
|
||||
int MedFilter(float *ima,
|
||||
float **result,
|
||||
Filter *f,
|
||||
int sizex,
|
||||
int sizey
|
||||
){
|
||||
int xlow = f->w / 2, xhigh = f->w - xlow;// filter area borders [x0-xlow, x0+xhigh)
|
||||
int ylow = f->h / 2, yhigh = f->h - ylow; // [y0-ylow, y0+yhigh)
|
||||
int x, xm=sizex-xhigh, ym=sizey-yhigh; // xm,ym - upper boundaries if filtered picture
|
||||
int ssize=sizex*sizey, fsz=f->w*f->h, H = f->h - 1;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
float (*medfn)(float **p, int n);
|
||||
*result = calloc(ssize, sizeof(float));
|
||||
if(!result) return FALSE;
|
||||
switch(f->w*f->h){
|
||||
case 3:
|
||||
medfn = opt_med3;
|
||||
break;
|
||||
case 5:
|
||||
medfn = opt_med5;
|
||||
break;
|
||||
case 7:
|
||||
medfn = opt_med7;
|
||||
break;
|
||||
case 9:
|
||||
medfn = opt_med9;
|
||||
break;
|
||||
case 25:
|
||||
medfn = opt_med25;
|
||||
break;
|
||||
default:
|
||||
medfn = quick_select;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Selection of picture elements on the square wxh into an array arr
|
||||
* x0, y0 - coordinates of the center of the square
|
||||
* cntr - current replacement string, or -1 if it is necessary to fill the entire arr
|
||||
* If cntr!=-1 next line replaces a string cntr
|
||||
*/
|
||||
float selarr0(int x0, int y0, float *arr, float **sel){
|
||||
int x,y,tx,ty;
|
||||
float *tmp, *ptr;
|
||||
tx=x0+xhigh; ty=y0+yhigh;
|
||||
tmp = arr;
|
||||
for(y=y0-ylow; y<ty; y++){ // completely fill the array
|
||||
ptr = &ima[y*sizex+x0-xlow]; // FILL BY LINES!!!
|
||||
for(x=x0-xlow; x<tx; x++)
|
||||
*tmp++ = *ptr++;
|
||||
}
|
||||
return medfn(sel, fsz);
|
||||
}
|
||||
float selarr1(int x0, int y0, float *arr, float **sel, int *cntr){
|
||||
int x,tx,ty;
|
||||
float *tmp, *ptr;
|
||||
tx=x0+xhigh; ty=y0+yhigh;
|
||||
tmp = &arr[*cntr*f->w]; // pointer to a changed line
|
||||
ptr = &ima[(ty-1)*sizex+x0-xlow];
|
||||
for(x=x0-xlow; x<tx; x++) // change data in column
|
||||
*tmp++ = *ptr++;
|
||||
if(++(*cntr) > H) *cntr = 0;
|
||||
return medfn(sel, fsz);
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
float *arr = calloc(fsz, sizeof(float*)); // array to sample storage
|
||||
float **sel = calloc(fsz, sizeof(float*));// array to sorted sample storage
|
||||
for(x = 0; x < fsz; x++) sel[x] = arr + x;
|
||||
if(arr){
|
||||
#pragma omp for
|
||||
for(x = xlow; x < xm; x++){
|
||||
int y, cntr = 0;
|
||||
(*result)[ylow*sizex + x] = selarr0(x,ylow, arr, sel);
|
||||
for(y = ylow+1; y < ym; y++){
|
||||
(*result)[y*sizex + x] = selarr1(x,y, arr, sel, &cntr);
|
||||
}
|
||||
}
|
||||
free(arr);
|
||||
free(sel);
|
||||
}
|
||||
}
|
||||
DBG("time=%f\n", dtime()-t0);
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
* Fill isolines' scale (an array)
|
||||
* Input:
|
||||
* f - filter for given method
|
||||
* min - minimum value of intensity
|
||||
* wd - max-min (dinamic range)
|
||||
* Output:
|
||||
* scale - a pointer to array (allocated in this function)
|
||||
*/
|
||||
int fillIsoScale(Filter *f, float **scale, float min, float wd){
|
||||
int M = f->w, y;
|
||||
float (*scalefn)(float in);
|
||||
float step, Nsteps = (float)f->w; // amount of intervals
|
||||
float Suniform(float in){
|
||||
return step*in + min;
|
||||
}
|
||||
float Slog(float in){
|
||||
return expf(in*step) + min - 1.;
|
||||
}
|
||||
float Sexp(float in){
|
||||
return wd*logf(in*step) + min;
|
||||
}
|
||||
float Ssqrt(float in){
|
||||
return in*in*step*step + min;
|
||||
}
|
||||
float Spow(float in){
|
||||
return sqrtf(in*step) + min;
|
||||
}
|
||||
if(!scale) return FALSE;
|
||||
|
||||
*scale = calloc(M, sizeof(float));
|
||||
if(!*scale) return FALSE;
|
||||
switch(f->h){
|
||||
case LOG:
|
||||
scalefn = Slog; step = logf(wd+1.)/Nsteps;
|
||||
break;
|
||||
case EXP:
|
||||
scalefn = Sexp; step = expf(1.)/Nsteps;
|
||||
break;
|
||||
case SQRT:
|
||||
scalefn = Ssqrt; step = sqrtf(wd)/Nsteps;
|
||||
break;
|
||||
case POW:
|
||||
scalefn = Spow; step = wd*wd/Nsteps;
|
||||
break;
|
||||
default:
|
||||
scalefn = Suniform; step = wd/Nsteps;
|
||||
}
|
||||
for(y = 0; y < M; y++){
|
||||
(*scale)[y] = scalefn(y+1);
|
||||
DBG("level %d: I=%g", y, (*scale)[y]);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Threshold filtering ("posterization")
|
||||
* Input:
|
||||
* ima - picture (free() must be executed in the caller)
|
||||
* f - filter:
|
||||
* f-> w - number of levels of posterization, [2.255]
|
||||
* f-> h - type of posterization (0 - uniform)
|
||||
* sizex, sizey - image size
|
||||
* min, max - minimum and maximum intensity of the image
|
||||
* Output:
|
||||
* result - filtered image, the memory is allocated in this procedure
|
||||
* scale - the scale of intensities, the memory is allocated here (if the scale!=NULL)
|
||||
*
|
||||
* TODO: save the result in the char, not float; learn display function
|
||||
*/
|
||||
int StepFilter(float *ima, float **result, Filter *f, int sizex, int sizey,
|
||||
float min, float max, float **scale){
|
||||
if(f->w < 2 || f->w > 255) return FALSE;
|
||||
int y;
|
||||
float Nsteps = (float)f->w; // amount of intervals
|
||||
float step;
|
||||
float wd = max - min;
|
||||
if(fabs(wd) < FLT_EPSILON) return FALSE;
|
||||
float (*stepfn)(float in);
|
||||
float Funiform(float in){
|
||||
return floor((in-min)/step);
|
||||
}
|
||||
float Flog(float in){
|
||||
return floor(logf(in-min+1.)/step);
|
||||
}
|
||||
float Fexp(float in){
|
||||
return floor(expf((in-min)/wd)/step);
|
||||
}
|
||||
float Fsqrt(float in){
|
||||
return floor(sqrtf(in-min)/step);
|
||||
}
|
||||
float Fpow(float in){
|
||||
return floor((in-min)*(in-min)/step);
|
||||
}
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
switch(f->h){
|
||||
case LOG:
|
||||
stepfn = Flog;
|
||||
step = logf(max-min+1.)/Nsteps;
|
||||
break;
|
||||
case EXP:
|
||||
stepfn = Fexp;
|
||||
step = expf(1.)/Nsteps;
|
||||
break;
|
||||
case SQRT:
|
||||
stepfn = Fsqrt;
|
||||
step = sqrtf(wd)/Nsteps;
|
||||
break;
|
||||
case POW:
|
||||
stepfn = Fpow;
|
||||
step = wd*wd/Nsteps;
|
||||
break;
|
||||
default:
|
||||
stepfn = Funiform;
|
||||
step = wd/Nsteps;
|
||||
}
|
||||
*result = calloc(sizex*sizey, sizeof(float));
|
||||
if(!result) return FALSE;
|
||||
#pragma omp parallel for
|
||||
for(y = 0; y < sizey; y++){
|
||||
int x; float *out, *in;
|
||||
in = ima + y*sizex; out = *result + y*sizex;
|
||||
for(x = 0; x < sizex; x++, in++, out++){
|
||||
*out = stepfn(*in);
|
||||
}
|
||||
}
|
||||
if(scale && !fillIsoScale(f, scale, min, wd)) g_err(_("No memory left"));
|
||||
DBG("SF: %d sublevels, step=%g, time=%f\n", f->w, step, dtime()-t0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
506
src/contours.c
Normal file
506
src/contours.c
Normal file
@ -0,0 +1,506 @@
|
||||
// contours.c - find isophotos
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
#include "contours.h"
|
||||
#include "opengl.h"
|
||||
|
||||
// contours' minimum size limits
|
||||
const int MIN_CONTOUR_SIZE = 4;
|
||||
const int MIN_CLOSED_CONTOUR_SIZE = 7;
|
||||
// maximum amount of contour levels
|
||||
const int MAX_CONTOUR_LEVELS = 255;
|
||||
|
||||
// frees contour's data
|
||||
void free_contour(Contour **c){
|
||||
cPoint *pp, *p;
|
||||
p = (*c)->first;
|
||||
while(p){ // go through all points of current contour
|
||||
pp = p; p = p->next;
|
||||
_FREE(pp);
|
||||
}
|
||||
_FREE(*c);
|
||||
}
|
||||
|
||||
// delete contours' list for the picture
|
||||
void free_contours(IMAGE *image){
|
||||
FNAME();
|
||||
int i;
|
||||
cList *l;
|
||||
Contour *cp, *c;
|
||||
if(image->Ncontours < 1 || !image->contours) return;
|
||||
for(i = 0; i < image->Ncontours; i++){ // go through all levels
|
||||
l = image->contours[i];
|
||||
c = l->first;
|
||||
while(c){ // go throug all contours of current level
|
||||
cp = c; c = c->next;
|
||||
free_contour(&cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create new element of contours' list
|
||||
cList *new_clist(int lvl){
|
||||
DBG("level: %d", lvl);
|
||||
cList *c = calloc(1, sizeof(cList));
|
||||
c->L = lvl;
|
||||
return c;
|
||||
}
|
||||
// create new contour
|
||||
Contour *new_contour(){
|
||||
Contour *c = calloc(1, sizeof(Contour));
|
||||
return c;
|
||||
}
|
||||
// create new point
|
||||
cPoint *new_point(){
|
||||
cPoint *p = calloc(1, sizeof(cPoint));
|
||||
return p;
|
||||
}
|
||||
// add contour c to list
|
||||
void cList_add(cList *cl, Contour *c){
|
||||
cl->N++;
|
||||
//DBG("contour #%d added to list with levl %d", cl->N, cl->L);
|
||||
if(!cl->first)
|
||||
cl->first = c;
|
||||
else
|
||||
cl->last->next = c;
|
||||
cl->last = c;
|
||||
}
|
||||
// add point p to contour c
|
||||
// headflag == 0 - add to tail; ==1 - add to head
|
||||
void c_add(Contour *c, cPoint *p, char headflag){
|
||||
c->N++;
|
||||
if(!c->first || !c->last){
|
||||
c->first = p;
|
||||
c->last = p;
|
||||
}else{
|
||||
if(headflag){ // add point to head
|
||||
c->first->prev = p;
|
||||
p->next = c->first;
|
||||
c->first = p;
|
||||
}
|
||||
else{
|
||||
c->last->next = p; // add point to tail
|
||||
p->prev = c->last;
|
||||
c->last = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* copy contours from image in to image out
|
||||
* with shift (dX, dY): Xnew=Xold+dX, Ynew=Yold+dY
|
||||
*/
|
||||
int copy_contours(IMAGE *in, IMAGE *out, float dX, float dY){
|
||||
int i, N = in->Ncontours;
|
||||
cList *l;
|
||||
cPoint *pCur, *p;
|
||||
Contour *cCur, *c;
|
||||
if(N < 1 || !N) return TRUE;
|
||||
if(!(out->contours = calloc(in->Ncontours, sizeof(Contour)))) return FALSE;
|
||||
for(i = 0; i < N; i++){ // go through all levels
|
||||
l = in->contours[i];
|
||||
if(!(out->contours[i] = new_clist(i))) goto badExit;
|
||||
c = l->first;
|
||||
while(c){ // go throug all contours of current level
|
||||
if(!(cCur = new_contour())) goto badExit;
|
||||
pCur = c->first;
|
||||
while(pCur){
|
||||
if(!(p = new_point())) goto badExit;
|
||||
p->x = pCur->x+dX; p->y = pCur->y+dY;
|
||||
c_add(cCur, p, 0);
|
||||
pCur = pCur->next;
|
||||
}
|
||||
cList_add(out->contours[i], cCur);
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
out->Ncontours = in->Ncontours;
|
||||
return TRUE;
|
||||
badExit:
|
||||
free_contours(out); return FALSE;
|
||||
}
|
||||
|
||||
// direction bits
|
||||
enum{
|
||||
D_RIGHT = 1
|
||||
,D_LEFT = 2
|
||||
,D_DOWN = 4
|
||||
,D_UP = 8
|
||||
};
|
||||
|
||||
// directions of next moving for mask values
|
||||
// spetial values 6 & 9 also checks separately
|
||||
int directions[16] = {
|
||||
0, // no isoline
|
||||
D_RIGHT | D_DOWN,
|
||||
D_LEFT | D_DOWN,
|
||||
D_RIGHT | D_LEFT,
|
||||
D_RIGHT | D_UP,
|
||||
D_UP | D_DOWN,
|
||||
0, // special point 6
|
||||
D_LEFT | D_UP,
|
||||
D_LEFT | D_UP,
|
||||
0, // special point 9
|
||||
D_UP | D_DOWN,
|
||||
D_RIGHT | D_UP,
|
||||
D_RIGHT | D_LEFT,
|
||||
D_LEFT | D_DOWN,
|
||||
D_RIGHT | D_DOWN,
|
||||
0 // no isoline
|
||||
};
|
||||
|
||||
/*
|
||||
* coordinate shifts {dx, dy} according to direction value bits
|
||||
* their values are choosen so, that even if there would be some non-zero
|
||||
* bits in direction mask, new direction of isoline search will be choosen
|
||||
* as possible nearest to "right" or " down" direction
|
||||
*/
|
||||
int dxdy[9][2] = {
|
||||
{0 , 0}, // 0
|
||||
{1 , 0}, // D_RIGHT
|
||||
{-1, 0}, // D_LEFT
|
||||
{0 , 0},
|
||||
{0 , 1}, // D_DOWN
|
||||
{0 , 0},
|
||||
{0 , 0},
|
||||
{0 , 0},
|
||||
{0 ,-1} // D_UP
|
||||
};
|
||||
// new directions in simplex case, 2nd dimension - head flag (if==1, rotate CCW)
|
||||
int newdirs[16][2] = {
|
||||
{0, 0}, // 0
|
||||
{D_RIGHT,D_RIGHT},// D_RIGHT
|
||||
{D_LEFT, D_LEFT}, // D_LEFT
|
||||
{D_RIGHT, D_LEFT},// D_RIGHT | D_LEFT
|
||||
{D_DOWN, D_DOWN}, // D_DOWN
|
||||
{D_RIGHT, D_DOWN},// D_DOWN | D_RIGHT
|
||||
{D_DOWN, D_LEFT}, // D_DOWN | D_LEFT
|
||||
{D_RIGHT, D_LEFT},// D_DOWN | D_RIGHT | D_LEFT
|
||||
{D_UP, D_UP}, // D_UP
|
||||
{D_RIGHT, D_UP}, // D_UP | D_RIGHT
|
||||
{D_LEFT, D_UP}, // D_UP | D_LEFT
|
||||
{D_RIGHT, D_UP}, // D_UP | D_RIGHT | D_LEFT
|
||||
{D_DOWN, D_UP}, // D_UP | D_DOWN
|
||||
{D_RIGHT, D_UP}, // D_UP | D_DOWN | D_RIGHT
|
||||
{D_DOWN, D_UP}, // D_UP | D_DOWN | D_LEFT
|
||||
{D_RIGHT, D_UP} // D_UP | D_DOWN | D_RIGHT | D_LEFT
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions that calculate the position of the contour (linear interpolation)
|
||||
* P - the point at which are recorded the coordinates (relative to the center of the upper left quadrant)
|
||||
* to the resulting coordinates p shold be added the coordinates of the square to obtain the coordinates in image SC
|
||||
* A, b, c, d - intensity in the UL, UR DL and DR corners of the square
|
||||
* Lvl - contours level
|
||||
*/
|
||||
// right & up borders
|
||||
void getRU(cPoint *p, float a, float b, float c __attribute__((unused)), float d, float I){
|
||||
float x = 0., y = 0.;
|
||||
if(fabs(b-a) > FLT_EPSILON) x = (I-a)/(b-a);
|
||||
if(fabs(d-b) > FLT_EPSILON) y = (I-b)/(d-b);
|
||||
p->x = x/2.+0.5; p->y = y/2.;
|
||||
}
|
||||
// left & up
|
||||
void getLU(cPoint *p, float a, float b, float c, float d __attribute__((unused)), float I){
|
||||
float x = 0., y = 0.;
|
||||
if(fabs(b-a) > FLT_EPSILON) x = (I-a)/(b-a);
|
||||
if(fabs(c-a) > FLT_EPSILON) y = (I-a)/(c-a);
|
||||
p->x = x/2.; p->y = y/2.;
|
||||
}
|
||||
// left & down
|
||||
void getLD(cPoint *p, float a, float b __attribute__((unused)), float c, float d, float I){
|
||||
float x = 0., y = 0.;
|
||||
if(fabs(d-c) > FLT_EPSILON) x = (I-c)/(d-c);
|
||||
if(fabs(c-a) > FLT_EPSILON) y = (I-a)/(c-a);
|
||||
p->x = x/2.; p->y = y/2.+0.5;
|
||||
}
|
||||
// right & down
|
||||
void getRD(cPoint *p, float a __attribute__((unused)), float b, float c, float d, float I){
|
||||
float x = 0., y = 0.;
|
||||
if(fabs(d-c) > FLT_EPSILON) x = (I-c)/(d-c);
|
||||
if(fabs(d-b) > FLT_EPSILON) y = (I-b)/(d-b);
|
||||
p->x = x/2.+0.5; p->y = y/2.+0.5;
|
||||
}
|
||||
// up & down
|
||||
void getUD(cPoint *p, float a, float b, float c, float d, float I){
|
||||
float x1 = 0., x2 = 1.;
|
||||
if(fabs(d-c) > FLT_EPSILON) x1 = (I-c)/(d-c);
|
||||
if(fabs(b-a) > FLT_EPSILON) x2 = (I-a)/(b-a);
|
||||
p->x = (x1+x2)/2.; p->y = 0.5;
|
||||
}
|
||||
// right & left
|
||||
void getRL(cPoint *p, float a, float b, float c, float d, float I){
|
||||
float y1 = 0., y2 = 1.;
|
||||
if(fabs(d-b) > FLT_EPSILON) y1 = (I-b)/(d-b);
|
||||
if(fabs(c-a) > FLT_EPSILON) y2 = (I-a)/(c-a);
|
||||
p->x = 0.5; p->y = (y1+y2)/2.;
|
||||
}
|
||||
// bung for a case
|
||||
void getNull(cPoint *p __attribute__((unused)), float a __attribute__((unused)),
|
||||
float b __attribute__((unused)), float c __attribute__((unused)),
|
||||
float d __attribute__((unused)), float I __attribute__((unused))){
|
||||
p->x = 0.; p->y = 0.;
|
||||
}
|
||||
|
||||
// array of a funtions to coordinates calculation
|
||||
typedef void (*FnXY)(cPoint *p, float a, float b, float c, float d, float I);
|
||||
FnXY getXY[16] = {
|
||||
getNull, // 0
|
||||
getRD,
|
||||
getLD,
|
||||
getRL,
|
||||
getRU,
|
||||
getUD,
|
||||
getNull,//6 must be getLU or get RD
|
||||
getLU,
|
||||
getLU,
|
||||
getNull,//9 must be getLD or get RU
|
||||
getUD,
|
||||
getRU,
|
||||
getRL,//12
|
||||
getLD,
|
||||
getRD,
|
||||
getNull
|
||||
};
|
||||
|
||||
static float *isoscale = NULL;
|
||||
static int w, w1, h, h1;
|
||||
static cList **contours = NULL;
|
||||
|
||||
/*
|
||||
* filling of the contour line, beginning at the point x1, y1
|
||||
* flag==1 - add points not to the tail of the circuit but to the head
|
||||
* cCur - contour to add the point
|
||||
* imdata - the original picture
|
||||
* lvl - isoline level number
|
||||
* olddir - direction (D_...) to a previous point
|
||||
* mask - pointer to current mask
|
||||
*/
|
||||
int proc_contour(int x1, int y1, int flag,
|
||||
Contour *cCur, float *imdata,
|
||||
int lvl, int olddir,
|
||||
unsigned char *mask){
|
||||
int frst = flag;
|
||||
float Lvl = isoscale[lvl]; // intensity at isoline level lvl
|
||||
float *point;
|
||||
int newdir;
|
||||
do{
|
||||
int mid = y1*w1 + x1, iid = y1*w + x1;
|
||||
unsigned char m = mask[mid];
|
||||
if(m == 0 || m > 14) break;
|
||||
if(!frst){
|
||||
cPoint *p = new_point();
|
||||
if(!p) return FALSE;
|
||||
c_add(cCur, p, flag);
|
||||
// get coordinates p->x, p->y (by simplified linear approximation)
|
||||
point = imdata + iid; // LU pixel for a square
|
||||
// find coordinates
|
||||
switch(m){ // check special points 6 & 9, their values depends on olddir
|
||||
case 6: // m = 7/14, mask=14/7
|
||||
switch(olddir){
|
||||
case D_LEFT: // next - UP or LEFT
|
||||
case D_UP:
|
||||
m = 7; mask[mid] = 14; // clear only used point
|
||||
break;
|
||||
default: // D_DOWN/D_RIGHT, next - RIGHT or UP
|
||||
m = 14; mask[mid] = 7;
|
||||
}
|
||||
break;
|
||||
case 9: // m = 13/11, mask=11/13
|
||||
switch(olddir){
|
||||
case D_LEFT: // next - DOWN or LEFT
|
||||
case D_DOWN:
|
||||
m = 13; mask[mid] = 11; // clear only used point
|
||||
break;
|
||||
default: // D_UP/D_RIGHT, next - RIGHT or DOWN
|
||||
m = 11; mask[mid] = 13;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mask[mid] = 0; // just clear used mask's point
|
||||
}
|
||||
getXY[m](p,point[0],point[1],point[w],point[w+1],Lvl);
|
||||
if(p->x < -0.5 || p->x > 1.5) p->x = 0.5;
|
||||
if(p->y < -0.5 || p->y > 1.5) p->y = 0.5;
|
||||
// add .5, beacause of mask's shift
|
||||
p->x += (float)x1 + .5;
|
||||
p->y += (float)y1 + .5;
|
||||
}
|
||||
gboolean found = FALSE; // whether next isoline point was found
|
||||
int x2, y2;
|
||||
do{ // find next contour's point
|
||||
unsigned char pp;
|
||||
// check right new direction
|
||||
newdir = newdirs[directions[m] & (~olddir)][flag];
|
||||
//newdir = directions[m] & (~olddir);
|
||||
if(newdir > 8){DBG("WTF? m=%d, newdir=%d, olddir=%d",m,newdir, olddir); break;} // This can't be so, but WTF if?
|
||||
x2 = x1 + dxdy[newdir][0];
|
||||
y2 = y1 + dxdy[newdir][1];
|
||||
if(x1 == x2 && y1 == y2) break;
|
||||
// is next square out of an picture?
|
||||
if(x2 < 0 || x2 >= w1 || y2 < 0 || y2 >= h1) break;
|
||||
int ii = y2*w1+x2;
|
||||
pp = mask[ii];
|
||||
// has the next square a contour points?
|
||||
if(pp == 0 || pp > 14) break;
|
||||
found = TRUE;
|
||||
}while(0);
|
||||
x1 = x2; y1 = y2;
|
||||
if(!found){
|
||||
break; // end of isoline
|
||||
}
|
||||
switch(newdir){ // calculate old direction
|
||||
case D_LEFT: olddir = D_RIGHT; break;
|
||||
case D_RIGHT: olddir = D_LEFT; break;
|
||||
case D_UP: olddir = D_DOWN; break;
|
||||
case D_DOWN: olddir = D_UP; break;
|
||||
default: olddir = 0;
|
||||
}
|
||||
frst = FALSE;
|
||||
}while(1); // cycle through the contour
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
* Processing of the point with coordinates x, y
|
||||
* imdata - the original picture
|
||||
* lvl - number of contour's level
|
||||
* mask - current mask
|
||||
* return FALSE if failed
|
||||
*/
|
||||
int process_it_(int x, int y, int lvl, float *imdata, unsigned char *mask){
|
||||
Contour *cCur;
|
||||
unsigned char pt0 = mask[y*w1+x];
|
||||
if(pt0 == 0 || pt0 > 14) return TRUE;;
|
||||
do{
|
||||
if(!contours[lvl]){ // countour wasn't created - create it
|
||||
contours[lvl] = new_clist(lvl);
|
||||
if(!contours[lvl]){
|
||||
g_err(_("Can't allocate memory"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
cCur = new_contour();
|
||||
if(!cCur){
|
||||
g_err(_("Can't allocate memory"));
|
||||
return FALSE;
|
||||
}
|
||||
// start processing contour, adding points to its tail
|
||||
// D_LEFT - beacause we check points from left to the right
|
||||
if(!proc_contour(x, y, 0, cCur, imdata, lvl, D_LEFT, mask))
|
||||
return FALSE;
|
||||
// continue processing contour, adding points to its head
|
||||
// D_UP - beacause there's no more contour points upper
|
||||
// if((y + 1) < w1) // mask(x,y) == 0, so we check down point
|
||||
// if(!proc_contour(x, y+1, 1, cCur, imdata, lvl, D_UP, mask))
|
||||
// return FALSE;
|
||||
if(cCur->N < MIN_CONTOUR_SIZE){ // contour is too short
|
||||
free_contour(&cCur);
|
||||
break;
|
||||
}
|
||||
if( (fabs(cCur->first->x - cCur->last->x) +
|
||||
fabs(cCur->first->y - cCur->last->y)) < 2.){ // closed contour
|
||||
cCur->closed = TRUE;
|
||||
if(cCur->N < MIN_CLOSED_CONTOUR_SIZE){ // contour is too short
|
||||
free_contour(&cCur);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cList_add(contours[lvl], cCur);
|
||||
}while(0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find isophotos on picture window->image
|
||||
* nLevl - amount of isophotos
|
||||
* type - type of isophotos segmentation (the same as f->h for STEP filter)
|
||||
*/
|
||||
void find_contours(Window *window,
|
||||
int nLevl,
|
||||
int type){
|
||||
IMAGE *ima = window->image;
|
||||
int y, level;
|
||||
float *image = ima->data;
|
||||
if(nLevl < 2 || nLevl > MAX_CONTOUR_LEVELS) return;
|
||||
unsigned char *mask; // array for marching squares matrix
|
||||
Filter f;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
w = ima->width; w1=w-1; h = ima->height; h1=h-1;
|
||||
mask = calloc((w1)*(h1),1); // mask - one mask pixel is square of 2x2 pixels on an picture
|
||||
if(!mask){g_err(_("Can't allocate memory"));return;}
|
||||
// prepare isoscale
|
||||
f.FilterType = STEP; f.w = nLevl; f.h = type;
|
||||
if(!fillIsoScale(&f, &isoscale, ima->stat.min, ima->stat.max - ima->stat.min)){
|
||||
g_err(_("Can't allocate memory"));goto endOF;}
|
||||
// Go through all levels
|
||||
contours = calloc(nLevl, sizeof(Contour)); // all-picture contours array
|
||||
if(!contours){g_err(_("Can't allocate memory"));goto endOF;}
|
||||
for(level = 0; level < nLevl; ++level){
|
||||
/*
|
||||
* 1. level segmentation & build mask
|
||||
* Mask by square (if zero point in left upper corner)
|
||||
* _______
|
||||
* | a | b |
|
||||
* |---+---|
|
||||
* | c | d |
|
||||
* -------
|
||||
* bits order: 0000abcd
|
||||
*/
|
||||
int y;
|
||||
float lvl = isoscale[level]; // current isoline's intensity level
|
||||
#pragma omp parallel for
|
||||
for(y = 0; y < h1; y++){
|
||||
int x;
|
||||
unsigned char *out = &mask[y*w1];
|
||||
float *in = &image[y*w];
|
||||
for(x = 0; x < w1; x++, in++, out++)
|
||||
*out = (unsigned char)
|
||||
((in[0]>lvl)<<3) |
|
||||
((in[1]>lvl)<<2) |
|
||||
((in[w]>lvl)<<1) |
|
||||
(in[w+1]>lvl);
|
||||
}
|
||||
// go through all mask's points
|
||||
for(y = 0; y < h1; y++){
|
||||
int x;
|
||||
for(x = 0; x < w1; x++)
|
||||
if(!process_it_(x, y, level, image, mask)) goto endOF;
|
||||
}
|
||||
}
|
||||
endOF:
|
||||
_FREE(mask);
|
||||
if(contours){
|
||||
for(y = 0; y < nLevl; y++){
|
||||
g_print("Level: %d", y);
|
||||
if(contours[y]) g_print(", %d contours\n", contours[y]->N);
|
||||
else g_print("\n");
|
||||
}
|
||||
// fill contour structure
|
||||
ima->contours = contours; contours = NULL;
|
||||
ima->Ncontours = nLevl;
|
||||
if(isoscale){ima->cLevels = isoscale; isoscale = NULL;}
|
||||
}
|
||||
DBG("time: %g", dtime()-t0);
|
||||
window->context->visualMode |= SHOW_ISOLINES;
|
||||
gen_texture(ima, window, TRUE);
|
||||
force_redraw(window->drawingArea);
|
||||
}
|
||||
168
src/filelist.c
Normal file
168
src/filelist.c
Normal file
@ -0,0 +1,168 @@
|
||||
// filelist.c - functions to work with list of FITS files in current directory
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
#include "filelist.h"
|
||||
#include "fits.h"
|
||||
/*
|
||||
* receiving the file name of list, type can be one of the following:
|
||||
* CURRENT - current file
|
||||
* FIRST - first file
|
||||
* LAST - last file
|
||||
* PREVIOUS - previous file
|
||||
* NEXT - next file
|
||||
*/
|
||||
gchar *get_filename(guchar type, Window *window){
|
||||
DBG("length of list = %d", window->files.list_length);
|
||||
if(window->files.list_length < 1) return NULL;
|
||||
if(!window->files.list_current){
|
||||
DBG("No current file. WTF?");
|
||||
return NULL;
|
||||
}
|
||||
//~ g_list_foreach(window->files.files_list, (GFunc)prnt, NULL);
|
||||
switch(type){
|
||||
case FIRST:
|
||||
if(window->files.list_current == window->files.files_list){
|
||||
DBG("1st or only file");
|
||||
return NULL; // try to open current opened file or there's no files
|
||||
}
|
||||
window->files.list_current = window->files.files_list;
|
||||
break;
|
||||
case LAST:
|
||||
if(window->files.list_length < 2 ||
|
||||
window->files.list_current == window->files.list_end){
|
||||
DBG("last or only file");
|
||||
return NULL;
|
||||
}
|
||||
window->files.list_current = window->files.list_end;
|
||||
break;
|
||||
case PREVIOUS:
|
||||
if(!window->files.list_current->prev){
|
||||
DBG("1st file");
|
||||
return NULL;
|
||||
}
|
||||
window->files.list_current = window->files.list_current->prev;
|
||||
break;
|
||||
case NEXT:
|
||||
if(!window->files.list_current->next){
|
||||
DBG("last file");
|
||||
return NULL;
|
||||
}
|
||||
window->files.list_current = window->files.list_current->next;
|
||||
break;
|
||||
default: // current
|
||||
break;
|
||||
}
|
||||
if(!window->files.list_current || !window->files.list_current->data){
|
||||
DBG("no current file? WTF?");
|
||||
return NULL;
|
||||
}
|
||||
DBG("change filename: %s\n\n", (gchar*)window->files.list_current->data);
|
||||
return (gchar*)window->files.list_current->data;
|
||||
}
|
||||
|
||||
// get filename suffix
|
||||
gboolean get_ext(gchar *filename){
|
||||
gchar *basename, *ext;
|
||||
basename = strrchr(filename, '/');
|
||||
if(!basename) basename = filename;
|
||||
else basename++;
|
||||
ext = strrchr(basename, '.');
|
||||
if(!ext) return FALSE;
|
||||
else ext++;
|
||||
//DBG("basename = %s; ext = %s", basename, ext);
|
||||
if(strcasecmp(ext, "fts") == 0 || strcasecmp(ext, "fit") == 0 ||
|
||||
strcasecmp(ext, "fits") == 0) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// File test for loadable
|
||||
gboolean is_loadable(gchar *filename){
|
||||
if(!Global->add_all){ // if we don't try to open any file
|
||||
if(!get_ext(filename)) // file suffix isn't fit/fits/fts
|
||||
return FALSE;
|
||||
}
|
||||
return guess_fits(filename);
|
||||
}
|
||||
|
||||
gint add_file_to_list(gchar *filename, Window *window){
|
||||
if(is_loadable(filename)){
|
||||
DBG("File %s is FITS file\n", filename);
|
||||
window->files.files_list = g_list_prepend(window->files.files_list, (gpointer)filename);
|
||||
window->files.list_length++;
|
||||
if(window->files.list_length == 1)
|
||||
window->files.list_end = window->files.files_list;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_filelist(Window *window){
|
||||
if(window->files.files_list){
|
||||
g_list_foreach(window->files.files_list, (GFunc)free, NULL);
|
||||
g_list_free(window->files.files_list);
|
||||
window->files.list_length = 0;
|
||||
window->files.files_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get a FITS files list in current directory
|
||||
* filename - full filename (with path)
|
||||
* returns a files number in list
|
||||
*/
|
||||
gint fill_filelist(gchar *filename, Window *window){
|
||||
gint nb_inserted = 0;
|
||||
GDir *dir;
|
||||
GError *err = NULL;
|
||||
const gchar *dir_entry;
|
||||
gchar *dirname = g_path_get_dirname(filename);
|
||||
DBG("Open directory %s", dirname);
|
||||
dir = g_dir_open(dirname, 0, &err);
|
||||
if(dir == NULL){
|
||||
g_err(err->message);
|
||||
g_error_free(err);
|
||||
return 0;
|
||||
}
|
||||
free_filelist(window); // clear list if it was already created
|
||||
while((dir_entry = g_dir_read_name(dir))){
|
||||
gchar *full_path = g_build_filename(dirname, dir_entry, NULL);
|
||||
if(!g_file_test(full_path, G_FILE_TEST_IS_DIR)){
|
||||
nb_inserted += add_file_to_list(full_path, window);
|
||||
}
|
||||
}
|
||||
g_dir_close(dir);
|
||||
g_free(dirname);
|
||||
window->files.files_list = g_list_sort(window->files.files_list, (GCompareFunc)strcmp);
|
||||
DBG("\nSort %d items\n", nb_inserted);
|
||||
window->files.list_end = g_list_last(window->files.files_list);
|
||||
window->files.list_current = g_list_find_custom(window->files.files_list, filename,(GCompareFunc)strcmp);
|
||||
//if(!window->files.list_current) window->files.list_current = g_list_first(window->files.files_list);
|
||||
//~ place_first = g_list_find_custom(window->files.files_list, filename, strcmp);
|
||||
//~ if(place_first && place_first->prev){
|
||||
//~ place_first->prev->next = place_first->next;
|
||||
//~ if(place_first->next)
|
||||
//~ place_first->next->prev = place_first->prev;
|
||||
//~ place_first->prev = NULL;
|
||||
//~ place_first->next = window->files.files_list;
|
||||
//~ window->files.files_list->prev = place_first;
|
||||
//~ window->files.files_list = place_first;
|
||||
//~ }
|
||||
return nb_inserted;
|
||||
}
|
||||
|
||||
396
src/fits.c
Normal file
396
src/fits.c
Normal file
@ -0,0 +1,396 @@
|
||||
// fits.c - main functions to work with FITS files
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "fits.h"
|
||||
#include "gtk.h"
|
||||
#include "fitsheaders.h"
|
||||
|
||||
/*
|
||||
* Macros for error processing when working with cfitsio functions
|
||||
*/
|
||||
#define TRYFITS(f, ...) \
|
||||
do{ gboolean status = FALSE; \
|
||||
f(__VA_ARGS__, &status); \
|
||||
if(status){ \
|
||||
fits_report_error(stderr, status); \
|
||||
return FALSE;} \
|
||||
}while(0)
|
||||
#define FITSFUN(f, ...) \
|
||||
do{ gboolean status = FALSE; \
|
||||
int ret = f(__VA_ARGS__, &status); \
|
||||
if(ret || status) \
|
||||
fits_report_error(stderr, status); \
|
||||
}while(0)
|
||||
#define WRITEKEY(...) \
|
||||
do{ gboolean status = FALSE; \
|
||||
fits_write_key(__VA_ARGS__, &status); \
|
||||
if(status) fits_report_error(stderr, status);\
|
||||
}while(0)
|
||||
|
||||
/*
|
||||
* Check whether a number is a complex
|
||||
* If yes - returns true, no - false
|
||||
* If re and/or im!=NULL, in them stored values
|
||||
* of real and imaginary components
|
||||
*/
|
||||
gboolean cmplx_conv(gchar *value, double *re, double *im){
|
||||
double sign = 1.;
|
||||
double r,i;
|
||||
gchar *ptr1, *ptr2, *eptr;
|
||||
ptr1 = g_strstr_len(value, -1, "(");
|
||||
if(ptr1){ // form is (re, im) or (re im)
|
||||
ptr1++;
|
||||
ptr2 = g_strstr_len(ptr1, -1, ")");
|
||||
if(ptr2) *ptr2 = 0;
|
||||
ptr2 = g_strstr_len(ptr1, -1, ",");
|
||||
if(!ptr2)
|
||||
ptr2 = g_strstr_len(ptr1, -1, " ");
|
||||
}
|
||||
else{ // form is re + iim or re + jim
|
||||
ptr1 = value;
|
||||
ptr2 = g_strstr_len(ptr1, -1, "i");
|
||||
if(!ptr2)
|
||||
ptr2 = g_strstr_len(ptr1, -1, "j");
|
||||
}
|
||||
if(ptr2){
|
||||
*ptr2 = 0;
|
||||
ptr2++;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
if(g_strrstr_len(ptr1, 3, "-")) sign=-1.;
|
||||
r = strtod(ptr1, &eptr);
|
||||
if(eptr == ptr1) return FALSE;
|
||||
i = sign*strtod(ptr2, &eptr);
|
||||
if(eptr == ptr2) return FALSE;
|
||||
if(re) *re = r;
|
||||
if(im) *im = i;
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
* try to guess key type:
|
||||
* TLONGLONG, TDOUBLE, TDBLCOMPLEX or TSTRING
|
||||
*/
|
||||
int guess_type(gchar *keyval, gchar* keytype){
|
||||
char *eptr, *val;
|
||||
int dtype = TSTRING;
|
||||
val = strdup(keyval);
|
||||
if(strchr(val, '.')){
|
||||
errno = 0;
|
||||
strtod(val, &eptr);
|
||||
if(eptr != val && errno != ERANGE)
|
||||
dtype = TDOUBLE;
|
||||
}
|
||||
if(dtype == TSTRING){
|
||||
errno = 0;
|
||||
strtoll(val, &eptr, 0);
|
||||
if(eptr != val && errno != ERANGE) dtype = TLONGLONG;
|
||||
}
|
||||
if(dtype == TSTRING && cmplx_conv(val, NULL, NULL))
|
||||
dtype = TDBLCOMPLEX;
|
||||
if(keytype) switch(dtype){
|
||||
case TDOUBLE:
|
||||
sprintf(keytype, "TDOUBLE");
|
||||
break;
|
||||
case TLONGLONG:
|
||||
sprintf(keytype, "TLONGLONG");
|
||||
break;
|
||||
case TDBLCOMPLEX:
|
||||
sprintf(keytype, "TDBLCOMPLEX");
|
||||
break;
|
||||
default:
|
||||
sprintf(keytype, "TSTRING");
|
||||
}
|
||||
//~ DBG("dtype: %d, keytype: %s", dtype, (keytype) ? keytype : "");
|
||||
free(val);
|
||||
return dtype;
|
||||
}
|
||||
/*
|
||||
* Save image-structure to a FITS file
|
||||
* (together whith keys)
|
||||
*/
|
||||
gboolean writefits(char *filename, IMAGE *image){
|
||||
FNAME();
|
||||
long naxes[2] = {image->width, image->height};
|
||||
int w = image->width, h = image->height;
|
||||
ssize_t sz = w * h;
|
||||
gchar *keytype, *keyname, *keyval, *keycomment; int keyfitstype;
|
||||
GtkTreeIter iter;
|
||||
fitsfile *fp;
|
||||
gchar *card;
|
||||
#ifdef EBUG
|
||||
int n = 0;
|
||||
#endif
|
||||
TRYFITS(fits_create_file, &fp, filename);
|
||||
TRYFITS(fits_create_img, fp, image->dtype, 2, naxes);
|
||||
if(image->store){
|
||||
GtkTreePath *path = gtk_tree_path_new_first();
|
||||
GtkTreeModel *tree_model = GTK_TREE_MODEL(image->store);
|
||||
if(gtk_tree_model_get_iter(tree_model, &iter, path)){ // there's keys
|
||||
DBG("filename: %s", filename);
|
||||
do{
|
||||
gtk_tree_model_get(tree_model, &iter,
|
||||
L_TYPENM, &keytype,
|
||||
L_KEY, &keyname,
|
||||
L_VAL, &keyval,
|
||||
L_COMM, &keycomment,
|
||||
L_TYPE, &keyfitstype,
|
||||
-1);
|
||||
if(keyfitstype == TSTRING) // make sure, that string is in quotes
|
||||
if(*keyval != '\''){
|
||||
gchar *str = g_strdup_printf("'%s'", keyval);
|
||||
g_free(keyval);
|
||||
keyval = str;
|
||||
}
|
||||
card = g_strdup_printf("%-8s= %s / %s",
|
||||
keyname, keyval, keycomment);
|
||||
g_free(keytype); g_free(keyname); g_free(keyval);
|
||||
g_free(keycomment);
|
||||
DBG("key#%d: %s", ++n, card);
|
||||
FITSFUN(fits_write_record, fp, card);
|
||||
g_free(card);
|
||||
}while(gtk_tree_model_iter_next(tree_model, &iter));
|
||||
}
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
GLfloat min, wd;
|
||||
min = image->stat.min;
|
||||
wd = image->stat.max - min;
|
||||
DBG("min = %f, wd = %f", min, wd);
|
||||
/* int i,j;
|
||||
GLfloat *newdata = malloc(sz*sizeof(GLfloat));
|
||||
GLfloat *ptro = newdata, *ptri = image->data;
|
||||
for(i=0; i<h; i++)
|
||||
for(j=0; j<w; j++, ptro++, ptri++){
|
||||
*ptro = min + (*ptri) * wd;
|
||||
}
|
||||
TRYFITS(fits_write_img, fp, TFLOAT, 1, sz, newdata);
|
||||
free(newdata);*/
|
||||
TRYFITS(fits_write_img, fp, TFLOAT, 1, sz, image->data);
|
||||
TRYFITS(fits_close_file, fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean try_open_file(gchar *filename, IMAGE *ima){
|
||||
if(!readfits(filename, ima)){
|
||||
g_err(_("Can't read fits file"));
|
||||
ima->data = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
char *del_spaces(char *str){
|
||||
char *beg, *end;
|
||||
beg = str;
|
||||
end = str + strlen(str);
|
||||
while(*beg == ' ' && beg < end) beg++;
|
||||
if(beg == end) return beg;
|
||||
end--;
|
||||
if(beg == end) return beg;
|
||||
while(*end == ' ' && end > beg)
|
||||
*end-- = 0;
|
||||
return beg;
|
||||
}
|
||||
gboolean strip_card(char *card, char *keyname, char *keyval, char *keycomment){
|
||||
char *ptr, *ptr1, *end;
|
||||
char *c = strdup(card);
|
||||
end = c + strlen(c);
|
||||
ptr = strchr(c, '=');
|
||||
if(!ptr) return FALSE;
|
||||
*ptr = 0; ptr++;
|
||||
ptr1 = del_spaces(c);
|
||||
strncpy(keyname, ptr1, FLEN_KEYWORD-1);
|
||||
ptr1 = strchr(ptr, '\'');
|
||||
if(ptr1){
|
||||
ptr1++;
|
||||
ptr = strchr(ptr1, '\'');
|
||||
if(!ptr){
|
||||
ptr = strchr(ptr1, '/');
|
||||
if(!ptr){
|
||||
free(c);
|
||||
return FALSE;
|
||||
}
|
||||
*ptr = 0; ptr++;
|
||||
}else{
|
||||
*ptr = 0; ptr = strchr(ptr+1, '/');
|
||||
if(!ptr){
|
||||
free(c);
|
||||
return FALSE;
|
||||
}
|
||||
*ptr = 0; ptr++;
|
||||
}
|
||||
}else{
|
||||
ptr1 = ptr;
|
||||
ptr = strchr(ptr1, '/');
|
||||
if(!ptr){
|
||||
free(c);
|
||||
return FALSE;
|
||||
}
|
||||
*ptr = 0; ptr++;
|
||||
ptr1 = del_spaces(ptr1);
|
||||
}
|
||||
if(ptr >= end) return FALSE;
|
||||
ptr1 = del_spaces(ptr1);
|
||||
strncpy(keyval, ptr1, FLEN_VALUE);
|
||||
ptr1 = del_spaces(ptr);
|
||||
strncpy(keycomment, ptr1, FLEN_COMMENT);
|
||||
free(c);
|
||||
return TRUE;
|
||||
}*/
|
||||
|
||||
/*
|
||||
* Read FITS file filename to a structure image
|
||||
*/
|
||||
gboolean readfits(gchar *filename, IMAGE *image){
|
||||
FNAME();
|
||||
gboolean ret = TRUE;
|
||||
fitsfile *fp;
|
||||
GLfloat nullval = 0., imBits, bZero = 0., bScale = 1.;
|
||||
free(image->data);
|
||||
image->data = NULL;
|
||||
int i, j, hdunum, keynum, morekeys, dtype, stat;
|
||||
int naxis, w, h;
|
||||
double val_f = -1e6; // VAL_F value
|
||||
long naxes[4];
|
||||
ssize_t sz;
|
||||
//char card[FLEN_CARD];
|
||||
char keyname[FLEN_KEYWORD], keyval[FLEN_VALUE];
|
||||
char keycomment[FLEN_COMMENT], cdtype[32];
|
||||
TRYFITS(fits_open_file, &fp, filename, READWRITE);
|
||||
/* TRYFITS(fits_get_hdrspace, fp, &keynum, &morekeys);
|
||||
if(morekeys == -1){
|
||||
return FALSE;
|
||||
}
|
||||
g_print("Read header of %s, %d keys\n", filename, keynum);*/
|
||||
FITSFUN(fits_get_num_hdus, fp, &hdunum);
|
||||
//~ g_print(_("\nFile includes %d HDUs\n"), hdunum);
|
||||
if(hdunum < 1){
|
||||
g_err(_("Can't read HDU"));
|
||||
TRYFITS(fits_close_file, fp);
|
||||
return FALSE;
|
||||
}
|
||||
FITSFUN(fits_get_hdu_type, fp, &dtype);
|
||||
//~ if(dtype) g_print(_("Current HDU type: %d\n"), dtype);
|
||||
init_keylist(image);
|
||||
FITSFUN(fits_get_hdrpos ,fp, &keynum, &morekeys);
|
||||
|
||||
for (j = 1; j <= keynum; j++){
|
||||
/*FITSFUN(fits_read_record, fp, j, card);
|
||||
if(!strip_card(card, keyname, keyval, keycomment)){
|
||||
g_print("Corrupted card: %s!\n", card);
|
||||
continue;
|
||||
}*/
|
||||
FITSFUN(fits_read_keyn, fp, j, keyname, keyval, keycomment);
|
||||
if(strcmp(keyname, "SIMPLE") == 0 || strcmp(keyname, "EXTEND") == 0) // key "file does conform ..."
|
||||
continue;
|
||||
else if(strcmp(keyname, "COMMENT") == 0) // comment of obligatory key in FITS head
|
||||
continue;
|
||||
else if(strstr(keyname, "NAXIS") == keyname || strcmp(keyname, "BITPIX") == 0) // NAXIS, NAXISxxx, BITPIX
|
||||
continue;
|
||||
else if(strcmp(keyname, "BZERO") == 0){
|
||||
bZero = atof(keyval);
|
||||
//continue;
|
||||
}
|
||||
else if(strcmp(keyname, "BSCALE") == 0){
|
||||
bScale = atof(keyval);
|
||||
if(bScale < SCALE_MIN) bScale = 1.;
|
||||
//continue;
|
||||
}
|
||||
else if(strcmp(keyname, "VAL_F") == 0){
|
||||
val_f = atof(keyval);
|
||||
}
|
||||
dtype = guess_type(keyval, cdtype);
|
||||
//DBG("key#%d; name=%s, dtype=%d (%s), value=%s, comment=%s\n",
|
||||
// j, keyname, dtype, cdtype, keyval, keycomment);
|
||||
add_key(image, cdtype, keyname, keyval, keycomment, dtype);
|
||||
}
|
||||
if(hdunum > 1){
|
||||
for(i = 2; !(fits_movabs_hdu(fp, i, &dtype, &stat)); i++){
|
||||
FITSFUN(fits_get_hdrpos ,fp, &keynum, &morekeys);
|
||||
for (j = 1; j <= keynum; j++){
|
||||
FITSFUN(fits_read_keyn, fp, j, keyname, keyval, keycomment);
|
||||
dtype = guess_type(keyval, cdtype);
|
||||
add_key(image, cdtype, keyname, keyval, keycomment, dtype);
|
||||
}
|
||||
}
|
||||
if(stat != END_OF_FILE){
|
||||
fits_report_error(stderr, (stat));
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
TRYFITS(fits_get_img_param, fp, 4, &dtype, &naxis, naxes);
|
||||
if(dtype > 0) imBits = (GLfloat)(1LL << dtype); // compute the max amplitude
|
||||
else imBits = -1.; // image has floating point type
|
||||
DBG("Image type: %d (%f bits)", dtype, imBits);
|
||||
image->maxVal = imBits;
|
||||
image->dtype = dtype;
|
||||
if(naxis != 2){
|
||||
g_err(_("Not an image? (dimensions != 2)"));
|
||||
return FALSE;}
|
||||
|
||||
image->val_f = val_f;
|
||||
image->bZero = bZero;
|
||||
image->bScale = bScale;
|
||||
image->width = w = naxes[0];
|
||||
image->height = h = naxes[1];
|
||||
sz = (ssize_t)(w) * (ssize_t)(h);
|
||||
image->data = malloc(sz * sizeof(GLfloat));
|
||||
|
||||
TRYFITS(fits_read_img, fp, TFLOAT, 1, sz, &nullval, image->data, &stat);
|
||||
GLfloat *ptr = image->data;
|
||||
GLfloat min, max, wd;
|
||||
min = 1e6; max = 0.;
|
||||
for(i=0; i<h; i++)
|
||||
for(j=0; j<w; j++, ptr++){
|
||||
GLfloat tmp = *ptr;
|
||||
if(tmp > max) max = tmp;
|
||||
else if(tmp < min) min = tmp;
|
||||
}
|
||||
wd = max - min;
|
||||
DBG("min = %f, wd = %f", min, wd);
|
||||
image->stat.max = max;
|
||||
image->stat.min = min;
|
||||
// histogram isn't initialized yet
|
||||
image->stat.histogram.data = NULL;
|
||||
image->stat.histogram.size = 0;
|
||||
/*
|
||||
ptr = image->data;
|
||||
for(i=0; i<h; i++)
|
||||
for(j=0; j<w; j++, ptr++){
|
||||
// *ptr = (*ptr * bScale + bZero) / imBits;
|
||||
*ptr = (*ptr - min) / wd;
|
||||
}
|
||||
*/
|
||||
TRYFITS(fits_close_file, fp);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
// Try to open FITS and find an image in it
|
||||
gboolean guess_fits(gchar *filename){
|
||||
fitsfile *fp;
|
||||
long naxes[4];
|
||||
int naxis, dtype;
|
||||
DBG("Try to open file %s\n", filename);
|
||||
TRYFITS(fits_open_file, &fp, filename, READONLY);
|
||||
TRYFITS(fits_get_img_param, fp, 4, &dtype, &naxis, naxes);
|
||||
if(naxis != 2) return FALSE;
|
||||
TRYFITS(fits_close_file, fp);
|
||||
return TRUE;
|
||||
}
|
||||
530
src/fitsheaders.c
Normal file
530
src/fitsheaders.c
Normal file
@ -0,0 +1,530 @@
|
||||
// fitsheaders.c - functions to edit FITS head
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "fitsheaders.h"
|
||||
#include "fits.h"
|
||||
|
||||
GtkListStore *combo_ = NULL;
|
||||
GtkTreeSelection *sel;
|
||||
GtkTreeView* Tree;
|
||||
GtkWidget *del_button;
|
||||
GtkWidget *window;
|
||||
// Data types to write FITS keys into menu
|
||||
gchar* key_types[] = {
|
||||
"TSTRING", "TLOGICAL", "TBYTE", "TSHORT", "TUSHORT", "TINT", "TUINT",
|
||||
"TLONG", "TULONG", "TLONGLONG", "TFLOAT", "TDOUBLE", "TCOMPLEX",
|
||||
"TDBLCOMPLEX"
|
||||
};
|
||||
// Values itself
|
||||
int type_vals[] = {
|
||||
TSTRING,
|
||||
TLOGICAL,
|
||||
TBYTE,
|
||||
TSHORT,
|
||||
TUSHORT,
|
||||
TINT,
|
||||
TUINT,
|
||||
TLONG,
|
||||
TULONG,
|
||||
TLONGLONG,
|
||||
TFLOAT,
|
||||
TDOUBLE,
|
||||
TCOMPLEX,
|
||||
TDBLCOMPLEX
|
||||
};
|
||||
|
||||
int VALS_N; // Number of items
|
||||
|
||||
gchar *colnames[] = {N_("Type"), N_("Name"), N_("Value"), N_("Comment")};
|
||||
#define VISIBLE_COLS 4 // The amount of visible columns
|
||||
|
||||
int find_list_type(char *type){
|
||||
int i;
|
||||
for(i = 0; i < VALS_N; i++)
|
||||
if(strcmp(key_types[i], type) == 0) break;
|
||||
if(i == VALS_N) // Error: there's no such value in list
|
||||
i = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
gboolean ll_conv(gchar **value, int type){
|
||||
long long ll_val, oll_val;
|
||||
gboolean ret = TRUE;
|
||||
ll_val = oll_val = strtoll(*value, NULL, 0);
|
||||
//g_free(*value);
|
||||
switch(type){
|
||||
case TBYTE:
|
||||
if(ll_val > CHAR_MAX || ll_val < CHAR_MIN) ll_val = 0L;
|
||||
break;
|
||||
case TSHORT:
|
||||
if(ll_val > SHRT_MAX || ll_val < SHRT_MIN) ll_val = 0L;
|
||||
break;
|
||||
case TINT:
|
||||
if(ll_val > INT_MAX || ll_val < INT_MIN) ll_val = 0L;
|
||||
break;
|
||||
case TLONG:
|
||||
if(ll_val > LONG_MAX || ll_val < LONG_MIN) ll_val = 0L;
|
||||
break;
|
||||
case TLONGLONG:
|
||||
if(ll_val > LLONG_MAX || ll_val < LLONG_MIN) ll_val = 0L;
|
||||
break;
|
||||
case TUSHORT:
|
||||
if(ll_val > USHRT_MAX || ll_val < 0L) ll_val = 0L;
|
||||
break;
|
||||
case TUINT:
|
||||
if(ll_val > UINT_MAX || ll_val < 0L) ll_val = 0L;
|
||||
break;
|
||||
case TULONG:
|
||||
if((unsigned long)ll_val > ULONG_MAX || ll_val < 0L) ll_val = 0L;
|
||||
break;
|
||||
default:
|
||||
ll_val = 0L;
|
||||
break;
|
||||
}
|
||||
DBG("long long: %lld", ll_val);
|
||||
if(ll_val != oll_val){
|
||||
g_err(_("Error in value range!"));
|
||||
ret = FALSE;
|
||||
}
|
||||
g_free(*value);
|
||||
*value = g_strdup_printf("%lld", ll_val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean mystrtod(gchar **val){
|
||||
double d_val;
|
||||
gboolean ret = TRUE;
|
||||
char *eptr = NULL, *ptr = *val;
|
||||
errno = 0;
|
||||
d_val = strtod(ptr, &eptr);
|
||||
DBG("double: %.16e (was: %s)", d_val, *val);
|
||||
if((eptr && *eptr) || errno == ERANGE){
|
||||
g_free(*val);
|
||||
DBG("try convert %g into val", d_val);
|
||||
*val = g_strdup_printf("%.16e", d_val);
|
||||
g_err(_("Invalid double number!"));
|
||||
ret = FALSE;
|
||||
}
|
||||
DBG("val: %s", *val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean check_complex_number(gchar **val){
|
||||
double re = 0., im = 0.;
|
||||
gboolean ret = TRUE;
|
||||
if(!cmplx_conv(*val, &re, &im)){
|
||||
gchar *msg = g_strdup_printf("%s\n%s",
|
||||
_("Format error: complex number must be in format"),
|
||||
"RE + iIM, RE + jIM, RE iIM, RE jIM, (RE, IM) or (RE IM)");
|
||||
g_err(msg);
|
||||
g_free(msg);
|
||||
ret = FALSE;
|
||||
}
|
||||
DBG("complex: (%g, %g)", re, im);
|
||||
g_free(*val);
|
||||
*val = g_strdup_printf("(%g, %g)", re, im);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean check_val(gchar **newval, int type){
|
||||
gboolean b_val, ret = TRUE;
|
||||
switch(type){
|
||||
case TBYTE:
|
||||
case TSHORT:
|
||||
case TINT:
|
||||
case TLONG:
|
||||
case TLONGLONG:
|
||||
case TUSHORT:
|
||||
case TUINT:
|
||||
case TULONG:
|
||||
// convert *char -> long long vith checking value
|
||||
ret = ll_conv(newval, type);
|
||||
break;
|
||||
case TFLOAT:
|
||||
case TDOUBLE:
|
||||
// convert *char -> double
|
||||
ret = mystrtod(newval);
|
||||
break;
|
||||
case TCOMPLEX:
|
||||
case TDBLCOMPLEX:
|
||||
// check whether a number is complex
|
||||
ret = check_complex_number(newval);
|
||||
break;
|
||||
case TLOGICAL:
|
||||
// convert value into boolean
|
||||
if(g_ascii_strncasecmp("true", *newval, 4)==0) b_val = TRUE;
|
||||
else
|
||||
b_val = atoi(*newval);
|
||||
g_free(*newval);
|
||||
*newval = g_strdup_printf("%s", b_val ? "TRUE" : "FALSE");
|
||||
DBG("boolean: %s", *newval);
|
||||
break;
|
||||
default:
|
||||
DBG("string: %s", *newval); // all other values a strings
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean try_change_val(IMAGE *ima, gchar **newval){
|
||||
int type;
|
||||
GtkTreeIter cur_items;
|
||||
gboolean ret;
|
||||
GtkTreeModel *model;
|
||||
FNAME();
|
||||
if(!gtk_tree_selection_get_selected(sel,&model, &cur_items)) return FALSE;
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(ima->store), &cur_items, L_TYPE, &type, -1);
|
||||
ret = check_val(newval, type);
|
||||
gtk_list_store_set(ima->store, &cur_items, L_VAL, *newval, -1);
|
||||
DBG("ret");
|
||||
return ret;
|
||||
}
|
||||
guint cur_column;
|
||||
void edit_cell( GtkCellRendererText *cell,
|
||||
gchar *path,
|
||||
gchar *new_text,
|
||||
IMAGE *ima){
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter cur_items;
|
||||
cur_column = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(cell), "column_num"));
|
||||
gboolean nxtcol = TRUE, editable = TRUE;
|
||||
if(!path) return;
|
||||
DBG("path: %s, new: %s, colnum: %d", path, new_text, cur_column);
|
||||
gchar *textptr;
|
||||
if(!gtk_tree_selection_get_selected(sel,&model, &cur_items)) return;
|
||||
switch(cur_column){
|
||||
case L_TYPENM: // key type was changed
|
||||
gtk_list_store_set(ima->store, &cur_items, L_TYPE,
|
||||
type_vals[find_list_type(new_text)], -1);
|
||||
gtk_list_store_set(ima->store, &cur_items, cur_column, new_text, -1);
|
||||
break;
|
||||
case L_VAL: // key value was changed
|
||||
textptr = g_strdup_printf("%s", new_text);
|
||||
nxtcol = try_change_val(ima, &textptr); // try to change parameter according to its type
|
||||
g_free(textptr);
|
||||
break;
|
||||
default:
|
||||
gtk_list_store_set(ima->store, &cur_items, cur_column, new_text, -1);
|
||||
break;
|
||||
}
|
||||
if(nxtcol){
|
||||
if(cur_column < L_COMM) // it's not a last column - select next
|
||||
cur_column++;
|
||||
else{
|
||||
cur_column = 0;
|
||||
editable = FALSE;
|
||||
}
|
||||
}
|
||||
DBG("set cursor col:%d, e=%d", cur_column, editable);
|
||||
gtk_tree_view_set_cursor(Tree,
|
||||
gtk_tree_model_get_path(GTK_TREE_MODEL(ima->store), &cur_items),
|
||||
gtk_tree_view_get_column(Tree, cur_column), editable);
|
||||
DBG("ret");
|
||||
}
|
||||
/*
|
||||
void cancel_edit(GtkCellRenderer *renderer){
|
||||
cur_column = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(renderer), "column_num"));
|
||||
gtk_tree_view_set_cursor(Tree,
|
||||
gtk_tree_model_get_path(GTK_TREE_MODEL(store), &cur_items),
|
||||
gtk_tree_view_get_column(Tree, cur_column), FALSE);
|
||||
}
|
||||
*/
|
||||
void add_key( IMAGE *ima,
|
||||
gchar *keytype, gchar *keyname, gchar *keyval,
|
||||
gchar *keycomment, int keyfitstype){
|
||||
GtkTreeIter iter;
|
||||
//~ FNAME();
|
||||
gtk_list_store_append(ima->store, &iter);
|
||||
gtk_list_store_set(ima->store, &iter,
|
||||
L_TYPENM, keytype,
|
||||
L_KEY, keyname,
|
||||
L_VAL, keyval,
|
||||
L_COMM, keycomment,
|
||||
L_TYPE, keyfitstype,
|
||||
-1);// the last element must be -1
|
||||
}
|
||||
|
||||
void init_keylist(IMAGE *ima){
|
||||
/* Create a list model.
|
||||
* We will have 4 columns: name of key type, key name, key value, comment, type
|
||||
*/
|
||||
if(ima->store) g_object_unref(G_OBJECT(ima->store)); // clear list, if it already exists
|
||||
ima->store = gtk_list_store_new(L_MAX, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
|
||||
}
|
||||
|
||||
GtkWidget *create_treeview(IMAGE *ima){
|
||||
int i, i_max = sizeof(key_types)/sizeof(char*);;
|
||||
GtkTreeIter iter;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
if(combo_)
|
||||
gtk_list_store_clear(combo_);
|
||||
combo_ = gtk_list_store_new(1, G_TYPE_STRING);
|
||||
for(i = 0; i < i_max; i++){
|
||||
gtk_list_store_append(combo_, &iter);
|
||||
gtk_list_store_set(combo_, &iter, 0, key_types[i], -1);
|
||||
}
|
||||
// create list (treeview) according model store
|
||||
Tree = (GtkTreeView*)gtk_tree_view_new_with_model(GTK_TREE_MODEL(ima->store));
|
||||
// Create columns in list
|
||||
for(i = 0; i < VISIBLE_COLS; i++){
|
||||
if(i == 0){
|
||||
renderer = gtk_cell_renderer_combo_new();
|
||||
g_object_set(renderer, "text-column", 0,
|
||||
"editable", TRUE, "has-entry", FALSE, "model",
|
||||
GTK_TREE_MODEL(combo_), NULL);
|
||||
}
|
||||
else{
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
g_object_set(renderer, "editable", TRUE, NULL);
|
||||
}
|
||||
g_object_set_data(G_OBJECT(renderer), "column_num", GINT_TO_POINTER(i));
|
||||
column = gtk_tree_view_column_new_with_attributes(_(colnames[i]),
|
||||
renderer, "text", i, NULL);
|
||||
gtk_tree_view_append_column(Tree, column); // insert column
|
||||
gtk_tree_view_column_set_sort_column_id(column, i);// it may be sorted
|
||||
g_signal_connect(renderer, "edited", G_CALLBACK(edit_cell), ima);
|
||||
// g_signal_connect(renderer, "editing-canceled", G_CALLBACK(cancel_edit), NULL);
|
||||
}
|
||||
/*
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes ("hidden",renderer, NULL);
|
||||
g_object_set(column, "visible", FALSE, NULL);
|
||||
gtk_tree_view_append_column(Tree, column);
|
||||
*/
|
||||
return GTK_WIDGET(Tree);
|
||||
}
|
||||
|
||||
static void list_changed(GtkTreeSelection *sel){
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter cur_items;
|
||||
if(gtk_tree_selection_get_selected(sel,&model, &cur_items))
|
||||
gtk_widget_set_sensitive(del_button, TRUE);
|
||||
else
|
||||
gtk_widget_set_sensitive(del_button, FALSE);
|
||||
/*
|
||||
GtkTreeModel *model;
|
||||
FNAME();
|
||||
gboolean showdel = FALSE;
|
||||
if(!GTK_IS_TREE_SELECTION(sel)){
|
||||
showdel = TRUE;
|
||||
if(GTK_IS_TREE_SELECTION(obj)) DBG("!!!");
|
||||
cur_column = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(sel), "column_num"));
|
||||
DBG("curcol: %d", cur_column);
|
||||
}
|
||||
else if(gtk_tree_selection_get_selected(sel,&model, &cur_items)){
|
||||
gint column = L_VAL;
|
||||
gchar *value;
|
||||
gtk_tree_model_get(model, &cur_items, column, &value, -1);
|
||||
DBG("selected: %s", value);
|
||||
gtk_tree_view_set_cursor(Tree,
|
||||
gtk_tree_model_get_path(model, &cur_items),
|
||||
gtk_tree_view_get_column(Tree, cur_column), FALSE);
|
||||
g_free(value);
|
||||
showdel = TRUE;
|
||||
}
|
||||
gtk_widget_set_sensitive(del_button, showdel);
|
||||
DBG("ret");*/
|
||||
}
|
||||
|
||||
void newline(IMAGE *ima){
|
||||
FNAME();
|
||||
GtkTreeIter cur_items;
|
||||
gtk_list_store_append(ima->store, &cur_items);
|
||||
gtk_list_store_set(ima->store, &cur_items,
|
||||
L_TYPENM, key_types[0],
|
||||
L_KEY, "NEW_KEY",
|
||||
L_VAL, "",
|
||||
L_COMM, "",
|
||||
L_TYPE, type_vals[0],
|
||||
-1);
|
||||
// Set cursor onto a first field
|
||||
gtk_tree_view_set_cursor(Tree,
|
||||
gtk_tree_model_get_path(GTK_TREE_MODEL(ima->store), &cur_items),
|
||||
gtk_tree_view_get_column(Tree, 0), TRUE);
|
||||
DBG("ret");
|
||||
}
|
||||
|
||||
gboolean del_line(IMAGE *ima){
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model = GTK_TREE_MODEL(ima->store);
|
||||
gboolean ret = FALSE;
|
||||
FNAME();
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(Tree);
|
||||
GtkTreePath *path;
|
||||
if(gtk_tree_selection_get_selected(selection, NULL, &iter)){
|
||||
path = gtk_tree_model_get_path(model, &iter);
|
||||
ret = gtk_list_store_remove(ima->store, &iter);
|
||||
// check wherher &cur_items was last
|
||||
if(gtk_list_store_iter_is_valid(ima->store, &iter)){
|
||||
gtk_tree_path_free(path);
|
||||
path = gtk_tree_model_get_path(model, &iter);
|
||||
}
|
||||
else gtk_tree_path_prev(path); // goto previous
|
||||
if(path && gtk_tree_model_get_iter_first(model, &iter))
|
||||
gtk_tree_view_set_cursor(Tree, path, NULL, FALSE);
|
||||
else DBG("No entries");
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
DBG("ret");
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
void show_menu(){
|
||||
GtkWidget *menu, *menuitem;
|
||||
gchar *text;
|
||||
int i;
|
||||
menu = gtk_menu_new();
|
||||
for(i = 0; i < 10; i++){
|
||||
text = g_strdup_printf("%d", i);
|
||||
menuitem = gtk_menu_item_new_with_label(text);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||
gtk_widget_show(menuitem);
|
||||
g_free(text);
|
||||
}
|
||||
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, 0);
|
||||
}
|
||||
|
||||
gboolean treeview_button_press_cb(GtkWidget *wi, GdkEventButton *ev, gpointer user_data)
|
||||
{
|
||||
GtkTreeSelection *sel;
|
||||
GtkTreeModel *model;
|
||||
GtkTreePath *path, *oldpath;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeIter iter;
|
||||
gchar *colname;
|
||||
|
||||
// if there's no path where the click occurred...
|
||||
if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(wi), ev->x, ev->y, &path, &column, NULL, NULL))
|
||||
return FALSE; // ...return FALSE to allow the event to continue
|
||||
colname = strdup(gtk_tree_view_column_get_title(column));
|
||||
// get the tree view's selection
|
||||
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(wi));
|
||||
|
||||
switch(ev->button)
|
||||
{
|
||||
// LMB
|
||||
case 1:
|
||||
// check to see if this is already the selected path
|
||||
if(gtk_tree_selection_get_selected(sel, &model, &iter))
|
||||
{
|
||||
oldpath = gtk_tree_model_get_path(model, &iter);
|
||||
if(gtk_tree_path_compare(oldpath, path) == 0)
|
||||
{
|
||||
gtk_tree_path_free(oldpath);
|
||||
gtk_tree_path_free(path);
|
||||
return FALSE;
|
||||
}
|
||||
gtk_tree_path_free(oldpath);
|
||||
}
|
||||
|
||||
// select the clicked path
|
||||
gtk_tree_selection_select_path(sel, path);
|
||||
return TRUE;
|
||||
// RMB
|
||||
case 3:
|
||||
if(strncmp(colname, "No.", 3)){
|
||||
gtk_tree_path_free(path);
|
||||
return TRUE;
|
||||
}
|
||||
show_menu();
|
||||
// gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, ev->time);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// free our path
|
||||
gtk_tree_path_free(path);
|
||||
|
||||
return FALSE; // allow it to continue
|
||||
}
|
||||
*/
|
||||
|
||||
void close_dlg(){
|
||||
gtk_widget_destroy(window);
|
||||
}
|
||||
|
||||
static gboolean press_key(IMAGE *ima, GdkEventKey * event){
|
||||
gboolean ret = FALSE;
|
||||
if(event->state & (GDK_CONTROL_MASK)){
|
||||
switch(event->keyval){
|
||||
// ctrl+n inserts a line
|
||||
case 'n': case 'N':
|
||||
newline(ima);
|
||||
ret = TRUE;
|
||||
break;
|
||||
// ctrl+d deletes current line
|
||||
case 'd': case 'D':
|
||||
ret = del_line(ima);
|
||||
break;
|
||||
// ctrl+w closes the window
|
||||
case 'w': case 'W':
|
||||
close_dlg();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void edit_headers(Window *parent){
|
||||
VALS_N = sizeof(key_types) / sizeof(gchar *);
|
||||
GtkWidget *treeview, *vbox, *hbox, *button;
|
||||
if(!parent->image || !parent->image->store){
|
||||
g_err(_("Open fits file first"));
|
||||
return;
|
||||
}
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "List");
|
||||
gtk_signal_connect(GTK_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(gtk_false),NULL);
|
||||
gtk_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(close_dlg), NULL);
|
||||
treeview = create_treeview(parent->image);
|
||||
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(list_changed), NULL);
|
||||
//g_signal_connect(G_OBJECT(treeview), "cursor-changed", G_CALLBACK(list_changed), NULL);
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 5);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(sw), treeview);
|
||||
gtk_window_set_default_size(GTK_WINDOW (window), 640, 480);
|
||||
|
||||
//~ gtk_box_pack_start(GTK_BOX(vbox), treeview, TRUE, TRUE, 0);
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
|
||||
button = gtk_button_new_with_label(_("New entry (ctrl+n)"));
|
||||
g_signal_connect_swapped(G_OBJECT(button), "clicked",
|
||||
G_CALLBACK(newline), parent->image);
|
||||
gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
||||
|
||||
del_button = gtk_button_new_with_label(_("Delete entry (ctrl+d)"));
|
||||
g_signal_connect_swapped(G_OBJECT(del_button), "clicked",
|
||||
G_CALLBACK(del_line), parent->image);
|
||||
gtk_box_pack_end(GTK_BOX(hbox), del_button, FALSE, FALSE, 0);
|
||||
gtk_widget_set_sensitive(del_button, FALSE);
|
||||
|
||||
button = gtk_button_new_with_label(_("Close (ctrl+w)"));
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(close_dlg), NULL);
|
||||
gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
||||
g_signal_connect_swapped(G_OBJECT(window), "key-press-event",
|
||||
G_CALLBACK(press_key), parent->image);
|
||||
run_modal_window(GTK_WINDOW(window), parent);
|
||||
}
|
||||
BIN
src/fitsview
Executable file
BIN
src/fitsview
Executable file
Binary file not shown.
123
src/fitsview.c
Normal file
123
src/fitsview.c
Normal file
@ -0,0 +1,123 @@
|
||||
// fitsview.c - main project file
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "fitsview.h"
|
||||
#include "fits.h"
|
||||
#include "gtk.h"
|
||||
#include "opengl.h"
|
||||
#include "open_dialog.h"
|
||||
#include "filelist.h"
|
||||
|
||||
#define RED "\033[1;31;40m"
|
||||
#define GREEN "\033[1;32;40m"
|
||||
#define OLDCOLOR "\033[0;0;0m"
|
||||
|
||||
int (*red)(const char *fmt, ...);
|
||||
int (*green)(const char *fmt, ...);
|
||||
|
||||
int r_pr_(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
printf(RED);
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf(OLDCOLOR "\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
int g_pr_(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
printf(GREEN);
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf(OLDCOLOR "\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
Global_context *Global;
|
||||
|
||||
// init structures with zeros
|
||||
void *init_struct(int size){
|
||||
int8_t *ptr = calloc(1, size);
|
||||
return (void*) ptr;
|
||||
}
|
||||
// copy structure
|
||||
void *copy_struct(void *src, int size){
|
||||
int8_t *ptr = calloc(1, size);
|
||||
memcpy(ptr, src, size);
|
||||
return (void*)ptr;
|
||||
}
|
||||
|
||||
// current time (for random number generator initialisation & for debug purposes)
|
||||
double dtime(){
|
||||
double t;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
t = tv.tv_sec + ((double)tv.tv_usec)/1e6;
|
||||
return t;
|
||||
}
|
||||
|
||||
// if we'll save preferences global context should be read fom file
|
||||
void init_contexts(){
|
||||
// limit spot size
|
||||
Global->maxSpotH = 100;
|
||||
Global->minSpotH = 5;
|
||||
Global->maxSpotW = 100;
|
||||
Global->minSpotW = 5;
|
||||
}
|
||||
|
||||
// here will be a function to process command line arguments
|
||||
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
gchar *filename = NULL, *str;
|
||||
if(isatty(STDOUT_FILENO)){ // make color output in tty
|
||||
red = r_pr_; green = g_pr_;
|
||||
}else{ // no colors in case of pipe
|
||||
red = printf; green = printf;
|
||||
}
|
||||
#ifdef CUDA_FOUND
|
||||
DBG("CUDA found");
|
||||
#else
|
||||
DBG("CUDA not found, using CPU instead");
|
||||
#endif
|
||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
||||
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain(GETTEXT_PACKAGE);
|
||||
INIT(Global, Global_context);
|
||||
init_contexts();
|
||||
init_main_window(&argc, &argv);
|
||||
getGLinfo(mainWindow->drawingArea);
|
||||
setlocale(LC_NUMERIC, "C"); // for right strto[df] working
|
||||
// Show all for begin
|
||||
mainWindow->context->visualMode = SHOW_ALL;
|
||||
mainWindow->image->data = NULL;
|
||||
if(argc > 1){
|
||||
str = basename(argv[1]);
|
||||
saved_path = get_current_dir_name();
|
||||
filename = g_strdup_printf("%s/%s", saved_path, str);
|
||||
fill_filelist(filename, mainWindow);
|
||||
change_image(filename, mainWindow);
|
||||
g_free(filename);
|
||||
}else
|
||||
gen_texture(mainWindow->image, mainWindow, FALSE);
|
||||
gtk_main();
|
||||
return 0;
|
||||
}
|
||||
1358
src/fitsview.glade
Normal file
1358
src/fitsview.glade
Normal file
File diff suppressed because it is too large
Load Diff
1281
src/fitsview.ui
Normal file
1281
src/fitsview.ui
Normal file
File diff suppressed because it is too large
Load Diff
378
src/gauss.c
Normal file
378
src/gauss.c
Normal file
@ -0,0 +1,378 @@
|
||||
// gauss.c - funtions for gaussian approximation
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "gtk.h"
|
||||
#include "gauss.h"
|
||||
#ifdef GSL_FOUND // cmake found GSL library
|
||||
#include <gsl/gsl_rng.h>
|
||||
#include <gsl/gsl_randist.h>
|
||||
#include <gsl/gsl_vector.h>
|
||||
#include <gsl/gsl_blas.h>
|
||||
#include <gsl/gsl_multifit_nlin.h>
|
||||
|
||||
|
||||
#undef DBG
|
||||
#undef EBUG
|
||||
#define DBG(...)
|
||||
|
||||
|
||||
/*
|
||||
* Returns value of gaussian value in point x
|
||||
* x0, C, A, sigma - are parameters (middle, vertical shift, amplitude and std)
|
||||
*/
|
||||
double gaussian_pt(double C, double A, double sigma, double x0, double x){
|
||||
double s2 = sigma*sigma;
|
||||
double ss = A/sqrt(2*M_PI*s2);
|
||||
double E = x-x0;
|
||||
return C + ss*exp(-E*E/2/s2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills the ordinates of structure Points by Gaussian
|
||||
* (Abscissa does not move, so that this structure can be used
|
||||
* for multiple rendering of the same area but with different
|
||||
* parameters)
|
||||
*/
|
||||
void gaussian_v(double C, double A, double sigma, double x0, Points *pts){
|
||||
int i, n = pts->n;
|
||||
Point *pt = pts->data;
|
||||
double s2 = sigma*sigma * 2;
|
||||
double ss = A/sqrt(2*M_PI*s2);
|
||||
double E;
|
||||
for(i = 0; i < n; i++, pt++){
|
||||
E = pt->x - x0;
|
||||
pt->y = C + ss*exp(-E*E/s2);
|
||||
//DBG("pt %d (%g, %g)", i, pt->x, pt->y);
|
||||
}
|
||||
}
|
||||
|
||||
int gauss_f(const gsl_vector *parms, void *data, gsl_vector *f){
|
||||
size_t n = ((struct data *)data)->n;
|
||||
double *x = ((struct data *)data)->x;
|
||||
double *y = ((struct data *)data)->y;
|
||||
double *dy = ((struct data *)data)->dy;
|
||||
double x0 = gsl_vector_get(parms, 3);
|
||||
double sigma = gsl_vector_get(parms, 2);
|
||||
double A = gsl_vector_get(parms, 1) * 0.65; // without 0.65 A would be wrong (WTF?)
|
||||
double C = gsl_vector_get(parms, 0);
|
||||
size_t i;
|
||||
double mul = A/fabs(sigma)/sqrt(2.*M_PI);
|
||||
for (i = 0; i < n; i++){
|
||||
/* Model Yi = C + A/sqrt(2*pi*sigma^2) * exp(-(x-b)^2/2/sigma^2) */
|
||||
double E = (x[i]-x0)/sigma;
|
||||
double Yi = C + mul * exp(-E * E/2.);
|
||||
gsl_vector_set(f, i, (Yi - y[i])/dy[i]);
|
||||
}
|
||||
return GSL_SUCCESS;
|
||||
}
|
||||
|
||||
int gauss_df(const gsl_vector *parms, void *data, gsl_matrix *J){
|
||||
size_t n = ((struct data *)data)->n;
|
||||
double *x = ((struct data *)data)->x;
|
||||
double *dy = ((struct data *) data)->dy;
|
||||
double A = gsl_vector_get(parms, 1);
|
||||
double sigma = gsl_vector_get(parms, 2);
|
||||
double x0 = gsl_vector_get(parms, 3);
|
||||
double S2PI = 1. / sqrt(2.*M_PI);
|
||||
size_t i;
|
||||
for(i = 0; i < n; i++){
|
||||
/* Jacobian matrix J(i,j) = dfi / dxj, */
|
||||
/* and the xj are the parameters (C, A,sigma,x0) */
|
||||
double s = dy[i];
|
||||
double xbs = (x[i]-x0)/sigma;
|
||||
double y = exp(-xbs*xbs/2.) *S2PI / fabs(sigma) / s;
|
||||
double Ays = A*y/sigma;
|
||||
// df/dx0 = f * (x-x0)/sigma^2
|
||||
gsl_matrix_set(J, i, 3, Ays*xbs);
|
||||
// df/dsigma = -f(1-(x-x0)^2/sigma^2)/sigma
|
||||
gsl_matrix_set(J, i, 2, Ays*(xbs*xbs-1.));
|
||||
gsl_matrix_set(J, i, 1, y); // df/dA
|
||||
gsl_matrix_set(J, i, 0, 1. / s); // df/dC
|
||||
}
|
||||
return GSL_SUCCESS;
|
||||
}
|
||||
|
||||
int gauss_fdf(const gsl_vector *parms, void *data, gsl_vector *f, gsl_matrix *J){
|
||||
gauss_f(parms, data, f);
|
||||
gauss_df(parms, data, J);
|
||||
return GSL_SUCCESS;
|
||||
}
|
||||
|
||||
// pseudorandom numbers generator initialisation
|
||||
void urandom_ini(){
|
||||
double tt = dtime() * 1e6;
|
||||
double mx = (double)LONG_MAX;
|
||||
srand48((long)(tt - mx * floor(tt/mx)));
|
||||
}
|
||||
|
||||
|
||||
#define FIT(i) gsl_vector_get(s->x, i)
|
||||
#define ERR(i) sqrt(gsl_matrix_get(covar,i,i))
|
||||
#define FN(i) gsl_vector_get(s->f, i)
|
||||
/*
|
||||
* Gaussian parameters calculation y=A/sqrt(2*pi*sigma^2) exp(-(x-x_0)^2/2/sigma^2),
|
||||
* which approximates the points set pts
|
||||
* Parameters A_, sigma_, x0_ may be NULL (if you don't need any of them)
|
||||
*/
|
||||
void gauss_fit(Points *pts, double *C_, double *A_, double *sigma_, double *x0_){
|
||||
// VVVV lower parameters may be formed as a structure to change as function argument
|
||||
double
|
||||
epsabs = 1e-8,// absolute error
|
||||
epsrel = 1e-5,// relative error
|
||||
chi_max = 0.01;// max chi value for iterations criteria
|
||||
int max_iter = 300; // limit iterations number of gsl_multifit_fdfsolver
|
||||
size_t N_MIN = 10; // minimum points for approximation
|
||||
double x_init[4];
|
||||
// AAAA upper parameters may be formed as a structure to change as function argument
|
||||
/* x_init, the best approximations:
|
||||
* x0 - not far from real (the nearest is the better)
|
||||
* sigma - not far from real (the nearest is the better)
|
||||
* A - not large ~10 (it has a weak effect)
|
||||
*/
|
||||
const gsl_multifit_fdfsolver_type *T;
|
||||
gsl_multifit_fdfsolver *s;
|
||||
int status;
|
||||
#ifdef EBUG
|
||||
int appNo = 0;
|
||||
#endif
|
||||
int iter;
|
||||
size_t i, j, n = pts->n, oldn;
|
||||
const size_t p = 4;
|
||||
gsl_matrix *covar = gsl_matrix_alloc (p, p);
|
||||
#ifdef EBUG
|
||||
double t0;
|
||||
#endif
|
||||
double *x, *y, *dy, chi, C, A, sigma, x0;
|
||||
if(n < 1) return;
|
||||
x = malloc(n * sizeof(double));
|
||||
y = malloc(n * sizeof(double));
|
||||
dy = malloc(n * sizeof(double));
|
||||
struct data d = {n, x, y, dy};
|
||||
gsl_multifit_function_fdf f;
|
||||
gsl_vector_view xx = gsl_vector_view_array(x_init, p);
|
||||
const gsl_rng_type *type;
|
||||
gsl_rng *r;
|
||||
|
||||
gsl_rng_env_setup();
|
||||
type = gsl_rng_default;
|
||||
r = gsl_rng_alloc (type);
|
||||
f.f = &gauss_f;
|
||||
f.df = &gauss_df;
|
||||
f.fdf = &gauss_fdf;
|
||||
f.n = n;
|
||||
f.p = p;
|
||||
f.params = &d;
|
||||
// fill data structure. Don't forget Okkam's razor!!!
|
||||
{
|
||||
Point *pt = pts->data;
|
||||
double *px = x, *py = y, *pdy = dy, sum = 0.;
|
||||
for(i = 0; i < n; i++, pt++){
|
||||
*pdy++ = 1.; // I have no idea what is it, so init by 1
|
||||
*px++ = pt->x;
|
||||
*py++ = pt->y;
|
||||
sum += pt->y;
|
||||
//DBG("point %d: (%g, %g)", i, pt->x, pt->y);
|
||||
}
|
||||
// fill x_init: x0, sigma, C, A (it can be a funtion parameter)
|
||||
x_init[3] = (*(--px) + *x) / 2.;
|
||||
x_init[2] = fabs((*x - *px) / 4.);
|
||||
x_init[0] = sum/(double)n;
|
||||
x_init[1] = sum;
|
||||
DBG("\nInitial parameters: x0=%.1f, sigma=%.1f, A=%.1f, C=%.1f",
|
||||
x_init[3], x_init[2], x_init[1], x_init[0]);
|
||||
}
|
||||
T = gsl_multifit_fdfsolver_lmder; // or also gsl_multifit_fdfsolver_lmsder
|
||||
s = gsl_multifit_fdfsolver_alloc(T, n, p);
|
||||
#ifdef EBUG
|
||||
t0 = dtime();
|
||||
#endif
|
||||
do{
|
||||
double dof, tres, c;
|
||||
DBG("\n************ Approximation %d ******************\n", appNo++);
|
||||
iter = 0;
|
||||
gsl_multifit_fdfsolver_set(s, &f, &xx.vector);
|
||||
do{
|
||||
iter++;
|
||||
status = gsl_multifit_fdfsolver_iterate(s);
|
||||
if(status)
|
||||
break;
|
||||
status = gsl_multifit_test_delta(s->dx, s->x, epsabs, epsrel);
|
||||
}while(status == GSL_CONTINUE && iter < max_iter);
|
||||
DBG("time=%g\n", dtime()-t0);
|
||||
gsl_multifit_covar(s->J, 0.0, covar);
|
||||
chi = gsl_blas_dnrm2(s->f);
|
||||
dof = n - p;
|
||||
tres = chi;
|
||||
c = chi / sqrt(dof); // GSL_MAX_DBL(1., chi / sqrt(dof));
|
||||
C = FIT(0), A = FIT(1), sigma = FIT(2), x0 = FIT(3);
|
||||
DBG("Number of iteratons = %d\n", iter);
|
||||
DBG("chi = %g, chi/dof = %g\n", chi, chi / sqrt(dof));
|
||||
DBG("C = %.5f +/- %.5f\n", C, c*ERR(0));
|
||||
DBG("A = %.5f +/- %.5f\n", A, c*ERR(1));
|
||||
DBG("sigma = %.5f +/- %.5f\n", sigma, c*ERR(2));
|
||||
DBG("x0 = %.5f +/- %.5f\n", x0, c*ERR(3));
|
||||
j = 0;
|
||||
oldn = n;
|
||||
if(c < chi_max) break;
|
||||
// throw out bad (by chi) data
|
||||
for(i = 0; i < n; i++){
|
||||
if(fabs(FN(i)) < tres){
|
||||
if(i != j){
|
||||
x[j] = x[i];
|
||||
y[j] = y[i];
|
||||
dy[j] = dy[i];
|
||||
}
|
||||
j++; continue;
|
||||
}
|
||||
}
|
||||
if(j != n){
|
||||
DBG("Chi tresholding %g, %zd points of %zd\n", tres, j, n);
|
||||
n = j;
|
||||
d.n = n;
|
||||
}
|
||||
}while(chi > chi_max && n != oldn && n > N_MIN);
|
||||
if(C_) *C_ = C;
|
||||
if(A_) *A_ = A;
|
||||
if(sigma_) *sigma_ = sigma;
|
||||
if(x0_) *x0_ = x0;
|
||||
//printf ("status = %s\n", gsl_strerror (status));
|
||||
gsl_multifit_fdfsolver_free(s);
|
||||
gsl_matrix_free(covar);
|
||||
gsl_rng_free(r);
|
||||
free(x); free(y); free(dy);
|
||||
}
|
||||
/*
|
||||
int circle_f(const gsl_vector *parms, void *data, gsl_vector *f){
|
||||
size_t n = ((struct data *)data)->n;
|
||||
double *x = ((struct data *)data)->x;
|
||||
double *y = ((struct data *)data)->y;
|
||||
//double *dy = ((struct data *)data)->dy;
|
||||
double X = gsl_vector_get(parms, 0);
|
||||
double Y = gsl_vector_get(parms, 1);
|
||||
double R = gsl_vector_get(parms, 2);
|
||||
double sign, Yi, DX;
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++){
|
||||
sign = (y[i] > Y) ? 1. : -1.;
|
||||
DX = x[i] - X;
|
||||
// Model Yi = Yc +- sqrt[R^2-(x-Xc)^2]
|
||||
Yi = Y + sign * sqrt(R*R - DX*DX);
|
||||
gsl_vector_set(f, i, (Yi - y[i]));
|
||||
}
|
||||
return GSL_SUCCESS;
|
||||
}
|
||||
|
||||
int circle_df(const gsl_vector *parms, void *data, gsl_matrix *J){
|
||||
size_t n = ((struct data *)data)->n;
|
||||
double *x = ((struct data *)data)->x;
|
||||
double *y = ((struct data *)data)->y;
|
||||
//double *dy = ((struct data *)data)->dy;
|
||||
double X = gsl_vector_get(parms, 0);
|
||||
double Y = gsl_vector_get(parms, 1);
|
||||
double R = gsl_vector_get(parms, 2);
|
||||
double sign, Yi, DX;
|
||||
size_t i;
|
||||
for(i = 0; i < n; i++){
|
||||
// Jacobian matrix J(i,j) = dfi / dxj,
|
||||
// and the xj are the parameters (Xc, Yc, R)
|
||||
DX = x[i] - X;
|
||||
sign = (y[i] > Y) ? 1. : -1.;
|
||||
Yi = sign / sqrt(R*R - DX*DX);
|
||||
gsl_matrix_set(J, i, 2, R*Yi); // df/dR
|
||||
gsl_matrix_set(J, i, 1, 1.); // df/dYc
|
||||
gsl_matrix_set(J, i, 0, DX * Yi); // df/dXc
|
||||
}
|
||||
return GSL_SUCCESS;
|
||||
}
|
||||
|
||||
int circle_fdf(const gsl_vector *parms, void *data, gsl_vector *f, gsl_matrix *J){
|
||||
circle_f(parms, data, f);
|
||||
circle_df(parms, data, J);
|
||||
return GSL_SUCCESS;
|
||||
}
|
||||
|
||||
void circle_fit(struct data *d, double *Xcenter,
|
||||
double *Ycenter, double *Radius){
|
||||
double
|
||||
epsabs = 1e-8,
|
||||
epsrel = 1e-5;
|
||||
int max_iter = 30;
|
||||
double x_init[3], c, chi;
|
||||
const gsl_multifit_fdfsolver_type *T;
|
||||
gsl_multifit_fdfsolver *s;
|
||||
int status;
|
||||
int iter = 0;
|
||||
size_t n = d->n;
|
||||
const size_t p = 3;
|
||||
FNAME();
|
||||
gsl_matrix *covar = gsl_matrix_alloc (p, p);
|
||||
gsl_multifit_function_fdf f;
|
||||
gsl_vector_view xx = gsl_vector_view_array(x_init, p);
|
||||
const gsl_rng_type *type;
|
||||
gsl_rng *r;
|
||||
gsl_rng_env_setup();
|
||||
type = gsl_rng_default;
|
||||
r = gsl_rng_alloc(type);
|
||||
f.f = &circle_f;
|
||||
f.df = &circle_df;
|
||||
f.fdf = &circle_fdf;
|
||||
f.n = n;
|
||||
f.p = p;
|
||||
f.params = d;
|
||||
T = gsl_multifit_fdfsolver_lmder;
|
||||
s = gsl_multifit_fdfsolver_alloc(T, n, p);
|
||||
gsl_multifit_fdfsolver_set(s, &f, &xx.vector);
|
||||
x_init[0] = *Xcenter;
|
||||
x_init[1] = *Ycenter;
|
||||
x_init[2] = *Radius;
|
||||
do{
|
||||
iter++;
|
||||
status = gsl_multifit_fdfsolver_iterate(s);
|
||||
if(status) break;
|
||||
DBG("iter %d", iter);
|
||||
status = gsl_multifit_test_delta(s->dx, s->x, epsabs, epsrel);
|
||||
}while(status == GSL_CONTINUE && iter < max_iter);
|
||||
DBG("iter end");
|
||||
gsl_multifit_covar(s->J, 0.0, covar);
|
||||
chi = gsl_blas_dnrm2(s->f);
|
||||
c = chi / sqrt((double)(n - p));
|
||||
*Xcenter = FIT(0);
|
||||
*Ycenter = FIT(1);
|
||||
*Radius = FIT(2);
|
||||
DBG("Number of iteratons = %d\n", iter);
|
||||
DBG("chi = %g, chi/dof = %g\n", chi, c);
|
||||
DBG("Xc = %.5f +/- %.5f\n", *Xcenter, c*ERR(0));
|
||||
DBG("Yc = %.5f +/- %.5f\n", *Ycenter, c*ERR(1));
|
||||
DBG("R = %.5f +/- %.5f\n", *Radius, c*ERR(2));
|
||||
gsl_multifit_fdfsolver_free(s);
|
||||
gsl_matrix_free(covar);
|
||||
gsl_rng_free(r);
|
||||
}
|
||||
*/
|
||||
|
||||
#else // GSL not found
|
||||
|
||||
//double gaussian_pt(double C, double A, double sigma, double x0, double x){
|
||||
// GSLERR; return A+C+sigma+x+x0;}
|
||||
void gaussian_v(double C __attribute__((unused)), double A __attribute__((unused)),
|
||||
double sigma __attribute__((unused)), double x0 __attribute__((unused)),
|
||||
Points *pts __attribute__((unused))){GSLERR;}
|
||||
void gauss_fit(Points *pts __attribute__((unused)), double *C_ __attribute__((unused)),
|
||||
double *A_ __attribute__((unused)), double *sigma_ __attribute__((unused)),
|
||||
double *x0_ __attribute__((unused))){ GSLERR;}
|
||||
#endif // GSL_FOUND
|
||||
638
src/imtools.c
Normal file
638
src/imtools.c
Normal file
@ -0,0 +1,638 @@
|
||||
// imtools.c - different image transforms
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "fitsheaders.h"
|
||||
#include "imtools.h"
|
||||
#include "contours.h"
|
||||
#include "opengl.h"
|
||||
#include "gauss.h"
|
||||
#include "CUtools.h"
|
||||
|
||||
// Histogram size, 256 by default
|
||||
const int HIST_SIZE = 256;
|
||||
const int MIN_SPOT_NO = 200; // minimum amount of spots on a hartmanogram
|
||||
const int MAX_SPOT_NO = 258; // max amount -//-
|
||||
|
||||
void destroy_image(IMAGE *image){
|
||||
if(!image) return;
|
||||
_FREE(image->data);
|
||||
g_free(image->filename);
|
||||
if(image->store) // clear parameters from FITS header
|
||||
gtk_list_store_clear(image->store);
|
||||
_FREE(image->cLevels); // isolines' intensity
|
||||
free_contours(image); // isolines itself
|
||||
_FREE(image);
|
||||
}
|
||||
|
||||
#ifdef LEPTONICA_FOUND
|
||||
/*
|
||||
* Convert an image ima (after tresholding)
|
||||
* into a pixmap for pixConnComp from leptonica
|
||||
*/
|
||||
PIX *conv_image2pix(IMAGE *ima){
|
||||
PIX *pixs;
|
||||
l_uint32 byte, *pptr;
|
||||
GLfloat *iptr, *idata;
|
||||
int w, h, wpl, i, j, k, N;
|
||||
w = ima->width;
|
||||
h = ima->height;
|
||||
pixs = pixCreate(w, h, 1);
|
||||
wpl = pixGetWpl(pixs);
|
||||
pptr = pixGetData(pixs);
|
||||
idata = ima->data;
|
||||
for(i = h - 1; i > -1; i--){ // lines cycle
|
||||
N = 0;
|
||||
iptr = &idata[i * w];
|
||||
for(j = 0; j < wpl; j++){ // cycle by 32 columns
|
||||
byte = 0;
|
||||
for(k = 0; k < 32; k++){ // cycle by a 32-bit word bits
|
||||
byte <<= 1;
|
||||
// if string still doesn't end & intensity higher 0.1%
|
||||
if(N++ < w && *iptr++ > 0.001)
|
||||
byte |= 1; // set lesser bit
|
||||
}
|
||||
*pptr++ = byte;
|
||||
}
|
||||
}
|
||||
return pixs;
|
||||
}
|
||||
|
||||
gboolean check_box(Window *window, BOX *box, int *X0, int *Y0, int *X, int *Y){
|
||||
if(!window->image->data) return FALSE;
|
||||
int WD = window->image->width, HT = window->image->height - 1;
|
||||
if(!(box && X0 && Y0 && X && Y)) return FALSE;
|
||||
*X0 = box->x;
|
||||
*Y0 = box->y;
|
||||
*X = *X0 + box->w;
|
||||
*Y = *Y0 + box->h; // coordinates of a box corners
|
||||
if(box->w < 5 || box->h < 5) return FALSE;
|
||||
if(*X0 < 0 || *X0 > WD || *X < 0 || *X > WD ||
|
||||
*Y0 < 0 || *Y0 > HT || *Y < 0 || *Y > HT)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//Calculation of min & max intensity by picture to show it
|
||||
void compute_minmax(IMAGE *ima){
|
||||
float min, max, *dst = ima->data;
|
||||
int i, j, w=ima->width, h=ima->height;
|
||||
max = min = *dst;
|
||||
for(i=0; i<h; i++)
|
||||
for(j=0; j<w; j++, dst++){
|
||||
float tmp = *dst;
|
||||
if(tmp > max) max = tmp;
|
||||
else if(tmp < min) min = tmp;
|
||||
}
|
||||
ima->stat.max = max;
|
||||
ima->stat.min = min;
|
||||
//ima->width = w; ima->height = h;
|
||||
DBG("stat: max=%.2f, min=%.2f", max, min);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculation of the center of box for image ima
|
||||
* by inscribing a Gaussian to a vector obtained
|
||||
* by addition of box columns (for X) and rows (for Y)
|
||||
*/
|
||||
gboolean get_gaussian_center(Window *window, BOX *box, Coordinates *crds){
|
||||
int WD = window->image->width, HT = window->image->height - 1;
|
||||
int x, y;
|
||||
GLfloat *data;
|
||||
Points row, col;
|
||||
Point *rptr, *cptr;
|
||||
double x0, sigma;
|
||||
int X0, Y0, X, Y;
|
||||
#ifndef GSL_FOUND
|
||||
return FALSE;
|
||||
#endif
|
||||
if(!check_box(window, box, &X0, &Y0, &X, &Y)) return FALSE;
|
||||
if(!crds) return FALSE;
|
||||
row.data = calloc(box->w, sizeof(Point));
|
||||
row.n = box->w;
|
||||
col.data = calloc(box->h, sizeof(Point));
|
||||
col.n = box->h;
|
||||
cptr = col.data;
|
||||
for(y = Y0; y < Y; y++, cptr++){
|
||||
data = &window->image->data[(HT - y) * WD + X0];
|
||||
cptr->x = (double)y;
|
||||
rptr = row.data;
|
||||
for(x = X0; x < X; x++, data++, rptr++){
|
||||
double d = (double) *data;
|
||||
rptr->y += d;
|
||||
cptr->y += d;
|
||||
}
|
||||
}
|
||||
rptr = row.data;
|
||||
for(x = X0; x < X; x++, rptr++) rptr->x = (double)x;
|
||||
// we inscribe Gaussian and change the the coordinates and half-widths of the spot
|
||||
gauss_fit(&row, NULL, NULL, &sigma, &x0);
|
||||
crds->x = x0; crds->rx = sigma;
|
||||
gauss_fit(&col, NULL, NULL, &sigma, &x0);
|
||||
crds->y = x0; crds->ry = sigma;
|
||||
_FREE(row.data); _FREE(col.data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// count of bits amount in word i
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
||||
// http://en.wikipedia.org/wiki/Hamming_weight
|
||||
int count_bits(l_uint32 i){
|
||||
i = i - ((i >> 1) & 0x55555555);
|
||||
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||||
return ((i + ((i >> 4) & 0xF0F0F0F)) * 0x1010101) >> 24;
|
||||
}
|
||||
|
||||
gboolean get_circle_center(Window *window, BOX *box, PIX *pix, Coordinates *crds){
|
||||
int WD = window->image->width, HT = window->image->height - 1;
|
||||
int N = 0, X0, Y0, X, Y, n;
|
||||
l_uint32 *pixdata, *pixptr;
|
||||
l_int32 w, h, d, wpl, sz, i, x, y;
|
||||
double Xcenter, Ycenter, Radius, xx, yy, Intens, X2, Y2;
|
||||
GLfloat *data;
|
||||
if(!check_box(window, box, &X0, &Y0, &X, &Y)) return FALSE;
|
||||
if(!(pix && crds)) return FALSE;
|
||||
pixGetDimensions(pix, &w, &h, &d);
|
||||
if(d != 1) return FALSE;
|
||||
wpl = pixGetWpl(pix);
|
||||
pixdata = pixGetData(pix);
|
||||
pixptr = pixdata;
|
||||
sz = wpl * h;
|
||||
for(i = 0; i < sz; i++) N += count_bits(*pixptr++);
|
||||
if(N < 200000) return FALSE;
|
||||
n = 0;
|
||||
Xcenter = (double)(X0 + X) / 2.;
|
||||
Ycenter = (double)(Y0 + Y) / 2.;
|
||||
Radius = (double)(w + h) / 4.;
|
||||
DBG("x0=%g, y0=%g, r0=%g, N=%d", Xcenter, Ycenter, Radius, N);
|
||||
Xcenter = Ycenter = X2 = Y2 = Intens = 0.;
|
||||
AxisX = 0.; AxisY = (double)HT;
|
||||
for(y = 0; y < h; y++){
|
||||
yy = (double)(HT - y - Y0);
|
||||
data = &window->image->data[(HT - y - Y0) * WD + X0];
|
||||
l_uint32 *line = pixdata + y * wpl;
|
||||
for(x = 0; x < w; x++, data++){
|
||||
if(GET_DATA_BIT(line, x)){
|
||||
double d = *data;
|
||||
xx= (X0 + x);
|
||||
n++;
|
||||
Intens += d;
|
||||
Xcenter += xx * d;
|
||||
Ycenter += yy * d;
|
||||
X2 += xx*xx*d;
|
||||
Y2 += yy*yy*d;
|
||||
}
|
||||
}
|
||||
}
|
||||
xx = Xcenter / Intens;
|
||||
yy = Ycenter / Intens;
|
||||
crds->x = xx;
|
||||
crds->y = yy;
|
||||
crds->rx= sqrt(X2 / Intens - xx*xx);
|
||||
crds->ry= sqrt(Y2 / Intens - yy*yy);
|
||||
DBG("xx: %g, yy: %g, rx:%g, ry: %g", xx, yy, crds->rx, crds->ry);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Detection of spots' center, yet lousy through gaussians
|
||||
void get_spots_coords(Window *window, IMAGE *ima){
|
||||
BOXA *boxa;
|
||||
BOX *box;
|
||||
PIX *pixs;
|
||||
Spot spot;
|
||||
Spots *spots;
|
||||
Coordinates scrds;
|
||||
int n, i, k;
|
||||
float xc, yc;
|
||||
if(!( /*(window->context->transformMask & TRANS_TRES) &&*/ window->image_transformed->data)){
|
||||
g_err(_("Define treshold limits first"));
|
||||
window->context->graphMode = GR_HISTOGRAM;
|
||||
show_histogram(window);
|
||||
return;
|
||||
}
|
||||
pixs = conv_image2pix(ima);
|
||||
boxa = pixConnComp(pixs, NULL, 8);
|
||||
n = boxaGetCount(boxa);
|
||||
red("Number of boxes: %d", n);
|
||||
spots_free(&window->spots);
|
||||
if(!(window->spots = spots_alloc(n))) return;
|
||||
spots = window->spots;
|
||||
#ifndef GSL_FOUND
|
||||
g_err(_("No GSL library found, don't calculate centroids"));
|
||||
#endif
|
||||
for(i = 0, k = 0; i < n; i++){
|
||||
if((box = boxaGetBox(boxa, i, L_CLONE)) == NULL){
|
||||
g_err(_("Box not found"));
|
||||
continue;
|
||||
}
|
||||
if( box->w < Global->minSpotW ||
|
||||
box->h < Global->minSpotH ||
|
||||
box->w > Global->maxSpotW ||
|
||||
box->h > Global->maxSpotH){
|
||||
boxDestroy(&box);
|
||||
continue;
|
||||
}
|
||||
if(!get_gaussian_center(window, box, &scrds)){
|
||||
scrds.rx = ((double)box->w-1.)/2.;
|
||||
scrds.ry = ((double)box->h-1.)/2.;
|
||||
xc = box->x + scrds.rx;
|
||||
yc = box->y + scrds.ry;
|
||||
scrds.x = xc; scrds.y = yc;
|
||||
}
|
||||
spot.c = scrds; spot.id = k++;
|
||||
spot.box.x = box->x;
|
||||
spot.box.y = box->y;
|
||||
spot.box.w = box->w;
|
||||
spot.box.h = box->h;
|
||||
spots_add(spots, &spot, BY_COPY);
|
||||
boxDestroy(&box);
|
||||
}
|
||||
red("Number of spots: %d", k);
|
||||
boxaDestroy(&boxa);
|
||||
gdk_window_invalidate_rect(window->drawingArea->window,
|
||||
&window->drawingArea->allocation, FALSE);
|
||||
DBG("return");
|
||||
}
|
||||
|
||||
void hartmann_spots(Window *window){ // 'r'
|
||||
Spots *spots = window->spots;
|
||||
if(!spots){
|
||||
g_err(_("Find spots first"));
|
||||
return;
|
||||
}
|
||||
int n = spots->n;
|
||||
if(n > MAX_SPOT_NO){
|
||||
g_err(_("Too many points"));
|
||||
return;
|
||||
}
|
||||
if(n < MIN_SPOT_NO){
|
||||
g_err(_("Not enough points"));
|
||||
return;
|
||||
}
|
||||
sort_spots(window);
|
||||
window->context->transformMask |= TRANS_HARTMANN; // points are sorted
|
||||
gdk_window_invalidate_rect(window->drawingArea->window,
|
||||
&window->drawingArea->allocation, FALSE);
|
||||
}
|
||||
|
||||
void get_circles_params(Window *window, IMAGE *ima){
|
||||
BOXA *boxa;
|
||||
PIXA *pixa;
|
||||
BOX *box;
|
||||
PIX *pixs, *pix;
|
||||
Spot spot;
|
||||
Coordinates scrds;
|
||||
Spots *spots;
|
||||
int n, i;
|
||||
if(!( (window->context->transformMask & TRANS_TRES) && window->image_transformed->data)){
|
||||
g_err(_("Define treshold limits first"));
|
||||
window->context->graphMode = GR_HISTOGRAM;
|
||||
show_histogram(window);
|
||||
return;
|
||||
}
|
||||
pixs = conv_image2pix(ima);
|
||||
|
||||
boxa = pixConnComp(pixs, &pixa, 8);
|
||||
n = boxaGetCount(boxa);
|
||||
|
||||
red("Number of boxes: %d", n);
|
||||
spots_free(&window->spots);
|
||||
if(!(window->spots = spots_alloc(n))) return;
|
||||
spots = window->spots;
|
||||
for(i = 0; i < n; i++){
|
||||
if((box = boxaGetBox(boxa, i, L_CLONE)) == NULL){
|
||||
g_err(_("Box not found"));
|
||||
continue;
|
||||
}
|
||||
if((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL){
|
||||
g_err(_("Pix not found"));
|
||||
continue;
|
||||
}
|
||||
if(get_circle_center(window, box, pix, &scrds)){
|
||||
spot.c = scrds; spot.id = i;
|
||||
spot.box.x = box->x;
|
||||
spot.box.y = box->y;
|
||||
spot.box.w = box->w;
|
||||
spot.box.h = box->h;
|
||||
spots_add(spots, &spot, BY_COPY);
|
||||
}
|
||||
boxDestroy(&box);
|
||||
}
|
||||
|
||||
boxaDestroy(&boxa);
|
||||
pixaDestroy(&pixa);
|
||||
|
||||
gdk_window_invalidate_rect(window->drawingArea->window,
|
||||
&window->drawingArea->allocation, FALSE);
|
||||
DBG("return");
|
||||
}
|
||||
#else // LEPTONICA_FOUND not defined
|
||||
void get_spots_coords(Window *window __attribute__((unused)),
|
||||
IMAGE *ima __attribute__((unused))){
|
||||
LEPTERR;
|
||||
}
|
||||
gboolean get_gaussian_center(Window *window __attribute__((unused)),
|
||||
BOX *box __attribute__((unused)), Coordinates *crds __attribute__((unused))){
|
||||
LEPTERR;
|
||||
return FALSE;
|
||||
}
|
||||
PIX *conv_image2pix(IMAGE *ima __attribute__((unused))){
|
||||
LEPTERR;
|
||||
return NULL;
|
||||
}
|
||||
void get_circles_params(Window *window __attribute__((unused)),
|
||||
IMAGE *ima __attribute__((unused))){
|
||||
LEPTERR;
|
||||
}
|
||||
#endif // LEPTONICA_FOUND
|
||||
|
||||
|
||||
/*
|
||||
* Build the histogram of picture ima
|
||||
* The default is 256 shades of gray
|
||||
*/
|
||||
gboolean make_histogram(IMAGE *ima){
|
||||
FNAME();
|
||||
ssize_t i, sz;
|
||||
int j, pt, *hdata, max, min; // hmax
|
||||
GLfloat *ptr, hsize, datamin = ima->stat.min, datawd = ima->stat.max - datamin;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
if(!ima->data){
|
||||
g_err(_("Image is empty"));
|
||||
return FALSE;
|
||||
}
|
||||
_FREE(ima->stat.histogram.data);
|
||||
// to change the size of the histogram replace HIST_SIZE by a variable value
|
||||
ima->stat.histogram.data = calloc(HIST_SIZE+1, sizeof(int));
|
||||
if(!ima->stat.histogram.data){
|
||||
g_err(_("Can't allocate memory for histogram"));
|
||||
return FALSE;
|
||||
}
|
||||
hdata = ima->stat.histogram.data;
|
||||
ima->stat.histogram.size = HIST_SIZE;
|
||||
hsize = (GLfloat) HIST_SIZE / datawd;
|
||||
ima->stat.histogram.scale = 1. / hsize;
|
||||
//hmax = HIST_SIZE - 1;
|
||||
ptr = ima->data;
|
||||
sz = (ssize_t)(ima->width) * (ssize_t)(ima->height);
|
||||
DBG("datamin=%g, hsize=%g, sz=%zd, scale=%g", datamin, hsize, sz, ima->stat.histogram.scale);
|
||||
#pragma omp parallel for private(i, pt) shared(hdata)
|
||||
for(i = 0; i < sz; i++){
|
||||
pt = (int)((ptr[i] - datamin) * hsize);
|
||||
#pragma omp atomic
|
||||
hdata[pt]++;
|
||||
}
|
||||
/* for(i = 0; i < sz; i++, ptr++){
|
||||
pt = (int)(*ptr * hsize);
|
||||
if(pt < 0) pt = 0;
|
||||
else if(pt > hmax) pt = hmax;
|
||||
hdata[pt]++;
|
||||
}*/
|
||||
max = min = hdata[0];
|
||||
for(j = 1; j < HIST_SIZE; j++){
|
||||
pt = hdata[j];
|
||||
if(max < pt) max = pt;
|
||||
else if(min > pt) min = pt;
|
||||
}
|
||||
ima->stat.histogram.max = max;
|
||||
ima->stat.histogram.min = min;
|
||||
ima->stat.histogram.bot_tres = -1.;
|
||||
ima->stat.histogram.top_tres = -1.;
|
||||
DBG("max: %d, min: %d; time: %g", max, min, dtime() - t0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the structure image_transformed by adjusted by the threshold values
|
||||
* Bottom - the lower bound, top - upper bound (in units of image intensity)
|
||||
* Brightness less than bottom, replaced by zero
|
||||
* Brightness larger than top, replaced by a unit
|
||||
* The rest - are calculated linearly (equalization histogram)
|
||||
*/
|
||||
void treshold_image(Window *window, GLfloat bottom, GLfloat top){
|
||||
FNAME();
|
||||
ssize_t i, sz;
|
||||
IMAGE *ima = window->image;
|
||||
IMAGE *i_new = window->image_transformed;
|
||||
GLfloat *p_old, *p_new, pt, wd;
|
||||
GLfloat scale = ima->stat.histogram.scale * (GLfloat)ima->stat.histogram.size;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
if(!(p_old = ima->data)){
|
||||
g_err(_("Image is empty"));
|
||||
return;
|
||||
}
|
||||
_FREE(i_new->data);
|
||||
if((top - bottom) < 0.01) top = bottom + 0.01;
|
||||
sz = (ssize_t)(ima->width) * (ssize_t)(ima->height);
|
||||
i_new->data = malloc(sz * sizeof(GLfloat));
|
||||
i_new->width = ima->width; i_new->height = ima->height;
|
||||
i_new->bZero = 0.; i_new->bScale = 1.;
|
||||
i_new->maxVal = ima->maxVal;
|
||||
i_new->stat.max = 1.;//top * ima->stat.max;
|
||||
i_new->stat.min = 0.;
|
||||
p_new = i_new->data;
|
||||
DBG("top=%g, bottom=%g, scale=%g", top, bottom, ima->stat.histogram.scale);
|
||||
top = top * scale+ima->stat.min;
|
||||
bottom = bottom * scale+ima->stat.min;
|
||||
DBG("top=%g, bottom=%g", top, bottom);
|
||||
wd = top - bottom;
|
||||
for(i = 0; i < sz; i++, p_new++, p_old++){
|
||||
pt = *p_old;
|
||||
if(pt < bottom) pt = 0.;
|
||||
else if(pt > top) pt = 1.;
|
||||
else pt = (pt - bottom) / wd;
|
||||
*p_new = pt;
|
||||
}
|
||||
DBG("time: %g", dtime() - t0);
|
||||
window->context->transformMask |= TRANS_TRES;
|
||||
window->context->current_image = window->image_transformed;
|
||||
gen_texture(window->image_transformed, window, TRUE);
|
||||
}
|
||||
|
||||
const int SINCOSSIZE = 540; // size of the array of sines & cosines
|
||||
// [-90 , +180) degrees
|
||||
|
||||
void hough_lines(Window *window){ // key 'i'
|
||||
FNAME();
|
||||
int w, h, Rmax, sz;
|
||||
double hd, wd;
|
||||
IMAGE *ima = window->image;
|
||||
Window *outwin = init_window(window, OPENGL_WINDOW);
|
||||
IMAGE *i_new = outwin->image;
|
||||
if(!ima->data){
|
||||
g_err(_("Image is empty"));
|
||||
return;
|
||||
}
|
||||
_FREE(i_new->data);
|
||||
w = ima->width; h = ima->height;
|
||||
wd = (double)w; hd = (double)h;
|
||||
Rmax = (int)(0.5 + sqrt(wd*wd + hd*hd));
|
||||
sz = SINCOSSIZE * Rmax;
|
||||
DBG("sz: %d", sz);
|
||||
i_new->data = calloc(sz, sizeof(GLfloat));
|
||||
if(!i_new->data){
|
||||
g_err(_("Can't allocate memory for Hough transform"));
|
||||
return;
|
||||
}
|
||||
i_new->width = Rmax; i_new->height = SINCOSSIZE;
|
||||
i_new->bZero = 0.; i_new->bScale = 1.;
|
||||
i_new->maxVal = 1.;
|
||||
i_new->dtype = FLOAT_IMG;
|
||||
gchar *str = malloc(256);
|
||||
snprintf(str, 255, "Hough transform of file %s", ima->filename);
|
||||
init_keylist(i_new);
|
||||
add_key(i_new, "TSTRING", "OBJECT", "Hough", str, TSTRING);
|
||||
_FREE(str);
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
if(!fill_hough_lines(ima->data, ima->stat.min, ima->stat.max, w, h, Rmax, SINCOSSIZE, i_new->data)){
|
||||
g_err(_("Error in Hough transform module"));
|
||||
destroy_window(outwin);
|
||||
return;
|
||||
}
|
||||
DBG("Hough transform for lines, time: %gs", dtime() - t0);
|
||||
//Context->transformMask |= TRANS_TRES;
|
||||
//DBG("HOUGH: maxR=%d, size=%d, max: %g at R=%d, theta=%g",
|
||||
//i_new->width, i_new->height, max, R%Rmax, ((double)(R/Rmax))/2.-90.);
|
||||
outwin->context->current_image = outwin->image;
|
||||
compute_minmax(outwin->image);
|
||||
gen_texture(outwin->image, outwin, FALSE);
|
||||
force_redraw(outwin->drawingArea);
|
||||
outwin->image->imagetype = HOUGH;
|
||||
CH_WIN_TITLE(outwin, "%s (Hough) %s", PRGNAME, window->image->filename);
|
||||
}
|
||||
|
||||
/*
|
||||
* respect to the coordinates (x, y) of a click in the window of a Hough transform
|
||||
* we obtain the parameters of the line (R, phi) and display in the parent window
|
||||
* the corresponding line
|
||||
*/
|
||||
void get_houg_line( Window *window,
|
||||
double x, double y, // mouse click coordinates
|
||||
double *phi_, double *R_ // Output: parameters of line
|
||||
){
|
||||
double R, phi, ang_sep, sinphi, cosphi;
|
||||
double x1=0.,y1=0., x2=0.,y2=0., yl,yr, xu,xd, X1, X2, Y1, Y2;
|
||||
if(!window || !window->parent) return;
|
||||
double W = window->parent->image->width-1., H = window->parent->image->height-1.;
|
||||
int rdy = 0;
|
||||
IMAGE *image = window->image;
|
||||
conv_mouse_to_image_coords(x, y, &R, &phi, window);
|
||||
ang_sep = 270. / (double)image->height / 180. * M_PI;
|
||||
phi = phi*ang_sep - M_PI/2.;
|
||||
sinphi = sin(phi); cosphi = cos(phi);
|
||||
phi *= 180./M_PI; // convert rad => deg
|
||||
DBG("line: phi = %g, R = %g", phi, R);
|
||||
*phi_ = phi; *R_ = R;
|
||||
GdkDrawable *d = window->parent->drawingArea->window;
|
||||
static GdkGC *gc = NULL;
|
||||
if(!gc){
|
||||
gc = gdk_gc_new(d);
|
||||
gdk_gc_set_foreground(gc, &(window->parent->drawingArea->style->white));
|
||||
gdk_gc_set_function(gc, GDK_XOR);
|
||||
}
|
||||
yl = R/sinphi; yr = (R-W*cosphi)/sinphi; // left & right bounds of a picture
|
||||
xd = R/cosphi; xu = (R-H*sinphi)/cosphi; // down & up bounds
|
||||
DBG("yl=%g, yr=%g, xd=%g, xu=%g",yl,yr,xd,xu);
|
||||
if(yl < H && yl > -0.5){
|
||||
DBG("left selected");
|
||||
y1 = yl; x1 = 0.; rdy = 1;
|
||||
}
|
||||
if(yr < H && yr > -0.5){
|
||||
DBG("right selected");
|
||||
if(rdy == 0){
|
||||
y1 = yr; x1 = W; rdy = 1;
|
||||
}else{
|
||||
y2 = yr; x2 = W; rdy = 2; goto lines_selected;
|
||||
}
|
||||
}
|
||||
if(xd < W && xd > -0.5){
|
||||
DBG("down selected");
|
||||
if(rdy == 0){
|
||||
x1 = xd; y1 = 0.; rdy = 1;
|
||||
}else{
|
||||
x2 = xd; y2 = 0.; rdy = 2; goto lines_selected;
|
||||
}
|
||||
}
|
||||
if(xu < W && xu > -0.5){
|
||||
DBG("up selected");
|
||||
if(rdy == 0){
|
||||
x1 = xu; y1 = H; rdy = 1;
|
||||
}else{
|
||||
x2 = xu; y2 = H; rdy = 2;
|
||||
}
|
||||
}
|
||||
lines_selected:
|
||||
if(rdy != 2) DBG("WTF? not two points");
|
||||
else{
|
||||
DBG("line in image CS: (%g, %g) - (%g, %g)", x1,y1,x2,y2);
|
||||
conv_image_to_mouse_coords(x1, y1, &X1, &Y1, window->parent);
|
||||
conv_image_to_mouse_coords(x2, y2, &X2, &Y2, window->parent);
|
||||
gdk_draw_line(d, gc, X1,Y1, X2,Y2);
|
||||
DBG("line in window CS: (%g, %g) - (%g, %g)", X1,Y1,X2,Y2);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtering of an picture window->image by filter f
|
||||
void filter_image( Window *window,
|
||||
Filter *f
|
||||
){
|
||||
float *src, *dst;
|
||||
int w,h;
|
||||
gboolean res = FALSE;
|
||||
// If picture already transformed
|
||||
if(window->context->current_image == window->image_transformed){
|
||||
src = window->image_transformed->data;
|
||||
w = window->image_transformed->width;
|
||||
h = window->image_transformed->height;
|
||||
}else{
|
||||
src = window->image->data;
|
||||
w = window->image->width;
|
||||
h = window->image->height;
|
||||
if(window->image_transformed) _FREE(window->image_transformed->data);
|
||||
// window->image_transformed = COPY(window->image, IMAGE);
|
||||
// window->image_transformed->data = NULL;
|
||||
}
|
||||
switch(f->FilterType){
|
||||
case MEDIAN:
|
||||
res = MedFilter(src, &dst, f, w, h);
|
||||
break;
|
||||
case SIMPLEGRAD:
|
||||
res = GradFilterSimple(src, &dst, f, w, h);
|
||||
break;
|
||||
case STEP: // "posterisation"
|
||||
res = StepFilter(src, &dst, f, w, h, window->image->stat.min, window->image->stat.max, NULL);
|
||||
break;
|
||||
default: // differential filters
|
||||
res = DiffFilter(src, &dst, f, w, h);
|
||||
}
|
||||
if(!res){ g_err(_("Error in image filter module")); return; }
|
||||
window->context->transformMask |= TRANS_FILTER;
|
||||
_FREE(src);
|
||||
window->image->data = dst;
|
||||
window->context->current_image = window->image;
|
||||
compute_minmax(window->image);
|
||||
//gen_texture(window->image_transformed, window, TRUE);
|
||||
gen_texture(window->image, window, TRUE);
|
||||
force_redraw(window->drawingArea);
|
||||
}
|
||||
|
||||
51
src/include/CUtools.h
Normal file
51
src/include/CUtools.h
Normal file
@ -0,0 +1,51 @@
|
||||
// CUtools.h - common definitions and functions for CUDA.c and NOCUDA.c
|
||||
#ifndef _CUTOOLS_H_
|
||||
#define _CUTOOLS_H_
|
||||
#ifdef _CUDA_CU_ // file was included from CUDA.cu
|
||||
#define EXTERN extern "C"
|
||||
#else
|
||||
#define EXTERN
|
||||
#endif
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct{
|
||||
unsigned char FilterType; // filter type
|
||||
int w; // filter width
|
||||
int h; // height
|
||||
double sx; // x half-width
|
||||
double sy; // y half-width (sx, sy - for Gaussian-type filters)
|
||||
} Filter;
|
||||
// FilterType
|
||||
enum{
|
||||
LAPGAUSS // laplasian of gaussian
|
||||
,GAUSS // gaussian
|
||||
,SOBELH // Sobel horizontal
|
||||
,SOBELV // -//- vertical
|
||||
,SIMPLEGRAD // simple gradient (by Sobel)
|
||||
,PREWITTH // Prewitt (horizontal) - simple derivative
|
||||
,PREWITTV // -//- (vertical)
|
||||
,MEDIAN // median
|
||||
,STEP // "posterisation"
|
||||
};
|
||||
// f->h for STEP filter
|
||||
enum{
|
||||
UNIFORM
|
||||
,LOG
|
||||
,EXP
|
||||
,SQRT
|
||||
,POW
|
||||
};
|
||||
|
||||
// export section
|
||||
EXTERN int fill_hough_lines(float *ima, float min, float max, int imW, int imH, int Rmax, int angles, float *hough);
|
||||
EXTERN int DiffFilter(float *ima, float **result, Filter *f, int sizex, int sizey);
|
||||
EXTERN int MedFilter(float *ima, float **result, Filter *f, int sizex, int sizey);
|
||||
EXTERN int fillIsoScale(Filter *f, float **scale, float min, float wd);
|
||||
EXTERN int StepFilter(float *ima, float **result, Filter *f, int sizex, int sizey, float min, float max, float **scale);
|
||||
EXTERN int GradFilterSimple(float *ima, float **result, Filter *f, int sizex, int sizey);
|
||||
#endif // _CUTOOLS_H_
|
||||
9
src/include/contours.h
Normal file
9
src/include/contours.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __CONTOURS_H__
|
||||
#define __CONTOURS_H__
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
#include "spots.h"
|
||||
void find_contours(Window *window, int n, int type);
|
||||
void free_contours(IMAGE *image);
|
||||
int copy_contours(IMAGE *in, IMAGE *out, float dX, float dY);
|
||||
#endif // __CONTOURS_H__
|
||||
19
src/include/filelist.h
Normal file
19
src/include/filelist.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __FILELIST_H__
|
||||
#define __FILELIST_H__
|
||||
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
|
||||
enum{
|
||||
CURRENT,
|
||||
FIRST,
|
||||
LAST,
|
||||
PREVIOUS,
|
||||
NEXT
|
||||
};
|
||||
|
||||
void free_filelist(Window *window);
|
||||
gint fill_filelist(gchar *filename, Window *window);
|
||||
gchar *get_filename(guchar type, Window *window);
|
||||
gboolean get_ext(gchar *filename);
|
||||
#endif // __FILELIST_H__
|
||||
11
src/include/fits.h
Normal file
11
src/include/fits.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _FITS_H_
|
||||
#define _FITS_H_
|
||||
#include "fitsview.h"
|
||||
|
||||
#define SCALE_MIN (0.01) // scale smaller than this is wrong
|
||||
gboolean cmplx_conv(gchar *value, double *re, double *im);
|
||||
gboolean readfits(gchar *filename, IMAGE *data);
|
||||
gboolean writefits(gchar *filename, IMAGE *data);
|
||||
gboolean try_open_file(gchar *filename, IMAGE *data);
|
||||
gboolean guess_fits(gchar *filename);
|
||||
#endif // _FITS_H_
|
||||
20
src/include/fitsheaders.h
Normal file
20
src/include/fitsheaders.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef _FITSHEADERS_H_
|
||||
#define _FITSHEADERS_H_
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
|
||||
enum{ // key parameters field
|
||||
L_TYPENM, // type name
|
||||
L_KEY, // key name
|
||||
L_VAL, // key value
|
||||
L_COMM, // comment
|
||||
L_TYPE, // key type (invisible column, we need you?)
|
||||
L_MAX // amount of parameters
|
||||
};
|
||||
|
||||
void edit_headers(Window *parent);
|
||||
void add_key( IMAGE *ima,
|
||||
gchar *keytype, gchar *keyname, gchar *keyval,
|
||||
gchar *keycomment, int keyfitstype);
|
||||
void init_keylist(IMAGE *ima);
|
||||
#endif
|
||||
233
src/include/fitsview.h
Normal file
233
src/include/fitsview.h
Normal file
@ -0,0 +1,233 @@
|
||||
#ifndef _FITSVIEW_H_
|
||||
#define _FITSVIEW_H_
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <GL/gl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtk/gtkgl.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <libintl.h> // for locale
|
||||
#include <sys/time.h> // for dtime
|
||||
#include <libgen.h> // for basename
|
||||
#include <fitsio.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <strings.h>
|
||||
#include <stdarg.h> // for color text in tty
|
||||
|
||||
|
||||
#include "CUtools.h"
|
||||
|
||||
#ifndef GETTEXT_PACKAGE
|
||||
#define GETTEXT_PACKAGE "fitsview"
|
||||
#endif
|
||||
#define PRGNAME GETTEXT_PACKAGE
|
||||
#ifndef LOCALEDIR
|
||||
#define LOCALEDIR "/home/eddy/locale"
|
||||
#endif
|
||||
|
||||
#define _(String) gettext(String)
|
||||
#define gettext_noop(String) String
|
||||
#define N_(String) gettext_noop(String)
|
||||
|
||||
#ifndef THREAD_NUMBER
|
||||
#define THREAD_NUMBER 2
|
||||
#endif
|
||||
#ifndef OMP_NUM_THREADS
|
||||
#define OMP_NUM_THREADS THREAD_NUMBER
|
||||
#endif
|
||||
|
||||
extern const int HIST_SIZE;
|
||||
void *copy_struct(void *src, int size);
|
||||
void *init_struct(int size);
|
||||
#define INIT(var, type) var = (type*)init_struct(sizeof(type))
|
||||
#define COPY(src, type) (type*)copy_struct((void*)src, sizeof(type))
|
||||
#define _FREE(ptr) do{free(ptr); ptr = NULL;}while(0)
|
||||
|
||||
/*
|
||||
* If the distance from the current position of the mouse to a certain point
|
||||
* less than this value, it is believed that this kind of chosen point
|
||||
*/
|
||||
#define PT_TRESHOLD 5
|
||||
|
||||
// debug mode, -DEBUG
|
||||
#ifdef EBUG
|
||||
#define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__)
|
||||
#define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n");} while(0)
|
||||
#else
|
||||
#define FNAME() do{}while(0)
|
||||
#define DBG(...) do{}while(0)
|
||||
#endif //EBUG
|
||||
|
||||
extern int (*red)(const char *fmt, ...);
|
||||
extern int (*green)(const char *fmt, ...);
|
||||
|
||||
// contour poing
|
||||
typedef struct _cPoint{
|
||||
float x; // coordinates of the contour point in the CS picture
|
||||
float y;
|
||||
struct _cPoint *prev;// pointers to the previous and next points of the contour
|
||||
struct _cPoint *next;
|
||||
} cPoint;
|
||||
// contour structure
|
||||
typedef struct _Contour{
|
||||
int N; // amount of points
|
||||
cPoint *first; // the first point of the contour (list)
|
||||
cPoint *last; // last -//-
|
||||
// struct _Contour *prev; // pointers to the previous and following contour of the group
|
||||
struct _Contour *next;
|
||||
unsigned char closed;// == TRUE, if contour is closed
|
||||
} Contour;
|
||||
typedef struct{
|
||||
int L; // level (at the lower boundary of 0, 1, etc)
|
||||
int N; // number of units in the structure
|
||||
Contour *first; // pointer to the first contour in the list
|
||||
Contour *last; // pointer to the last contour in the list
|
||||
}cList;
|
||||
|
||||
// image histogram
|
||||
typedef struct{
|
||||
int size; // it is possible that the size of the histogram can be changed
|
||||
int max; // maximum and minimum values of the histogram (the amplitude)
|
||||
int min;
|
||||
double bot_tres; // upper and lower thresholds for equalization (normalized to 1)
|
||||
double top_tres;
|
||||
GLfloat scale; // the scale - the range of intensities per unit of histogram
|
||||
int *data;
|
||||
} ImageHistogram;
|
||||
// image statistics
|
||||
struct ImageStat{
|
||||
GLfloat max;
|
||||
GLfloat min;
|
||||
ImageHistogram histogram;
|
||||
/*GLfloat median;
|
||||
GLfloat mean;
|
||||
GLfloat std;*/
|
||||
};
|
||||
|
||||
// image itself
|
||||
typedef struct{
|
||||
int width; // width
|
||||
int height; // height
|
||||
float bZero; // conditional zero point
|
||||
float bScale; // scale
|
||||
float maxVal; // the limiting value of the intensity (1<<BITTPIX)
|
||||
double val_f; // the value of a focus in mm (if not defined - '-1e6')
|
||||
int dtype; // data type
|
||||
struct ImageStat stat; // image statistica
|
||||
float *data; // picture data
|
||||
GtkListStore *store;// list of options for each key
|
||||
gchar *filename; // file name (basename) for the image
|
||||
int imagetype; // type of image (for any changes)
|
||||
cList **contours; // isolines array
|
||||
int Ncontours; // dimension of the array of isolines
|
||||
float *cLevels; // array of intensity levels corresponding to each contour
|
||||
} IMAGE;
|
||||
// imagetype
|
||||
enum{
|
||||
SIMPLE_IMAGE // normal (not converted) image
|
||||
,HOUGH // Hough transform
|
||||
};
|
||||
|
||||
// the context
|
||||
typedef struct{
|
||||
unsigned char drawingMode; // drawing mode: cross section area, etc.
|
||||
unsigned char trackingMode; // drawing mode sections
|
||||
unsigned char graphYaxis; // form the Y-axis chart: logarithmic, or common
|
||||
unsigned char graphMode; // chart mode (chart, histogram, etc.)
|
||||
unsigned char transformMask;// mask changes made to image_transformed
|
||||
unsigned char visualMode; // display mode (additional areas, etc.)
|
||||
IMAGE *current_image; // displayed image (window->image or window->image_transformed)
|
||||
} Context;
|
||||
|
||||
typedef struct{
|
||||
unsigned char previewMode; // preview settings
|
||||
gboolean add_all; // try to add all the files (or only .fts / .fit [s])
|
||||
int minSpotW; // the limit sizes of points
|
||||
int maxSpotW;
|
||||
int minSpotH;
|
||||
int maxSpotH;
|
||||
} Global_context;
|
||||
|
||||
extern Global_context *Global;
|
||||
|
||||
/*
|
||||
* description fields of the structure of context
|
||||
* the first (zero) should go the default values
|
||||
*/
|
||||
// drawingMode:
|
||||
enum{
|
||||
DRAW_TRACK // tracking mode
|
||||
,DRAW_SELECTION // and so on
|
||||
,DRAW_QUAD
|
||||
,GAME_MODE
|
||||
};
|
||||
// trackingMode:
|
||||
enum{
|
||||
TRACK_ANY
|
||||
,TRACK_VERT
|
||||
,TRACK_HORIZ
|
||||
,TRACK_DIAG
|
||||
};
|
||||
// graphYaxis, may be masking: LSB - the graph, Sr. - histogram
|
||||
enum{
|
||||
Y_LINEAR = 0
|
||||
,Y_LOGBOTH = 3
|
||||
,Y_LOGHIST = 2
|
||||
,Y_LOGGRAPH= 1
|
||||
};
|
||||
// graphMode - what is shown on graph (histogram or track)
|
||||
enum{
|
||||
GR_GRAPH
|
||||
,GR_HISTOGRAM
|
||||
};
|
||||
// transformMask - bit components
|
||||
enum{
|
||||
TRANS_NONE = 0
|
||||
,TRANS_TRES = 1
|
||||
,TRANS_ROT = 2
|
||||
,TRANS_MOVE = 4
|
||||
,TRANS_SCALE = 8
|
||||
,TRANS_FILTER = 16
|
||||
,TRANS_HARTMANN = 32
|
||||
};
|
||||
// visualMode - bit components
|
||||
enum{
|
||||
SHOW_ONLY_IMAGE = 0
|
||||
,SHOW_POTBOXES = 1
|
||||
,SHOW_POTSELECT = 2
|
||||
,SHOW_ISOLINES = 4
|
||||
,SHOW_ALL = 255
|
||||
};
|
||||
// previewMode - bit components, masks
|
||||
enum{
|
||||
PREVIEW_DEFAULT // (512x512, sqrt)
|
||||
,PREVIEW_128
|
||||
,PREVIEW_256
|
||||
,PREVIEW_512
|
||||
,PREVIEW_768
|
||||
,PREVIEW_1024
|
||||
,PREVIEW_SIZEMASK = 7
|
||||
,PREVIEW_LINEAR = 8
|
||||
,PREVIEW_LOG = 16
|
||||
,PREVIEW_SQRT = 24
|
||||
,PREVIEW_COLFNMASK = 24
|
||||
};
|
||||
|
||||
double dtime();
|
||||
|
||||
#endif // _FITSVIEW_H_
|
||||
20
src/include/gauss.h
Normal file
20
src/include/gauss.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef _GAUSS_H_
|
||||
#define _GAUSS_H_
|
||||
#include "fitsview.h"
|
||||
#include "tracking.h"
|
||||
#ifndef GSL_FOUND
|
||||
#define GSLERR g_err(_("Install GSL library and remake sources for this functions"))
|
||||
#endif
|
||||
struct data {
|
||||
size_t n;
|
||||
double *x;
|
||||
double *y;
|
||||
double *dy;
|
||||
};
|
||||
|
||||
double gaussian_pt(double C, double A, double sigma, double x0, double x);
|
||||
void gaussian_v(double C, double A, double sigma, double x0, Points *pts);
|
||||
void gauss_fit(Points *pts, double *C_, double *A_, double *sigma_, double *x0_);
|
||||
/*void circle_fit(struct data *data, double *Xcenter,
|
||||
double *Ycenter, double *Radius);*/
|
||||
#endif // _GAUSS_H_
|
||||
92
src/include/gtk.h
Normal file
92
src/include/gtk.h
Normal file
@ -0,0 +1,92 @@
|
||||
#ifndef _GTK_H_
|
||||
#define _GTK_H_
|
||||
#include "fitsview.h"
|
||||
#define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
|
||||
|
||||
#define CH_WIN_TITLE(wndw, ...) do{ \
|
||||
gchar *title = g_strdup_printf(__VA_ARGS__); \
|
||||
gtk_window_set_title(GTK_WINDOW(wndw->window), title);\
|
||||
g_free(title); \
|
||||
}while(0)
|
||||
|
||||
// Maximum number of cells lines the status window
|
||||
#define SBAR_MAX 4
|
||||
// Status bar fields
|
||||
enum{
|
||||
StatusText
|
||||
,StatusState
|
||||
,StatusCoords
|
||||
,StatusAdd
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
GLuint tex; // texture itself
|
||||
GLuint w; // its size
|
||||
GLuint h;
|
||||
} TEXTURE;
|
||||
|
||||
typedef struct{
|
||||
double x;
|
||||
double y;
|
||||
} XY;
|
||||
|
||||
// List of files in the current directory for this window
|
||||
typedef struct{
|
||||
gint list_length;
|
||||
GList *files_list;
|
||||
GList *list_current;
|
||||
GList *list_end;
|
||||
} FITSlist;
|
||||
|
||||
struct Spots;
|
||||
// window description structure
|
||||
struct Window{
|
||||
int id; // identificator: MAIN_WINDOW, GRAPH_WINDOW, OPENGL_WINDOW
|
||||
GtkWidget *window; // pointer to a window
|
||||
Context *context; // context of a window
|
||||
struct Window *parent; // parent window (NULL for the main)
|
||||
struct Window *graphWindow; // window's graph (while there's no - NULL)
|
||||
GtkWidget *drawingArea; // drawing area (openGL)
|
||||
GtkWidget *hRule; // rulers
|
||||
GtkWidget *vRule;
|
||||
GtkEntry *SBars[SBAR_MAX]; // an array of pointers to the cells of the status bar
|
||||
guint statusBlocks; // status bar blocks amount
|
||||
IMAGE *image; // image for a window
|
||||
IMAGE *image_transformed; // and its transformation
|
||||
struct Spots *spots; // spots array for a window
|
||||
TEXTURE *texture; // texture or VBO buffers
|
||||
GtkRadioAction *LinLogMenu[2]; // scale lin/log
|
||||
double Zoom; // zoom scale
|
||||
double Daspect; // scale in image region (in window)
|
||||
XY move; // image motions (in window)
|
||||
XY mouse; // .x, .y - the beginning of the window coordinates in SC of a picture
|
||||
GLfloat Xangle; // angles rotation relative to the X and Z axes
|
||||
GLfloat Zangle;
|
||||
FITSlist files; // files in current directory for this window
|
||||
};
|
||||
typedef struct Window Window;
|
||||
// window id
|
||||
enum{
|
||||
MAIN_WINDOW,
|
||||
GRAPH_WINDOW,
|
||||
OPENGL_WINDOW,
|
||||
GL3D_WINDOW
|
||||
};
|
||||
|
||||
extern Window *mainWindow;
|
||||
|
||||
void change_image(gchar *filename, Window *window);
|
||||
void init_main_window(int *argc, char ***argv);
|
||||
Window *init_window(Window *parent, int winId);
|
||||
void destroy_window(Window* window);
|
||||
void run_modal_window(GtkWindow *w, Window *parent);
|
||||
gint run_modal_dialog(GtkDialog *dialog, Window *parent);
|
||||
void g_err(gchar *text);
|
||||
void set_Drulers(double x0, double y0, double xm, double ym, Window *window);
|
||||
void set_Grulers(double y0, double xm, double ym, Window *window);
|
||||
void show_histogram(Window *window);
|
||||
void set_status_text(guint barName, gchar *text, Window *window);
|
||||
void refresh_state(Window *window);
|
||||
gchar *get_open_filename(Window *window);
|
||||
void get_prefocal(Window *window, gboolean *prefocal);
|
||||
#endif // _GTK_H_
|
||||
19
src/include/imtools.h
Normal file
19
src/include/imtools.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _IMTOOLS_H_
|
||||
#define _IMTOOLS_H_
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
#include "spots.h"
|
||||
|
||||
void destroy_image(IMAGE *image);
|
||||
void free_contours(IMAGE *image);
|
||||
gboolean make_histogram(IMAGE *ima);
|
||||
void treshold_image(Window *window, GLfloat bottom, GLfloat top);
|
||||
void get_spots_coords(Window *window, IMAGE *ima);
|
||||
void hartmann_spots(Window *window);
|
||||
gboolean get_gaussian_center(Window *window, BOX *box, Coordinates *crds);
|
||||
PIX *conv_image2pix(IMAGE *ima);
|
||||
void get_circles_params(Window *window, IMAGE *ima);
|
||||
void hough_lines(Window *window);
|
||||
void get_houg_line(Window *window, double x, double y, double *phi_, double *R_);
|
||||
void filter_image(Window *window, Filter *f);
|
||||
#endif // _IMTOOLS_H_
|
||||
8
src/include/open_dialog.h
Normal file
8
src/include/open_dialog.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _OPEN_DIALOG_H_
|
||||
#define _OPEN_DIALOG_H_
|
||||
#include "gtk.h"
|
||||
|
||||
extern gchar *saved_path;
|
||||
GtkFileChooser *open_fits_dialog();
|
||||
void gray2rgb(float gray, guchar *rgb);
|
||||
#endif
|
||||
21
src/include/opengl.h
Normal file
21
src/include/opengl.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _OPENGL_H_
|
||||
#define _OPENGL_H_
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "fitsview.h"
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glext.h>
|
||||
#include <GL/glut.h>
|
||||
#include "gtk.h"
|
||||
|
||||
extern gboolean useVBO;
|
||||
|
||||
void initGl(GtkWidget *drawingArea);
|
||||
void gen_texture(IMAGE *image, Window *window, gboolean redraw);
|
||||
void force_redraw(GtkWidget *Area);
|
||||
void pickRegion(double x, double y);
|
||||
void conv_mouse_to_image_coords(double x, double y, double *X, double *Y, Window *window);
|
||||
void conv_image_to_mouse_coords(double x, double y, double *X, double *Y, Window *window);
|
||||
void init3D(Window *window);
|
||||
void getGLinfo(GtkWidget *Area);
|
||||
void freeGLmemory(Window *window);
|
||||
#endif // _OPENGL_H_
|
||||
61
src/include/spots.h
Normal file
61
src/include/spots.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _SPOTS_H_
|
||||
#define _SPOTS_H_
|
||||
#include "fitsview.h"
|
||||
|
||||
#ifndef LEPTONICA_FOUND
|
||||
#define LEPTERR g_err(_("Install Leptonica library and remake sources for this functions"))
|
||||
typedef struct{double x; double y; double w; double h;} BOX;
|
||||
typedef void* PIX;
|
||||
#else
|
||||
#include <leptonica/allheaders.h> // from leptonica
|
||||
#endif // LEPTONICA_FOUND
|
||||
|
||||
/*
|
||||
* Coordinates of the center of area and its sizes was originally initiated
|
||||
* based on the box-structures, then adjusted to a coordinate system relative
|
||||
* to the optical axis, further refined by a Gaussian
|
||||
* (x and y - as the central parameters of Gaussians,
|
||||
* rx and ry - as the standard deviation of a Gaussian
|
||||
*/
|
||||
typedef struct{
|
||||
double x;
|
||||
double y; // center coordinates
|
||||
double rx;
|
||||
double ry; // half-sizes
|
||||
} Coordinates;
|
||||
|
||||
// spot parameters
|
||||
typedef struct{
|
||||
BOX box; // bounding box
|
||||
Coordinates c; // dimensions and coordinates in CS relative to the optical axis, without rotation
|
||||
double r; // module of the radius vector in the CS of the center of spots
|
||||
double phi; // angular coordinate (from OX counter-clockwise)
|
||||
double xC; // coordinates of spots in the CS of an optical axis, taking into account the rotation
|
||||
double yC;
|
||||
int id; // number, id etc.
|
||||
} Spot;
|
||||
|
||||
// spots array
|
||||
struct Spots{
|
||||
int size; // array size
|
||||
int n; // amount of spots in array
|
||||
int memflag;// BY_COPY or BY_PTR - method of spots allocation
|
||||
Spot **spot;// spots themselves
|
||||
};
|
||||
|
||||
typedef struct Spots Spots;
|
||||
|
||||
Spots* spots_alloc(int n);
|
||||
Spot* spots_add(Spots *spots, Spot *spot, int copy);
|
||||
enum { // definition for the function spots_add
|
||||
BY_COPY, // copy spot
|
||||
BY_PTR // only insert pointer to a spot
|
||||
};
|
||||
void spots_free(Spots **spots);
|
||||
struct Window;
|
||||
void sort_spots(struct Window *window);
|
||||
void spots_save(Spots *spots, gchar *filename);
|
||||
|
||||
extern double AxisX, AxisY;
|
||||
|
||||
#endif // _SPOTS_H_
|
||||
9
src/include/terrain.h
Normal file
9
src/include/terrain.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __TERRAIN_H__
|
||||
#define __TERRAIN_H__
|
||||
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
|
||||
void terrain_3D(Window *window, double x0, double y0, double x, double y, gboolean from_file);
|
||||
|
||||
#endif // __TERRAIN_H__
|
||||
31
src/include/tracking.h
Normal file
31
src/include/tracking.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef _TRACKING_H_
|
||||
#define _TRACKING_H_
|
||||
|
||||
#include "fitsview.h"
|
||||
#include "gtk.h"
|
||||
|
||||
typedef struct{
|
||||
double x;
|
||||
double y;
|
||||
} Point;
|
||||
|
||||
typedef struct{
|
||||
int n;
|
||||
Point *data;
|
||||
} Points;
|
||||
|
||||
extern double gYmax, gXmax;
|
||||
extern double xScale, yScale;
|
||||
|
||||
void do_tracking(double x, double y, gboolean start, Window *window);
|
||||
void do_histogram(Window *window);
|
||||
gboolean graph_mouse_btn(int x, Window *window);
|
||||
gboolean isYlog(Window *window);
|
||||
|
||||
void gen_tres_texture(Window *window);
|
||||
gboolean Gexpose(Window *window);
|
||||
gboolean Gconfigure(Window *window);
|
||||
gboolean fit_gaussian(Window *window);
|
||||
void get_image_crds(double x, double *xx, double *yy);
|
||||
void get_sel_region(double *x1, double *y1, double *x2, double *y2);
|
||||
#endif // _TRACKING_H_
|
||||
BIN
src/locale/ru/LC_MESSAGES/fitsview.mo
Normal file
BIN
src/locale/ru/LC_MESSAGES/fitsview.mo
Normal file
Binary file not shown.
596
src/locale/ru/messages.po
Normal file
596
src/locale/ru/messages.po
Normal file
@ -0,0 +1,596 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-12-10 17:22+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: gtk.c:58
|
||||
#, c-format
|
||||
msgid "Error: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:174 fits.c:191
|
||||
msgid "Can't read fits file"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:185
|
||||
msgid "Can't save file"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:367
|
||||
msgid "Selected line"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:473
|
||||
msgid "Both max values are less than min"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:476
|
||||
msgid "Max height value less than min"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:478
|
||||
msgid "Max width value less than min"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:525
|
||||
msgid "No recognized spots"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:1090
|
||||
msgid "Quit"
|
||||
msgstr ""
|
||||
|
||||
#: gtk.c:1093
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:53
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:53
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:53
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:53
|
||||
msgid "Comment"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:101
|
||||
msgid "Error in value range!"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:120
|
||||
msgid "Invalid double number!"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:132
|
||||
msgid "Format error: complex number must be in format"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:486
|
||||
msgid "Open fits file first"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:513
|
||||
msgid "New entry (ctrl+n)"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:518
|
||||
msgid "Delete entry (ctrl+d)"
|
||||
msgstr ""
|
||||
|
||||
#: fitsheaders.c:524
|
||||
msgid "Close (ctrl+w)"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:57 tracking.c:62 tracking.c:350
|
||||
msgid "Can't allocate memory for track points"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:483
|
||||
#, c-format
|
||||
msgid "Selected region from %.1f to %.1f, %d datapoints"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:518
|
||||
msgid "No parent window or image"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:526
|
||||
msgid "No data points"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:531
|
||||
msgid "Bad amount of data points"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:536
|
||||
msgid "Invalid number of first point"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:543 contours.c:394 contours.c:400 contours.c:449 contours.c:453
|
||||
#: contours.c:456 terrain.c:264 terrain.c:270
|
||||
msgid "Can't allocate memory"
|
||||
msgstr ""
|
||||
|
||||
#: tracking.c:559
|
||||
#, c-format
|
||||
msgid "Fit gaussian, x0=%.2f I(%.2f, %.2f), s=%.2f, A=%.1f, C=%.3f"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:63
|
||||
msgid "Too many markers"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:64
|
||||
msgid "Not enough markers"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:65
|
||||
msgid "Bad markers angle"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:66
|
||||
msgid "Too many rings"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:83
|
||||
msgid "Can't allocate memory for new spots"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:88
|
||||
msgid "Can't allocate memory for pointers in spots array"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:122
|
||||
msgid "Spots array is full, can't place new spot\n"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:126
|
||||
msgid "Zero pointer to spot\n"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:132
|
||||
msgid "Can't allocate memory for new spot"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:137
|
||||
msgid "Can't copy spot to new one"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:499
|
||||
msgid "Can't open file"
|
||||
msgstr ""
|
||||
|
||||
#: spots.c:511
|
||||
msgid "Can't write to file"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:222 imtools.c:302
|
||||
msgid "Define treshold limits first"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:235
|
||||
msgid "No GSL library found, don't calculate centroids"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:239 imtools.c:318
|
||||
msgid "Box not found"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:274
|
||||
msgid "Find spots first"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:279
|
||||
msgid "Too many points"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:283
|
||||
msgid "Not enough points"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:322
|
||||
msgid "Pix not found"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:377 imtools.c:439 imtools.c:481
|
||||
msgid "Image is empty"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:384
|
||||
msgid "Can't allocate memory for histogram"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:492
|
||||
msgid "Can't allocate memory for Hough transform"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:508
|
||||
msgid "Error in Hough transform module"
|
||||
msgstr ""
|
||||
|
||||
#: imtools.c:628
|
||||
msgid "Error in image filter module"
|
||||
msgstr ""
|
||||
|
||||
#: NOCUDA.c:809
|
||||
msgid "No memory left"
|
||||
msgstr ""
|
||||
|
||||
#: fits.c:284
|
||||
msgid "Can't read HDU"
|
||||
msgstr ""
|
||||
|
||||
#: fits.c:345
|
||||
msgid "Not an image? (dimensions != 2)"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:34
|
||||
msgid "OpenGL not supported"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:55
|
||||
msgid ""
|
||||
"\n"
|
||||
"OpenGL info:\n"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:60
|
||||
msgid "Color bits"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:65
|
||||
msgid "Depth bits"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:66
|
||||
msgid "Stencil bits"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:66
|
||||
msgid "Max amount of lights"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:69
|
||||
msgid "Max texture size"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:70
|
||||
msgid "Max clip planes"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:75
|
||||
msgid "Max stack depths"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:76
|
||||
msgid "modelview"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:76
|
||||
msgid "projection"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:76
|
||||
msgid "attrib"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:77
|
||||
msgid "texture"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:80
|
||||
msgid "VBO is supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:288
|
||||
msgid "Empty region"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:295
|
||||
msgid "Selected spot[s]:\n"
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:297
|
||||
msgid "Selected spot: "
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:299
|
||||
msgid "Selected spots: "
|
||||
msgstr ""
|
||||
|
||||
#: opengl.c:483 terrain.c:321
|
||||
msgid "Can't allocate memory for texture"
|
||||
msgstr ""
|
||||
|
||||
#: terrain.c:227
|
||||
msgid "Selected area too small"
|
||||
msgstr ""
|
||||
|
||||
#: terrain.c:233
|
||||
msgid "Error occured when tried to add contours"
|
||||
msgstr ""
|
||||
|
||||
#: terrain.c:256
|
||||
msgid "No image in parent window"
|
||||
msgstr ""
|
||||
|
||||
#: terrain.c:332
|
||||
msgid "Can't generate VBO / GL list"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:79
|
||||
msgid "linear"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:79
|
||||
msgid "log"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:79
|
||||
msgid "square root"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:96 open_dialog.c:354
|
||||
msgid "Preview size"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:105
|
||||
msgid "Colormap function"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:142
|
||||
msgid "Select fits file to open"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:155
|
||||
msgid "FITS files"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:164
|
||||
msgid "All files"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:188
|
||||
msgid "Preview settings"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:353
|
||||
msgid "Image size"
|
||||
msgstr ""
|
||||
|
||||
#: open_dialog.c:355
|
||||
msgid "Preview scale"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:16 fitsview.glade:448 fitsview.glade:679
|
||||
msgid "_File"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:40
|
||||
msgid "Open in _new window"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:55
|
||||
msgid "Open in _3D window"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:92 fitsview.glade:474 fitsview.glade:713
|
||||
msgid "_Edit"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:99 fitsview.glade:481 fitsview.glade:720
|
||||
msgid "_View"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:107
|
||||
msgid "Show _histogram"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:115
|
||||
msgid "Show _headers"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:128
|
||||
msgid "3D view of full image"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:136
|
||||
msgid "3D view of subframe"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:144
|
||||
msgid "Select _spots"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:152
|
||||
msgid "Draw _tracks"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:165
|
||||
msgid "_Zoom frame"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:173 fitsview.glade:834
|
||||
msgid "_Restore image"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:181
|
||||
msgid "Zoom _in"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:189
|
||||
msgid "Zoom _out"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:201 fitsview.glade:525 fitsview.glade:846
|
||||
msgid "_Math"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:209
|
||||
msgid "Find and enumerate spots"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:210
|
||||
msgid "_Spots"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:218
|
||||
msgid "Choose minimal & maximal spot size"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:219
|
||||
msgid "Size _tresholds"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:227
|
||||
msgid "Identify _spots"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:235
|
||||
msgid "So_rt hartmann spots"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:243
|
||||
msgid "Sa_ve spots"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:255
|
||||
msgid "Identify _circles"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:263
|
||||
msgid "_Hough transform"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:271
|
||||
msgid "_Filter"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:283
|
||||
msgid "_Help"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:489
|
||||
msgid "Y axis scale"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:497
|
||||
msgid "Linear"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:507
|
||||
msgid "Log"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:533
|
||||
msgid "Approximate by _gaussian"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:728
|
||||
msgid "_Move"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:736
|
||||
msgid "Rotate X CW"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:744
|
||||
msgid "Rotate X CCW"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:752
|
||||
msgid "Rotate Z CCW"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:760
|
||||
msgid "Rotate Z CW"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:768
|
||||
msgid "Move right"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:776
|
||||
msgid "Move left"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:784
|
||||
msgid "Move down"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:792
|
||||
msgid "Move up"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:800
|
||||
msgid "Move backward"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:808
|
||||
msgid "Move forward"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:825
|
||||
msgid "Mouse and arrow keys navigation"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:826
|
||||
msgid "_Game mode"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:942
|
||||
msgid "Spots' size treshold"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:986 fitsview.glade:1084
|
||||
msgid "Min"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1018 fitsview.glade:1116
|
||||
msgid "Max"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1050
|
||||
msgid "<b>Width</b>"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1148
|
||||
msgid "<b>Height</b>"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1248
|
||||
msgid "<b>Focus value, mm</b>"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1277
|
||||
msgid "Prefocal"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1290
|
||||
msgid "Postfocal"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:1308
|
||||
msgid "<b>Image type</b>"
|
||||
msgstr ""
|
||||
590
src/locale/ru/ru.po
Normal file
590
src/locale/ru/ru.po
Normal file
@ -0,0 +1,590 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr "Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-07-15 11:01+0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=koi8-r\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: opengl.c:53
|
||||
#, fuzzy
|
||||
msgid "\n"
|
||||
"OpenGL info:\n"
|
||||
msgstr "éÎÆÏÒÍÁÃÉÑ Ï OpenGL:\n"
|
||||
|
||||
#: fitsview.glade:128
|
||||
msgid "3D view of full image"
|
||||
msgstr "ðÒÏÓÍÏÔÒ ×ÓÅÇÏ ÉÚÏÂÒÁÖÅÎÉÑ × 3D"
|
||||
|
||||
#: fitsview.glade:136
|
||||
msgid "3D view of subframe"
|
||||
msgstr "ðÒÏÓÍÏÔÒ ÞÁÓÔÉ ÉÚÏÂÒÁÖÅÎÉÑ × 3D"
|
||||
|
||||
#: fitsview.glade:1240
|
||||
msgid "<b>Focus value, mm</b>"
|
||||
msgstr "<b>æÏËÕÓ, ÍÍ</b>"
|
||||
|
||||
#: fitsview.glade:1140
|
||||
msgid "<b>Height</b>"
|
||||
msgstr "<b>÷ÙÓÏÔÁ</b>"
|
||||
|
||||
#: fitsview.glade:1300
|
||||
msgid "<b>Image type</b>"
|
||||
msgstr "<b>ôÉÐ ÉÚÏÂÒÁÖÅÎÉÑ</b>"
|
||||
|
||||
#: fitsview.glade:1042
|
||||
msgid "<b>Width</b>"
|
||||
msgstr "<b>ûÉÒÉÎÁ</b>"
|
||||
|
||||
#: opengl.c:76
|
||||
msgid "All extensions"
|
||||
msgstr "÷ÓÅ ÒÁÓÛÉÒÅÎÉÑ"
|
||||
|
||||
#: open_dialog.c:164
|
||||
msgid "All files"
|
||||
msgstr "÷ÓÅ ÆÁÊÌÙ"
|
||||
|
||||
#: fitsview.glade:525
|
||||
msgid "Approximate by _gaussian"
|
||||
msgstr "áÐÐÒÏËÓÉÍÁÃÉÑ _ÇÁÕÓÓÉÁÎÏÊ"
|
||||
|
||||
#. ÍÁÌÏ ÌÉÂÏ ÍÎÏÇÏ ÔÏÞÅË
|
||||
#: tracking.c:523
|
||||
msgid "Bad amount of data points"
|
||||
msgstr "îÅ×ÅÒÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÔÏÞÅË Ó ÄÁÎÎÙÍÉ"
|
||||
|
||||
#: spots.c:68
|
||||
msgid "Bad markers angle"
|
||||
msgstr "îÅ×ÅÒÎÙÊ ÕÇÏÌ ÍÅÖÄÕ ÍÁÒËÅÒÁÍÉ"
|
||||
|
||||
#: gtk.c:461
|
||||
msgid "Both max values are less than min"
|
||||
msgstr "ïÂÅ ÍÁËÓÉÍÁÌØÎÙÅ ×ÅÌÉÞÉÎÙ ÍÅÎØÛÅ ÍÉÎÉÍÁÌØÎÏÊ"
|
||||
|
||||
#: imtools.c:217 imtools.c:292
|
||||
msgid "Box not found"
|
||||
msgstr "ïÂÌÁÓÔØ ÎÅ ÏÂÎÁÒÕÖÅÎÁ"
|
||||
|
||||
#: tracking.c:535 terrain.c:207 terrain.c:213
|
||||
msgid "Can't allocate memory"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ"
|
||||
|
||||
#: imtools.c:445
|
||||
msgid "Can't allocate memory for Hough transform"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÏÂÒÁÚÁ èÁÆÁ"
|
||||
|
||||
#: imtools.c:356
|
||||
msgid "Can't allocate memory for histogram"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÇÉÓÔÏÇÒÁÍÍÙ"
|
||||
|
||||
#: spots.c:138
|
||||
msgid "Can't allocate memory for new spot"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÎÏ×ÏÊ ÔÏÞËÉ"
|
||||
|
||||
#: spots.c:89
|
||||
msgid "Can't allocate memory for new spots"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÎÏ×ÙÈ ÔÏÞÅË"
|
||||
|
||||
#: spots.c:94
|
||||
msgid "Can't allocate memory for pointers in spots array"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÕËÁÚÁÔÅÌÅÊ × ÍÁÓÓÉ×Å ÔÏÞÅË"
|
||||
|
||||
#: opengl.c:425 terrain.c:258
|
||||
msgid "Can't allocate memory for texture"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÔÅËÓÔÕÒÙ"
|
||||
|
||||
#: tracking.c:57 tracking.c:62 tracking.c:351
|
||||
msgid "Can't allocate memory for track points"
|
||||
msgstr "îÅ ÍÏÇÕ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ ÄÌÑ ÔÏÞÅË ÔÒÅËÁ"
|
||||
|
||||
#: spots.c:143
|
||||
msgid "Can't copy spot to new one"
|
||||
msgstr "îÅ ÍÏÇÕ ÓËÏÐÉÒÏ×ÁÔØ ÔÏÞËÕ"
|
||||
|
||||
#: terrain.c:269
|
||||
msgid "Can't generate VBO / GL list"
|
||||
msgstr "îÅ ÍÏÇÕ ÓÇÅÎÅÒÉÒÏ×ÁÔØ VBO / GL ÓÐÉÓËÉ"
|
||||
|
||||
#: spots.c:507
|
||||
#, fuzzy
|
||||
msgid "Can't open file"
|
||||
msgstr "îÅ ÍÏÇÕ ÓÏÈÒÁÎÉÔØ ÆÁÊÌ"
|
||||
|
||||
#: fits.c:287
|
||||
msgid "Can't read HDU"
|
||||
msgstr "îÅ ÍÏÇÕ ÐÒÏÞÅÓÔØ HDU"
|
||||
|
||||
#: fits.c:192
|
||||
msgid "Can't read fits file"
|
||||
msgstr "îÅ ÍÏÇÕ ÐÒÏÞÅÓÔØ fits ÆÁÊÌ"
|
||||
|
||||
#: gtk.c:183
|
||||
msgid "Can't save file"
|
||||
msgstr "îÅ ÍÏÇÕ ÓÏÈÒÁÎÉÔØ ÆÁÊÌ"
|
||||
|
||||
#: spots.c:519
|
||||
#, fuzzy
|
||||
msgid "Can't write to file"
|
||||
msgstr "îÅ ÍÏÇÕ ÐÒÏÞÅÓÔØ fits ÆÁÊÌ"
|
||||
|
||||
#: fitsview.glade:218
|
||||
msgid "Choose minimal & maximal spot size"
|
||||
msgstr "÷ÙÂÅÒÉÔÅ ÐÒÅÄÅÌØÎÙÅ ÒÁÚÍÅÒÙ ÐÑÔÅÎ"
|
||||
|
||||
#: gtk.c:1084
|
||||
msgid "Close"
|
||||
msgstr "úÁËÒÙÔØ"
|
||||
|
||||
#: fitsheaders.c:524
|
||||
msgid "Close (ctrl+w)"
|
||||
msgstr "úÁËÒÙÔØ (ctrl+w)"
|
||||
|
||||
#: opengl.c:58
|
||||
msgid "Color bits"
|
||||
msgstr "âÉÔÙ Ã×ÅÔÁ"
|
||||
|
||||
#: open_dialog.c:105
|
||||
msgid "Colormap function"
|
||||
msgstr "ã×ÅÔÏ×ÁÑ ÆÕÎËÃÉÑ"
|
||||
|
||||
#: fitsheaders.c:54
|
||||
msgid "Comment"
|
||||
msgstr "ëÏÍÍÅÎÔÁÒÉÊ"
|
||||
|
||||
#. (window->context->transformMask & TRANS_TRES) &&
|
||||
#: imtools.c:200 imtools.c:276
|
||||
msgid "Define treshold limits first"
|
||||
msgstr "ïÐÒÅÄÅÌÉÔÅ ÐÏÒÏÇÉ ÎÁ ÇÉÓÔÏÇÒÁÍÍÅ"
|
||||
|
||||
#: fitsheaders.c:518
|
||||
msgid "Delete entry (ctrl+d)"
|
||||
msgstr "õÄÁÌÉÔØ ÚÁÐÉÓØ (ctrl+d)"
|
||||
|
||||
#: opengl.c:63
|
||||
msgid "Depth bits"
|
||||
msgstr "âÉÔÙ ÇÌÕÂÉÎÙ"
|
||||
|
||||
#: fitsview.glade:152
|
||||
msgid "Draw _tracks"
|
||||
msgstr "ðÏÓÔÒÏÅÎÉÅ Ô_ÒÅËÏ×"
|
||||
|
||||
#: opengl.c:232
|
||||
msgid "Empty region"
|
||||
msgstr "ðÕÓÔÁÑ ÏÂÌÁÓÔØ"
|
||||
|
||||
#: imtools.c:462
|
||||
msgid "Error in Hough transform module"
|
||||
msgstr "ïÛÉÂËÁ × ÍÏÄÕÌÅ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ èÁÆÁ"
|
||||
|
||||
#: fitsheaders.c:102
|
||||
msgid "Error in value range!"
|
||||
msgstr "ïÛÉÂËÁ × ÄÉÁÐÁÚÏÎÅ ÚÎÁÞÅÎÉÊ!"
|
||||
|
||||
#: gtk.c:58
|
||||
#, c-format
|
||||
msgid "Error: %s\n"
|
||||
msgstr "ïÛÉÂËÁ: %s\n"
|
||||
|
||||
#: open_dialog.c:155
|
||||
msgid "FITS files"
|
||||
msgstr "FITS ÆÁÊÌÙ"
|
||||
|
||||
#: fitsview.glade:209
|
||||
msgid "Find and enumerate spots"
|
||||
msgstr "òÁÓÐÏÚÎÁ×ÁÎÉÅ ÐÑÔÅÎ"
|
||||
|
||||
#: tracking.c:551
|
||||
#, c-format
|
||||
msgid "Fit gaussian, x0=%.2f I(%.2f, %.2f), s=%.2f, A=%.1f, C=%.3f"
|
||||
msgstr "áÐÐÒÏËÓÉÍÁÃÉÑ ÇÁÕÓÓÉÁÎÏÊ, x0=%.2f I(%.2f, %.2f), s=%.2f, A=%.1f, C="
|
||||
"%.3f"
|
||||
|
||||
#: fitsheaders.c:133
|
||||
msgid "Format error: complex number must be in format"
|
||||
msgstr "ïÛÉÂËÁ ÆÏÒÍÁÔÁ: ËÏÍÐÌÅËÓÎÏÅ ÞÉÓÌÏ ÄÏÌÖÎÏ ÉÍÅÔØ ÆÏÒÍÁÔ"
|
||||
|
||||
#: fitsview.glade:255
|
||||
msgid "Identify _circles"
|
||||
msgstr "éÄÅÎÔÉÆÉËÁÃÉÑ _ÏËÒÕÖÎÏÓÔÅÊ"
|
||||
|
||||
#: fitsview.glade:227
|
||||
msgid "Identify _spots"
|
||||
msgstr "éÄÅÎÔÉÆÉËÁÃÉÑ _ÐÑÔÅÎ"
|
||||
|
||||
#: imtools.c:348 imtools.c:398 imtools.c:434
|
||||
msgid "Image is empty"
|
||||
msgstr "éÚÏÂÒÁÖÅÎÉÅ ÎÅ ÚÁÇÒÕÖÅÎÏ"
|
||||
|
||||
#: open_dialog.c:326
|
||||
msgid "Image size"
|
||||
msgstr "òÁÚÍÅÒ ÉÚÏÂÒÁÖÅÎÉÑ"
|
||||
|
||||
#: fitsheaders.c:121
|
||||
msgid "Invalid double number!"
|
||||
msgstr "îÅ×ÅÒÎÏÅ ÞÉÓÌÏ Ä×ÏÊÎÏÊ ÔÏÞÎÏÓÔÉ!"
|
||||
|
||||
#. ÎÏÍÅÒ ÐÅÒ×ÏÊ ÔÏÞËÉ
|
||||
#. ÎÅ ÔÕÄÁ ÐÏÐÁÌÉ?
|
||||
#: tracking.c:528
|
||||
msgid "Invalid number of first point"
|
||||
msgstr "îÅ×ÅÒÎÙÊ ÎÏÍÅÒ ÐÅÒ×ÏÊ ÔÏÞËÉ"
|
||||
|
||||
#: fitsview.glade:489
|
||||
msgid "Linear"
|
||||
msgstr "ìÉÎÅÊÎÙÊ"
|
||||
|
||||
#: fitsview.glade:499
|
||||
msgid "Log"
|
||||
msgstr "ìÏÇÁÒÉÆÍÉÞÅÓËÉÊ"
|
||||
|
||||
#: fitsview.glade:1010 fitsview.glade:1108
|
||||
msgid "Max"
|
||||
msgstr "íÁËÓÉÍÕÍ"
|
||||
|
||||
#: opengl.c:64
|
||||
msgid "Max amount of lights"
|
||||
msgstr "íÁËÓÉÍÁÌØÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÉÓÔÏÞÎÉËÏ× ÏÓ×ÅÝÅÎÉÑ"
|
||||
|
||||
#: opengl.c:68
|
||||
msgid "Max clip planes"
|
||||
msgstr "íÁËÓÉÍÁÌØÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÌÏÓËÏÓÔÅÊ ÏÔÓÅÞÅÎÉÑ"
|
||||
|
||||
#: gtk.c:464
|
||||
msgid "Max height value less than min"
|
||||
msgstr "íÁËÓÉÍÁÌØÎÁÑ ×ÙÓÏÔÁ ÐÑÔÎÁ ÍÅÎØÛÅ ÍÉÎÉÍÁÌØÎÏÊ"
|
||||
|
||||
#: opengl.c:73
|
||||
msgid "Max stack depths"
|
||||
msgstr "íÁËÓÉÍÁÌØÎÁÑ ÇÌÕÂÉÎÁ ÓÔÅËÁ"
|
||||
|
||||
#: opengl.c:67
|
||||
msgid "Max texture size"
|
||||
msgstr "íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÔÅËÓÔÕÒÙ"
|
||||
|
||||
#: gtk.c:466
|
||||
msgid "Max width value less than min"
|
||||
msgstr "íÁËÓÉÍÁÌØÎÁÑ ÛÉÒÉÎÁ ÍÅÎØÛÅ ÍÉÎÉÍÁÌØÎÏÊ"
|
||||
|
||||
#: fitsview.glade:978 fitsview.glade:1076
|
||||
msgid "Min"
|
||||
msgstr "íÉÎÉÍÕÍ"
|
||||
|
||||
#: fitsview.glade:817
|
||||
msgid "Mouse and arrow keys navigation"
|
||||
msgstr "îÁ×ÉÇÁÃÉÑ ÍÙÛØÀ É ËÌÁ×ÉÁÔÕÒÏÊ"
|
||||
|
||||
#: fitsview.glade:792
|
||||
msgid "Move backward"
|
||||
msgstr "îÁÚÁÄ"
|
||||
|
||||
#: fitsview.glade:776
|
||||
msgid "Move down"
|
||||
msgstr "÷ÎÉÚ"
|
||||
|
||||
#: fitsview.glade:800
|
||||
msgid "Move forward"
|
||||
msgstr "÷ÐÅÒÅÄ"
|
||||
|
||||
#: fitsview.glade:768
|
||||
msgid "Move left"
|
||||
msgstr "÷ÌÅ×Ï"
|
||||
|
||||
#: fitsview.glade:760
|
||||
msgid "Move right"
|
||||
msgstr "÷ÐÒÁ×Ï"
|
||||
|
||||
#: fitsview.glade:784
|
||||
msgid "Move up"
|
||||
msgstr "÷×ÅÒÈ"
|
||||
|
||||
#: fitsheaders.c:54
|
||||
msgid "Name"
|
||||
msgstr "îÁÚ×ÁÎÉÅ"
|
||||
|
||||
#: fitsheaders.c:513
|
||||
msgid "New entry (ctrl+n)"
|
||||
msgstr "îÏ×ÁÑ ÚÁÐÉÓØ (ctrl+n)"
|
||||
|
||||
#: imtools.c:213
|
||||
msgid "No GSL library found, don't calculate centroids"
|
||||
msgstr "îÅ ÏÂÎÁÒÕÖÅÎÁ ÂÉÂÌÉÏÔÅËÁ GSL, ÎÅ ×ÙÞÉÓÌÑÀ ÃÅÎÔÒÏÉÄÙ"
|
||||
|
||||
#. ÔÏÞÅË ÎÅÔ? (ï_Ï, Á ÔÁËÏÅ ×ÏÏÂÝÅ ÍÏÖÅÔ ÂÙÔØ?)
|
||||
#: tracking.c:518
|
||||
msgid "No data points"
|
||||
msgstr "ïÔÓÕÔÓÔ×ÕÀÔ ÔÏÞËÉ Ó ÄÁÎÎÙÍÉ"
|
||||
|
||||
#: terrain.c:199
|
||||
msgid "No image in parent window"
|
||||
msgstr "÷ ÒÏÄÉÔÅÌØÓËÏÅ ÏËÎÏ ÎÅ ÚÁÇÒÕÖÅÎÏ ÉÚÏÂÒÁÖÅÎÉÅ"
|
||||
|
||||
#: tracking.c:510
|
||||
msgid "No parent window or image"
|
||||
msgstr "ïÔÓÕÔÓÔ×ÕÅÔ ÒÏÄÉÔÅÌØÓËÏÅ ÏËÎÏ ÉÌÉ ÉÚÏÂÒÁÖÅÎÉÅ × ÎÅÍ"
|
||||
|
||||
#. "ïÔÓÕÔÓÔ×ÕÀÔ ÒÁÓÐÏÚÎÁÎÎÙÅ ÐÑÔÎÁ"
|
||||
#: gtk.c:514
|
||||
msgid "No recognized spots"
|
||||
msgstr "ïÔÓÕÔÓÔ×ÕÀÔ ÒÁÓÐÏÚÎÁÎÎÙÅ ÐÑÔÎÁ"
|
||||
|
||||
#: fits.c:356
|
||||
msgid "Not an image? (dimensions != 2)"
|
||||
msgstr "FITS-ÆÁÊÌ ÎÅ Ñ×ÌÑÅÔÓÑ ÉÚÏÂÒÁÖÅÎÉÅÍ? (ÒÁÚÍÅÒÎÏÓÔØ ÎÅ ÒÁ×ÎÁ Ä×ÕÍ)"
|
||||
|
||||
#: spots.c:67
|
||||
msgid "Not enough markers"
|
||||
msgstr "îÅÄÏÓÔÁÔÏÞÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÍÁÒËÅÒÏ×"
|
||||
|
||||
#: imtools.c:257
|
||||
msgid "Not enough points"
|
||||
msgstr "îÅÄÏÓÔÁÔÏÞÎÏ ÔÏÞÅË"
|
||||
|
||||
#: fitsheaders.c:486
|
||||
msgid "Open fits file first"
|
||||
msgstr "÷ÎÁÞÁÌÅ ÏÔËÒÏÊÔÅ fits-ÆÁÊÌ"
|
||||
|
||||
#: fitsview.glade:55
|
||||
msgid "Open in _3D window"
|
||||
msgstr "ïÔËÒÙÔØ × ÏËÎÅ _3D"
|
||||
|
||||
#: fitsview.glade:40
|
||||
msgid "Open in _new window"
|
||||
msgstr "ïÔËÒÙÔØ × _ÎÏ×ÏÍ ÏËÎÅ"
|
||||
|
||||
#: opengl.c:32
|
||||
msgid "OpenGL not supported"
|
||||
msgstr "OpenGL ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ×ÁÛÅÊ ÓÉÓÔÅÍÏÊ"
|
||||
|
||||
#: imtools.c:296
|
||||
msgid "Pix not found"
|
||||
msgstr "íÁÓËÁ ÎÅ ÏÂÎÁÒÕÖÅÎÁ"
|
||||
|
||||
#: fitsview.glade:1282
|
||||
msgid "Postfocal"
|
||||
msgstr "úÁÆÏËÁÌØÎÏÅ"
|
||||
|
||||
#: fitsview.glade:1269
|
||||
msgid "Prefocal"
|
||||
msgstr "ðÒÅÄÆÏËÁÌØÎÏÅ"
|
||||
|
||||
#: open_dialog.c:328
|
||||
msgid "Preview scale"
|
||||
msgstr "íÁÓÛÔÁ ÐÒÅÄÐÒÏÓÍÏÔÒÁ"
|
||||
|
||||
#: open_dialog.c:188
|
||||
msgid "Preview settings"
|
||||
msgstr "îÁÓÔÒÏÊËÉ ÐÒÅÄÐÒÏÓÍÏÔÒÁ"
|
||||
|
||||
#: open_dialog.c:96 open_dialog.c:327
|
||||
msgid "Preview size"
|
||||
msgstr "òÁÚÍÅÒ ÐÒÅÄÐÒÏÓÍÏÔÒÁ"
|
||||
|
||||
#: gtk.c:1081
|
||||
msgid "Quit"
|
||||
msgstr "_÷ÙÈÏÄ"
|
||||
|
||||
#: fitsview.glade:736
|
||||
msgid "Rotate X CCW"
|
||||
msgstr "÷ÒÁÝÁÔØ ÐÒÏÔÉ× þó ×ÏËÒÕÇ ÏÓÉ X"
|
||||
|
||||
#: fitsview.glade:728
|
||||
msgid "Rotate X CW"
|
||||
msgstr "÷ÒÏÝÁÔØ ÐÏ þó ×ÏËÒÕÇ ÏÓÉ X"
|
||||
|
||||
#: fitsview.glade:744
|
||||
msgid "Rotate Z CCW"
|
||||
msgstr "÷ÒÁÝÁÔØ ÐÒÏÔÉ× þó ×ÏËÒÕÇ ÏÓÉ Z"
|
||||
|
||||
#: fitsview.glade:752
|
||||
msgid "Rotate Z CW"
|
||||
msgstr "÷ÒÏÝÁÔØ ÐÏ þó ×ÏËÒÕÇ ÏÓÉ Z"
|
||||
|
||||
#: fitsview.glade:243
|
||||
msgid "Sa_ve spots"
|
||||
msgstr "óÏ_ÈÒÁÎÉÔØ ÔÏÞËÉ"
|
||||
|
||||
#: fitsview.glade:144
|
||||
msgid "Select _spots"
|
||||
msgstr "÷ÙÂÏÒ _ÔÏÞÅË"
|
||||
|
||||
#: open_dialog.c:142
|
||||
msgid "Select fits file to open"
|
||||
msgstr "÷ÙÂÅÒÉÔÅ, ËÁËÏÊ fits-ÆÁÊÌ ÏÔËÒÙÔØ"
|
||||
|
||||
#: terrain.c:177
|
||||
msgid "Selected area too small"
|
||||
msgstr "÷ÙÄÅÌÅÎÎÁÑ ÏÂÌÁÓÔØ ÓÌÉÛËÏÍ ÍÁÌÁ"
|
||||
|
||||
#: gtk.c:358
|
||||
msgid "Selected line"
|
||||
msgstr "÷ÙÂÒÁÎÁ ÌÉÎÉÑ"
|
||||
|
||||
#: tracking.c:475
|
||||
#, c-format
|
||||
msgid "Selected region from %.1f to %.1f, %d datapoints"
|
||||
msgstr "÷ÙÄÅÌÅÎÁ ÏÂÌÁÓÔØ ÏÔ %.1f ÄÏ %.1f, %d ÔÏÞÅË"
|
||||
|
||||
#: opengl.c:241
|
||||
msgid "Selected spot: "
|
||||
msgstr "÷ÙÂÒÁÎÏ ÐÑÔÎÏ: "
|
||||
|
||||
#: opengl.c:239
|
||||
msgid "Selected spot[s]:\n"
|
||||
msgstr "÷ÙÂÒÁÎÙ ÐÑÔÎÁ:\n"
|
||||
|
||||
#: opengl.c:243
|
||||
msgid "Selected spots: "
|
||||
msgstr "÷ÙÂÒÁÎÙ ÐÑÔÎÁ: "
|
||||
|
||||
#: fitsview.glade:115
|
||||
msgid "Show _headers"
|
||||
msgstr "ïÔÏÂÒÁÚÉÔØ _ÚÁÇÏÌÏ×ËÉ"
|
||||
|
||||
#: fitsview.glade:107
|
||||
msgid "Show _histogram"
|
||||
msgstr "ïÔÏÂÒÁÚÉÔØ _ÇÉÓÔÏÇÒÁÍÍÕ"
|
||||
|
||||
#: fitsview.glade:219
|
||||
msgid "Size _tresholds"
|
||||
msgstr "ïÇÒÁÎÉÞÅÎÉÅ ÒÁÚÍÅÒÏ×"
|
||||
|
||||
#: fitsview.glade:235
|
||||
msgid "So_rt hartmann spots"
|
||||
msgstr "óÏÒÔÉÒÏ×ÁÔØ ÐÑÔÎÁ ÇÁÒÔÍÁÎÏÇÒÁÍÍÙ"
|
||||
|
||||
#: spots.c:128
|
||||
msgid "Spots array is full, can't place new spot\n"
|
||||
msgstr "íÁÓÓÉ× ÔÏÞÅË ÐÏÌÏÎ, ÎÅ ÍÏÇÕ ÄÏÂÁ×ÉÔØ ÎÏ×ÕÀ ÔÏÞËÕ\n"
|
||||
|
||||
#: fitsview.glade:934
|
||||
msgid "Spots' size treshold"
|
||||
msgstr "ïÇÒÁÎÉÞÅÎÉÅ ÒÁÚÍÅÒÏ× ÐÑÔÅÎ"
|
||||
|
||||
#: opengl.c:64
|
||||
msgid "Stencil bits"
|
||||
msgstr "âÉÔÙ ÔÒÁÆÁÒÅÔÁ"
|
||||
|
||||
#: spots.c:66
|
||||
msgid "Too many markers"
|
||||
msgstr "óÌÉÛËÏÍ ÍÎÏÇÏ ÍÁÒËÅÒÏ×"
|
||||
|
||||
#: imtools.c:253
|
||||
msgid "Too many points"
|
||||
msgstr "óÌÉÛËÏÍ ÍÎÏÇÏ ÔÏÞÅË"
|
||||
|
||||
#: spots.c:69
|
||||
msgid "Too many rings"
|
||||
msgstr "óÌÉÛËÏÍ ÍÎÏÇÏ ËÏÌÅÃ"
|
||||
|
||||
#. ËÏÌÉÞÅÓÔ×Ï ÚÁÐÉÓÅÊ
|
||||
#: fitsheaders.c:54
|
||||
msgid "Type"
|
||||
msgstr "ôÉÐ"
|
||||
|
||||
#: opengl.c:78
|
||||
msgid "VBO is supported\n"
|
||||
msgstr "ðÏÄÄÅÒÖÉ×ÁÀÔÓÑ ÂÕÆÅÒÙ ÏÂßÅËÔÏ×\n"
|
||||
|
||||
#: fitsheaders.c:54
|
||||
msgid "Value"
|
||||
msgstr "úÎÁÞÅÎÉÅ"
|
||||
|
||||
#: fitsview.glade:481
|
||||
msgid "Y axis scale"
|
||||
msgstr "íÁÓÛÔÁ ÏÓÉ Y"
|
||||
|
||||
#: spots.c:132
|
||||
msgid "Zero pointer to spot\n"
|
||||
msgstr "îÕÌÅ×ÏÊ ÕËÁÚÁÔÅÌØ ÎÁ ÔÏÞËÕ\n"
|
||||
|
||||
#: fitsview.glade:181
|
||||
msgid "Zoom _in"
|
||||
msgstr "õ_×ÅÌÉÞÉÔØ"
|
||||
|
||||
#: fitsview.glade:189
|
||||
msgid "Zoom _out"
|
||||
msgstr "õ_ÍÅÎØÛÉÔØ"
|
||||
|
||||
#: fitsview.glade:92 fitsview.glade:466 fitsview.glade:705
|
||||
msgid "_Edit"
|
||||
msgstr "_éÚÍÅÎÉÔØ"
|
||||
|
||||
#: fitsview.glade:16 fitsview.glade:440 fitsview.glade:671
|
||||
msgid "_File"
|
||||
msgstr "_æÁÊÌ"
|
||||
|
||||
#: fitsview.glade:818
|
||||
msgid "_Game mode"
|
||||
msgstr ""
|
||||
|
||||
#: fitsview.glade:275
|
||||
msgid "_Help"
|
||||
msgstr "_ðÏÍÏÝØ"
|
||||
|
||||
#: fitsview.glade:263
|
||||
msgid "_Hough transform"
|
||||
msgstr "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ _èÁÆÁ"
|
||||
|
||||
#: fitsview.glade:201 fitsview.glade:517 fitsview.glade:838
|
||||
msgid "_Math"
|
||||
msgstr "_íÁÔÅÍÁÔÉËÁ"
|
||||
|
||||
#: fitsview.glade:720
|
||||
msgid "_Move"
|
||||
msgstr "_ðÅÒÅÍÅÓÔÉÔØ"
|
||||
|
||||
#: fitsview.glade:173 fitsview.glade:826
|
||||
msgid "_Restore image"
|
||||
msgstr "_÷ÏÓÓÔÁÎÏ×ÉÔØ ÍÁÓÛÔÁÂ"
|
||||
|
||||
#: fitsview.glade:210
|
||||
msgid "_Spots"
|
||||
msgstr "_ðÑÔÎÁ"
|
||||
|
||||
#: fitsview.glade:99 fitsview.glade:473 fitsview.glade:712
|
||||
msgid "_View"
|
||||
msgstr "_÷ÉÄ"
|
||||
|
||||
#: fitsview.glade:165
|
||||
msgid "_Zoom frame"
|
||||
msgstr "_õ×ÅÌÉÞÅÎÉÅ ÒÁÍËÏÊ"
|
||||
|
||||
#: opengl.c:74
|
||||
msgid "attrib"
|
||||
msgstr "ÁÔÒÉÂÕÔÏ×ÙÊ"
|
||||
|
||||
#: open_dialog.c:79
|
||||
msgid "linear"
|
||||
msgstr "ÌÉÎÅÊÎÁÑ"
|
||||
|
||||
#: open_dialog.c:79
|
||||
msgid "log"
|
||||
msgstr "ÌÏÇÁÒÉÆÍÉÞÅÓËÁÑ"
|
||||
|
||||
#: opengl.c:74
|
||||
msgid "modelview"
|
||||
msgstr "ÍÏÄÅÌØÎÏ-×ÉÄÏ×ÙÊ"
|
||||
|
||||
#: opengl.c:74
|
||||
msgid "projection"
|
||||
msgstr "ÐÒÏÅËÃÉÊ"
|
||||
|
||||
#: open_dialog.c:79
|
||||
msgid "square root"
|
||||
msgstr "Ë×ÁÄÒÁÔÎÙÊ ËÏÒÅÎØ"
|
||||
|
||||
#: opengl.c:75
|
||||
msgid "texture"
|
||||
msgstr "ÔÅËÓÔÕÒ"
|
||||
|
||||
#~ msgid "You sure, you want exit?"
|
||||
#~ msgstr "÷Ù Õ×ÅÒÅÎÙ, ÞÔÏ ÈÏÔÉÔÅ ×ÙÊÔÉ?"
|
||||
2
src/locale/ru/update
Executable file
2
src/locale/ru/update
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
msgmerge -Uis ru.po messages.po
|
||||
433
src/open_dialog.c
Normal file
433
src/open_dialog.c
Normal file
@ -0,0 +1,433 @@
|
||||
// open_dialog.c - open file dialog with preview
|
||||
// Copyright:
|
||||
// Guillaume Chazarain <guichaz@gmail.com> (gliv project)
|
||||
// 2011 Edward V. Emelianoff <eddy@sao.ru> (modification for fits open)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "fitsview.h"
|
||||
#include "open_dialog.h"
|
||||
|
||||
gchar *saved_path = NULL;
|
||||
|
||||
typedef struct{
|
||||
GtkLabel *label;
|
||||
GtkWidget *image;
|
||||
} fits_preview;
|
||||
|
||||
GdkPixbuf *getfits(char *filename, gchar **descr);
|
||||
|
||||
void update_preview( GtkFileChooser *file_chooser,
|
||||
fits_preview *FP){
|
||||
GtkWidget *preview = FP->image;
|
||||
GtkLabel *ilabel = FP->label;
|
||||
char *filename;
|
||||
gchar *descr = NULL;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
filename = gtk_file_chooser_get_preview_filename(file_chooser);
|
||||
if (filename == NULL) return;
|
||||
pixbuf = getfits(filename, &descr);
|
||||
if(pixbuf){
|
||||
gint w = gdk_pixbuf_get_width(pixbuf);
|
||||
w = w - w/4;
|
||||
if(w < 200) w = 200;
|
||||
gtk_widget_set_size_request(GTK_WIDGET(ilabel), w, -1);
|
||||
gtk_label_set_text(ilabel, descr);
|
||||
}
|
||||
g_free(filename);
|
||||
gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf);
|
||||
if(pixbuf) g_object_unref(pixbuf);
|
||||
gtk_file_chooser_set_preview_widget_active(file_chooser, (pixbuf != NULL));
|
||||
}
|
||||
|
||||
void cb_changed(GtkComboBox *combo, GtkObject *chooser){
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
int val;
|
||||
gtk_combo_box_get_active_iter(combo, &iter);
|
||||
model = gtk_combo_box_get_model(combo);
|
||||
gtk_tree_model_get(model, &iter, 1, &val, -1);
|
||||
// clear needed config bits
|
||||
if(val & PREVIEW_SIZEMASK) Global->previewMode &= ~PREVIEW_SIZEMASK;
|
||||
else if(val & PREVIEW_COLFNMASK) Global->previewMode &= ~PREVIEW_COLFNMASK;
|
||||
Global->previewMode |= val; // set new
|
||||
gtk_signal_emit_by_name(chooser, "update-preview"); // redraw
|
||||
}
|
||||
|
||||
// arguments of funtion which creates menu
|
||||
enum{
|
||||
COMBO_SIZE,
|
||||
COMBO_COLORFN
|
||||
};
|
||||
GtkWidget *create_combo(unsigned char type, GtkObject *chooser){
|
||||
#define SIZES 5
|
||||
#define COLORFNS 3
|
||||
gchar *sizes[] = {"128 x 128", "256 x 256", "512 x 512",
|
||||
"768 x 768", "1024 x 1024"};
|
||||
gchar *colorfns[] = {N_("linear"), N_("log"), N_("square root")};
|
||||
gchar **ptr;
|
||||
GtkWidget *label = NULL, *vbox = NULL;
|
||||
gchar *label_text = NULL;
|
||||
int curpos, i, n;
|
||||
int startpos = 0; // bit position of appropriate numbers
|
||||
GtkListStore *store;
|
||||
GtkWidget *combo;
|
||||
GtkCellRenderer *cell;
|
||||
GtkTreeIter iter;
|
||||
if(type == COMBO_SIZE){
|
||||
ptr = sizes; n = SIZES;
|
||||
if((curpos = Global->previewMode & PREVIEW_SIZEMASK))
|
||||
curpos--;
|
||||
else
|
||||
curpos = PREVIEW_512 - 1;
|
||||
startpos = 0;
|
||||
label_text = g_strdup_printf(_("Preview size"));
|
||||
}
|
||||
else if(type == COMBO_COLORFN){
|
||||
ptr = colorfns; n = COLORFNS;
|
||||
if((curpos = (Global->previewMode & PREVIEW_COLFNMASK) >> 3))
|
||||
curpos--;
|
||||
else
|
||||
curpos = (PREVIEW_SQRT>>3) - 1;
|
||||
startpos = 3;
|
||||
label_text = g_strdup_printf(_("Colormap function"));
|
||||
}
|
||||
else return NULL;
|
||||
vbox = gtk_vbox_new(FALSE, 3);
|
||||
label = gtk_label_new(label_text);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
||||
store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
|
||||
for(i = 0; i < n; i++){
|
||||
gtk_list_store_append(store, &iter);
|
||||
gtk_list_store_set(store, &iter, 0, _(ptr[i]), 1, (i+1)<<startpos, -1);
|
||||
}
|
||||
combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
|
||||
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
|
||||
cell = gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
|
||||
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell, "text", 0, NULL);
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), curpos);
|
||||
g_signal_connect(combo, "changed", G_CALLBACK(cb_changed), (gpointer)chooser);
|
||||
g_object_unref(store);
|
||||
free(label_text);
|
||||
return vbox;
|
||||
}
|
||||
|
||||
//GtkFileChooser *open_fits_dialog(gboolean select_dir){
|
||||
GtkFileChooser *open_fits_dialog(){
|
||||
GtkLabel *ilabel = NULL;
|
||||
GtkImage *preview = NULL;
|
||||
GtkWidget *vbox = NULL, *combo = NULL, *frame = NULL, *sbox = NULL;
|
||||
GtkFileChooserAction action;
|
||||
const gchar *label;
|
||||
GtkFileChooser *chooser;
|
||||
static fits_preview FP;
|
||||
/* if (select_dir) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
label = _("Select a folder to open");
|
||||
} else { */
|
||||
action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
label = _("Select fits file to open");
|
||||
//}
|
||||
chooser = GTK_FILE_CHOOSER(
|
||||
gtk_file_chooser_dialog_new(label, NULL,
|
||||
action,
|
||||
GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN,
|
||||
GTK_RESPONSE_ACCEPT,
|
||||
NULL)
|
||||
);
|
||||
// it CAN CAUSED MEMORY LEAKS: filter doesn't deletes
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, _("FITS files"));
|
||||
gtk_file_filter_add_pattern(filter, "*.fit");
|
||||
gtk_file_filter_add_pattern(filter, "*.FIT");
|
||||
gtk_file_filter_add_pattern(filter, "*.fts");
|
||||
gtk_file_filter_add_pattern(filter, "*.FTS");
|
||||
gtk_file_filter_add_pattern(filter, "*.fits");
|
||||
gtk_file_filter_add_pattern(filter, "*.FITS");
|
||||
gtk_file_chooser_add_filter(chooser, filter);
|
||||
filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, _("All files"));
|
||||
gtk_file_filter_add_pattern(filter, "*");
|
||||
gtk_file_chooser_add_filter(chooser, filter);
|
||||
|
||||
if(saved_path)
|
||||
gtk_file_chooser_set_current_folder(chooser, saved_path);
|
||||
// if (!select_dir) {
|
||||
vbox = gtk_vbox_new(FALSE, 8);
|
||||
ilabel = GTK_LABEL(gtk_label_new(NULL));
|
||||
gtk_label_set_line_wrap(ilabel, TRUE);
|
||||
gtk_label_set_max_width_chars(ilabel, 80);
|
||||
gtk_label_set_line_wrap_mode(ilabel, PANGO_WRAP_WORD);
|
||||
// either wrap or angle
|
||||
//gtk_label_set_angle(ilabel, 30.);
|
||||
preview = GTK_IMAGE(gtk_image_new());
|
||||
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(preview),
|
||||
FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(ilabel),
|
||||
FALSE, FALSE, 0);
|
||||
FP.label = ilabel; FP.image = GTK_WIDGET(preview);
|
||||
//gtk_file_chooser_set_select_multiple(chooser, TRUE);
|
||||
gtk_widget_show_all(GTK_WIDGET(vbox));
|
||||
gtk_file_chooser_set_preview_widget(chooser, GTK_WIDGET(vbox));
|
||||
vbox = gtk_hbox_new(FALSE, 10);
|
||||
frame = gtk_frame_new(_("Preview settings"));
|
||||
gtk_box_pack_end(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
|
||||
sbox = gtk_hbox_new(FALSE, 10);
|
||||
gtk_container_add(GTK_CONTAINER(frame), sbox);
|
||||
combo = create_combo(COMBO_SIZE, GTK_OBJECT(chooser));
|
||||
gtk_box_pack_start(GTK_BOX(sbox), combo, FALSE, FALSE, 0);
|
||||
combo = create_combo(COMBO_COLORFN, GTK_OBJECT(chooser));
|
||||
gtk_box_pack_start(GTK_BOX(sbox), combo, FALSE, FALSE, 0);
|
||||
gtk_widget_show_all(frame);
|
||||
gtk_file_chooser_set_extra_widget(chooser, vbox);
|
||||
g_signal_connect(chooser, "update-preview",
|
||||
G_CALLBACK(update_preview), (gpointer)&FP);
|
||||
// }
|
||||
return chooser;
|
||||
}
|
||||
/*
|
||||
// gray - intensity from 0.f to 1.f
|
||||
void gray2rgb(float gray, guchar *rgb){
|
||||
int i = (int)(gray * 4.);
|
||||
float x = gray - (float)i * .25;
|
||||
guchar r = 0, g = 0, b = 0;
|
||||
switch(i){
|
||||
case 0:
|
||||
b = (guchar)(255. * x);
|
||||
break;
|
||||
case 1:
|
||||
b = 255;
|
||||
g = (guchar)(255. * x);
|
||||
break;
|
||||
case 2:
|
||||
r = (guchar)(255. * x);
|
||||
g = 255;
|
||||
b = (guchar)(255. * (1. - x));
|
||||
break;
|
||||
case 3:
|
||||
r = 255;
|
||||
g = (guchar)(255. * (1. - x));
|
||||
break;
|
||||
default:
|
||||
if(i>3) r=255;
|
||||
}
|
||||
*rgb++ = r;
|
||||
*rgb++ = g;
|
||||
*rgb++ = b;
|
||||
}*/
|
||||
void gray2rgb(float gray, guchar *rgb){
|
||||
int i = (int)(gray * 4.);
|
||||
float x = gray - (float)i * .25;
|
||||
guchar r = 0, g = 0, b = 0;
|
||||
switch(i){
|
||||
case 0:
|
||||
g = (guchar)(255. * x);
|
||||
b = 255;
|
||||
break;
|
||||
case 1:
|
||||
g = 255;
|
||||
b = (guchar)(255. * (1. - x));
|
||||
break;
|
||||
case 2:
|
||||
r = (guchar)(255. * x);
|
||||
g = 255;
|
||||
break;
|
||||
case 3:
|
||||
r = 255;
|
||||
g = (guchar)(255. * (1. - x));
|
||||
break;
|
||||
default:
|
||||
r = 255;
|
||||
}
|
||||
*rgb++ = r;
|
||||
*rgb++ = g;
|
||||
*rgb++ = b;
|
||||
}
|
||||
|
||||
GdkPixbufDestroyNotify free_preview_data(guchar *pixels, gpointer data){
|
||||
free(pixels);
|
||||
free(data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get preview from FITS file filename
|
||||
GdkPixbuf *getfits(char *filename, gchar **descr){
|
||||
gboolean status;
|
||||
fitsfile *fp;
|
||||
double (*colorfun)(double);
|
||||
double linfun(double arg){ return arg; } // bung for PREVIEW_LINEAR
|
||||
double logfun(double arg){ return log(1.+arg); } // for PREVIEW_LOG
|
||||
gchar *description = NULL; // some keywords from FITS header
|
||||
#define TRYFITS(f, ...) \
|
||||
do{ status = FALSE; \
|
||||
f(__VA_ARGS__, &status); \
|
||||
if(status){ \
|
||||
free(ima_data); free(pixbuf_data); \
|
||||
free(description); free(pix); \
|
||||
fits_close_file(fp, &status); \
|
||||
return NULL;} \
|
||||
}while(0)
|
||||
void add_keyw(char *keyw){
|
||||
char keyval[FLEN_VALUE], *ptr;
|
||||
if(VALUE_UNDEFINED == fits_read_key(fp,
|
||||
TSTRING, keyw, keyval, NULL, &status)) return;
|
||||
if(status) return;
|
||||
ptr = g_strdup_printf("%s;\t%s=%s", description, keyw, keyval);
|
||||
free(description);
|
||||
description = ptr;
|
||||
}
|
||||
int MAX_SIZE = 512; // max preview size
|
||||
unsigned char cntxt;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
float nullval = 0.;
|
||||
int i, j, k, l, N, M, stat;
|
||||
int naxis, w, h, pixScale, Ws, Hs, dtype;
|
||||
int sz;
|
||||
cntxt = Global->previewMode & PREVIEW_SIZEMASK; // get preview size
|
||||
if(cntxt)
|
||||
switch(cntxt){
|
||||
case PREVIEW_128: MAX_SIZE = 128;
|
||||
break;
|
||||
case PREVIEW_256: MAX_SIZE = 256;
|
||||
break;
|
||||
case PREVIEW_512: MAX_SIZE = 512;
|
||||
break;
|
||||
case PREVIEW_768: MAX_SIZE = 768;
|
||||
break;
|
||||
case PREVIEW_1024:MAX_SIZE = 1024;
|
||||
break;
|
||||
}
|
||||
// array for preview picture line
|
||||
float *pix = malloc(MAX_SIZE * sizeof(float));
|
||||
long naxes[4];
|
||||
float *ima_data = NULL, *ptr, byte, n, m, max, min, wd, avr;
|
||||
guchar *pptr, *pixbuf_data = NULL;
|
||||
DBG("Try to open file %s\n", filename);
|
||||
TRYFITS(fits_open_file, &fp, filename, READONLY);
|
||||
TRYFITS(fits_get_img_param, fp, 4, &dtype, &naxis, naxes);
|
||||
if(naxis != 2) return NULL;
|
||||
w = naxes[0];
|
||||
h = naxes[1];
|
||||
sz = w * h;
|
||||
ima_data = malloc(sz * sizeof(float));
|
||||
pixbuf_data = malloc(3 * MAX_SIZE * MAX_SIZE * sizeof(guchar));
|
||||
|
||||
TRYFITS(fits_read_img, fp, TFLOAT, 1, sz, &nullval, ima_data, &stat);
|
||||
ptr = ima_data;
|
||||
min = max = *ptr; avr = 0.;
|
||||
// get statistics:
|
||||
for(i=0; i<h; i++)
|
||||
for(j=0; j<w; j++, ptr++){
|
||||
float tmp = *ptr;
|
||||
if(tmp > max) max = tmp;
|
||||
else if(tmp < min) min = tmp;
|
||||
avr += tmp;
|
||||
}
|
||||
avr /= (float)sz;
|
||||
wd = max - min;
|
||||
i = (int)ceil((float)w / MAX_SIZE);
|
||||
j = (int)ceil((float)h / MAX_SIZE);
|
||||
DBG("i=%d, j=%d, ms=%d",i,j,MAX_SIZE);
|
||||
pixScale = (i > j) ? i : j; // picture scale factor
|
||||
Ws = w / pixScale; // picture width in pixScale blocks
|
||||
Hs = h / pixScale; // -//- height pixScale
|
||||
DBG("w=%d, h=%d, Ws=%d, Hs=%d, pixScale=%d",w,h,Ws,Hs,pixScale);
|
||||
// prepare a comment to a prewiew:
|
||||
description = g_strdup_printf(
|
||||
"%s=%dx%d\n%s=%dx%d\n%s=%.1f%%;\tMax=%g,\tMin=%g,\tAvr=%g",
|
||||
_("Image size"), w, h,
|
||||
_("Preview size"), Ws, Hs,
|
||||
_("Preview scale"), 100./(double)pixScale,
|
||||
max, min, avr
|
||||
);
|
||||
add_keyw("BITPIX");
|
||||
add_keyw("IMAGETYP");
|
||||
add_keyw("OBJECT");
|
||||
add_keyw("EXPTIME"); add_keyw("EXP");
|
||||
add_keyw("AUTHOR");
|
||||
add_keyw("DATE");
|
||||
M = 0; // line number
|
||||
for(i = 0; i < Hs; i++){ // cycle through a blocks by lines
|
||||
//pptr = &pixbuf_data[i * Ws * 3];
|
||||
for(j = 0; j < MAX_SIZE; j++) pix[j] = 0;
|
||||
m = 0.; // amount of strings read in block
|
||||
for(l = 0; l < pixScale; l++, m++){ // cycle through a block lines
|
||||
ptr = &ima_data[M * w];
|
||||
N = 0; // number of column
|
||||
for(j = 0; j < Ws; j++){ // cycle through a blocks by columns
|
||||
n = 0.; // amount of columns read in block
|
||||
byte = 0.; // average intensity in block
|
||||
for(k = 0; k < pixScale; k++, n++){ // cycle through block pixels
|
||||
if(N++ < w) // row didn't end
|
||||
byte += *ptr++; // sum[(pix-min)/wd]/n = [sum(pix)/n-min]/wd
|
||||
else break;
|
||||
}
|
||||
pix[j] += byte / n;//(byte / n - min)/wd;
|
||||
}
|
||||
if(++M >= h) break;
|
||||
}
|
||||
// fill unused picture pixels
|
||||
ptr = &ima_data[i*Ws];
|
||||
for(l = 0; l < Ws; l++)
|
||||
*ptr++ = pix[l] / m;
|
||||
}
|
||||
ptr = ima_data;
|
||||
sz = Ws * Hs;
|
||||
max = min = *ptr;
|
||||
avr = 0;
|
||||
for(i=0; i < sz; i++, ptr++){
|
||||
float tmp = *ptr;
|
||||
if(tmp > max) max = tmp;
|
||||
else if(tmp < min) min = tmp;
|
||||
avr += tmp;
|
||||
}
|
||||
avr /= (float)sz;
|
||||
wd = max - min;
|
||||
avr = (avr - min) / wd; // normal average by preview
|
||||
avr = -log(avr); // scale factor
|
||||
if(avr > 1.) wd /= avr;
|
||||
ptr = ima_data;
|
||||
colorfun = sqrt;
|
||||
if((Global->previewMode & PREVIEW_COLFNMASK) == PREVIEW_LINEAR)
|
||||
colorfun = linfun;
|
||||
else if((Global->previewMode & PREVIEW_COLFNMASK) == PREVIEW_LOG)
|
||||
colorfun = logfun;
|
||||
for(i = Hs - 1; i > -1; i--){// fill pixbuf mirroring image by vertical
|
||||
pptr = &pixbuf_data[Ws * i * 3];
|
||||
for(j = 0; j < Ws; j++){
|
||||
gray2rgb(colorfun((*ptr++ - min) / wd), pptr);
|
||||
pptr += 3;
|
||||
}
|
||||
}
|
||||
fits_close_file(fp, &status);
|
||||
pixbuf = gdk_pixbuf_new_from_data(
|
||||
pixbuf_data, // guchar* data
|
||||
GDK_COLORSPACE_RGB, // only this supported
|
||||
FALSE, // no alpha
|
||||
8, // number of bits in byte (WTF? who is this idiot?)
|
||||
Ws, Hs, // size
|
||||
Ws * 3, // line length in bytes
|
||||
(GdkPixbufDestroyNotify)free_preview_data, // function (*GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
|
||||
(gpointer)description // pointer data
|
||||
);
|
||||
free(ima_data);
|
||||
free(pix);
|
||||
*descr = description;
|
||||
DBG("OK, preview is ready, previewMode = %d", Global->previewMode);
|
||||
return pixbuf;
|
||||
}
|
||||
731
src/opengl.c
Normal file
731
src/opengl.c
Normal file
@ -0,0 +1,731 @@
|
||||
// opengl.c - functions to work with openGL
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "opengl.h"
|
||||
#include "spots.h"
|
||||
#include "imtools.h"
|
||||
#include "contours.h"
|
||||
#include "open_dialog.h"
|
||||
|
||||
#define BUFSIZE 512 // select buffer sizw
|
||||
GLdouble ObjX = 0., ObjY = 0.; // mouse click coordinates (in window CS)
|
||||
gboolean forcesel = FALSE;
|
||||
gboolean useVBO = FALSE; // use VBO or lists
|
||||
|
||||
// these functions are absent in headers
|
||||
void glBlendEquation(GLenum);
|
||||
void glBlendFuncSeparate(GLenum, GLenum, GLenum, GLenum);
|
||||
|
||||
#define BADOGL() do{g_err(_("OpenGL not supported")); \
|
||||
g_assert_not_reached();}while(0)
|
||||
|
||||
gboolean queryExtension(char *extName){
|
||||
char *p = (char *)glGetString(GL_EXTENSIONS);
|
||||
char *end = p + strlen(p);
|
||||
while(p < end){
|
||||
size_t n = strcspn(p, " ");
|
||||
if((strlen(extName)==n) && (strncmp(extName,p,n)==0))
|
||||
return TRUE;
|
||||
p += (n + 1);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void getGLinfo(GtkWidget *Area){
|
||||
GLint a,b,c,d;
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
g_print(_("\nOpenGL info:\n"));
|
||||
glGetIntegerv(GL_RED_BITS, &a);
|
||||
glGetIntegerv(GL_GREEN_BITS, &b);
|
||||
glGetIntegerv(GL_BLUE_BITS, &c);
|
||||
glGetIntegerv(GL_ALPHA_BITS, &d);
|
||||
g_print("%s (R, G, B, alpha) = (%d, %d, %d, %d)\n", _("Color bits"),
|
||||
a, b, c, d);
|
||||
glGetIntegerv(GL_DEPTH_BITS, &a);
|
||||
glGetIntegerv(GL_STENCIL_BITS, &b);
|
||||
glGetIntegerv(GL_MAX_LIGHTS, &c);
|
||||
g_print("%s = %d, %s = %d, %s = %d\n", _("Depth bits"), a,
|
||||
_("Stencil bits"), b, _("Max amount of lights"), c);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &a);
|
||||
glGetIntegerv(GL_MAX_CLIP_PLANES, &b);
|
||||
g_print("%s = %d, %s = %d\n", _("Max texture size"), a,
|
||||
_("Max clip planes"), b);
|
||||
glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &a);
|
||||
glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, &b);
|
||||
glGetIntegerv(GL_MAX_ATTRIB_STACK_DEPTH, &c);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, &d);
|
||||
g_print("%s: %s = %d, %s = %d, %s = %d, %s = %d\n", _("Max stack depths"),
|
||||
_("modelview"), a, _("projection"), b, _("attrib"), c,
|
||||
_("texture"), d);
|
||||
//g_print("%s: %s\n", _("All extensions"), (char *)glGetString(GL_EXTENSIONS));
|
||||
useVBO = queryExtension("GL_ARB_vertex_buffer_object");
|
||||
if(useVBO) g_print(_("VBO is supported\n"));
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
}
|
||||
|
||||
void freeGLmemory(Window *window){
|
||||
if(!window->texture) return;
|
||||
GLuint *tex = &window->texture->tex;
|
||||
if(!*tex) return;
|
||||
if(useVBO)
|
||||
glDeleteBuffersARB(1, tex);
|
||||
else
|
||||
glDeleteLists(*tex, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Coordinates transformation from CS of drawingArea into CS of picture
|
||||
* x,y - pointer coordinates
|
||||
* X,Y - coordinates of appropriate point at picture
|
||||
*/
|
||||
void conv_mouse_to_image_coords(double x, double y,
|
||||
double *X, double *Y,
|
||||
Window *window){
|
||||
double a = window->Daspect / window->Zoom;
|
||||
*X = x * a - window->mouse.x;
|
||||
*Y = window->mouse.y - y * a;
|
||||
}
|
||||
|
||||
void conv_image_to_mouse_coords(double X, double Y,
|
||||
double *x, double *y,
|
||||
Window *window){
|
||||
double a = window->Zoom / window->Daspect;
|
||||
*x = (X + window->mouse.x) * a;
|
||||
*y = (window->mouse.y - Y) * a;
|
||||
}
|
||||
|
||||
gboolean configure(GtkWidget *Area, GdkEventExpose *event, Window *window){
|
||||
//FNAME();
|
||||
double a, A, W, H, w, h;
|
||||
double Zoom = window->Zoom;
|
||||
if(event)
|
||||
if(event->count) return FALSE;
|
||||
TEXTURE *texture = (TEXTURE*)window->texture;
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
gdk_gl_drawable_wait_gdk(glDrawable);
|
||||
// set position
|
||||
double W0, H0, x0,y0, xm,ym;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
W = W0 = Area->allocation.width;
|
||||
H = H0 = Area->allocation.height;
|
||||
A = W / H;
|
||||
glViewport(0, 0, W, H);
|
||||
if(texture){
|
||||
// compute the right dimensions for rectangle with picture
|
||||
w = texture->w; h = texture->h;
|
||||
a = w / h; w /= 2.; h /= 2.;
|
||||
if(A > a){
|
||||
W = h * A; H = h;
|
||||
//window->mouse.rx = (W0 - H0*a)/2.; window->mouse.ry = 0.;
|
||||
window->Daspect = h / H0 * 2.;
|
||||
}
|
||||
else{
|
||||
H = w / A; W = w;
|
||||
//window->mouse.ry = (H0 - W0/a)/2.; window->mouse.rx = 0.;
|
||||
window->Daspect = w / W0 * 2.;
|
||||
}
|
||||
// recalculate limits for the rulers
|
||||
x0 = W/Zoom - w + window->move.x / Zoom;
|
||||
window->mouse.x = x0;
|
||||
y0 = H/Zoom - h + window->move.y / Zoom;
|
||||
xm = 2. * W / Zoom - x0;
|
||||
ym = 2. * H / Zoom - y0;
|
||||
window->mouse.y = ym;
|
||||
//DBG("W=%g, w=%g, Zoom=%g, x0=%g, xm=%g, Da=%g", W, w, Zoom, x0, xm, Daspect);
|
||||
set_Drulers(x0, y0, xm, ym, window);
|
||||
glOrtho(-W,W, -H,H, -1., 1.);
|
||||
}
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glEnable(GL_BLEND);
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
refresh_state(window);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ellipse with center at (x,y) and radii (rx,ry)
|
||||
* plots as polyline with stride of 10 degr
|
||||
*/
|
||||
void draw_ellipce(GLfloat x, GLfloat y, GLfloat rx, GLfloat ry){
|
||||
GLfloat pi2 = M_PI * 2., step = pi2 / 36., angle;
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for(angle = 0.; angle < pi2; angle += step)
|
||||
glVertex2f(x+rx*cos(angle), y+ry*sin(angle));
|
||||
glEnd();
|
||||
}
|
||||
|
||||
/*
|
||||
* Graphical indication of recognized spots
|
||||
* window - the window with picture
|
||||
* w, h - half-width & half-height of picture (texture)
|
||||
* CX0, CY0 - zero point coordinates in picture CS (in center)
|
||||
* box == TRUE - draw region, == FALSE - set selection region
|
||||
*/
|
||||
void draw_squares(Window *window, double w, double h, double CX0, double CY0, gboolean box){
|
||||
int i, n;
|
||||
double x0, y0, x1, y1;
|
||||
BOX *bbox; Spot **spot; Coordinates *crds;
|
||||
Spots *spots = window->spots;
|
||||
if(!spots) return;
|
||||
n = spots->n;
|
||||
spot = spots->spot;
|
||||
glPushMatrix();
|
||||
for(i = 0; i < n; i++){
|
||||
bbox = &spot[i]->box;
|
||||
crds = &spot[i]->c;
|
||||
x0 = bbox->x - w; y0 = h - bbox->y;
|
||||
x1 = x0 + bbox->w; y1 = y0 - bbox->h;
|
||||
if(box){
|
||||
glColor3f(0., 1., 0.); // green is box borders
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(x0, y0); glVertex2f(x1, y0);
|
||||
glVertex2f(x1, y1); glVertex2f(x0, y1);
|
||||
glEnd();
|
||||
if(window->context->transformMask & TRANS_HARTMANN){
|
||||
x0 = crds->x + CX0;
|
||||
y0 = crds->y + CY0;
|
||||
glColor3f(1., 0., 0.); // red is spot half-widths
|
||||
draw_ellipce(x0, y0, crds->rx, crds->ry);
|
||||
//glColor3f(0., 1., 0.);
|
||||
}
|
||||
}else{ // box == FALSE - set frames for selection
|
||||
glLoadName(i);
|
||||
glRectf(x0, y0, x1, y1);
|
||||
}
|
||||
}
|
||||
if(box){ // draw cross - CS zero
|
||||
glColor3f(1., 0., 1.);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(CX0-15., CY0-15.); glVertex2f(CX0+15., CY0+15.);
|
||||
glVertex2f(CX0-15., CY0+15.); glVertex2f(CX0+15., CY0-15.);
|
||||
glEnd();
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
/*
|
||||
* graphical indication of isolines
|
||||
* window - the window
|
||||
* w, h - half-width & half-height of picture (texture)
|
||||
* CX0, CY0 - zero point coordinates in picture CS (in center)
|
||||
* _2D == TRUE for 2D images
|
||||
*/
|
||||
void draw_isolines(Window *window, double w, double h, gboolean _2D){
|
||||
//FNAME();
|
||||
IMAGE *ima = window->image;
|
||||
if(!ima) return;
|
||||
Contour *c;
|
||||
cPoint *p;
|
||||
cList **cl = window->image->contours;
|
||||
int i, n = window->image->Ncontours;
|
||||
if(!cl || n < 1) return;
|
||||
float m = ima->stat.min, wd = ima->stat.max - m;
|
||||
float *lvls = ima->cLevels, curLevel;
|
||||
guchar colr[3] = {255,0,0}; // isolines' colors
|
||||
glPushMatrix();
|
||||
for(i = 0; i < n; i++, cl++){ // cycle by isolines
|
||||
if(!*cl) continue; // given level doesn't have isolines
|
||||
c = (*cl)->first; // first contour for given level
|
||||
if(!c || (*cl)->N < 1) continue;
|
||||
gray2rgb((lvls[(*cl)->L]-m)/wd, colr); // convert level into color
|
||||
glColor3ubv(colr);
|
||||
if(_2D) curLevel = 0.;
|
||||
else curLevel = lvls[(*cl)->L] * ((GLfloat)w + (GLfloat)h) / 2./ wd;
|
||||
//DBG("curLevel=%g, gray=%g, color=(%d,%d,%d)", curLevel, (lvls[(*cl)->L]-m)/wd, colr[0],colr[1],colr[2]);
|
||||
while(c){ // cycle by contours
|
||||
p = c->first;
|
||||
if(!p || c->N < 1){ c = c->next; continue;}
|
||||
if(c->closed)
|
||||
glBegin(GL_LINE_LOOP);
|
||||
else
|
||||
glBegin(GL_LINE_STRIP);
|
||||
while(p){ // cycle by contour points
|
||||
glVertex3f(p->x-w, p->y-h, curLevel);
|
||||
p = p->next;
|
||||
}
|
||||
glEnd();
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void processHits(Window *window, GLint hits, GLuint buffer[]){
|
||||
unsigned int i, j;
|
||||
GLuint names, *ptr;
|
||||
Spot *spot;
|
||||
//Coordinates crds;
|
||||
gchar buf[256];
|
||||
int l = 255;
|
||||
Spots *spots = window->spots;
|
||||
if(!spots) return;
|
||||
printf ("hits = %d\n", hits);
|
||||
ptr = (GLuint *) buffer;
|
||||
if(hits < 1){
|
||||
set_status_text(StatusText, _("Empty region"), window);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < (unsigned int)hits; i++){
|
||||
names = *ptr;
|
||||
DBG("number of names for this hit = %d\n", names);
|
||||
ptr += 3;
|
||||
g_print(_("Selected spot[s]:\n"));
|
||||
if(names == 1)
|
||||
g_sprintf(buf, _("Selected spot: "));
|
||||
else
|
||||
g_sprintf(buf, _("Selected spots: "));
|
||||
l -= strlen(buf);
|
||||
for (j = 0; j < names; j++){
|
||||
if(*ptr < (GLuint)spots->n){
|
||||
spot = spots->spot[*ptr];
|
||||
g_print("id: %d, xC=%.2f, yC=%.2f, r=%.2f, phi=%.2f, ",
|
||||
spot->id, spot->xC, spot->yC, spot->r, spot->phi);
|
||||
g_print("cn: (%.1f, %.1f), dr:(%.1f, %.1f)\n",
|
||||
spot->c.x, spot->c.y, spot->c.rx, spot->c.ry);
|
||||
g_print("box X: [%d, %d], box Y: [%d, %d], cn: [%d, %d]\n",
|
||||
spot->box.x, spot->box.x+spot->box.w,
|
||||
spot->box.y, spot->box.y+spot->box.h,
|
||||
spot->box.x+spot->box.w/2, spot->box.y+spot->box.h/2);
|
||||
/* get_gaussian_center(&spot->box, &crds);
|
||||
g_print("\tCenter: (%.1f, %.1f), wd: (%.1f, %.1f)",
|
||||
crds.x, (double)image->height-crds.y-1., crds.rx, crds.ry);
|
||||
*/
|
||||
l -= g_snprintf(&buf[strlen(buf)], l, "%d ", spot->id);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
g_print("\n");
|
||||
set_status_text(StatusText, buf, window);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean expose(GtkWidget *Area, GdkEventExpose *event, Window *window){
|
||||
TEXTURE *texture = (TEXTURE*)window->texture;
|
||||
double w, h;
|
||||
GLfloat tred[4] = {1.,0.,0.,1.};
|
||||
GLfloat twhite[4] = {1.,1.,1.,1.};
|
||||
if(event)
|
||||
if(event->count) return FALSE;
|
||||
//FNAME();
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
glClearColor(.1, .1, .1, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glColor3fv(tred);
|
||||
if(texture){
|
||||
w = texture->w / 2.; h = texture->h / 2.;
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef(window->move.x, window->move.y, 0.);
|
||||
glScalef(window->Zoom, window->Zoom, 1.);
|
||||
//DBG("moveXY=%g, %g; Zoom=%g, texture: id=%d, w=%d",
|
||||
// window->move.x, window->move.y, window->Zoom, texture->tex, texture->w);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->tex);
|
||||
//DBG("texture: %d", texture->tex);
|
||||
//DBG("w=%g, h=%g\n", w, h);
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, twhite);
|
||||
glDisable(GL_BLEND);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex2f(-w, -h );
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex2f( w, -h );
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex2f( w, h );
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex2f(-w, h );
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
/*glBegin(GL_LINE_LOOP);
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex2f(-w, -h );
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex2f( w, -h );
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex2f( w, h );
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex2f(-w, h );
|
||||
glEnd();*/
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
// draw addition information
|
||||
if(window->context->visualMode &
|
||||
(SHOW_POTBOXES|SHOW_POTSELECT|SHOW_ISOLINES)){
|
||||
GLuint selectBuf[BUFSIZE];
|
||||
GLint hits;
|
||||
double CX0 = AxisX - w, CY0 = h - AxisY;
|
||||
gboolean showiso = window->context->visualMode & SHOW_ISOLINES;
|
||||
gboolean showbox = window->context->visualMode & SHOW_POTBOXES;
|
||||
gboolean showsel = window->context->visualMode & SHOW_POTSELECT;
|
||||
GLint viewport[4];
|
||||
if(showsel && forcesel){ // get coordinates from selection buffer
|
||||
glPushMatrix();
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
glSelectBuffer(BUFSIZE, selectBuf);
|
||||
glRenderMode(GL_SELECT);
|
||||
glInitNames();
|
||||
glPushName(0);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
/* create pixel picking region near cursor location */
|
||||
DBG("x=%g, y=%g", ObjX, ObjY);
|
||||
gluPickMatrix(ObjX, (viewport[3] - ObjY), 5.0, 5.0, viewport);
|
||||
//gluPickMatrix(ObjX, ObjY, 10.0, 10.0, viewport);
|
||||
double W = Area->allocation.width;
|
||||
double H = Area->allocation.height;
|
||||
double A = W / H;
|
||||
if(A > w / h){
|
||||
W = h * A; H = h;}
|
||||
else{
|
||||
H = w / A; W = w;}
|
||||
glOrtho(-W,W, -H,H, -1., 1.);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
if(showbox) draw_squares(window, w, h, CX0, CY0, FALSE);
|
||||
if(showiso) draw_isolines(window, w, h, TRUE);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
hits = glRenderMode(GL_RENDER);
|
||||
processHits(window, hits, selectBuf);
|
||||
forcesel = FALSE;
|
||||
glPopMatrix();
|
||||
}
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
if(showbox) draw_squares(window, w, h, CX0, CY0, TRUE);
|
||||
if(showiso) draw_isolines(window, w, h, TRUE);
|
||||
}
|
||||
/*
|
||||
// layers mix ===>
|
||||
glLoadIdentity();
|
||||
//glTranslatef(moveX,moveY,0);
|
||||
glScalef(window->Zoom, window->Zoom, 1.);
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, tred);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex2f(-w, -h );
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex2f( w, -h );
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex2f( w, h );
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex2f(-w, h );
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
// <====
|
||||
*/
|
||||
}
|
||||
else DBG("No texture");
|
||||
gdk_gl_drawable_swap_buffers(glDrawable);
|
||||
gdk_gl_drawable_wait_gl(glDrawable);
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
gboolean idle(gpointer userData){
|
||||
GtkWidget *Area = GTK_WIDGET(userData);
|
||||
gdk_window_invalidate_rect(Area->window, &Area->allocation, FALSE);
|
||||
return TRUE;
|
||||
}*/
|
||||
|
||||
void initGl(GtkWidget *Area){
|
||||
FNAME();
|
||||
GdkGLConfig *glConfig;
|
||||
GdkGLConfigMode mode = GDK_GL_MODE_RGB |
|
||||
GDK_GL_MODE_DEPTH |
|
||||
GDK_GL_MODE_ALPHA |
|
||||
GDK_GL_MODE_DOUBLE;
|
||||
if(!gdk_gl_query_extension())
|
||||
BADOGL();
|
||||
glConfig = gdk_gl_config_new_by_mode(mode);
|
||||
if(!glConfig)
|
||||
glConfig = gdk_gl_config_new_by_mode(mode & ~GDK_GL_MODE_ALPHA);
|
||||
if(!glConfig)
|
||||
BADOGL();
|
||||
if(!gtk_widget_set_gl_capability(Area, glConfig, NULL, TRUE,
|
||||
GDK_GL_RGBA_TYPE))
|
||||
BADOGL();
|
||||
}
|
||||
|
||||
/*
|
||||
* generation of textures to show in Area widget of image
|
||||
* if redraw == TRUE texture substitutes previous otherwise generate the new one
|
||||
*/
|
||||
void gen_texture(IMAGE *image, Window *window, gboolean redraw){
|
||||
//~ FNAME();
|
||||
TEXTURE *texture = window->texture;
|
||||
GtkWidget *Area = window->drawingArea;
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
if(!texture){
|
||||
INIT(window->texture, TEXTURE);
|
||||
texture = window->texture;
|
||||
if(!texture){
|
||||
g_err(_("Can't allocate memory for texture"));
|
||||
return;
|
||||
}
|
||||
//~ g_print(_("Generating texture\n"));
|
||||
glGenTextures(1, &texture->tex);
|
||||
//~ DBG("%s, tex=%d\n", gluErrorString(glGetError()), texture->tex);
|
||||
}
|
||||
//~ DBG("Image size: w=%d, h=%d", image->width, image->height);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->tex);
|
||||
if(image && image->data){
|
||||
int i,j, k, w = image->width, h = image->height;
|
||||
GLfloat *tex = NULL;
|
||||
GLfloat min = image->stat.min, wd = image->stat.max - min;
|
||||
GLfloat *ptri = image->data, *ptro;
|
||||
DBG("min = %g, wd = %g", min, wd);
|
||||
if(image->stat.max > 1. || min < 0.){
|
||||
tex = malloc(w * h * sizeof(GLfloat));
|
||||
ptro = tex;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
#pragma omp parallel for
|
||||
for(i=0; i<h; i++){
|
||||
k = i*w;
|
||||
for(j=0; j<w; j++, k++){//, ptri++, ptro++){
|
||||
//*ptro = (*ptri - min) / wd;
|
||||
ptro[k] = (ptri[k] - min) / wd;
|
||||
}
|
||||
}
|
||||
DBG("time: %g", dtime() - t0);
|
||||
}else ptro = image->data;
|
||||
if(redraw)
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
|
||||
GL_LUMINANCE, GL_FLOAT, ptro); // s/image->data/tex/
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, w, h,
|
||||
0, GL_LUMINANCE, GL_FLOAT, ptro);
|
||||
//DBG("%s\n", gluErrorString(glGetError()));
|
||||
//DBG("W: %d, H:%d, im[100]=%f\n", image->width, image->height, image->data[100]);
|
||||
texture->w = image->width; texture->h = image->height;
|
||||
free(tex);
|
||||
}
|
||||
else{
|
||||
DBG("Empty texture");
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, 10., 10.,
|
||||
0, GL_INTENSITY, GL_FLOAT, NULL);
|
||||
}
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
|
||||
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
|
||||
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
/*
|
||||
* Events:
|
||||
* expose - redraw part of an image
|
||||
* configure - redraw window when size/position changed
|
||||
* if handler returns TRUE signal processing stops
|
||||
* otherwise it can be process by other handlers
|
||||
*/
|
||||
g_signal_connect(Area, "expose-event",
|
||||
G_CALLBACK(expose), window);
|
||||
g_signal_connect(Area, "configure-event",
|
||||
G_CALLBACK(configure), window);
|
||||
//~ DBG("end");
|
||||
force_redraw(Area);
|
||||
}
|
||||
|
||||
void force_redraw(GtkWidget *Area){
|
||||
gtk_widget_queue_resize(Area);
|
||||
gtk_widget_queue_draw(Area);
|
||||
}
|
||||
|
||||
void pickRegion(double x, double y){
|
||||
FNAME();
|
||||
forcesel = TRUE;
|
||||
ObjX = x;
|
||||
ObjY = y;
|
||||
}
|
||||
|
||||
gboolean configure3D(GtkWidget *Area, GdkEventExpose *event, Window *window){
|
||||
FNAME();
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
double w, h;
|
||||
GLfloat ratio;
|
||||
if(!window)return FALSE;
|
||||
//~ GLfloat H = (GLfloat)window->texture->h;
|
||||
if(event)
|
||||
if(event->count) return FALSE;
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
w = Area->allocation.width;
|
||||
h = Area->allocation.height;
|
||||
ratio = w / h;
|
||||
glViewport(0, 0, w, h);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(45., ratio, 0.1, 1e10);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean expose3D(GtkWidget *Area, GdkEventExpose *event, Window *window){
|
||||
FNAME();
|
||||
TEXTURE *texture = window->texture;
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
GLfloat H = (GLfloat)window->image->height;
|
||||
if(event)
|
||||
if(event->count) return FALSE;
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
GLfloat spotDir[] = {0.,0.,-1.,1.};
|
||||
GLfloat pos[] = {0.,0.,0.,1.};
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
glLightfv(GL_LIGHT1,GL_POSITION,pos);
|
||||
glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION, spotDir);
|
||||
if(window->context->drawingMode == GAME_MODE){ // mouse navigation
|
||||
GLfloat lx, ly, lz, za = window->Zangle, xa = window->Xangle;
|
||||
GLfloat x = window->move.x, y = window->move.y, z = H * window->Zoom;
|
||||
lx = cosf(za)*sinf(xa);
|
||||
ly = -sinf(za);
|
||||
lz = -cosf(za)*cosf(xa);
|
||||
gluLookAt(x, y, z,
|
||||
x+lx, y+ly, z+lz,
|
||||
0., 1., 0.);
|
||||
//~ GLfloat w = Area->allocation.width, h = Area->allocation.height;
|
||||
//GLfloat z = H * window->Zoom;
|
||||
//~ GLfloat yangle = 180. / M_PI * atan2f(window->Xangle - w/2., z);
|
||||
//~ GLfloat xangle = 180. / M_PI * atan2f(window->Zangle - h/2., z);
|
||||
//~ glRotatef(yangle, 0.,1.,0.);
|
||||
//~ glRotatef(xangle, 1.,0.,0.);
|
||||
//~ glTranslatef(window->move.x, 0., -z);
|
||||
//glRotatef(window->Xangle, 0.,1.,0.);
|
||||
//~ glRotatef(window->Zangle, 1.,0.,0.);
|
||||
//glRotatef(window->Zangle, cosf(window->Xangle*M_PI/180.),0.,sinf(window->Xangle*M_PI/180.));
|
||||
//glTranslatef(window->move.x, 0., -z);
|
||||
}else{ // key navigation
|
||||
glTranslatef(window->move.x, window->move.y, -H * window->Zoom);
|
||||
glRotatef(window->Xangle, 1.,0.,0.);
|
||||
glRotatef(window->Zangle, 0.,0.,1.);
|
||||
}
|
||||
glPushMatrix();
|
||||
glEnable(GL_LIGHTING);
|
||||
if(useVBO){
|
||||
GLint y, w = window->image->width, h = window->image->height;
|
||||
GLint pts = w*2;
|
||||
size_t sz = w * h * 3 * sizeof(GLfloat);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, texture->tex);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, texture->w);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_INDEX_ARRAY);
|
||||
glNormalPointer(GL_FLOAT, 0, (GLfloat*)sz);
|
||||
glIndexPointer(GL_UNSIGNED_INT, 0, 0 );
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
h--;
|
||||
sz = 0; w = pts * sizeof(GLfloat);
|
||||
for(y = 0; y < h; y++, sz += w)
|
||||
glDrawElements(GL_TRIANGLE_STRIP, pts, GL_UNSIGNED_INT, (GLvoid*)(sz));
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_INDEX_ARRAY);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
}else
|
||||
glCallList(texture->tex);
|
||||
glPushMatrix();
|
||||
glDisable(GL_LIGHTING);
|
||||
glLineWidth(3.0);
|
||||
draw_isolines(window, ((double)window->image->width)/2.+.5,
|
||||
((double)window->image->height)/2.+.5, FALSE);
|
||||
/*glColor3f(0.,0.,1.);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex3f(-100.f, -100.f, -12.f );
|
||||
glVertex3f(-100.f, 100.f, -12.f );
|
||||
glVertex3f( 100.f, 100.f, -12.f );
|
||||
glVertex3f( 100.f, -100.f, -12.f );
|
||||
glEnd();
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(pos);
|
||||
glColor3f(1.f,0.f,0.f);
|
||||
glVertex3fv(spotDir);
|
||||
glEnd();*/
|
||||
glPopMatrix();
|
||||
gdk_gl_drawable_swap_buffers(glDrawable);
|
||||
gdk_gl_drawable_wait_gl(glDrawable);
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void init3D(Window *window){
|
||||
FNAME();
|
||||
GtkWidget *Area = window->drawingArea;
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
GLfloat lAmbient[] = {0.3,0.3,0.3,1.0};
|
||||
GLfloat lDiffuse[] = {1.0,1.0,1.0,1.0};
|
||||
GLfloat lSpecular[]= {1.0,1.0,1.0,1.0};
|
||||
GLfloat l2Ambient[] = {0.0,0.0,0.1,1.0};
|
||||
GLfloat l2Diffuse[] = {0.0,0.0,0.3,1.0};
|
||||
GLfloat l2Specular[]= {0.0,0.0,0.5,1.0};
|
||||
GLfloat mShininess[] = {110.0};
|
||||
GLfloat mSpecular[] = {0.8,0.8,1.0,1.0};
|
||||
GLfloat mDiffuse[] = {0.8,0.8,1.0,1.0};
|
||||
GLfloat mAmbient[] = {0.2,0.2,0.2,1.0};
|
||||
if (!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
glEnable(GL_RESCALE_NORMAL);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
//~ glEnable(GL_CULL_FACE);
|
||||
//~ glCullFace(GL_BACK);
|
||||
GLfloat spotDir[] = {0.,0.,-1.,1.};
|
||||
GLfloat pos[] = {0.,0.,0.,1.};
|
||||
glLightfv(GL_LIGHT1,GL_POSITION,pos);
|
||||
glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION, spotDir);
|
||||
glLightf(GL_LIGHT1,GL_SPOT_CUTOFF, 90.);
|
||||
glLightf(GL_LIGHT1,GL_SPOT_EXPONENT, 20.);
|
||||
glLightfv(GL_LIGHT0,GL_AMBIENT,l2Ambient);
|
||||
glLightfv(GL_LIGHT0,GL_DIFFUSE,l2Diffuse);
|
||||
glLightfv(GL_LIGHT0,GL_SPECULAR,l2Specular);
|
||||
glLightfv(GL_LIGHT1,GL_AMBIENT,lAmbient);
|
||||
glLightfv(GL_LIGHT1,GL_DIFFUSE,lDiffuse);
|
||||
glLightfv(GL_LIGHT1,GL_SPECULAR,lSpecular);
|
||||
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE);
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, mSpecular);
|
||||
glMaterialfv(GL_FRONT, GL_SHININESS,mShininess);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT, mAmbient);
|
||||
glMaterialfv(GL_FRONT, GL_DIFFUSE, mDiffuse);
|
||||
//~ glMaterialfv(GL_BACK, GL_SPECULAR, mSpecular);
|
||||
//~ glMaterialfv(GL_BACK, GL_SHININESS,mShininess);
|
||||
//~ glMaterialfv(GL_BACK, GL_AMBIENT, mGray);
|
||||
//~ glMaterialfv(GL_BACK, GL_DIFFUSE, mWhite);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_LIGHT1);
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
g_signal_connect(Area, "expose-event",
|
||||
G_CALLBACK(expose3D), window);
|
||||
g_signal_connect(Area, "configure-event",
|
||||
G_CALLBACK(configure3D), window);
|
||||
force_redraw(Area);
|
||||
}
|
||||
3
src/scripts/genh
Executable file
3
src/scripts/genh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
echo "const gchar *ui = `sed -r 's/^[[:space:]]*//;s/\"/\\\\\"/g;s/(^.*$$)/\"&\"/' $1` ;" > ui.h
|
||||
echo "Wrote ui.h"
|
||||
534
src/spots.c
Normal file
534
src/spots.c
Normal file
@ -0,0 +1,534 @@
|
||||
// spots.c - functions to work with spots (sorting, enumerating & so on)
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
|
||||
/*
|
||||
* Since our image is mirrored, to establish the direction of the axis
|
||||
* of symmetry it is necessary to know the position angle of the camera, etc.
|
||||
* It is easier to work in a "mirror" coordinates. Similarly, the coordinates
|
||||
* of the mask should also be given the "mirror".
|
||||
*/
|
||||
#include "gtk.h"
|
||||
#include "spots.h"
|
||||
#include "gauss.h"
|
||||
|
||||
const double M_2PI = 2. * M_PI;
|
||||
// about a quarter of 11.25 degrees - the threshold for the identification of radial points and frames
|
||||
const double PHI_STEP = 0.05;
|
||||
// angle between the markers (for identification), 56.25 degrees
|
||||
const double DPHI_MARKERS = 0.98;
|
||||
const double aStep = M_PI / 16.; // 11.25 degrees, the angle between adjacent rays
|
||||
const int N_ANGLES = 16; // number of lines on hartmanogramm (half of number of rays)
|
||||
const int N_RINGS = 8; // number of rings on hartmanogramm
|
||||
|
||||
// angle of the Y-axis of the matrix relative to the Y-axis mask
|
||||
double SlopeAngle;
|
||||
// angular position of the marker (near the center) for a zero slope, -101.25 degrees
|
||||
const double Slope0 = -1.767146;
|
||||
|
||||
/*
|
||||
* these constants are the position of the axis of rotation of the table.
|
||||
* In the coordinate system of the image (ie, the Y axis goes from top to bottom)
|
||||
* means that it coincides with the optical axis. Naturally, in the work
|
||||
* program these coordinates should be calculated
|
||||
*/
|
||||
double AxisX = 1523., AxisY = 1533.;
|
||||
|
||||
|
||||
// declaration of the flags of errors leading to the exit from auto mode
|
||||
enum{
|
||||
TOO_MANY_MARKERS // discovered more than two markers
|
||||
,NOT_ENOUGH_MARKERS // not found the two markers
|
||||
,BAD_MARKERS_ANGLE // angle between the markers over DPHI_MARKERS +- PHI_STEP
|
||||
,TOO_MANY_RINGS // found more rings than it should be
|
||||
};
|
||||
|
||||
// messages appropriate to flags
|
||||
char *errmsg[] = {
|
||||
N_("Too many markers")
|
||||
,N_("Not enough markers")
|
||||
,N_("Bad markers angle")
|
||||
,N_("Too many rings")
|
||||
};
|
||||
|
||||
#ifdef LEPTONICA_FOUND
|
||||
/*
|
||||
* Violated any restrictions on the automatic mode
|
||||
* In theory the function should exit the batch mode with the mapping errors
|
||||
*/
|
||||
void bad_circumstances(int errcode){
|
||||
red("\nerror, need to stop\n");
|
||||
g_err(_(errmsg[errcode]));
|
||||
}
|
||||
|
||||
// memory allocation for n spots array
|
||||
Spots* spots_alloc(int n){
|
||||
Spots *ptr = malloc(sizeof(Spots));
|
||||
if(!ptr){
|
||||
g_err(_("Can't allocate memory for new spots"));
|
||||
return NULL;
|
||||
}
|
||||
ptr->spot = malloc(n * sizeof(Spot*));
|
||||
if(!ptr->spot){
|
||||
g_err(_("Can't allocate memory for pointers in spots array"));
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
ptr->size = n;
|
||||
ptr->n = 0;
|
||||
// originally put the flag BY_COPY, which is removed by the first copy BY_PTR,
|
||||
// order to do not try to free one area several times
|
||||
ptr->memflag = BY_COPY;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void spots_free(Spots **spots){
|
||||
FNAME();
|
||||
int i, n;
|
||||
if(!(*spots)) return;
|
||||
n = (*spots)->n;
|
||||
Spot **spot = (*spots)->spot;
|
||||
if((*spots)->memflag != BY_PTR) // check whether spot-regions were allocated
|
||||
for(i = 0; i < n; i++, spot++)
|
||||
free(*spot);
|
||||
free((*spots)->spot);
|
||||
free(*spots);
|
||||
*spots = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add point spot into array spots by copy.
|
||||
* If array is full return NULL
|
||||
*
|
||||
*/
|
||||
Spot* spots_add(Spots *spots, Spot *spot, int copy){
|
||||
Spot *ptr = NULL;
|
||||
if(spots->size <= spots->n){
|
||||
g_err(_("Spots array is full, can't place new spot\n"));
|
||||
return NULL; // there's no enough space
|
||||
}
|
||||
if(!spot){
|
||||
g_err(_("Zero pointer to spot\n"));
|
||||
return NULL;
|
||||
}
|
||||
if(copy == BY_COPY){
|
||||
ptr = malloc(sizeof(Spot));
|
||||
if(!ptr){
|
||||
g_err(_("Can't allocate memory for new spot"));
|
||||
return NULL;
|
||||
}
|
||||
if(!memcpy(ptr, spot, sizeof(Spot))){
|
||||
free(ptr);
|
||||
g_err(_("Can't copy spot to new one"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(copy == BY_PTR){
|
||||
spots->memflag = BY_PTR; // change flag to not do free()
|
||||
ptr = spot;
|
||||
}
|
||||
spots->spot[spots->n] = ptr; // jam into array
|
||||
spots->n++; // increment points number
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* alignment of the coordinate system spot.c to CS relative to the optical axis,
|
||||
* approximate calculation of the angular and radial coordinates of each spot in
|
||||
* the coordinates with respect to the center of gravity of spots (for further identification)
|
||||
*/
|
||||
void spots_center(Spots *spots){
|
||||
int i, n;
|
||||
double X = 0., Y = 0., N, x0, y0;
|
||||
double *xx, *yy, *px, *py;
|
||||
Spot **spot;
|
||||
n = spots->n; N = (double) n;
|
||||
if(n == 0) return;
|
||||
xx = malloc(n * sizeof(double)); px = xx;
|
||||
yy = malloc(n * sizeof(double)); py = yy;
|
||||
spot = spots->spot;
|
||||
for(i = 0; i < n; i++, px++, py++, spot++){
|
||||
//x0 = (*spot)->c.x; y0 = (*spot)->c.y;
|
||||
x0 = (*spot)->c.x - AxisX;
|
||||
//y0 = (*spot)->c.y - AxisY;
|
||||
y0 = AxisY - (*spot)->c.y; // flip into right coordinates
|
||||
(*spot)->c.x = x0; (*spot)->c.y = y0;
|
||||
*px = x0;
|
||||
*py = y0;
|
||||
X += *px; Y += *py;
|
||||
}
|
||||
X /= N; Y /= N;
|
||||
green("\nspots center: %g, %g", X, Y);
|
||||
px = xx; py = yy;
|
||||
spot = spots->spot;
|
||||
for(i = 0; i < n; i++, px++, py++, spot++){
|
||||
x0 = *px - X; y0 = *py - Y;
|
||||
(*spot)->phi = atan2(y0, x0);
|
||||
(*spot)->r = sqrt(x0*x0 + y0*y0);
|
||||
}
|
||||
free(xx); free(yy);
|
||||
}
|
||||
|
||||
int cmp_spots_r(const void *spot1, const void *spot2){
|
||||
return ((*(Spot**)spot1)->r > (*(Spot**)spot2)->r);
|
||||
}
|
||||
void sort_spots_by_r(Spots *spots){
|
||||
qsort(spots->spot, spots->n, sizeof(Spot*), cmp_spots_r);
|
||||
}
|
||||
|
||||
int cmp_spots_phi(const void *spot1, const void *spot2){
|
||||
return ((*(Spot**)spot1)->phi > (*(Spot**)spot2)->phi);
|
||||
}
|
||||
void sort_spots_by_phi(Spots *spots){
|
||||
qsort(spots->spot, spots->n, sizeof(Spot*), cmp_spots_phi);
|
||||
}
|
||||
|
||||
int cmp_spots_id(const void *spot1, const void *spot2){
|
||||
return ((*(Spot**)spot1)->id > (*(Spot**)spot2)->id);
|
||||
}
|
||||
void sort_spots_by_id(Spots *spots){
|
||||
qsort(spots->spot, spots->n, sizeof(Spot*), cmp_spots_id);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting the points in R and phi we find the markers.
|
||||
* After sorting, id of markers is set to <Beam number> + 100 * <ring number>.
|
||||
* The markers are numbered as 100 * <ring number> + <number of the next clockwise beam>
|
||||
*/
|
||||
void sort_spots(Window *window){
|
||||
FNAME();
|
||||
Spots *spots = window->spots;
|
||||
gboolean Prefocal = TRUE;
|
||||
int i, n;
|
||||
int step = 0, // a step - goto next group
|
||||
num = 0, // number of ray or ring
|
||||
mZero = 0; // id of zero ray
|
||||
Spot **spot = spots->spot;
|
||||
Spots *markers = spots_alloc(2); // allocate space for markers
|
||||
double *angles_pre, *angles_post; // angle coordinate of each ray in "normal" orientation
|
||||
const int N_RAY_MAX = 2 * N_ANGLES - 1; // max ray number
|
||||
const int N_RAYS = 2 * N_ANGLES;
|
||||
const int N_ANGLE_MAX = N_ANGLES - 1; // max line number
|
||||
double r_aver = 0.; // mid radius of spots
|
||||
n = spots->n;
|
||||
// fill the array angles_0 (for obtaining further angle of inclination of hartmanogramm)
|
||||
angles_pre = calloc(N_ANGLES, sizeof(double));
|
||||
angles_post = calloc(N_ANGLES, sizeof(double));
|
||||
{
|
||||
angles_post[0] = M_PI_2 - aStep/2.;
|
||||
angles_pre[0] = M_PI_2 + aStep/2.;
|
||||
for(i = 1; i < N_ANGLES; i++){
|
||||
angles_pre[i] = angles_pre[i-1] + aStep;
|
||||
angles_post[i] = angles_post[i-1] - aStep;
|
||||
green("angles[%d]: pre=%g, post=%g",
|
||||
i, angles_pre[i]*180/M_PI, angles_post[i]*180/M_PI);
|
||||
}
|
||||
}
|
||||
// find the center of gravity of points on hartmanogramm and determine
|
||||
// for each point the polar coordinates in the system of the center of gravity
|
||||
spots_center(spots);
|
||||
// sort points by phi to find markers and number by rays
|
||||
{
|
||||
sort_spots_by_phi(spots);
|
||||
double phi0 = (*spot)->phi, phi, dphi;
|
||||
green("\nSort by phi\n");
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
phi = (*spot)->phi;
|
||||
dphi = fabs(phi-phi0);
|
||||
phi0 = phi;
|
||||
// If we two consecutive jump occurs, the previous point has to be a marker.
|
||||
// If we we find two more markers, generate an error
|
||||
if(dphi > PHI_STEP){
|
||||
num++;
|
||||
if(!step){
|
||||
step = 1;
|
||||
}else{
|
||||
num--;
|
||||
red("FOUND MARKER");
|
||||
(*(spot-1))->id = 99 - (*(spot-1))->id;
|
||||
DBG("spot[%d]: r=%g, phi=%g\n", (*(spot-1))->id,
|
||||
(*(spot-1))->r, (*(spot-1))->phi);
|
||||
if(!spots_add(markers, *(spot-1), BY_PTR)){
|
||||
bad_circumstances(TOO_MANY_MARKERS);
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else step = 0;
|
||||
(*spot)->id = num;
|
||||
//DBG("spot[%d]: r=%g, phi=%g, dphi=%g\n", (*spot)->id, (*spot)->r,
|
||||
// phi, dphi);
|
||||
}
|
||||
}
|
||||
// check markers
|
||||
{
|
||||
if(markers->n != 2){
|
||||
if(markers->n == 0){
|
||||
bad_circumstances(NOT_ENOUGH_MARKERS);
|
||||
goto ret; // no marker found
|
||||
}
|
||||
spot = spots->spot;
|
||||
for(i = 0; i < n; i++, spot++)
|
||||
if((*spot)->id < N_RAYS) r_aver += (*spot)->r;
|
||||
r_aver /= (double)n;
|
||||
green("R_aver = %.2f, R=%.2f", r_aver, markers->spot[0]->r);
|
||||
if(window->image->val_f < 0.){
|
||||
// obtain the value of Prefocal from human as VAL_F is unknown
|
||||
get_prefocal(window, &Prefocal);
|
||||
}else Prefocal = (window->image->val_f < 100.) ? TRUE : FALSE;
|
||||
int m_id = markers->spot[0]->id;
|
||||
if(!Prefocal){
|
||||
if(markers->spot[0]->r < r_aver){ // nearest, zero marker
|
||||
mZero = 99 - m_id;
|
||||
}else{ // far, fifth marker
|
||||
mZero = 104 - m_id; // 5 rays clockwise
|
||||
}
|
||||
}else{
|
||||
if(markers->spot[0]->r < r_aver){
|
||||
mZero = 98 - m_id;
|
||||
}else{
|
||||
mZero = 93 - m_id;
|
||||
}
|
||||
}
|
||||
if(markers->spot[0]->r < r_aver)
|
||||
markers->spot[0]->id = 299; // finally change markers' numbers
|
||||
else
|
||||
markers->spot[0]->id = 794;
|
||||
if(mZero > N_RAY_MAX) mZero -= N_RAYS;
|
||||
else if(mZero < 0) mZero += N_RAYS;
|
||||
}else{
|
||||
sort_spots_by_r(markers);
|
||||
spot = markers->spot;
|
||||
for(i = 0; i < 2; i++)
|
||||
green("marker #%d: r=%g, phi=%g, tmp_id=%d, x=%g, y=%g", i,
|
||||
spot[i]->r, spot[i]->phi, spot[i]->id, spot[i]->c.x, spot[i]->c.y);
|
||||
double dphi = spot[0]->phi - spot[1]->phi;
|
||||
DBG("Angle between markers: %g degr\n", dphi*180./M_PI);
|
||||
if(fabs(dphi - DPHI_MARKERS) > PHI_STEP){
|
||||
bad_circumstances(BAD_MARKERS_ANGLE);
|
||||
goto ret;
|
||||
}
|
||||
if(dphi > 0.){
|
||||
Prefocal = FALSE;
|
||||
mZero = 99 - spot[0]->id; // number of ray to be zero
|
||||
}else{
|
||||
mZero = 98 - spot[0]->id; // number of ray to be zero
|
||||
if(mZero > N_RAY_MAX) mZero -= N_RAYS;
|
||||
}
|
||||
spot[0]->id = 299;
|
||||
spot[1]->id = 794;
|
||||
}
|
||||
}
|
||||
// renumbers points in a clockwise direction, starting from the scheme
|
||||
// EEERRRRRRROOOOOOORRRRR!!!!
|
||||
// ÓÍÅÎÙ ÎÁÐÒÁ×ÌÅÎÉÑ ÏÔÓÞÅÔÏ× ÎÅÔ: É ÎÁ ÐÒÅÄ- É ÎÁ ÚÁÆÏËÁÌØÎÏÍ ÏÄÉÎÁËÏ×Ï!
|
||||
// The numbering starts from zero!
|
||||
spot = spots->spot;
|
||||
green("\nmZero = %d\n", mZero);
|
||||
if(!Prefocal){ // postfocal image
|
||||
red("\nPostfocal image\n");
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
if((*spot)->id > N_RAY_MAX) continue; // don't convert markers' numbers
|
||||
int sid = mZero - (*spot)->id; // change the numbering and its direction
|
||||
if(sid < 0) sid += N_RAYS;
|
||||
(*spot)->id = sid;
|
||||
}
|
||||
}else{ // prefocal image
|
||||
red("\nPrefocal image\n");
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
if((*spot)->id > N_RAY_MAX) continue;
|
||||
int sid = (*spot)->id - mZero; // only change the numbering
|
||||
if(sid < 0) sid += N_RAYS;
|
||||
(*spot)->id = sid;
|
||||
}
|
||||
}
|
||||
/* by the method of least squares we are counting angle of inclination
|
||||
* y=a+bx, b=tg(slope+alpha_i0)
|
||||
* b = [\sum x_i \sum y_i - n\sum (x_i y_i)] /
|
||||
* [ (\sum x_i)^2 - n\sum (x_i)^2 ]
|
||||
*
|
||||
* Let S1 = \sum x_i, S2 = \sum y_i, S3 = \sum(x_i)^2,
|
||||
* S4 = \sum(x_i y_i), then
|
||||
* b = (S1*S2 - n*S4) / (S1*S1 - n*S3)
|
||||
*
|
||||
* Set up arrays four elements Sj of 16 (for each line by an item)
|
||||
* In the loop over all spots (except markers) fill the array.
|
||||
* Then we are counting the coefficients b and fill the matrix of slope angles
|
||||
*/
|
||||
{
|
||||
double *S1, *S2, *S3, *S4, *N, *angles;
|
||||
double x, y, *angles_0;
|
||||
int idx;
|
||||
angles_0 = (Prefocal) ? angles_pre : angles_post;
|
||||
S1 = calloc(N_ANGLES, sizeof(double));
|
||||
S2 = calloc(N_ANGLES, sizeof(double));
|
||||
S3 = calloc(N_ANGLES, sizeof(double));
|
||||
S4 = calloc(N_ANGLES, sizeof(double));
|
||||
N = calloc(N_ANGLES, sizeof(double));
|
||||
angles = calloc(N_ANGLES, sizeof(double));
|
||||
SlopeAngle = 0.;
|
||||
spot = spots->spot;
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
idx = (*spot)->id;
|
||||
if(idx > N_RAY_MAX) continue;
|
||||
if(idx > N_ANGLE_MAX) idx -= N_ANGLES; // convert the ray number to the number of line
|
||||
x = (*spot)->c.x; y = (*spot)->c.y;
|
||||
S1[idx] += x; // \sum x_i
|
||||
S2[idx] += y; // \sum y_i
|
||||
S3[idx] += x*x; // \sum (x_i)^2
|
||||
S4[idx] += x*y; // \sum (x_i y_i)
|
||||
N[idx] += 1.;
|
||||
}
|
||||
for(i = 0; i < N_ANGLES; i++){
|
||||
double ang;
|
||||
// calculate an shift for i-th line
|
||||
angles[i] = atan2((S1[i]*S2[i] - N[i]*S4[i]) ,
|
||||
(S1[i]*S1[i] - N[i]*S3[i]));
|
||||
DBG("Angle: %g", angles[i]*180./M_PI);
|
||||
// check whether there's no jumps near +-pi
|
||||
if(i){
|
||||
ang = angles[i] - angles[i-1];
|
||||
DBG("Ang: %g", ang*180./M_PI);
|
||||
if(!Prefocal){
|
||||
if(ang > M_PI) angles[i] -= M_2PI;
|
||||
else if(ang > 0.) angles[i] -= M_PI;
|
||||
else if(ang < -M_2PI) angles[i] += M_2PI;
|
||||
else if(ang < -M_PI) angles[i] += M_PI;
|
||||
}else{
|
||||
if(ang < -M_PI) angles[i] += M_2PI;
|
||||
else if(ang < 0.) angles[i] += M_PI;
|
||||
else if(ang > M_2PI) angles[i] -= M_2PI;
|
||||
else if(ang > M_PI) angles[i] -= M_PI;
|
||||
}
|
||||
}
|
||||
ang = angles[i] - angles_0[i];
|
||||
if(ang > M_2PI) ang -= M_2PI;
|
||||
else if(ang < 0.) ang += M_2PI;
|
||||
SlopeAngle += ang;
|
||||
DBG("angle[%d] = %g; ang=%g; a0=%g\n", i, angles[i]*180./M_PI,
|
||||
ang*180./M_PI, angles_0[i]*180./M_PI);
|
||||
}
|
||||
SlopeAngle /= (double)N_ANGLES; // average
|
||||
red("Slope Angle: %g degr", SlopeAngle * 180. / M_PI);
|
||||
free(S1); free(S2); free(S3); free(S4); free(N); free(angles);
|
||||
}
|
||||
// sort spots by r to enumerate by rings
|
||||
{
|
||||
sort_spots_by_r(spots);
|
||||
spot = spots->spot;
|
||||
double r0 = (*spot)->r, r;
|
||||
// rtres == 1/7 of average distance between rings
|
||||
double rtres = (spot[n-1]->r - r0) / ((double)N_RINGS - 1.) / 7.;
|
||||
num = 0;
|
||||
green("\nSort by r\n");
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
if((*spot)->id > N_RAY_MAX) continue; // we have already counts markers
|
||||
r = (*spot)->r;
|
||||
if(fabs(r-r0) > rtres){
|
||||
num+=100;
|
||||
}
|
||||
(*spot)->id += num;
|
||||
// DBG("spot[%d]: r=%g, phi=%g, dr=%g\n", (*spot)->id, r,
|
||||
// (*spot)->phi, r - r0);
|
||||
r0 = r;
|
||||
}
|
||||
if((num/100 + 1) > N_RINGS)
|
||||
bad_circumstances(TOO_MANY_RINGS);
|
||||
}
|
||||
/*
|
||||
* At this stage it would be nice to display the picture boxes,
|
||||
* numbered points, detected angle and center.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Recalculate the the coordinates of centers points' for the translation
|
||||
* to the coordinate system relative to the optical axis
|
||||
* (rotation + reflection from the vertical axis).
|
||||
* (\beta == SlopeAngle)
|
||||
* x^0_i = -x_i\cos\beta - y_i\sin\beta;
|
||||
* y^0_i = -x_i\sin\beta + y_i\cos\beta
|
||||
*/
|
||||
{
|
||||
double cosSA = cos(SlopeAngle);
|
||||
double sinSA = sin(SlopeAngle);
|
||||
double x,y;
|
||||
spot = spots->spot;
|
||||
if(!Prefocal){
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
x = (*spot)->c.x; y = (*spot)->c.y;
|
||||
(*spot)->xC = -x*cosSA - y*sinSA;
|
||||
(*spot)->yC = -x*sinSA + y*cosSA;
|
||||
}
|
||||
}else{
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
x = (*spot)->c.x; y = (*spot)->c.y;
|
||||
(*spot)->xC = x*cosSA + y*sinSA;
|
||||
(*spot)->yC = -x*sinSA + y*cosSA;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret:
|
||||
free(angles_pre); free(angles_post);
|
||||
}
|
||||
|
||||
void spots_save(Spots *spots, gchar *filename){
|
||||
Spot **spot, *s;
|
||||
FILE *f;
|
||||
if(! spots || ! spots->spot || ! filename) return;
|
||||
int i, n = spots->n;
|
||||
sort_spots_by_id(spots);
|
||||
spot = spots->spot;
|
||||
f = fopen(filename, "w");
|
||||
if(!f){
|
||||
g_err(_("Can't open file"));
|
||||
return;
|
||||
}
|
||||
fprintf(f, "\t***** Bounding boxes *****\t** Coords w/o rot. comp. **\tCoords with rot. comp.\n");
|
||||
fprintf(f, "id\tx0\ty0\tw\th\txc\tyc\tw2\th2\txc\tyc\n");
|
||||
for(i = 0; i < n; i++, spot++){
|
||||
s = *spot;
|
||||
if(fprintf(f, "%03d\t%d\t%d\t%d\t%d\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
|
||||
s->id,
|
||||
s->box.x, s->box.y, s->box.w, s->box.h,
|
||||
s->c.x, s->c.y, s->c.rx, s->c.ry,
|
||||
s->xC, s->yC) <= 0){
|
||||
g_err(_("Can't write to file"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#else // LEPTONICA_FOUND not set
|
||||
Spots* spots_alloc(int n __attribute__((unused))){
|
||||
LEPTERR;
|
||||
return NULL;
|
||||
}
|
||||
Spot* spots_add(Spots *spots __attribute__((unused)),
|
||||
Spot *spot __attribute__((unused)), int copy __attribute__((unused))){
|
||||
LEPTERR;
|
||||
return NULL;
|
||||
}
|
||||
void spots_free(Spots **spots __attribute__((unused))){
|
||||
LEPTERR;
|
||||
}
|
||||
void sort_spots(Spots *spots __attribute__((unused))){
|
||||
LEPTERR;
|
||||
}
|
||||
#endif // LEPTONICA_FOUND
|
||||
423
src/terrain.c
Normal file
423
src/terrain.c
Normal file
@ -0,0 +1,423 @@
|
||||
// terrain.c - functions for 3D view
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "opengl.h"
|
||||
#include "terrain.h"
|
||||
#include "contours.h"
|
||||
#include "fits.h"
|
||||
#include "imtools.h" // for destroy_image
|
||||
|
||||
|
||||
#define MINSZ 5 // minimal size of a selection region
|
||||
|
||||
/*
|
||||
* Calculate the normals for the point (x, y) of the image.
|
||||
* First, fill arrays of normals for the the lower right and upper
|
||||
* left triangles with one vertex at a given point.
|
||||
* Then for each point the total normal is calculated
|
||||
*
|
||||
* Principle
|
||||
* *---B---*---* (rd is the lower right triangle, ul is upper left)
|
||||
* | / | / | / | Normal at the point A at the map of triangles (as shown)
|
||||
* E---A---C---* is composed of normal Aul + Bdr + Cul + Adr + Dul + Edr
|
||||
* | / | / | / | The normals for individual triangles (X - intensity at a point):
|
||||
* *---D---*---* (normal = vertical vector x horizontal vector)
|
||||
* Not normalized Aul = (E-A, A-B, 1)
|
||||
* Adr = (A-C, D-A, 1)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Computing of the normals UL & DR
|
||||
* REWRITE FOR CUDA
|
||||
*/
|
||||
GLfloat *mkTrNormals(IMAGE *image){
|
||||
FNAME();
|
||||
int W = image->width, H = image->height, x, y, i;
|
||||
/*
|
||||
* Normal for the the lower right and upper left triangles coming out of a given point
|
||||
* Component 0 - UL, 1 - DR
|
||||
* To simplify further calculations, supplemented by a frame in one node (zeros)
|
||||
*/
|
||||
GLfloat *tr_norms = calloc((W+2)*(H+2), 6*sizeof(GLfloat));
|
||||
int Wstride = (W + 2) * 6;
|
||||
int ww = W - 1, hh = H - 1;
|
||||
GLfloat *heights = image->data;
|
||||
GLfloat *ptr;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
inline void soft_normalize(GLfloat *v){
|
||||
GLfloat l,x,y;
|
||||
x = v[0];
|
||||
y = v[1];
|
||||
l = sqrtf((x*x) + (y*y) + 1.f);
|
||||
v[0] = x / l;
|
||||
v[1] = y / l;
|
||||
v[2] = 1.f/ l;
|
||||
}
|
||||
inline void calc_UL(GLfloat *height, GLfloat *ptr){
|
||||
GLfloat A = *height;
|
||||
if(A){};
|
||||
ptr[0] = height[-1] - A; // E - A
|
||||
ptr[1] = height[-W] - A; // B - A
|
||||
ptr[2] = 1.f;
|
||||
soft_normalize(ptr);
|
||||
}
|
||||
inline void calc_DR(GLfloat *height, GLfloat *ptr){
|
||||
GLfloat A = *height;
|
||||
if(A){};
|
||||
ptr += 3; // move to DR
|
||||
ptr[0] = A - height[1]; // A - C
|
||||
ptr[1] = A - height[W]; // A - D
|
||||
ptr[2] = 1.f;
|
||||
soft_normalize(ptr);
|
||||
}
|
||||
inline void calc_two_norms(GLfloat *height, GLfloat *ptr){
|
||||
calc_UL(height, ptr);
|
||||
calc_DR(height, ptr);
|
||||
}
|
||||
ptr = &tr_norms[Wstride + 1];
|
||||
#pragma omp parallel for
|
||||
for(x = 0; x < ww; x++){
|
||||
calc_DR(heights+x, ptr + 6*x); // upper border without right point, only DR
|
||||
}
|
||||
i = 0;
|
||||
#pragma omp parallel for private(y, ptr, x, i)
|
||||
for(y = 1; y < hh; y++){
|
||||
ptr = &tr_norms[Wstride*(y+1)+1];
|
||||
i = y * W;
|
||||
calc_DR(heights+(i++), ptr); // left border - only DR
|
||||
ptr += 6;
|
||||
for(x = 1; x < ww; x++, ptr += 6){
|
||||
calc_two_norms(heights+(i++), ptr);
|
||||
}
|
||||
calc_UL(heights+i, ptr); // right border - only UL
|
||||
}
|
||||
ptr = &tr_norms[Wstride * H + 1];
|
||||
heights = &image->data[hh * W];
|
||||
#pragma omp parallel for
|
||||
for(x = 1; x < W; x++)
|
||||
calc_UL(heights, ptr+6*x); // down border - onlyUL
|
||||
/*
|
||||
ptr = &tr_norms[Wstride + 1];
|
||||
for(x = 0; x < ww; x++, ptr += 6, heights++)
|
||||
calc_DR(heights, ptr);
|
||||
heights++;
|
||||
for(y = 1; y < hh; y++){
|
||||
ptr = &tr_norms[Wstride*(y+1)+1];
|
||||
calc_DR(heights++, ptr);
|
||||
ptr += 6;
|
||||
for(x = 1; x < ww; x++, ptr += 6, heights++){
|
||||
calc_two_norms(heights, ptr);
|
||||
}
|
||||
calc_UL(heights++, ptr);
|
||||
}
|
||||
heights++;
|
||||
ptr = &tr_norms[Wstride * H + 2];
|
||||
for(x = 1; x < W; x++, heights++, ptr += 6)
|
||||
calc_UL(heights, ptr);
|
||||
*/
|
||||
DBG("time: %g", dtime() - t0);
|
||||
return tr_norms;
|
||||
}
|
||||
|
||||
void computeNormals(Window *window){
|
||||
FNAME();
|
||||
int x, y;
|
||||
IMAGE *verts = window->image;
|
||||
IMAGE *norms = window->image_transformed;
|
||||
int W = verts->width, H = verts->height;
|
||||
int Wstride = (W + 2) * 6;
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
GLfloat *tr_norms = mkTrNormals(verts);
|
||||
GLfloat *ptr;
|
||||
GLfloat *normal = norms->data;
|
||||
inline void addVectors(GLfloat *norm, GLfloat *dbl){
|
||||
GLfloat *Aul, *Adr, *Bdr, *Cul, *Dul, *Edr;
|
||||
Aul = dbl; Adr = dbl + 3;
|
||||
Bdr = dbl - Wstride + 3;
|
||||
Cul = dbl + 6;
|
||||
Dul = dbl + Wstride;
|
||||
Edr = dbl - 3;
|
||||
*norm++ = (*Aul++) + (*Bdr++) + (*Cul++) + (*Adr++) + (*Dul++) + (*Edr++);
|
||||
*norm++ = (*Aul++) + (*Bdr++) + (*Cul++) + (*Adr++) + (*Dul++) + (*Edr++);
|
||||
*norm = (*Aul) + (*Bdr) + (*Cul) + (*Adr) + (*Dul) + (*Edr);
|
||||
}
|
||||
inline void normalize(GLfloat *v){
|
||||
GLfloat l,x,y,z;
|
||||
x = v[0];
|
||||
y = v[1];
|
||||
z = v[2];
|
||||
l = sqrtf((x*x) + (y*y) + (z*z));
|
||||
v[0] = x / l;
|
||||
v[1] = y / l;
|
||||
v[2] = z / l;
|
||||
}
|
||||
/*
|
||||
int WW = W*3;
|
||||
#pragma omp parallel for private(y, ptr, normal)
|
||||
for(y = 0; y < H; y++){
|
||||
ptr = &tr_norms[Wstride*(y+1)+1];
|
||||
normal = &norms->data[y*WW];
|
||||
for(x = 0; x < W; x++, normal+=3, ptr+=6){
|
||||
addVectors(normal, ptr);
|
||||
normalize(normal);
|
||||
}
|
||||
}*/
|
||||
for(y = 0; y < H; y++){
|
||||
ptr = &tr_norms[Wstride*(y+1)+1];
|
||||
for(x = 0; x < W; x++, normal+=3, ptr+=6){
|
||||
addVectors(normal, ptr);
|
||||
normalize(normal);
|
||||
}
|
||||
}
|
||||
free(tr_norms);
|
||||
DBG("time: %g", dtime() - t0);
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple 3D-display selected in window->parent field
|
||||
* Image corners coordinates (x0, y0), (x, y)
|
||||
* Coordinates in CS IMAGES, ANGLES are outermost, not known
|
||||
* window - a window with the 3D image
|
||||
* X0, y0, x, y - the image area of the parent window, from which information will be taken
|
||||
* from_file - TRUE to load the file into the same window (then the coordinates do not care)
|
||||
* FALSE for download from the [sub] the image of the parent window
|
||||
*/
|
||||
gboolean loadTerrain(Window *window,
|
||||
double x0, double y0, double x, double y,
|
||||
gboolean from_file){
|
||||
FNAME();
|
||||
int i, j, imW;
|
||||
IMAGE *verts, *norms; // vertexes & normals (pointers to w->im, w->im_tr)
|
||||
IMAGE *image = NULL; // pointer to the parent image or a new image
|
||||
int X0,Y0, X1,Y1; // here will be stored the coordinates of the upper left and lower right corners
|
||||
int W, H; // Here are the dimensions of the selected area
|
||||
GLfloat *in, *out; // Pointers to the points in the image
|
||||
GLfloat scale; // scale (1/8 of the perimeter of selected region)
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
if(!from_file){
|
||||
if(x0 < x){ X0 = (int)(x0+0.5); X1 = (int)(x+0.5);}
|
||||
else{ X0 = (int)(x+0.5); X1 = (int)(x0+0.5);}
|
||||
if(y0 < y){ Y0 = (int)(y0+0.5); Y1 = (int)(y+0.5);}
|
||||
else{ Y0 = (int)(y+0.5); Y1 = (int)(y0+0.5);}
|
||||
W = X1 - X0; H = Y1 - Y0;
|
||||
DBG("subimage size: %dx%d", W, H);
|
||||
DBG("subimage @ (%d,%d)-(%d,%d)", X0, Y0, X1, Y1);
|
||||
if(W < MINSZ || H < MINSZ){
|
||||
g_err(_("Selected area too small"));
|
||||
return FALSE;
|
||||
}
|
||||
image = window->parent->image;
|
||||
if(!copy_contours(image, window->image,
|
||||
(float)-X0, (float)-Y0))
|
||||
g_err(_("Error occured when tried to add contours"));
|
||||
window->image->cLevels = image->cLevels;
|
||||
|
||||
window->image->stat.min = image->stat.min;
|
||||
window->image->stat.max = image->stat.max;
|
||||
}else{ // load to the same window from file
|
||||
gchar *filename;
|
||||
INIT(image, IMAGE);
|
||||
if( !(filename = get_open_filename(window)) ||
|
||||
!readfits(filename, image)){
|
||||
g_free(filename);
|
||||
destroy_image(image);
|
||||
return FALSE;
|
||||
}
|
||||
g_free(filename);
|
||||
X1 = W = image->width;
|
||||
Y1 = H = image->height;
|
||||
X0 = Y0 = 0;
|
||||
}
|
||||
// check if there are shoals with the filling of the structure of points and normals
|
||||
free(window->image->data); window->image->data = NULL;
|
||||
free(window->image_transformed->data); window->image_transformed->data = NULL;
|
||||
if(!image || !image->data){
|
||||
g_err(_("No image in parent window"));
|
||||
goto abnormal_exit;
|
||||
}
|
||||
imW = image->width;
|
||||
verts = window->image;
|
||||
norms = window->image_transformed;
|
||||
verts->data = calloc(W*H, sizeof(GLfloat));
|
||||
if(!verts->data){
|
||||
g_err(_("Can't allocate memory"));
|
||||
goto abnormal_exit;
|
||||
}
|
||||
// normals for each point
|
||||
norms->data = calloc(W*H*3, sizeof(GLfloat));
|
||||
if(!norms->data){
|
||||
g_err(_("Can't allocate memory"));
|
||||
free(verts->data);
|
||||
verts->data = NULL;
|
||||
goto abnormal_exit;
|
||||
}
|
||||
verts->width = W; verts->height = H;
|
||||
norms->width = W; norms->height = H;
|
||||
scale = ((GLfloat)W + (GLfloat)H) / 4.f / (image->stat.max-image->stat.min);
|
||||
// Copy the selected piece of image with scaling
|
||||
#pragma omp parallel for
|
||||
for(j = Y0; j < Y1; j++){
|
||||
//int l = (j - Y0)*W;
|
||||
in = &image->data[j * imW + X0];
|
||||
out = &verts->data[(j - Y0)*W];
|
||||
for(i = 0; i < W; i++)
|
||||
(*out++) = (*in++) * scale;
|
||||
}
|
||||
if(from_file)
|
||||
destroy_image(image);
|
||||
DBG("time: %g", dtime() - t0);
|
||||
return TRUE;
|
||||
abnormal_exit:
|
||||
if(from_file)
|
||||
destroy_image(image);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean createList(Window *window){
|
||||
FNAME();
|
||||
TEXTURE *texture = window->texture; // number of list stores in texture->tex
|
||||
GLfloat *Verts = window->image->data;
|
||||
GLfloat *Norms = window->image_transformed->data;
|
||||
int W = window->image->width, H = window->image->height;
|
||||
int x, y, stride = 3 * W;
|
||||
GLfloat dX = -(GLfloat)W / 2.f, dY = -(GLfloat)H / 2.f;
|
||||
GtkWidget *Area = window->drawingArea;
|
||||
if(!Area){
|
||||
g_err("???");
|
||||
return FALSE;
|
||||
}
|
||||
GdkGLContext *glContext = gtk_widget_get_gl_context(Area);
|
||||
GdkGLDrawable *glDrawable = gtk_widget_get_gl_drawable(Area);
|
||||
if(!gdk_gl_drawable_gl_begin(glDrawable, glContext))
|
||||
g_assert_not_reached();
|
||||
#ifdef EBUG
|
||||
double t0 = dtime();
|
||||
#endif
|
||||
if(!texture){
|
||||
INIT(window->texture, TEXTURE);
|
||||
texture = window->texture;
|
||||
if(!texture){
|
||||
g_err(_("Can't allocate memory for texture"));
|
||||
return FALSE;
|
||||
}
|
||||
if(useVBO){
|
||||
glGenBuffersARB(1, &texture->tex);
|
||||
glGenBuffersARB(1, &texture->w);
|
||||
}else{
|
||||
texture->tex = glGenLists(1);
|
||||
texture->w = W;
|
||||
}
|
||||
if(texture->tex == 0){
|
||||
g_err(_("Can't generate VBO / GL list"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
texture->h = H;
|
||||
if(useVBO){
|
||||
GLint sz = W*H*3*sizeof(GLfloat), szi = W*(H-1)*2*sizeof(GLuint);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, texture->tex);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, texture->w);
|
||||
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sz*2,
|
||||
0, GL_STATIC_DRAW_ARB);
|
||||
GLfloat *vertexes = malloc(sz);
|
||||
GLuint *indexes = malloc(szi);
|
||||
GLfloat *ptr = vertexes;
|
||||
#pragma omp parallel for
|
||||
for(y = 0; y < H; y++){
|
||||
ptr = &vertexes[y*W*3];
|
||||
Verts = &window->image->data[y*W];
|
||||
for(x = 0; x < W; x++, Verts++){
|
||||
*ptr++ = dX + x;
|
||||
*ptr++ = dY + y;
|
||||
*ptr++ = *Verts;
|
||||
}
|
||||
}
|
||||
H--;
|
||||
#pragma omp parallel for
|
||||
for(y = 0; y < H; y++){
|
||||
GLuint *iptr = &indexes[y*W*2];
|
||||
GLuint idx = y*W;
|
||||
for(int x = 0; x < W; x++, idx++){
|
||||
*iptr++ = idx + W;
|
||||
*iptr++ = idx;
|
||||
}
|
||||
}
|
||||
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, szi, 0, GL_STATIC_DRAW_ARB);
|
||||
glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER, 0, szi, indexes);
|
||||
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sz, vertexes);
|
||||
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sz,
|
||||
sz, window->image_transformed->data);
|
||||
free(vertexes);
|
||||
free(indexes);
|
||||
free(window->image->data);
|
||||
window->image->data = NULL;
|
||||
free(window->image_transformed->data);
|
||||
window->image_transformed->data = NULL;
|
||||
//~ free(window->image_transformed); window->image_transformed = NULL;
|
||||
|
||||
}else{
|
||||
glNewList(texture->tex, GL_COMPILE);
|
||||
H--;
|
||||
for(y = 0 ; y < H; y++){
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for(x = 0; x < W; x++, Verts++, Norms+=3){
|
||||
glNormal3fv(Norms);
|
||||
glVertex3f(dX + x, dY + y, *Verts);
|
||||
glNormal3fv(&Norms[stride]);
|
||||
glVertex3f(dX + x, dY + (y + 1), Verts[W]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
glEndList();
|
||||
}
|
||||
gdk_gl_drawable_gl_end(glDrawable);
|
||||
DBG("time: %g", dtime() - t0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* External function for the preparation of [[section] [parental]] picture
|
||||
* to download into 3D-box
|
||||
* window - 3D-window
|
||||
* x0, y0, x, y - the corners of the selected area from picture of the parent window
|
||||
* from_file - TRUE to load from the called file selection window
|
||||
* FALSE for download from the parent window
|
||||
* If from_file == TRUE, the coordinates of the corners of subimage are ignored
|
||||
*/
|
||||
void terrain_3D(Window *window,
|
||||
double x0, double y0, double x, double y,
|
||||
gboolean from_file){
|
||||
FNAME();
|
||||
if(!window) return;
|
||||
if(!loadTerrain(window, x0, y0, x, y, from_file)){
|
||||
if(!from_file) destroy_window(window);
|
||||
return;
|
||||
}
|
||||
computeNormals(window);
|
||||
if(!createList(window)){
|
||||
destroy_window(window);
|
||||
return;
|
||||
}
|
||||
init3D(window); // initialisation of openGL window
|
||||
}
|
||||
565
src/tracking.c
Normal file
565
src/tracking.c
Normal file
@ -0,0 +1,565 @@
|
||||
// tracking.c - funcions for cutting tracking
|
||||
//
|
||||
// Copyright 2011 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
// MA 02110-1301, USA.
|
||||
#include "tracking.h"
|
||||
#include "imtools.h"
|
||||
#include "gauss.h"
|
||||
#include "opengl.h"
|
||||
|
||||
const double LHWD = 5.; // length of the cross-mark bar
|
||||
double x_1, y_1, x_2, y_2; // coordinates the selection frame or line
|
||||
//double GW, GH; // height and width of the graph
|
||||
|
||||
double gY0, gYm, gXm; // range of values of Y, the maximum value of X
|
||||
double gYmax; // limits to indicate the coordinates in the status bar
|
||||
double xScale, yScale; // scale by axes
|
||||
double bot_X = -1., top_X = -1.; // values (in units of X) of the lower and upper bounds on the abscissa
|
||||
gint g_botX, g_topX; // the same, but in the coordinates of the window
|
||||
|
||||
/* the data for translation of the x coordinate from Pdata into coordinates x, y of image
|
||||
* X = x0 + x*cx, Y= y0 + x*cy (cx - the cosine of the angle of the cutting, cy - sine) */
|
||||
struct{
|
||||
double x0; // starting poing
|
||||
double y0;
|
||||
double cx; // cosine of the angle of inclination
|
||||
double cy; // sine -//-
|
||||
} Pdata2image;
|
||||
Points *Pdata = NULL; // array of data points
|
||||
GdkPoint *gPoints = NULL; // points in window coordinates
|
||||
Points selection = {0, NULL}; // the same for the selected region
|
||||
GdkPoint *selPoints = NULL;
|
||||
|
||||
gint Npts; // number of data points
|
||||
|
||||
Point *alloc_Pdata(int N){
|
||||
if(Pdata){
|
||||
free(Pdata->data);
|
||||
Pdata->data = NULL;
|
||||
}
|
||||
else
|
||||
Pdata = malloc(sizeof(Pdata));
|
||||
if(!Pdata){
|
||||
g_err(_("Can't allocate memory for track points"));
|
||||
return NULL;
|
||||
}
|
||||
Pdata->data = malloc(N*sizeof(Point));
|
||||
if(!Pdata->data){
|
||||
g_err(_("Can't allocate memory for track points"));
|
||||
return NULL;
|
||||
}
|
||||
return Pdata->data;
|
||||
}
|
||||
// returns the coordinates xx and yy on the image (in CS of the window!)
|
||||
// for the point with coordinate x in the graph
|
||||
void get_image_crds(double x, double *xx, double *yy){
|
||||
*xx = Pdata2image.x0 + x * Pdata2image.cx;
|
||||
*yy = Pdata2image.y0 + x * Pdata2image.cy;
|
||||
}
|
||||
|
||||
// reset the sample
|
||||
void clear_selection(){
|
||||
free(selection.data);
|
||||
selection.data = NULL;
|
||||
selection.n = 0;
|
||||
}
|
||||
/*
|
||||
* filling an array Pdata based on the values of coordinates initial (X0, Y0)
|
||||
* and final (X, Y) points
|
||||
*/
|
||||
void get_data(double X0, double X, double Y0, double Y, Window *window){
|
||||
int n = 0, N; // new array size
|
||||
IMAGE *image = window->image;
|
||||
int x0, y0, yi, WD = image->width, HT = image->height;
|
||||
double x, y, A, xstep, ystep;
|
||||
Point *ptr;
|
||||
gboolean Vert = FALSE;
|
||||
double tgXY, cosXY;
|
||||
inline void minmax(double amp){
|
||||
if(gY0 > amp) gY0 = amp;
|
||||
else if(gYm < amp) gYm = amp;
|
||||
}
|
||||
inline double dist(double dx, double dy){
|
||||
return sqrtf(dx*dx + dy*dy);
|
||||
}
|
||||
gXm = dist(X-X0, Y-Y0);
|
||||
N = (int)(gXm + 1.);
|
||||
if(N < 2) return;
|
||||
if(!image->data)
|
||||
return;
|
||||
if( X0 < 0. || X0 > WD || X < 0. || X > WD ||
|
||||
Y0 < 0. || Y0 > HT || Y < 0. || Y > HT) return;
|
||||
if(!(ptr = alloc_Pdata(N))) return;
|
||||
Pdata2image.x0 = X0;
|
||||
Pdata2image.y0 = Y0; //HT - 1. - Y0;
|
||||
Pdata2image.cx = (X-X0)/gXm;
|
||||
Pdata2image.cy = (Y-Y0)/gXm;
|
||||
//DBG("N=%d, ", N);
|
||||
x0 = (int)(X0 + 0.5);
|
||||
y0 = (int)(Y0 + 0.5);
|
||||
if(fabs(X-X0) < fabs(Y-Y0)){ // closer to the vertical
|
||||
Vert = TRUE;
|
||||
tgXY = (X-X0) / (Y-Y0);
|
||||
cosXY = fabs(cos(atan(tgXY)));
|
||||
}
|
||||
else{
|
||||
tgXY = (Y-Y0) / (X-X0);
|
||||
cosXY = fabs(cos(atan(tgXY)));
|
||||
}
|
||||
yi = x0 + WD * y0;
|
||||
gY0 = gYm = image->data[yi];// * wd + min;
|
||||
if(Vert){
|
||||
ystep = (Y > Y0) ? cosXY : -cosXY;
|
||||
for(y = Y0; ; y+=ystep, n++, ptr++){
|
||||
if(n > N) break;
|
||||
if(ystep > 0.){
|
||||
if(y > Y) break;
|
||||
}
|
||||
else{
|
||||
if(y < Y) break;
|
||||
}
|
||||
ptr->x = (double)n;
|
||||
x = X0 + tgXY * (y - Y0);
|
||||
//yi = (int)(x+0.5) + WD * (HT - (int)(y+0.5));
|
||||
yi = (int)(x+0.5) + WD * ((int)(y+0.5));
|
||||
A = image->data[yi];// * wd + min;
|
||||
ptr->y = A;
|
||||
minmax(A);
|
||||
}
|
||||
}
|
||||
else{
|
||||
xstep = (X > X0)? cosXY : -cosXY;
|
||||
for(x = X0; ; x+=xstep, n++, ptr++){
|
||||
if(n > N) break;
|
||||
if(xstep > 0.){
|
||||
if(x > X) break;
|
||||
}
|
||||
else{
|
||||
if(x < X) break;
|
||||
}
|
||||
y = Y0 + tgXY * (x-X0);
|
||||
ptr->x = (double)n;
|
||||
//yi = (int)(x+0.5) + WD * (HT - (int)(y+0.5));
|
||||
yi = (int)(x+0.5) + WD * ((int)(y+0.5));
|
||||
A = image->data[yi];// * wd + min;
|
||||
ptr->y = A;
|
||||
minmax(A);
|
||||
}
|
||||
}
|
||||
//DBG("Ymin=%g, Ymax=%g\n", gY0, gYm);
|
||||
Pdata->n = n - 1;
|
||||
}
|
||||
|
||||
void draw_cross(GdkDrawable *d, GdkGC *gc, double x, double y){
|
||||
gdk_draw_line(d, gc, x-LHWD,y, x+LHWD, y);
|
||||
gdk_draw_line(d, gc, x,y-LHWD, x, y+LHWD);
|
||||
}
|
||||
// draw rectangle (gdk_draw_rectangle don't match because it require x,y > x0,y0
|
||||
void draw_rect(GdkDrawable *d, GdkGC *gc, double x0, double y0, double x, double y){
|
||||
gdk_draw_line(d, gc, x0,y0, x0,y);
|
||||
gdk_draw_line(d, gc, x0,y0, x,y0);
|
||||
gdk_draw_line(d, gc, x,y, x, y0);
|
||||
gdk_draw_line(d, gc, x,y, x0, y);
|
||||
}
|
||||
|
||||
// get coordinates of selected region
|
||||
void get_sel_region(double *x0, double *y0, double *x, double *y){
|
||||
*x0 = x_1; *y0 = y_1; *x = x_2; *y = y_2;
|
||||
}
|
||||
void do_tracking(double xx, double yy, gboolean start, Window *window){
|
||||
static double xold, yold, X0, Y0;
|
||||
double X, Y;
|
||||
double imW = (double)window->texture->w;
|
||||
double imH = (double)window->texture->h;
|
||||
Context *c = window->context;
|
||||
gboolean conv = FALSE;
|
||||
x_2 = xx; y_2 = yy;
|
||||
conv_mouse_to_image_coords(x_2, y_2, &X, &Y, window);
|
||||
//FNAME();
|
||||
if(!window->image->data) return;
|
||||
if(X > imW){ X = imW; conv = TRUE;}
|
||||
else if(X < 0){ X = 0; conv = TRUE;}
|
||||
if(Y > imH){ Y = imH; conv = TRUE;}
|
||||
else if(Y < 0){ Y = 0; conv = TRUE;}
|
||||
if(conv) conv_image_to_mouse_coords(X, Y, &x_2, &y_2, window);
|
||||
//DBG("X=%g, Y=%g, x=%g, y=%g", X, Y, x_2, y_2);
|
||||
if(start){
|
||||
clear_selection();
|
||||
X0 = X; Y0 = Y;
|
||||
x_1 = xold = x_2;
|
||||
y_1 = yold = y_2;
|
||||
return;
|
||||
}
|
||||
if(c->trackingMode == TRACK_VERT){
|
||||
X = X0; x_2 = x_1;
|
||||
}
|
||||
else if(c->trackingMode == TRACK_HORIZ){
|
||||
Y = Y0; y_2 = y_1;
|
||||
}
|
||||
else if(c->trackingMode == TRACK_DIAG){
|
||||
double s, adx, ady;
|
||||
gboolean changed = FALSE;
|
||||
adx = fabs(X-X0); ady = fabs(Y-Y0);
|
||||
void corrY(){
|
||||
s = (Y > Y0) ? 1. : -1.;
|
||||
Y = Y0 + s * adx;
|
||||
y_2 = y_1 + s * fabs(x_2-x_1);
|
||||
if(Y > imH || Y < 0.){
|
||||
if(Y > imH) Y = imH;
|
||||
else Y = 0.;
|
||||
conv_image_to_mouse_coords(X, Y, &x_2, &y_2, window);
|
||||
changed = TRUE;
|
||||
}
|
||||
/*
|
||||
if(Y > imH){ Y = imH; y = Y/Daspect + Dy; changed = TRUE;}
|
||||
else if(Y < 0){ Y = 0; y = Dy; changed = TRUE;}*/
|
||||
ady = fabs(Y-Y0);
|
||||
//DBG("Y=%g, Y0=%g", Y, Y0);
|
||||
}
|
||||
void corrX(){
|
||||
s = (X > X0) ? 1. : -1;
|
||||
X = X0 + s * ady;
|
||||
x_2 = x_1 + s * fabs(y_2-y_1);
|
||||
if(X > imW || X < 0.){
|
||||
if(X > imW) X = imW;
|
||||
else X = 0.;
|
||||
conv_image_to_mouse_coords(X, Y, &x_2, &y_2, window);
|
||||
changed = TRUE;
|
||||
}
|
||||
adx = fabs(X-X0);
|
||||
//DBG("X=%g, X0=%g", X, X0);
|
||||
}
|
||||
if(adx > ady){
|
||||
corrY();
|
||||
if(changed) corrX();
|
||||
}
|
||||
else{
|
||||
corrX();
|
||||
if(changed) corrY();
|
||||
}
|
||||
}
|
||||
|
||||
GdkDrawable *d = window->drawingArea->window;
|
||||
static GdkGC *gc = NULL;
|
||||
if(!gc){
|
||||
gc = gdk_gc_new(d);
|
||||
gdk_gc_set_foreground(gc, &(window->drawingArea->style->white));
|
||||
gdk_gc_set_function(gc, GDK_XOR);
|
||||
}
|
||||
if(c->drawingMode == DRAW_QUAD){// draw rectangle
|
||||
draw_rect(d, gc, x_1,y_1, xold,yold);
|
||||
draw_rect(d, gc, x_1,y_1, x_2,y_2);
|
||||
}
|
||||
else{ // draw lint
|
||||
// first erase old one
|
||||
gdk_draw_line(d, gc, x_1,y_1, xold,yold);
|
||||
draw_cross(d, gc, xold, yold);
|
||||
// then draw new one
|
||||
gdk_draw_line(d, gc, x_1,y_1, x_2,y_2);
|
||||
draw_cross(d, gc, x_2, y_2);
|
||||
//DBG("Xima=%g, Yima=%g (X0=%g, Y0=%g)", X, Y, X0, Y0);
|
||||
get_data(X0, X, Y0, Y, window);
|
||||
bot_X = 0.; top_X = gXm;
|
||||
//DBG("X=%g, X0=%g, Y=%g, Y0=%g", X, X0, Y, Y0);
|
||||
gchar str[80];
|
||||
g_snprintf(str, 79, "length=%.1f, angle=%.1fdegr",
|
||||
sqrt((X-X0)*(X-X0)+(Y-Y0)*(Y-Y0)),
|
||||
atan2(Y-Y0,X-X0)/M_PI*180.);
|
||||
set_status_text(StatusText, str, window->parent);
|
||||
set_status_text(StatusText, "", window);
|
||||
Gconfigure(window->graphWindow);
|
||||
gdk_window_invalidate_rect(window->graphWindow->drawingArea->window,
|
||||
NULL, TRUE);
|
||||
}
|
||||
xold = x_2; yold = y_2;
|
||||
}
|
||||
|
||||
gboolean Gexpose(Window *window){//, GdkEventExpose *event, gpointer userData){
|
||||
cairo_t *cr = NULL;
|
||||
int i;
|
||||
GtkWidget *Area = window->drawingArea;
|
||||
int H = (int)(Area->allocation.height + 0.5);
|
||||
GdkPoint *gptr = &gPoints[1];
|
||||
if(!cr){
|
||||
cr = gdk_cairo_create(Area->window);
|
||||
cairo_set_line_width (cr, 1.);
|
||||
}
|
||||
cairo_set_source_rgb(cr, 0., 0., 0.);
|
||||
if(!Pdata || !gPoints)
|
||||
return FALSE;
|
||||
if(!Pdata->data || Pdata->n < 2)
|
||||
return FALSE;
|
||||
cairo_move_to(cr, gPoints->x, gPoints->y);
|
||||
for(i = 1; i < Npts; i++, gptr++)
|
||||
cairo_line_to(cr, gptr->x, gptr->y);
|
||||
cairo_stroke(cr);
|
||||
cairo_set_source_rgb(cr, 0., 1., 0.);
|
||||
cairo_move_to(cr, g_botX, 0);
|
||||
cairo_line_to(cr, g_botX, H);
|
||||
cairo_stroke(cr);
|
||||
cairo_set_source_rgb(cr, 1., 0., 0.);
|
||||
cairo_move_to(cr, g_topX, 0);
|
||||
cairo_line_to(cr, g_topX, H);
|
||||
cairo_stroke(cr);
|
||||
if(selPoints && selection.n){
|
||||
int n = selection.n;
|
||||
cairo_set_source_rgb(cr, 0., 0., 1.);
|
||||
cairo_move_to(cr, selPoints->x, selPoints->y);
|
||||
gptr = &selPoints[1];
|
||||
//DBG("n=%d", n);
|
||||
for(i = 1; i < n; i++, gptr++)
|
||||
cairo_line_to(cr, gptr->x, gptr->y);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
cairo_destroy(cr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// calculation of the chart points in window coordinates
|
||||
gboolean Gconfigure(Window *window){//, GdkEventConfigure *event, gpointer none){
|
||||
int i, n;
|
||||
Point *ptr;
|
||||
//FNAME();
|
||||
double W, H, ym, y0;
|
||||
GdkPoint *gptr;
|
||||
gboolean log_scale = isYlog(window);
|
||||
if(!Pdata)
|
||||
return FALSE;
|
||||
if(!Pdata->data || Pdata->n < 2)
|
||||
return FALSE;
|
||||
GtkWidget *Area = window->drawingArea;
|
||||
free(gPoints);
|
||||
gPoints = NULL;
|
||||
Npts = Pdata->n;
|
||||
gPoints = malloc((Npts + 1)* sizeof(GdkPoint));
|
||||
if(!gPoints){
|
||||
g_err(_("Can't allocate memory for track points"));
|
||||
return FALSE;
|
||||
}
|
||||
ptr = Pdata->data;
|
||||
if(!ptr) return FALSE;
|
||||
gptr = gPoints;
|
||||
W = Area->allocation.width;
|
||||
H = Area->allocation.height;
|
||||
ym = gYm; y0 = gY0;
|
||||
if(log_scale){
|
||||
if(y0 < 0.) y0 = -log(-y0 + 1.);
|
||||
else y0 = log(y0 + 1.);
|
||||
if(ym < 0.) ym = -log(-ym + 1.);
|
||||
else ym = log(ym + 1.);
|
||||
}
|
||||
xScale = W / gXm;
|
||||
yScale = H / (ym - y0);
|
||||
gYmax = ym;
|
||||
for(i = 0; i < Npts; i++, ptr++, gptr++){
|
||||
gptr->x = (int)(ptr->x * xScale + 0.5);
|
||||
if(log_scale){
|
||||
double yy = ptr->y;
|
||||
if(yy < 0.)
|
||||
yy = -log(-yy + 1.);
|
||||
else
|
||||
yy = log(yy + 1.);
|
||||
gptr->y = (int)(H - (yy - y0) * yScale + 0.5);
|
||||
}
|
||||
else
|
||||
gptr->y = (int)(H - (ptr->y - y0) * yScale + 0.5);
|
||||
}
|
||||
g_botX = (int)(bot_X * xScale + 0.5);
|
||||
g_topX = (int)(top_X * xScale + 0.5);
|
||||
// Long live code monkeys of all time!
|
||||
if(selection.data) do{
|
||||
n = selection.n;
|
||||
free(selPoints);
|
||||
selPoints = malloc((n+1)* sizeof(GdkPoint));
|
||||
if(!selPoints) break;
|
||||
gptr = selPoints;
|
||||
ptr = selection.data;
|
||||
for(i = 0; i < n; i++, ptr++, gptr++){
|
||||
gptr->x = (int)(ptr->x * xScale + 0.5);
|
||||
if(log_scale){
|
||||
double yy = ptr->y;
|
||||
if(yy < 0.)
|
||||
yy = -log(-yy + 1.);
|
||||
else
|
||||
yy = log(yy + 1.);
|
||||
gptr->y = (int)(H - (yy - y0) * yScale + 0.5);
|
||||
}
|
||||
else
|
||||
gptr->y = (int)(H - (ptr->y - y0) * yScale + 0.5);
|
||||
// DBG("g: (%g, %g), w: (%d, %d)", ptr->x, ptr->y, gptr->x, gptr->y);
|
||||
}
|
||||
}while(0);
|
||||
/*
|
||||
if(ym > 1000.)
|
||||
set_Grulers(y0/1000, gXm, ym/1000);
|
||||
else*/
|
||||
set_Grulers(y0, gXm, ym, window);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// display mode of the histogram in the field of graph
|
||||
void do_histogram(Window *window){
|
||||
FNAME();
|
||||
IMAGE *image = window->context->current_image;
|
||||
if(!image || !image->data) image = window->image;
|
||||
if(!image || !image->data) return;
|
||||
int i, hsize = image->stat.histogram.size;
|
||||
int *hptr = image->stat.histogram.data;
|
||||
Point *ptr;
|
||||
double histsiz = (double)image->stat.histogram.size;
|
||||
double scale = image->stat.histogram.scale * (double)image->stat.histogram.size;
|
||||
//double imin = image->stat.min;
|
||||
if(!(ptr = alloc_Pdata(hsize))) return;
|
||||
gXm = 1.;//scale+imin;
|
||||
scale /= histsiz;
|
||||
gYm = (double)(image->stat.histogram.max);
|
||||
gY0 = (double)(image->stat.histogram.min);
|
||||
for(i = 0; i < hsize; i++, ptr++, hptr++){
|
||||
ptr->x = (double) i / histsiz;
|
||||
//ptr->x = (double) i * scale + imin;
|
||||
ptr->y = (double) *hptr;
|
||||
}
|
||||
Pdata->n = hsize;
|
||||
DBG("bot: %g, top: %g", image->stat.histogram.bot_tres, image->stat.histogram.top_tres);
|
||||
if(image->stat.histogram.bot_tres > 0.)
|
||||
bot_X = image->stat.histogram.bot_tres;
|
||||
else
|
||||
bot_X = 0.;
|
||||
if(image->stat.histogram.top_tres > 0.)
|
||||
top_X = image->stat.histogram.top_tres;
|
||||
else
|
||||
top_X = gXm;
|
||||
Gconfigure(window->graphWindow);
|
||||
gdk_window_invalidate_rect(window->graphWindow->drawingArea->window, NULL, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* will try to move boundaries when clicking near graph borders
|
||||
* when clicked near a curve - something else can be done ...
|
||||
* Window - graphics window
|
||||
* Return value: TRUE, if will need to handle mouse motion events further
|
||||
*/
|
||||
gboolean graph_mouse_btn(int x, Window *window){
|
||||
gboolean redraw = FALSE;
|
||||
gboolean ret = FALSE;
|
||||
double W, xScale, tmp;
|
||||
GtkWidget *graphArea = window->drawingArea;
|
||||
int dist = (g_topX - g_botX) / 2; // half of a distance between borders
|
||||
if(dist < PT_TRESHOLD) dist = PT_TRESHOLD;
|
||||
W = graphArea->allocation.width;
|
||||
xScale = W / gXm;
|
||||
if(abs(x - g_botX) < dist || x < g_botX){ // select down border
|
||||
tmp = (double) x / xScale;
|
||||
if(tmp < top_X) bot_X = tmp;
|
||||
if(bot_X < 0.) bot_X = 0.;
|
||||
ret = TRUE;
|
||||
redraw = TRUE;
|
||||
}
|
||||
else if(abs(x - g_topX) < dist || x > g_topX){ // select up border
|
||||
tmp = (double) x / xScale;
|
||||
if(tmp > bot_X) top_X = tmp;
|
||||
if(top_X > gXm) top_X = gXm;
|
||||
ret = TRUE;
|
||||
redraw = TRUE;
|
||||
}
|
||||
if(redraw){
|
||||
gchar msg[80];
|
||||
//DBG("move: botX=%g, topX=%g", bot_X, top_X);
|
||||
g_snprintf(msg, 79,
|
||||
_("Selected region from %.1f to %.1f, %d datapoints"),
|
||||
bot_X, top_X, (int)(((double)Npts)/gXm*(top_X-bot_X)+0.5));
|
||||
set_status_text(StatusText, msg, window);
|
||||
Gconfigure(window);
|
||||
gdk_window_invalidate_rect(graphArea->window, NULL, TRUE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gen_tres_texture(Window *window){
|
||||
window->image->stat.histogram.bot_tres = bot_X;
|
||||
window->image->stat.histogram.top_tres = top_X;
|
||||
treshold_image(window, bot_X / gXm, top_X / gXm);
|
||||
}
|
||||
|
||||
gboolean isYlog(Window *window){
|
||||
gboolean log_scale = FALSE;
|
||||
if(window->context->graphMode == GR_GRAPH){
|
||||
if(window->context->graphYaxis & Y_LOGGRAPH)
|
||||
log_scale = TRUE;
|
||||
} else if(window->context->graphYaxis & Y_LOGHIST)
|
||||
log_scale = TRUE;
|
||||
return log_scale;
|
||||
}
|
||||
|
||||
gboolean fit_gaussian(Window *window){
|
||||
//FNAME();
|
||||
Point *pt, *pt0;
|
||||
double C, A, s, x0;
|
||||
double xx, yy;
|
||||
#ifndef GSL_FOUND
|
||||
GSLERR;
|
||||
return FALSE;
|
||||
#endif
|
||||
if(!window->parent || !window->parent->texture){
|
||||
g_err(_("No parent window or image"));
|
||||
return FALSE;
|
||||
}
|
||||
double imW = (double)window->parent->texture->w;
|
||||
double imH = (double)window->parent->texture->h;
|
||||
gchar msg[160];
|
||||
GtkWidget *graphArea = window->drawingArea;
|
||||
if(!Pdata){ // no points? (O_o, but such a thing be?)
|
||||
g_err(_("No data points"));
|
||||
return FALSE;
|
||||
}
|
||||
int n = (int)(((double)Npts)/gXm*(top_X-bot_X) + 0.5);
|
||||
if(n < 10 || n > (int)(sqrt(imW * imW + imH * imH))){ // few or many points
|
||||
g_err(_("Bad amount of data points"));
|
||||
return FALSE;
|
||||
}
|
||||
int n0 = (int)(((double)Npts)/gXm*bot_X); // the number of a first point
|
||||
if(n0 < 0 || (n0 + n) > Npts){ // do not get there?
|
||||
g_err(_("Invalid number of first point"));
|
||||
return FALSE;
|
||||
}
|
||||
clear_selection();
|
||||
selection.n = n;
|
||||
selection.data = malloc(n * sizeof(Point));
|
||||
if(!selection.data){
|
||||
g_err(_("Can't allocate memory"));
|
||||
return FALSE;
|
||||
}
|
||||
pt = selection.data;
|
||||
pt0 = &Pdata->data[n0];
|
||||
DBG("pt0: (%g, %g)", pt0->x, pt0->y);
|
||||
// Copy the desired sample into a separate array
|
||||
for(; n--; pt++, pt0++){
|
||||
pt->x = pt0->x;
|
||||
pt->y = pt0->y;
|
||||
}
|
||||
gauss_fit(&selection, &C, &A, &s, &x0);
|
||||
gaussian_v(C, A, s, x0, &selection);
|
||||
get_image_crds(x0, &xx, &yy);
|
||||
//DBG("move: botX=%g, topX=%g", bot_X, top_X);
|
||||
g_snprintf(msg, 159,
|
||||
_("Fit gaussian, x0=%.2f I(%.2f, %.2f), s=%.2f, A=%.1f, C=%.3f"),
|
||||
x0, xx, yy, s, A, C);
|
||||
set_status_text(StatusText, msg, window);
|
||||
Gconfigure(window);
|
||||
gdk_window_invalidate_rect(graphArea->window, NULL, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user