f.comb.cc (fotoxx-23.0) | : | f.comb.cc (fotoxx-23.1) | ||
---|---|---|---|---|
/******************************************************************************* * | /******************************************************************************* * | |||
Fotoxx edit photos and manage collections | Fotoxx - edit photos and manage collections | |||
Copyright 2007-2023 Michael Cornelison | Copyright 2007-2023 Michael Cornelison | |||
source code URL: https://kornelix.net | source code URL: https://kornelix.net | |||
contact: mkornelix@gmail.com | contact: mkornelix@gmail.com | |||
This program is free software: you can redistribute it and/or modify | 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 | it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation, either version 3 of the License, or | the Free Software Foundation, either version 3 of the License, or | |||
(at your option) any later version. See https://www.gnu.org/licenses | (at your option) any later version. See https://www.gnu.org/licenses | |||
skipping to change at line 46 | skipping to change at line 46 | |||
#define EX extern // enable extern declarations | #define EX extern // enable extern declarations | |||
#include "fotoxx.h" // (variables in fotoxx.h are refs) | #include "fotoxx.h" // (variables in fotoxx.h are refs) | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// File scope variables and functions for combine images | // File scope variables and functions for combine images | |||
// used by HDR, HDF, STP, STN, Panorama. | // used by HDR, HDF, STP, STN, Panorama. | |||
int cimNF; // image coun t, <= 10 | int cimNF; // image coun t, <= 10 | |||
int cimLF; // index of a lphabetically last input file | int cimLF; // index of a lphabetically last input file | |||
char *cimFile[10]; // input imag e files | ch *cimFile[10]; // input imag e files | |||
PXM *cimPXMf[10]; // original i mage pixmaps | PXM *cimPXMf[10]; // original i mage pixmaps | |||
PXM *cimPXMs[10]; // alignment images, scaled and curved (pano) | PXM *cimPXMs[10]; // alignment images, scaled and curved (pano) | |||
PXM *cimPXMw[10]; // alignment images, warped | PXM *cimPXMw[10]; // alignment images, warped | |||
struct cimoffs { // image alig nment offsets | struct cimoffs { // image alig nment offsets | |||
float xf, yf, tf; // x, y, thet a offsets | float xf, yf, tf; // x, y, thet a offsets | |||
float wx[4], wy[4]; // x/y corner warps, 0=NW, 1=NE, 2=SE, 3=SW | float wx[4], wy[4]; // x/y corner warps, 0=NW, 1=NE, 2=SE, 3=SW | |||
}; | }; | |||
cimoffs cimOffs[10]; // image alig nment data in E3 output image | cimoffs cimOffs[10]; // image alig nment data in E3 output image | |||
skipping to change at line 72 | skipping to change at line 72 | |||
float cimSearchStep; // alignment search step, vpixels | float cimSearchStep; // alignment search step, vpixels | |||
int cim_manualwarp; // alignment manual warping instead of auto | int cim_manualwarp; // alignment manual warping instead of auto | |||
int cim_manualalign; // alignment is manual instead of auto | int cim_manualalign; // alignment is manual instead of auto | |||
float cimWarpRange; // alignment corner warp range, pixels | float cimWarpRange; // alignment corner warp range, pixels | |||
float cimWarpStep; // alignment corner warp step, vpixels | float cimWarpStep; // alignment corner warp step, vpixels | |||
float cimSampSize; // pixel samp le size | float cimSampSize; // pixel samp le size | |||
int cimOv1xlo, cimOv1xhi, cimOv1ylo, cimOv1yhi; // rectangle enclosing overlap area, | int cimOv1xlo, cimOv1xhi, cimOv1ylo, cimOv1yhi; // rectangle enclosing overlap area, | |||
int cimOv2xlo, cimOv2xhi, cimOv2ylo, cimOv2yhi; // image 1 and image2 coordinates | int cimOv2xlo, cimOv2xhi, cimOv2ylo, cimOv2yhi; // image 1 and image2 coordinates | |||
float cimRGBmf1[3][256]; // RGB matchi ng factors for image 1/2 compare: | float cimRGBmf1[3][256]; // RGB matchi ng factors for image 1/2 compare: | |||
float cimRGBmf2[3][256]; // cimRGBmf1[ *][pix1[*]] == cimRGBmf2[*][pix2[*]] | float cimRGBmf2[3][256]; // cimRGBmf1[ *][pix1[*]] == cimRGBmf2[*][pix2[*]] | |||
char *cimRedpix = 0; // maps high- contrast pixels for alignment | ch *cimRedpix = 0; // maps high- contrast pixels for alignment | |||
int cimRedImage; // which imag e has red pixels | int cimRedImage; // which imag e has red pixels | |||
int cimNsearch; // alignment search counter | int cimNsearch; // alignment search counter | |||
int cimShowIm1, cimShowIm2; // two images for cim_show_images() | int cimShowIm1, cimShowIm2; // two images for cim_show_images() | |||
int cimShowAll; // if > 0, sh ow all images | int cimShowAll; // if > 0, sh ow all images | |||
int cimPano; // pano mode flag for cim_align_image() | int cimPano; // pano mode flag for cim_align_image() | |||
int cimPanoV; // vertical p ano flag | int cimPanoV; // vertical p ano flag | |||
int cimPanoNC; // pano no-cu rve flag (scanned image) | int cimPanoNC; // pano no-cu rve flag (scanned image) | |||
float cimPanoFL; // pano lens focal length at image scale | float cimPanoFL; // pano lens focal length at image scale | |||
int cim_get_files(int min, int max); // get list o f input files, load PXM images | int cim_get_files(int min, int max); // get list o f input files, load PXM images | |||
skipping to change at line 105 | skipping to change at line 105 | |||
void cim_warp_image(int im); // warp image corners: cimPXMs[im] >> cimPXMw[im] | void cim_warp_image(int im); // warp image corners: cimPXMs[im] >> cimPXMw[im] | |||
void cim_warp_image_pano(int im, int fblend); // pano versi on, all / left side / blend stripe | void cim_warp_image_pano(int im, int fblend); // pano versi on, all / left side / blend stripe | |||
void cim_warp_image_Vpano(int im, int fblend); // vertical p ans version: bottom side corners | void cim_warp_image_Vpano(int im, int fblend); // vertical p ans version: bottom side corners | |||
int cim_sigdiff(float d1, float d2, float signf); // test 2 val ues for significant difference | int cim_sigdiff(float d1, float d2, float signf); // test 2 val ues for significant difference | |||
void cim_align_image(int im1, int im2); // align imag e im2 to im1, modify im2 offsets | void cim_align_image(int im1, int im2); // align imag e im2 to im1, modify im2 offsets | |||
float cim_match_images(int im1, int im2); // compute ma tch for overlapped images | float cim_match_images(int im1, int im2); // compute ma tch for overlapped images | |||
void cim_show_images(int fnew, int fblend); // combine im ages >> E3pxm >> main window | void cim_show_images(int fnew, int fblend); // combine im ages >> E3pxm >> main window | |||
void cim_show_Vimages(int fnew, int fblend); // vertical p ano version | void cim_show_Vimages(int fnew, int fblend); // vertical p ano version | |||
void cim_trim(); // cut-off ed ges where all images do not overlap | void cim_trim(); // cut-off ed ges where all images do not overlap | |||
void cim_trim_margins(); // cut-off ex cess margins (panorama) | void cim_trim_margins(); // cut-off ex cess margins (panorama) | |||
void cim_dump_offsets(cchar *label); // diagnostic tool | void cim_dump_offsets(ch *label); // diagnostic tool | |||
void cim_flatten_image(float F); // flatten pa norama image | void cim_flatten_image(float F); // flatten pa norama image | |||
void cim_flatten_Vimage(float F); // flatten ve rt. panorama image | void cim_flatten_Vimage(float F); // flatten ve rt. panorama image | |||
/******************************************************************************* * | /******************************************************************************* * | |||
Make an HDR (high dynamic range) image from several images of the same | Make an HDR (high dynamic range) image from several images of the same | |||
subject with different exposure levels. The combined image has better | subject with different exposure levels. The combined image has better | |||
visibility of detail in both the brightest and darkest areas. | visibility of detail in both the brightest and darkest areas. | |||
******************************************************************************** */ | ******************************************************************************** */ | |||
skipping to change at line 145 | skipping to change at line 145 | |||
void * HDR_align(void *); // align 2 images | void * HDR_align(void *); // align 2 images | |||
void HDR_brightness(); // compute pixel brightness levels | void HDR_brightness(); // compute pixel brightness levels | |||
void HDR_adjust_dialog(); // adjust image contribution curves | void HDR_adjust_dialog(); // adjust image contribution curves | |||
void * HDR_adjust_weights(void *); // combine images per contribution curves | void * HDR_adjust_weights(void *); // combine images per contribution curves | |||
editfunc EFhdr; // edit function data | editfunc EFhdr; // edit function data | |||
// menu function | // menu function | |||
void m_HDR(GtkWidget *, cchar *menu) | void m_HDR(GtkWidget *, ch *menu) | |||
{ | { | |||
char *ftemp; | ch *ftemp; | |||
int imx, jj, err, px, py, ww, hh; | int imx, jj, err, px, py, ww, hh; | |||
float fbright[10], btemp; | float fbright[10], btemp; | |||
float pixsum, fnorm = 1.0 / 256.0; | float pixsum, fnorm = 1.0 / 256.0; | |||
float *pixel; | float *pixel; | |||
PXM *pxmtemp; | PXM *pxmtemp; | |||
F1_help_topic = "HDR"; | F1_help_topic = "HDR"; | |||
Plog(1,"m_HDR \n"); | Plog(1,"m_HDR \n"); | |||
skipping to change at line 211 | skipping to change at line 211 | |||
fbright[imx] = btemp; | fbright[imx] = btemp; | |||
ftemp = cimFile[jj]; | ftemp = cimFile[jj]; | |||
cimFile[jj] = cimFile[imx]; | cimFile[jj] = cimFile[imx]; | |||
cimFile[imx] = ftemp; | cimFile[imx] = ftemp; | |||
pxmtemp = cimPXMf[jj]; | pxmtemp = cimPXMf[jj]; | |||
cimPXMf[jj] = cimPXMf[imx]; | cimPXMf[jj] = cimPXMf[imx]; | |||
cimPXMf[imx] = pxmtemp; | cimPXMf[imx] = pxmtemp; | |||
} | } | |||
} | } | |||
Fescape = 1; | Fwatchescape = 1; | |||
// killable with escape | // killable with escape | |||
Fescape = 0; | ||||
HDR_align(0); | HDR_align(0); | |||
if (HDR_stat != 1) goto cancel; | if (HDR_stat != 1) goto cancel; | |||
if (Fescape > 1) { // user cancel | if (Fescape) { // user cancel | |||
zmessage_post_bold(Mwin,"parent",3,"function canceled"); | zmessage_post_bold(Mwin,"parent",3,"function canceled"); | |||
goto cancel; | goto cancel; | |||
} | } | |||
HDR_brightness(); // compute pixel brightness levels | HDR_brightness(); // compute pixel brightness levels | |||
if (HDR_stat != 1) goto cancel; | if (HDR_stat != 1) goto cancel; | |||
HDR_adjust_dialog(); // combine images based on user inputs | HDR_adjust_dialog(); // combine images based on user inputs | |||
if (HDR_stat != 1) goto cancel; | if (HDR_stat != 1) goto cancel; | |||
skipping to change at line 239 | skipping to change at line 241 | |||
goto cleanup; | goto cleanup; | |||
cancel: | cancel: | |||
edit_cancel(0); | edit_cancel(0); | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
if (HDR_bright) zfree(HDR_bright); | if (HDR_bright) zfree(HDR_bright); | |||
*paneltext = 0; | *paneltext = 0; | |||
Fescape = 0; | Fwatchescape = Fescape = 0; | |||
return; | return; | |||
} | } | |||
// HDR align each pair of input images, output combined image to E3pxm | // HDR align each pair of input images, output combined image to E3pxm | |||
// cimPXMf[*] original image | // cimPXMf[*] original image | |||
// cimPXMs[*] scaled and color adjusted for pixel comparisons | // cimPXMs[*] scaled and color adjusted for pixel comparisons | |||
// cimPXMw[*] warped for display | // cimPXMw[*] warped for display | |||
void * HDR_align(void *) | void * HDR_align(void *) | |||
{ | { | |||
skipping to change at line 306 | skipping to change at line 308 | |||
cim_get_overlap(im1,im2,cimPXMs); // get overlap area | cim_get_overlap(im1,im2,cimPXMs); // get overlap area | |||
cim_get_redpix(im1); // get high-contrast pixels | cim_get_redpix(im1); // get high-contrast pixels | |||
cimShowIm1 = im1; // show two images with 50/50 blend | cimShowIm1 = im1; // show two images with 50/50 blend | |||
cimShowIm2 = im2; | cimShowIm2 = im2; | |||
cimShowAll = 0; | cimShowAll = 0; | |||
cim_show_images(1,0); // (x/y offsets can change) | cim_show_images(1,0); // (x/y offsets can change) | |||
cim_align_image(im1,im2); // align im2 to im1 | cim_align_image(im1,im2); // align im2 to im1 | |||
if (Fescape > 1) goto finish; // user kill | if (Fescape) goto finish; // user kill | |||
zfree(cimRedpix); // clear red pixels | zfree(cimRedpix); // clear red pixels | |||
cimRedpix = 0; | cimRedpix = 0; | |||
if (cimScale == 1.0) break; // done | if (cimScale == 1.0) break; // done | |||
R = HDR_imageIncrease; // next larger image size | R = HDR_imageIncrease; // next larger image size | |||
cimScale = cimScale * R; | cimScale = cimScale * R; | |||
if (cimScale > 0.85) { // if close to end, jump to end | if (cimScale > 0.85) { // if close to end, jump to end | |||
R = R / cimScale; | R = R / cimScale; | |||
skipping to change at line 492 | skipping to change at line 494 | |||
zadd_locked(Ffuncbusy,-1); | zadd_locked(Ffuncbusy,-1); | |||
Fpaint2(); // update window | Fpaint2(); // update window | |||
return; | return; | |||
} | } | |||
// Dialog for user to control the contributions of each input image | // Dialog for user to control the contributions of each input image | |||
// while watching the output image which is updated in real time. | // while watching the output image which is updated in real time. | |||
void HDR_adjust_dialog() | void HDR_adjust_dialog() | |||
{ | { | |||
int HDR_adjust_dialog_event(zdialog *zd, cchar *event); | int HDR_adjust_dialog_event(zdialog *zd, ch *event); | |||
void HDR_curvedit(int); | void HDR_curvedit(int); | |||
int imx; | int imx; | |||
float cww = 1.0 / (cimNF-1); | float cww = 1.0 / (cimNF-1); | |||
/*** | /*** | |||
_____________________________________________________ | _____________________________________________________ | |||
| Adjust Image Contributions | | | Adjust Image Contributions | | |||
| _________________________________________________ | | | _________________________________________________ | | |||
| | | | | | | | | | |||
skipping to change at line 560 | skipping to change at line 562 | |||
zdialog_resize(zd,300,250); | zdialog_resize(zd,300,250); | |||
zdialog_run(zd,HDR_adjust_dialog_event,"save"); // run dialog | zdialog_run(zd,HDR_adjust_dialog_event,"save"); // run dialog | |||
zdialog_wait(zd); // wait for completion | zdialog_wait(zd); // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int HDR_adjust_dialog_event(zdialog *zd, cchar *event) // add file open dialog | int HDR_adjust_dialog_event(zdialog *zd, ch *event) // add file open dialog | |||
{ | { | |||
char *file, *pp; | ch *file, *pp; | |||
FILE *fid; | FILE *fid; | |||
spldat *sd = EFhdr.sd; | spldat *sd = EFhdr.sd; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"load")) // load saved curve | if (strmatch(event,"load")) // load saved curve | |||
{ | { | |||
file = zgetfile("load curve from a file",MWIN,"file",saved_curves_folder); | file = zgetfile("load curve from a file",MWIN,"file",saved_curves_folder); | |||
if (! file) return 1; | if (! file) return 1; | |||
fid = fopen(file,"r"); | fid = fopen(file,"r"); | |||
skipping to change at line 762 | skipping to change at line 764 | |||
void * HDF_align(void *); | void * HDF_align(void *); | |||
void HDF_adjust_dialog(); | void HDF_adjust_dialog(); | |||
void HDF_mousefunc(); | void HDF_mousefunc(); | |||
void * HDF_map_pixels(void *); | void * HDF_map_pixels(void *); | |||
editfunc EFhdf; // edit function data | editfunc EFhdf; // edit function data | |||
// menu function | // menu function | |||
void m_HDF(GtkWidget *, cchar *menu) | void m_HDF(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "HDF"; | F1_help_topic = "HDF"; | |||
Plog(1,"m_HDF \n"); | Plog(1,"m_HDF \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 793 | skipping to change at line 795 | |||
cim_manualwarp = 0; | cim_manualwarp = 0; | |||
err = f_open(cimFile[cimLF]); // curr_file = alphabetically last | err = f_open(cimFile[cimLF]); // curr_file = alphabetically last | |||
if (err) goto cleanup; | if (err) goto cleanup; | |||
EFhdf.menufunc = m_HDF; | EFhdf.menufunc = m_HDF; | |||
EFhdf.menuname = "HDF"; | EFhdf.menuname = "HDF"; | |||
EFhdf.mousefunc = HDF_mousefunc; | EFhdf.mousefunc = HDF_mousefunc; | |||
if (! edit_setup(EFhdf)) goto cleanup; // setup edit (will lock) | if (! edit_setup(EFhdf)) goto cleanup; // setup edit (will lock) | |||
Fescape = 1; | Fwatchescape = 1; | |||
// killable with escape | // killable with escape | |||
Fescape = 0; | ||||
HDF_align(0); // align each pair of images | HDF_align(0); // align each pair of images | |||
if (HDF_stat != 1) goto cancel; | if (HDF_stat != 1) goto cancel; | |||
if (Fescape > 1) { // user cancel | if (Fescape) { // user cancel | |||
zmessage_post_bold(Mwin,"parent",3,"function canceled"); | zmessage_post_bold(Mwin,"parent",3,"function canceled"); | |||
goto cancel; | goto cancel; | |||
} | } | |||
HDF_adjust_dialog(); // combine images based on user inputs | HDF_adjust_dialog(); // combine images based on user inputs | |||
if (HDF_stat != 1) goto cancel; | if (HDF_stat != 1) goto cancel; | |||
CEF->Fmods++; // done | CEF->Fmods++; // done | |||
CEF->Fsaved = 0; | CEF->Fsaved = 0; | |||
edit_done(0); | edit_done(0); | |||
goto cleanup; | goto cleanup; | |||
cancel: | cancel: | |||
edit_cancel(0); | edit_cancel(0); | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
*paneltext = 0; | *paneltext = 0; | |||
Fescape = 0; | Fwatchescape = Fescape = 0; | |||
return; | return; | |||
} | } | |||
// align each image 2nd-last to 1st image | // align each image 2nd-last to 1st image | |||
// cimPXMf[*] original image | // cimPXMf[*] original image | |||
// cimPXMs[*] scaled and color adjusted for pixel comparisons | // cimPXMs[*] scaled and color adjusted for pixel comparisons | |||
// cimPXMw[*] warped for display | // cimPXMw[*] warped for display | |||
void * HDF_align(void *) | void * HDF_align(void *) | |||
{ | { | |||
skipping to change at line 881 | skipping to change at line 885 | |||
cim_get_overlap(im1,im2,cimPXMs); // get overlap area | cim_get_overlap(im1,im2,cimPXMs); // get overlap area | |||
cim_get_redpix(im1); // get high-contrast pixels | cim_get_redpix(im1); // get high-contrast pixels | |||
cimShowIm1 = im1; // show these two images | cimShowIm1 = im1; // show these two images | |||
cimShowIm2 = im2; // with 50/50 blend | cimShowIm2 = im2; // with 50/50 blend | |||
cimShowAll = 0; | cimShowAll = 0; | |||
cim_show_images(1,0); // (x/y offsets can change) | cim_show_images(1,0); // (x/y offsets can change) | |||
cim_align_image(im1,im2); // align im2 to im1 | cim_align_image(im1,im2); // align im2 to im1 | |||
if (Fescape > 1) goto finish; // user kill | if (Fescape) goto finish; // user kill | |||
zfree(cimRedpix); // clear red pixels | zfree(cimRedpix); // clear red pixels | |||
cimRedpix = 0; | cimRedpix = 0; | |||
if (cimScale == 1.0) break; // done | if (cimScale == 1.0) break; // done | |||
R = HDF_imageIncrease; // next larger image size | R = HDF_imageIncrease; // next larger image size | |||
cimScale = cimScale * R; | cimScale = cimScale * R; | |||
if (cimScale > 0.85) { // if close to end, jump to end | if (cimScale > 0.85) { // if close to end, jump to end | |||
R = R / cimScale; | R = R / cimScale; | |||
skipping to change at line 932 | skipping to change at line 936 | |||
HDF_stat = 1; | HDF_stat = 1; | |||
return 0; | return 0; | |||
} | } | |||
// paint and warp output image | // paint and warp output image | |||
zdialog *HDF_adjustzd = 0; // paint/warp dialog | zdialog *HDF_adjustzd = 0; // paint/warp dialog | |||
int HDF_mode; // mode: paint or warp | int HDF_mode; // mode: paint or warp | |||
int HDF_image; // current image (0 based) | int HDF_image; // current image (0 based) | |||
int HDF_radius; // paint mode radius | int HDF_radius; // paint mode radius | |||
char *HDF_pixmap = 0; // map input image per output pixel | ch *HDF_pixmap = 0; // map input image per output pixel | |||
float *HDF_warpx[10], *HDF_warpy[10]; // warp memory, pixel displacements | float *HDF_warpx[10], *HDF_warpy[10]; // warp memory, pixel displacements | |||
void HDF_adjust_dialog() | void HDF_adjust_dialog() | |||
{ | { | |||
char imageN[8] = "imageN", labN[4] = "0"; | ch imageN[8] = "imageN", labN[4] = "0"; | |||
int cc, imx, ww, hh; | int cc, imx, ww, hh; | |||
int HDF_adjust_dialog_event(zdialog *zd, cchar *event); | int HDF_adjust_dialog_event(zdialog *zd, ch *event); | |||
/*** | /*** | |||
______________________________________ | ______________________________________ | |||
| Paint and Warp Image | | | Paint and Warp Image | | |||
| | | | | | |||
| Image (o) 1 (o) 2 (o) 3 ... | | | Image (o) 1 (o) 2 (o) 3 ... | | |||
| (o) paint Radius [____] | | | (o) paint Radius [____] | | |||
| (o) warp | | | (o) warp | | |||
| [ OK ] [Cancel] | | | [ OK ] [Cancel] | | |||
|______________________________________| | |______________________________________| | |||
skipping to change at line 988 | skipping to change at line 992 | |||
zdialog_stuff(zd,"warp",0); // warp button off | zdialog_stuff(zd,"warp",0); // warp button off | |||
zdialog_stuff(zd,"image1",1); // initial image = 1st | zdialog_stuff(zd,"image1",1); // initial image = 1st | |||
HDF_mode = 0; // start in paint mode | HDF_mode = 0; // start in paint mode | |||
HDF_image = 0; // initial image | HDF_image = 0; // initial image | |||
HDF_radius = 100; // paint radius | HDF_radius = 100; // paint radius | |||
takeMouse(HDF_mousefunc,0); // connect mouse function | takeMouse(HDF_mousefunc,0); // connect mouse function | |||
cc = E3pxm->ww * E3pxm->hh; // allocate pixel map | cc = E3pxm->ww * E3pxm->hh; // allocate pixel map | |||
HDF_pixmap = (char *) zmalloc(cc,"cim HDF"); | HDF_pixmap = (ch *) zmalloc(cc,"cim HDF"); | |||
memset(HDF_pixmap,cimNF,cc); // initial state, blend all images | memset(HDF_pixmap,cimNF,cc); // initial state, blend all images | |||
for (imx = 0; imx < cimNF; imx++) { // allocate warp memory | for (imx = 0; imx < cimNF; imx++) { // allocate warp memory | |||
ww = cimPXMw[imx]->ww; | ww = cimPXMw[imx]->ww; | |||
hh = cimPXMw[imx]->hh; | hh = cimPXMw[imx]->hh; | |||
HDF_warpx[imx] = (float *) zmalloc(ww * hh * sizeof(float),"cim HDF"); | HDF_warpx[imx] = (float *) zmalloc(ww * hh * sizeof(float),"cim HDF"); | |||
HDF_warpy[imx] = (float *) zmalloc(ww * hh * sizeof(float),"cim HDF"); | HDF_warpy[imx] = (float *) zmalloc(ww * hh * sizeof(float),"cim HDF"); | |||
} | } | |||
zdialog_resize(zd,250,0); // stretch a bit | zdialog_resize(zd,250,0); // stretch a bit | |||
zdialog_run(zd,HDF_adjust_dialog_event,"save"); // run dialog, parallel | zdialog_run(zd,HDF_adjust_dialog_event,"save"); // run dialog, parallel | |||
zdialog_wait(zd); // wait for completion | zdialog_wait(zd); // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int HDF_adjust_dialog_event(zdialog *zd, cchar *event) | int HDF_adjust_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int imx, nn; | int imx, nn; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) // dialog finish | if (zd->zstat) // dialog finish | |||
{ | { | |||
freeMouse(); // disconnect mouse function | freeMouse(); // disconnect mouse function | |||
if (zd->zstat == 1) HDF_stat = 1; | if (zd->zstat == 1) HDF_stat = 1; | |||
else HDF_stat = 0; | else HDF_stat = 0; | |||
skipping to change at line 1071 | skipping to change at line 1075 | |||
// HDF dialog mouse function | // HDF dialog mouse function | |||
// paint: during drag, selected image >> HDF_pixmap (within paint radius) >> E 3 | // paint: during drag, selected image >> HDF_pixmap (within paint radius) >> E 3 | |||
// warp: for selected image, cimPXMs >> warp >> cimPXMw >> E3 | // warp: for selected image, cimPXMs >> warp >> cimPXMw >> E3 | |||
void HDF_mousefunc() | void HDF_mousefunc() | |||
{ | { | |||
float vpix1[4], *pix2, *pix3; | float vpix1[4], *pix2, *pix3; | |||
int imx, radius, rect, radius2, vstat1; | int imx, radius, rect, radius2, vstat1; | |||
int mx, my, dx, dy, px3, py3; | int mx, my, dx, dy, px3, py3; | |||
char imageN[8] = "imageN"; | ch imageN[8] = "imageN"; | |||
float px1, py1; | float px1, py1; | |||
float xoff, yoff, sintf[10], costf[10]; | float xoff, yoff, sintf[10], costf[10]; | |||
int ii, px, py, ww, hh; | int ii, px, py, ww, hh; | |||
float mag, dispx, dispy, d1, d2; | float mag, dispx, dispy, d1, d2; | |||
PXM *pxm1, *pxm2; | PXM *pxm1, *pxm2; | |||
if (LMclick || RMclick) // mouse click | if (LMclick || RMclick) // mouse click | |||
return; // process zooms normally | return; // process zooms normally | |||
if (HDF_mode == 0) goto paint; | if (HDF_mode == 0) goto paint; | |||
skipping to change at line 1310 | skipping to change at line 1314 | |||
void * STP_align(void *); | void * STP_align(void *); | |||
void STP_adjust_dialog(); | void STP_adjust_dialog(); | |||
void STP_mousefunc(); | void STP_mousefunc(); | |||
void * STP_map_pixels(void *); | void * STP_map_pixels(void *); | |||
void STP_setpixel(int px, int py, int source); | void STP_setpixel(int px, int py, int source); | |||
editfunc EFstp; // edit function data | editfunc EFstp; // edit function data | |||
// menu function | // menu function | |||
void m_stack_paint(GtkWidget *, cchar *menu) | void m_stack_paint(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "stack/paint"; | F1_help_topic = "stack/paint"; | |||
Plog(1,"m_stack_paint \n"); | Plog(1,"m_stack_paint \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 1341 | skipping to change at line 1345 | |||
cim_manualwarp = 0; | cim_manualwarp = 0; | |||
err = f_open(cimFile[cimLF]); // curr_file = alphabetically last | err = f_open(cimFile[cimLF]); // curr_file = alphabetically last | |||
if (err) goto cleanup; | if (err) goto cleanup; | |||
EFstp.menufunc = m_stack_paint; | EFstp.menufunc = m_stack_paint; | |||
EFstp.menuname = "Stack/Paint"; | EFstp.menuname = "Stack/Paint"; | |||
EFstp.mousefunc = STP_mousefunc; | EFstp.mousefunc = STP_mousefunc; | |||
if (! edit_setup(EFstp)) goto cleanup; // setup edit (will lock) | if (! edit_setup(EFstp)) goto cleanup; // setup edit (will lock) | |||
Fescape = 1; | Fwatchescape = 1; | |||
// killable with escape | // killable with escape | |||
Fescape = 0; | ||||
STP_align(0); // align each pair of images | STP_align(0); // align each pair of images | |||
if (STP_stat != 1) goto cancel; | if (STP_stat != 1) goto cancel; | |||
if (Fescape > 1) { // user cancel | if (Fescape) { // user cancel | |||
zmessage_post_bold(Mwin,"parent",3,"function canceled"); | zmessage_post_bold(Mwin,"parent",3,"function canceled"); | |||
goto cancel; | goto cancel; | |||
} | } | |||
STP_adjust_dialog(); // combine images based on user inputs | STP_adjust_dialog(); // combine images based on user inputs | |||
if (STP_stat != 1) goto cancel; | if (STP_stat != 1) goto cancel; | |||
CEF->Fmods++; // done | CEF->Fmods++; // done | |||
CEF->Fsaved = 0; | CEF->Fsaved = 0; | |||
edit_done(0); | edit_done(0); | |||
goto cleanup; | goto cleanup; | |||
cancel: | cancel: | |||
edit_cancel(0); | edit_cancel(0); | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
*paneltext = 0; | *paneltext = 0; | |||
Fescape = 0; | Fwatchescape = Fescape = 0; | |||
return; | return; | |||
} | } | |||
// align each image 2nd-last to 1st image | // align each image 2nd-last to 1st image | |||
// cimPXMf[*] original image | // cimPXMf[*] original image | |||
// cimPXMs[*] scaled and color adjusted for pixel comparisons | // cimPXMs[*] scaled and color adjusted for pixel comparisons | |||
// cimPXMw[*] warped for display | // cimPXMw[*] warped for display | |||
void * STP_align(void *) | void * STP_align(void *) | |||
{ | { | |||
skipping to change at line 1429 | skipping to change at line 1435 | |||
cim_get_overlap(im1,im2,cimPXMs); // get overlap area | cim_get_overlap(im1,im2,cimPXMs); // get overlap area | |||
cim_get_redpix(im1); // get high-contrast pixels | cim_get_redpix(im1); // get high-contrast pixels | |||
cimShowIm1 = im1; // show these two images | cimShowIm1 = im1; // show these two images | |||
cimShowIm2 = im2; // with 50/50 blend | cimShowIm2 = im2; // with 50/50 blend | |||
cimShowAll = 0; | cimShowAll = 0; | |||
cim_show_images(1,0); // (x/y offsets can change) | cim_show_images(1,0); // (x/y offsets can change) | |||
cim_align_image(im1,im2); // align im2 to im1 | cim_align_image(im1,im2); // align im2 to im1 | |||
if (Fescape > 1) goto finish; // user kill | if (Fescape) goto finish; // user kill | |||
zfree(cimRedpix); // clear red pixels | zfree(cimRedpix); // clear red pixels | |||
cimRedpix = 0; | cimRedpix = 0; | |||
if (cimScale == 1.0) break; // done | if (cimScale == 1.0) break; // done | |||
R = STP_imageIncrease; // next larger image size | R = STP_imageIncrease; // next larger image size | |||
cimScale = cimScale * R; | cimScale = cimScale * R; | |||
if (cimScale > 0.85) { // if close to end, jump to end | if (cimScale > 0.85) { // if close to end, jump to end | |||
R = R / cimScale; | R = R / cimScale; | |||
skipping to change at line 1485 | skipping to change at line 1491 | |||
int STP_image; // current image (0 based) | int STP_image; // current image (0 based) | |||
int STP_radius; // paint mode radius | int STP_radius; // paint mode radius | |||
int STP_mode; // 1/2 = show/hide | int STP_mode; // 1/2 = show/hide | |||
float STP_show_adjust; // contrast adjustment | float STP_show_adjust; // contrast adjustment | |||
float STP_hide_adjust; // contrast adjustment | float STP_hide_adjust; // contrast adjustment | |||
void STP_adjust_dialog() | void STP_adjust_dialog() | |||
{ | { | |||
zdialog *zd; | zdialog *zd; | |||
char imageN[8] = "imageN", labN[4] = "0"; | ch imageN[8] = "imageN", labN[4] = "0"; | |||
int imx; | int imx; | |||
int STP_adjust_dialog_event(zdialog *zd, cchar *event); | int STP_adjust_dialog_event(zdialog *zd, ch *event); | |||
/*** | /*** | |||
_________________________________________ | _________________________________________ | |||
| Select and Paint Image | | | Select and Paint Image | | |||
| | | | | | |||
| image (o) 1 (o) 2 (o) 3 ... | | | image (o) 1 (o) 2 (o) 3 ... | | |||
| paint radius [___] | | | paint radius [___] | | |||
| | | | | | |||
| transient objects | | | transient objects | | |||
| show (o) =========[]================= | | | show (o) =========[]================= | | |||
skipping to change at line 1557 | skipping to change at line 1563 | |||
zdialog_resize(zd,250,0); | zdialog_resize(zd,250,0); | |||
zdialog_run(zd,STP_adjust_dialog_event,"save"); // run dialog, parallel | zdialog_run(zd,STP_adjust_dialog_event,"save"); // run dialog, parallel | |||
zdialog_wait(zd); // wait for completion | zdialog_wait(zd); // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int STP_adjust_dialog_event(zdialog *zd, cchar *event) | int STP_adjust_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int nn; | int nn; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) // dialog finish | if (zd->zstat) // dialog finish | |||
{ | { | |||
freeMouse(); | freeMouse(); | |||
if (zd->zstat == 1) STP_stat = 1; | if (zd->zstat == 1) STP_stat = 1; | |||
else STP_stat = 0; | else STP_stat = 0; | |||
skipping to change at line 1883 | skipping to change at line 1889 | |||
int STN_exlow = 0, STN_exhigh = 0; // exclude low/high pixel | int STN_exlow = 0, STN_exhigh = 0; // exclude low/high pixel | |||
void * STN_align(void *); | void * STN_align(void *); | |||
void STN_adjust_dialog(); | void STN_adjust_dialog(); | |||
void * STN_combine(void *); | void * STN_combine(void *); | |||
editfunc EFstn; // edit function data | editfunc EFstn; // edit function data | |||
// menu function | // menu function | |||
void m_stack_noise(GtkWidget *, cchar *menu) | void m_stack_noise(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "stack/noise"; | F1_help_topic = "stack/noise"; | |||
Plog(1,"m_stack_noise \n"); | Plog(1,"m_stack_noise \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 1913 | skipping to change at line 1919 | |||
cim_manualwarp = 0; | cim_manualwarp = 0; | |||
err = f_open(cimFile[cimLF]); // curr_file = alphabetically last | err = f_open(cimFile[cimLF]); // curr_file = alphabetically last | |||
if (err) goto cleanup; | if (err) goto cleanup; | |||
EFstn.menufunc = m_stack_noise; | EFstn.menufunc = m_stack_noise; | |||
EFstn.menuname = "Stack/Noise"; | EFstn.menuname = "Stack/Noise"; | |||
if (! edit_setup(EFstn)) goto cleanup; // setup edit (will lock) | if (! edit_setup(EFstn)) goto cleanup; // setup edit (will lock) | |||
Fescape = 1; | Fwatchescape = 1; | |||
// killable with escape | // killable with escape | |||
Fescape = 0; | ||||
STN_align(0); // align each pair of images | STN_align(0); // align each pair of images | |||
if (STN_stat != 1) goto cancel; | if (STN_stat != 1) goto cancel; | |||
if (Fescape > 1) { // user cancel | if (Fescape) { // user cancel | |||
zmessage_post_bold(Mwin,"parent",3,"function canceled"); | zmessage_post_bold(Mwin,"parent",3,"function canceled"); | |||
goto cancel; | goto cancel; | |||
} | } | |||
STN_adjust_dialog(); // combine images based on user inputs | STN_adjust_dialog(); // combine images based on user inputs | |||
if (STN_stat != 1) goto cancel; | if (STN_stat != 1) goto cancel; | |||
CEF->Fmods++; // done | CEF->Fmods++; // done | |||
CEF->Fsaved = 0; | CEF->Fsaved = 0; | |||
edit_done(0); | edit_done(0); | |||
goto cleanup; | goto cleanup; | |||
cancel: | cancel: | |||
edit_cancel(0); | edit_cancel(0); | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
*paneltext = 0; | *paneltext = 0; | |||
Fescape = 0; | Fwatchescape = Fescape = 0; | |||
return; | return; | |||
} | } | |||
// align each image 2nd-last to 1st image | // align each image 2nd-last to 1st image | |||
// cimPXMf[*] original image | // cimPXMf[*] original image | |||
// cimPXMs[*] scaled and color adjusted for pixel comparisons | // cimPXMs[*] scaled and color adjusted for pixel comparisons | |||
// cimPXMw[*] warped for display | // cimPXMw[*] warped for display | |||
void * STN_align(void *) | void * STN_align(void *) | |||
{ | { | |||
skipping to change at line 2001 | skipping to change at line 2009 | |||
cim_get_overlap(im1,im2,cimPXMs); // get overlap area | cim_get_overlap(im1,im2,cimPXMs); // get overlap area | |||
cim_get_redpix(im1); // get high-contrast pixels | cim_get_redpix(im1); // get high-contrast pixels | |||
cimShowIm1 = im1; // show these two images | cimShowIm1 = im1; // show these two images | |||
cimShowIm2 = im2; // with 50/50 blend | cimShowIm2 = im2; // with 50/50 blend | |||
cimShowAll = 0; | cimShowAll = 0; | |||
cim_show_images(1,0); // (x/y offsets can change) | cim_show_images(1,0); // (x/y offsets can change) | |||
cim_align_image(im1,im2); // align im2 to im1 | cim_align_image(im1,im2); // align im2 to im1 | |||
if (Fescape > 1) goto finish; // user kill | if (Fescape) goto finish; // user kill | |||
zfree(cimRedpix); // clear red pixels | zfree(cimRedpix); // clear red pixels | |||
cimRedpix = 0; | cimRedpix = 0; | |||
if (cimScale == 1.0) break; // done | if (cimScale == 1.0) break; // done | |||
R = STN_imageIncrease; // next larger image size | R = STN_imageIncrease; // next larger image size | |||
cimScale = cimScale * R; | cimScale = cimScale * R; | |||
if (cimScale > 0.85) { // if close to end, jump to end | if (cimScale > 0.85) { // if close to end, jump to end | |||
R = R / cimScale; | R = R / cimScale; | |||
skipping to change at line 2052 | skipping to change at line 2060 | |||
STN_stat = 1; | STN_stat = 1; | |||
return 0; | return 0; | |||
} | } | |||
// change pixel combination according to user input | // change pixel combination according to user input | |||
void STN_adjust_dialog() | void STN_adjust_dialog() | |||
{ | { | |||
zdialog *zd; | zdialog *zd; | |||
int STN_adjust_dialog_event(zdialog *zd, cchar *event); | int STN_adjust_dialog_event(zdialog *zd, ch *event); | |||
/*** | /*** | |||
_________________________________________ | _________________________________________ | |||
| Adjust Pixel Composition | | | Adjust Pixel Composition | | |||
| | | | | | |||
| (o) use average (o) use median | | | (o) use average (o) use median | | |||
| [x] omit low pixel [x] omit high pixel | | | [x] omit low pixel [x] omit high pixel | | |||
| | | | | | |||
| [ OK ] [Cancel] | | | [ OK ] [Cancel] | | |||
|_________________________________________| | |_________________________________________| | |||
skipping to change at line 2096 | skipping to change at line 2104 | |||
zdialog_resize(zd,250,0); | zdialog_resize(zd,250,0); | |||
zdialog_run(zd,STN_adjust_dialog_event,"save"); // run dialog, parallel | zdialog_run(zd,STN_adjust_dialog_event,"save"); // run dialog, parallel | |||
zdialog_wait(zd); // wait for completion | zdialog_wait(zd); // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int STN_adjust_dialog_event(zdialog *zd, cchar *event) | int STN_adjust_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) { // dialog finish | if (zd->zstat) { // dialog finish | |||
if (zd->zstat == 1) STN_stat = 1; | if (zd->zstat == 1) STN_stat = 1; | |||
else STN_stat = 0; | else STN_stat = 0; | |||
if (STN_stat == 1) cim_trim(); // trim edges | if (STN_stat == 1) cim_trim(); // trim edges | |||
return 1; | return 1; | |||
} | } | |||
skipping to change at line 2272 | skipping to change at line 2280 | |||
int STL_mode; | int STL_mode; | |||
int STL_image; // current image (0 based) | int STL_image; // current image (0 based) | |||
int STL_radius; // mouse paint radius | int STL_radius; // mouse paint radius | |||
int STL_center, STL_edge; // mouse center and edge opacity | int STL_center, STL_edge; // mouse center and edge opacity | |||
int STL_stat; | int STL_stat; | |||
editfunc EFstl; // edit function data | editfunc EFstl; // edit function data | |||
// menu function | // menu function | |||
void m_stack_layer(GtkWidget *, cchar *menu) | void m_stack_layer(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "stack/layer"; | F1_help_topic = "stack/layer"; | |||
Plog(1,"m_stack_layer \n"); | Plog(1,"m_stack_layer \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 2325 | skipping to change at line 2333 | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
return; | return; | |||
} | } | |||
// dialog to paint output image areas with selected input image | // dialog to paint output image areas with selected input image | |||
void STL_paint() | void STL_paint() | |||
{ | { | |||
zdialog *zd; | zdialog *zd; | |||
char imageN[8] = "imageN", labN[4] = "0"; | ch imageN[8] = "imageN", labN[4] = "0"; | |||
int imx, px, py; | int imx, px, py; | |||
int STL_paint_dialog_event(zdialog *zd, cchar *event); | int STL_paint_dialog_event(zdialog *zd, ch *event); | |||
/*** | /*** | |||
______________________________________ | ______________________________________ | |||
| Select and Paint Image | | | Select and Paint Image | | |||
| | | | | | |||
| Image (o) 1 (o) 2 (o) 3 ... | | | Image (o) 1 (o) 2 (o) 3 ... | | |||
| | | | | | |||
| [ fill ] using selected image | | | [ fill ] using selected image | | |||
| Paint Radius [___] | | | Paint Radius [___] | | |||
| opacity center [___] edge [___] | | | opacity center [___] edge [___] | | |||
skipping to change at line 2398 | skipping to change at line 2406 | |||
zdialog_resize(zd,250,0); | zdialog_resize(zd,250,0); | |||
zdialog_run(zd,STL_paint_dialog_event,"save"); // run dialog, parallel | zdialog_run(zd,STL_paint_dialog_event,"save"); // run dialog, parallel | |||
zdialog_wait(zd); // wait for completion | zdialog_wait(zd); // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int STL_paint_dialog_event(zdialog *zd, cchar *event) | int STL_paint_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int nn, px, py; | int nn, px, py; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) // dialog finish | if (zd->zstat) // dialog finish | |||
{ | { | |||
freeMouse(); | freeMouse(); | |||
if (zd->zstat == 1) STL_stat = 1; // user OK or cancel | if (zd->zstat == 1) STL_stat = 1; // user OK or cancel | |||
else STL_stat = 0; | else STL_stat = 0; | |||
skipping to change at line 2555 | skipping to change at line 2563 | |||
void STS_mousefunc(); | void STS_mousefunc(); | |||
void STS_split(); | void STS_split(); | |||
int STS_stat; | int STS_stat; | |||
int Eww, Ehh, P, PP; | int Eww, Ehh, P, PP; | |||
int Finit; | int Finit; | |||
editfunc EFsts; // edit function data | editfunc EFsts; // edit function data | |||
// menu function | // menu function | |||
void m_stack_split(GtkWidget *, cchar *menu) | void m_stack_split(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "stack/split"; | F1_help_topic = "stack/split"; | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
Plog(1,"m_stack_split \n"); | Plog(1,"m_stack_split \n"); | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 2610 | skipping to change at line 2618 | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
return; | return; | |||
} | } | |||
// dialog to paint output image areas with selected input image | // dialog to paint output image areas with selected input image | |||
void STS_start() | void STS_start() | |||
{ | { | |||
int STS_start_dialog_event(zdialog *zd, cchar *event); | int STS_start_dialog_event(zdialog *zd, ch *event); | |||
zdialog *zd; | zdialog *zd; | |||
/*** | /*** | |||
_____________________________ | _____________________________ | |||
| Split two Images | | | Split two Images | | |||
| | | | | | |||
| drag image boundary | | | drag image boundary | | |||
| | | | | | |||
| [ OK ] [Cancel] | | | [ OK ] [Cancel] | | |||
skipping to change at line 2642 | skipping to change at line 2650 | |||
takeMouse(STS_mousefunc,0); // connect mouse function | takeMouse(STS_mousefunc,0); // connect mouse function | |||
zdialog_run(zd,STS_start_dialog_event,"save"); // run dialog, parallel | zdialog_run(zd,STS_start_dialog_event,"save"); // run dialog, parallel | |||
zdialog_wait(zd); // wait for completion | zdialog_wait(zd); // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int STS_start_dialog_event(zdialog *zd, cchar *event) | int STS_start_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) // dialog finish | if (zd->zstat) // dialog finish | |||
{ | { | |||
freeMouse(); | freeMouse(); | |||
if (zd->zstat == 1) STS_stat = 1; // user OK or cancel | if (zd->zstat == 1) STS_stat = 1; // user OK or cancel | |||
else STS_stat = 0; | else STS_stat = 0; | |||
return 1; | return 1; | |||
} | } | |||
skipping to change at line 2776 | skipping to change at line 2784 | |||
Fpaint3(px,0,cc,Ehh,0); // paint new exposed area | Fpaint3(px,0,cc,Ehh,0); // paint new exposed area | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// show the differences between two images | // show the differences between two images | |||
namespace imagediffs_names | namespace imagediffs_names | |||
{ | { | |||
char *imagefile1, *imagefile2; | ch *imagefile1, *imagefile2; | |||
PXB *pxb1, *pxb2, *pxbdiffs; | PXB *pxb1, *pxb2, *pxbdiffs; | |||
int xalign, yalign; | int xalign, yalign; | |||
} | } | |||
// menu function | // menu function | |||
void m_image_diffs(GtkWidget *, const char *menu) | void m_image_diffs(GtkWidget *, ch *menu) | |||
{ | { | |||
using namespace imagediffs_names; | using namespace imagediffs_names; | |||
int imagediffs_dialog_event(zdialog* zd, const char *event); | int imagediffs_dialog_event(zdialog* zd, ch *event); | |||
F1_help_topic = "image diffs"; | F1_help_topic = "image diffs"; | |||
Plog(1,"m_image_diffs \n"); | Plog(1,"m_image_diffs \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
imagefile1 = imagefile2 = 0; | imagefile1 = imagefile2 = 0; | |||
pxb1 = pxb2 = pxbdiffs = 0; | pxb1 = pxb2 = pxbdiffs = 0; | |||
skipping to change at line 2844 | skipping to change at line 2852 | |||
zdialog_add_widget(zd,"label","space","hbalign",0,"space=5"); | zdialog_add_widget(zd,"label","space","hbalign",0,"space=5"); | |||
zdialog_add_widget(zd,"label","labyalign","hbalign","Y-align","space=3"); | zdialog_add_widget(zd,"label","labyalign","hbalign","Y-align","space=3"); | |||
zdialog_add_widget(zd,"zspin","yalign","hbalign","-999|999|1|0","space=3"); | zdialog_add_widget(zd,"zspin","yalign","hbalign","-999|999|1|0","space=3"); | |||
zdialog_run(zd,imagediffs_dialog_event,"save"); // run dialog - parallel | zdialog_run(zd,imagediffs_dialog_event,"save"); // run dialog - parallel | |||
return; | return; | |||
} | } | |||
// imagediffs dialog event and completion function | // imagediffs dialog event and completion function | |||
int imagediffs_dialog_event(zdialog *zd, const char *event) | int imagediffs_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
using namespace imagediffs_names; | using namespace imagediffs_names; | |||
void imagediffs_thread(); | void imagediffs_thread(); | |||
int err; | int err; | |||
char *pp; | ch *pp; | |||
GError *gerror = 0; | GError *gerror = 0; | |||
char *outfile; | ch *outfile; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"done")) zd->zstat = 1; // from edit_setup() or f_save() | if (strmatch(event,"done")) zd->zstat = 1; // from edit_setup() or f_save() | |||
if (strmatch(event,"cancel")) zd->zstat = 2; // from f_open() | if (strmatch(event,"cancel")) zd->zstat = 2; // from f_open() | |||
if (zd->zstat) // done or cancel | if (zd->zstat) // done or cancel | |||
{ | { | |||
Fpxb = 0; | Fpxb = 0; | |||
if (zd->zstat == 1) { // done | if (zd->zstat == 1) { // done | |||
if (pxbdiffs) { | if (pxbdiffs) { | |||
skipping to change at line 2897 | skipping to change at line 2905 | |||
if (pxb1) PXB_free(pxb1); | if (pxb1) PXB_free(pxb1); | |||
if (pxb2) PXB_free(pxb2); | if (pxb2) PXB_free(pxb2); | |||
if (pxbdiffs) PXB_free(pxbdiffs); | if (pxbdiffs) PXB_free(pxbdiffs); | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return 1; | return 1; | |||
} | } | |||
if (strmatch(event,"select")) // select 2 input files | if (strmatch(event,"select")) // select 2 input files | |||
{ | { | |||
///gallery_select_clear(); // remove 22.40 | ||||
err = gallery_select(); // choose thumbnails | err = gallery_select(); // choose thumbnails | |||
if (err) return 1; | if (err) return 1; | |||
if (GScount != 2) { | if (GScount != 2) { | |||
zmessageACK(Mwin,"select exactly 2 files"); | zmessageACK(Mwin,"select exactly 2 files"); | |||
return 1; | return 1; | |||
} | } | |||
if (imagefile1) zfree(imagefile1); // get chosen files | if (imagefile1) zfree(imagefile1); // get chosen files | |||
imagefile1 = zstrdup(GSfiles[0],"cim image diffs"); | imagefile1 = zstrdup(GSfiles[0],"cim image diffs"); | |||
if (imagefile2) zfree(imagefile2); | if (imagefile2) zfree(imagefile2); | |||
skipping to change at line 3101 | skipping to change at line 3108 | |||
void pano_align(); // auto fine-align | void pano_align(); // auto fine-align | |||
void pano_adjust(); // user color adjust | void pano_adjust(); // user color adjust | |||
void panowarp_mousefunc(); // image warp mouse function | void panowarp_mousefunc(); // image warp mouse function | |||
void panowarp_dowarps(int imx); | void panowarp_dowarps(int imx); | |||
editfunc EFpano; // edit function data | editfunc EFpano; // edit function data | |||
// menu function | // menu function | |||
void m_pano_horz(GtkWidget *, cchar *menu) | void m_pano_horz(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "panorama"; | F1_help_topic = "panorama"; | |||
Plog(1,"m_pano_horz \n"); | Plog(1,"m_pano_horz \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 3136 | skipping to change at line 3143 | |||
EFpano.menufunc = m_pano_horz; | EFpano.menufunc = m_pano_horz; | |||
EFpano.menuname = "Panorama"; | EFpano.menuname = "Panorama"; | |||
EFpano.mousefunc = panowarp_mousefunc; | EFpano.mousefunc = panowarp_mousefunc; | |||
if (! edit_setup(EFpano)) goto cleanup; // setup edit (will lock) | if (! edit_setup(EFpano)) goto cleanup; // setup edit (will lock) | |||
cimShowAll = 1; // for cim_show_images(), show all | cimShowAll = 1; // for cim_show_images(), show all | |||
cimPano = 1; // horizontal pano mode | cimPano = 1; // horizontal pano mode | |||
cimPanoV = 0; | cimPanoV = 0; | |||
Fescape = 1; | Fwatchescape = 1; | |||
// killable with escape | // killable with escape | |||
Fescape = 0; | ||||
pano_prealign(); // manual pre-alignment | pano_prealign(); // manual pre-alignment | |||
if (panStat != 1) goto cancel; | if (panStat != 1) goto cancel; | |||
pano_align(); // auto full alignment | pano_align(); // auto full alignment | |||
if (panStat != 1) goto cancel; | if (panStat != 1) goto cancel; | |||
pano_adjust(); // manual color adjustment | pano_adjust(); // manual color adjustment | |||
if (panStat != 1) goto cancel; | if (panStat != 1) goto cancel; | |||
CEF->Fmods++; // done | CEF->Fmods++; // done | |||
CEF->Fsaved = 0; | CEF->Fsaved = 0; | |||
edit_done(0); | edit_done(0); | |||
goto cleanup; | goto cleanup; | |||
cancel: // failed or canceled | cancel: // failed or canceled | |||
edit_cancel(0); | edit_cancel(0); | |||
if (Fescape > 1) // user cancel | if (Fescape) // user cancel | |||
zmessage_post_bold(Mwin,"parent",3,"function canceled"); | zmessage_post_bold(Mwin,"parent",3,"function canceled"); | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
*paneltext = 0; | *paneltext = 0; | |||
Fescape = 0; | Fwatchescape = Fescape = 0; | |||
return; | return; | |||
} | } | |||
// perform manual pre-align of all images | // perform manual pre-align of all images | |||
// returns alignment data in cimOffs[*] | // returns alignment data in cimOffs[*] | |||
// lens_mm may also be altered | // lens_mm may also be altered | |||
void pano_prealign() | void pano_prealign() | |||
{ | { | |||
int pano_prealign_event(zdialog *zd, cchar *event); // dialog event function | int pano_prealign_event(zdialog *zd, ch *event); // dialog event function | |||
void pano_prealign_mousefunc(); | void pano_prealign_mousefunc(); | |||
int imx, ww, err = 0; | int imx, ww, err = 0; | |||
cchar *exifkey[2] = { exif_focal_length_35_key, exif_focal_length_key } | ch *metakey[2] = { meta_focal_length_35_key, meta_focal_length_key } | |||
; | ; | |||
char *pp[2] = { 0, 0 }; | ch *pp[2] = { 0, 0 }; | |||
cchar *lens_source; | ch *lens_source; | |||
float temp; | float temp; | |||
cchar *align_mess = "Drag images into rough alignment.\n" | ch *align_mess = "Drag images into rough alignment.\n" | |||
"To rotate, drag from lower edge."; | "To rotate, drag from lower edge."; | |||
cchar *scan_mess = "no curve (scanned image)"; | ch *scan_mess = "no curve (scanned image)"; | |||
cchar *search_mess = "Search for lens mm"; | ch *search_mess = "Search for lens mm"; | |||
cchar *save_mess = "Save lens mm → image EXIF"; | ch *save_mess = "Save lens mm → image metadata"; | |||
err = 1; | err = 1; | |||
lens_source = "NO EXIF"; | lens_source = "no metadata"; | |||
exif_get(curr_file,exifkey,pp,2); | meta_get1(curr_file,(ch **) metakey,pp,2); | |||
// get lens mm from EXIF if available | // get lens mm from metadata if available | |||
if (pp[0]) err = convSF(pp[0], temp, 20, 1000); // try both keys | if (pp[0]) err = convSF(pp[0], temp, 20, 1000); // try both keys | |||
else if (pp[1]) err = convSF(pp[1], temp, 20, 1000); | else if (pp[1]) err = convSF(pp[1], temp, 20, 1000); | |||
if (! err) { | if (! err) { | |||
lens_mm = temp; | lens_mm = temp; | |||
lens_source = "(EXIF)"; | lens_source = "(metadata)"; | |||
} | } | |||
for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 | for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 | |||
memset(&cimOffs[imx],0,sizeof(cimoffs)); | memset(&cimOffs[imx],0,sizeof(cimoffs)); | |||
for (imx = ww = 0; imx < cimNF; imx++) // sum image widths | for (imx = ww = 0; imx < cimNF; imx++) // sum image widths | |||
ww += cimPXMf[imx]->ww; | ww += cimPXMf[imx]->ww; | |||
cimScale = 1.4 * panPreAlignSize / ww; // set alignment image scale | cimScale = 1.4 * panPreAlignSize / ww; // set alignment image scale | |||
if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) | if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) | |||
skipping to change at line 3231 | skipping to change at line 3239 | |||
cimBlend = panPreAlignBlend * cimPXMw[1]->ww; // overlap in align window | cimBlend = panPreAlignBlend * cimPXMw[1]->ww; // overlap in align window | |||
cim_show_images(1,0); // combine and show images in main window | cim_show_images(1,0); // combine and show images in main window | |||
/* | /* | |||
_________________________________________ | _________________________________________ | |||
| Pre-align Images | | | Pre-align Images | | |||
| | | | | | |||
| Drag images into rough alignment. | | | Drag images into rough alignment. | | |||
| To rotate, drag from lower edge. | | | To rotate, drag from lower edge. | | |||
| | | | | | |||
| [ 35.5 ] lens mm (EXIF) | | | [ 35.5 ] lens mm (metadata) | | |||
| [x] no curve (scanned image) | | | [x] no curve (scanned image) | | |||
| [x] no auto warp | | | [x] no auto warp | | |||
| [x] manual align | | | [x] manual align | | |||
| [Resize] resize window | | | [Resize] resize window | | |||
| [Search] Search for lens mm | | | [Search] Search for lens mm | | |||
| [Save] Save lens mm -> image EXIF | | | [Save] Save lens mm -> image metadata | | |||
| | | | | | |||
| [Proceed] [Cancel] | | | [Proceed] [Cancel] | | |||
|_________________________________________| | |_________________________________________| | |||
*/ | */ | |||
panozd = zdialog_new("Pre-align Images",Mwin,"Proceed","Cancel",null); // start pre-align dialog | panozd = zdialog_new("Pre-align Images",Mwin,"Proceed","Cancel",null); // start pre-align dialog | |||
zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=3"); | zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=3"); | |||
zdialog_add_widget(panozd,"hbox","hb1","dialog",0); | zdialog_add_widget(panozd,"hbox","hb1","dialog",0); | |||
zdialog_add_widget(panozd,"zspin","spmm","hb1","20|999|0.1|35","space=5"); | zdialog_add_widget(panozd,"zspin","spmm","hb1","20|999|0.1|35","space=5"); | |||
skipping to change at line 3286 | skipping to change at line 3294 | |||
zdialog_run(panozd,pano_prealign_event,"save"); // start dialog | zdialog_run(panozd,pano_prealign_event,"save"); // start dialog | |||
takeMouse(pano_prealign_mousefunc,dragcursor); // connect mouse | takeMouse(pano_prealign_mousefunc,dragcursor); // connect mouse | |||
zdialog_wait(panozd); // wait for dialog completion | zdialog_wait(panozd); // wait for dialog completion | |||
zdialog_free(panozd); // free dialog | zdialog_free(panozd); // free dialog | |||
freeMouse(); | freeMouse(); | |||
return; | return; | |||
} | } | |||
// pre-align dialog event function | // pre-align dialog event function | |||
int pano_prealign_event(zdialog *zd, cchar *event) | int pano_prealign_event(zdialog *zd, ch *event) | |||
{ | { | |||
void pano_autolens(); | void pano_autolens(); | |||
int imx, fchange = 0; | int imx, fchange = 0; | |||
float overlap; | float overlap; | |||
cchar *exifkey[1] = { exif_focal_length_35_key }; | ch *metakey[1] = { meta_focal_length_35_key }; | |||
cchar *exifdata[1]; | ch *metadata[1]; | |||
char lensdata[8]; | ch lensdata[8]; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"spmm")) { | if (strmatch(event,"spmm")) { | |||
zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data | zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data | |||
fchange = 1; | fchange = 1; | |||
} | } | |||
if (strmatch(event,"nocurve")) { | if (strmatch(event,"nocurve")) { | |||
zdialog_fetch(zd,"nocurve",cimPanoNC); // get "no-curve" option | zdialog_fetch(zd,"nocurve",cimPanoNC); // get "no-curve" option | |||
skipping to change at line 3339 | skipping to change at line 3347 | |||
if (strmatch(event,"search")) { // search for optimal lens parms | if (strmatch(event,"search")) { // search for optimal lens parms | |||
if (cimNF != 2) zmessageACK(Mwin,"use two images only"); | if (cimNF != 2) zmessageACK(Mwin,"use two images only"); | |||
else pano_autolens(); | else pano_autolens(); | |||
return 1; | return 1; | |||
} | } | |||
if (strmatch(event,"save")) { // put lens data into dialog | if (strmatch(event,"save")) { // put lens data into dialog | |||
zdialog_stuff(zd,"spmm",lens_mm); | zdialog_stuff(zd,"spmm",lens_mm); | |||
snprintf(lensdata,8,"%d",int(lens_mm)); | snprintf(lensdata,8,"%d",int(lens_mm)); | |||
exifdata[0] = lensdata; | metadata[0] = lensdata; | |||
for (imx = 0; imx < cimNF; imx++) | for (imx = 0; imx < cimNF; imx++) | |||
// save lens mm in EXIF data | // save lens mm in metadata | |||
exif_put(cimFile[imx],exifkey,exifdata,1); | meta_put(cimFile[imx],(ch **) metakey,metadata,1); | |||
} | } | |||
if (zd->zstat) // dialog complete | if (zd->zstat) // dialog complete | |||
{ | { | |||
if (zd->zstat != 1) { // cancel or other | if (zd->zstat != 1) { // cancel or other | |||
panStat = 0; | panStat = 0; | |||
return 1; | return 1; | |||
} | } | |||
m_zoom(0,"fit"); // reset poss. user zoom-in | m_zoom(0,"fit"); // reset poss. user zoom-in | |||
skipping to change at line 3376 | skipping to change at line 3384 | |||
return 1; | return 1; | |||
} | } | |||
// pre-align mouse function | // pre-align mouse function | |||
// convert mouse and KB events into image movements | // convert mouse and KB events into image movements | |||
void pano_prealign_mousefunc() | void pano_prealign_mousefunc() | |||
{ | { | |||
cimoffs offstemp; | cimoffs offstemp; | |||
PXM *pxmtemp; | PXM *pxmtemp; | |||
char *ftemp; | ch *ftemp; | |||
static int im1, im2, imm, imx; | static int im1, im2, imm, imx; | |||
static int mx0, my0, mx, my; // mouse drag origin, position | static int mx0, my0, mx, my; // mouse drag origin, position | |||
static int xoff, yoff, lox, hix; | static int xoff, yoff, lox, hix; | |||
static int hh, rotate, midx; | static int hh, rotate, midx; | |||
int sepx, minsep = 9999; | int sepx, minsep = 9999; | |||
float dx, dy, t1, t2, dt; | float dx, dy, t1, t2, dt; | |||
cimBlend = 0; // full blend during pre-align | cimBlend = 0; // full blend during pre-align | |||
if (! Mxdrag && ! Mydrag) // no drag underway | if (! Mxdrag && ! Mydrag) // no drag underway | |||
skipping to change at line 3512 | skipping to change at line 3520 | |||
zmessageACK(Mwin,"Too little overlap, cannot align"); | zmessageACK(Mwin,"Too little overlap, cannot align"); | |||
return; | return; | |||
} | } | |||
if (cimNF != 2) { | if (cimNF != 2) { | |||
zmessageACK(Mwin,"use 2 images only"); | zmessageACK(Mwin,"use 2 images only"); | |||
return; | return; | |||
} | } | |||
zadd_locked(Ffuncbusy,+1); | zadd_locked(Ffuncbusy,+1); | |||
Fwatchescape = 1; | ||||
// killable with escape key | ||||
Fescape = 0; | ||||
cimSampSize = 5000; | cimSampSize = 5000; | |||
cimNsearch = 0; | cimNsearch = 0; | |||
mm_range = 0.1 * lens_mm; // set initial search ranges | mm_range = 0.1 * lens_mm; // set initial search ranges | |||
xf_range = 7; | xf_range = 7; | |||
yf_range = 7; | yf_range = 7; | |||
tf_range = 0.01; | tf_range = 0.01; | |||
xf_rfinal = 0.3; // final xf range - when to quit | xf_rfinal = 0.3; // final xf range - when to quit | |||
skipping to change at line 3576 | skipping to change at line 3586 | |||
if (cim_sigdiff(matchlev,matchB,0.00001) > 0) { | if (cim_sigdiff(matchlev,matchB,0.00001) > 0) { | |||
matchB = matchlev; // save new best fit | matchB = matchlev; // save new best fit | |||
lens_mmB = lens_mm; // alignment is better | lens_mmB = lens_mm; // alignment is better | |||
offsetsB = cimOffs[1]; | offsetsB = cimOffs[1]; | |||
cim_show_images(0,0); | cim_show_images(0,0); | |||
squeeze = 1; // keep same search range as long | squeeze = 1; // keep same search range as long | |||
break; // as improvements are found | break; // as improvements are found | |||
} | } | |||
if (panStat != -1) goto done; // user kill | if (panStat != -1) goto done; // user kill | |||
if (Fescape > 1) goto done; // escape key kill | if (Fescape) goto done; // escape key kill | |||
zmainloop(); | zmainloop(); | |||
} | } | |||
if (xf_range < xf_rfinal) goto done; // finished | if (xf_range < xf_rfinal) goto done; // finished | |||
snprintf(paneltext,200,"align: %d match: %.5f lens: %.1f", | snprintf(paneltext,200,"align: %d match: %.5f lens: %.1f", | |||
cimNsearch, matchB, lens_mmB); | cimNsearch, matchB, lens_mmB); | |||
mm_range = squeeze * mm_range; // reduce search range if no | mm_range = squeeze * mm_range; // reduce search range if no | |||
if (mm_range < 0.02 * lens_mmB) mm_range = 0.02 * lens_mmB; // improvements were found | if (mm_range < 0.02 * lens_mmB) mm_range = 0.02 * lens_mmB; // improvements were found | |||
xf_range = squeeze * xf_range; | xf_range = squeeze * xf_range; | |||
yf_range = squeeze * yf_range; | yf_range = squeeze * yf_range; | |||
tf_range = squeeze * tf_range; | tf_range = squeeze * tf_range; | |||
zmainloop(); | zmainloop(); | |||
} | } | |||
done: | done: | |||
Fescape = 0; // keep Fwatchescape | ||||
zfree(cimRedpix); | zfree(cimRedpix); | |||
cimRedpix = 0; | cimRedpix = 0; | |||
lens_mm = lens_mmB; // save best lens param found | lens_mm = lens_mmB; // save best lens param found | |||
cimSampSize = panSampSize; // restore | cimSampSize = panSampSize; // restore | |||
zadd_locked(Ffuncbusy,-1); | zadd_locked(Ffuncbusy,-1); | |||
cim_show_images(1,0); // images are left color-matched | cim_show_images(1,0); // images are left color-matched | |||
return; | return; | |||
} | } | |||
skipping to change at line 3729 | skipping to change at line 3740 | |||
goto fail; | goto fail; | |||
} | } | |||
if (cim_manualalign) cim_show_images(0,0); | if (cim_manualalign) cim_show_images(0,0); | |||
else { | else { | |||
cim_get_redpix(im1); // get high-contrast pixels | cim_get_redpix(im1); // get high-contrast pixels | |||
cim_show_images(0,0); // show with 50/50 blend in overlaps | cim_show_images(0,0); // show with 50/50 blend in overlaps | |||
cim_align_image(im1,im2); // search for best offsets and warps | cim_align_image(im1,im2); // search for best offsets and warps | |||
zfree(cimRedpix); // clear red pixels | zfree(cimRedpix); // clear red pixels | |||
cimRedpix = 0; | cimRedpix = 0; | |||
if (Fescape > 1) goto fail; // user kill | if (Fescape) goto fail; // user kill | |||
} | } | |||
dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets | dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets | |||
dy = cimOffs[im2].yf - offsets0.yf; | dy = cimOffs[im2].yf - offsets0.yf; | |||
dt = cimOffs[im2].tf - offsets0.tf; | dt = cimOffs[im2].tf - offsets0.tf; | |||
for (imx = im2+1; imx < cimNF; imx++) // propagate to following images | for (imx = im2+1; imx < cimNF; imx++) // propagate to following images | |||
{ | { | |||
cimOffs[imx].xf += dx; | cimOffs[imx].xf += dx; | |||
cimOffs[imx].yf += dy; | cimOffs[imx].yf += dy; | |||
skipping to change at line 3793 | skipping to change at line 3804 | |||
cimBlend = 1; // tiny blend (increase in adjust) | cimBlend = 1; // tiny blend (increase in adjust) | |||
zadd_locked(Ffuncbusy,-1); | zadd_locked(Ffuncbusy,-1); | |||
cim_show_images(0,0); | cim_show_images(0,0); | |||
return; | return; | |||
} | } | |||
// get user inputs for RGB changes and blend width, update cimPXMw[*] | // get user inputs for RGB changes and blend width, update cimPXMw[*] | |||
void pano_adjust() | void pano_adjust() | |||
{ | { | |||
int pano_adjust_event(zdialog *zd, cchar *event); // dialog event function | int pano_adjust_event(zdialog *zd, ch *event); // dialog event function | |||
cchar *adjusttitle = "Match Brightness and Color"; | ch *adjusttitle = "Match Brightness and Color"; | |||
char imageN[8] = "imageN"; | ch imageN[8] = "imageN"; | |||
int ww, hh, cc, imx; | int ww, hh, cc, imx; | |||
for (imx = 0; imx < cimNF; imx++) { // neutral color adjustments | for (imx = 0; imx < cimNF; imx++) { // neutral color adjustments | |||
pano_adjust_RGB[imx][0] = 100; | pano_adjust_RGB[imx][0] = 100; | |||
pano_adjust_RGB[imx][1] = 100; | pano_adjust_RGB[imx][1] = 100; | |||
pano_adjust_RGB[imx][2] = 100; | pano_adjust_RGB[imx][2] = 100; | |||
} | } | |||
for (imx = 0; imx < cimNF; imx++) { // allocate warp memory | for (imx = 0; imx < cimNF; imx++) { // allocate warp memory | |||
ww = cimPXMw[imx]->ww; | ww = cimPXMw[imx]->ww; | |||
skipping to change at line 3886 | skipping to change at line 3897 | |||
panStat = -1; // busy status | panStat = -1; // busy status | |||
zdialog_run(panozd,pano_adjust_event,"save"); // run dialog, parallel | zdialog_run(panozd,pano_adjust_event,"save"); // run dialog, parallel | |||
zdialog_wait(panozd); // wait for dialog completion | zdialog_wait(panozd); // wait for dialog completion | |||
zdialog_free(panozd); // free dialog | zdialog_free(panozd); // free dialog | |||
return; | return; | |||
} | } | |||
// dialog event function | // dialog event function | |||
int pano_adjust_event(zdialog *zd, cchar *event) | int pano_adjust_event(zdialog *zd, ch *event) | |||
{ | { | |||
char imageN[8] = "imageN"; | ch imageN[8] = "imageN"; | |||
float R, G, B, R1, G1, B1, F; | float R, G, B, R1, G1, B1, F; | |||
float max$; | float max$; | |||
int imS, imx, im1, im2; | int imS, imx, im1, im2; | |||
int ww, hh, px, py, nn; | int ww, hh, px, py, nn; | |||
float bright, bright2, *pixel; | float bright, bright2, *pixel; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) // dialog complete | if (zd->zstat) // dialog complete | |||
{ | { | |||
skipping to change at line 4211 | skipping to change at line 4222 | |||
******************************************************************************** */ | ******************************************************************************** */ | |||
void vpano_prealign(); // manual pre-align | void vpano_prealign(); // manual pre-align | |||
void vpano_align(); // auto fine-align | void vpano_align(); // auto fine-align | |||
void vpano_adjust(); // user color adjust | void vpano_adjust(); // user color adjust | |||
editfunc EFvpano; // edit function data | editfunc EFvpano; // edit function data | |||
// menu function | // menu function | |||
void m_pano_vert(GtkWidget *, cchar *menu) | void m_pano_vert(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "vert. panorama"; | F1_help_topic = "vert. panorama"; | |||
Plog(1,"m_pano_vert \n"); | Plog(1,"m_pano_vert \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
skipping to change at line 4246 | skipping to change at line 4257 | |||
EFvpano.menufunc = m_pano_vert; | EFvpano.menufunc = m_pano_vert; | |||
EFvpano.menuname = "V. Panorama"; | EFvpano.menuname = "V. Panorama"; | |||
EFvpano.mousefunc = panowarp_mousefunc; | EFvpano.mousefunc = panowarp_mousefunc; | |||
if (! edit_setup(EFvpano)) goto cleanup; // setup edit (will lock) | if (! edit_setup(EFvpano)) goto cleanup; // setup edit (will lock) | |||
cimShowAll = 1; // for cim_show_images(), show all | cimShowAll = 1; // for cim_show_images(), show all | |||
cimPano = 0; // vertical pano mode | cimPano = 0; // vertical pano mode | |||
cimPanoV = 1; | cimPanoV = 1; | |||
Fescape = 1; | Fwatchescape = 1; | |||
// killable with escape key | // killable with escape key | |||
Fescape = 0; | ||||
vpano_prealign(); // manual pre-alignment | vpano_prealign(); // manual pre-alignment | |||
if (panStat != 1) goto cancel; | if (panStat != 1) goto cancel; | |||
vpano_align(); // auto full alignment | vpano_align(); // auto full alignment | |||
if (panStat != 1) goto cancel; | if (panStat != 1) goto cancel; | |||
vpano_adjust(); // manual color adjustment | vpano_adjust(); // manual color adjustment | |||
if (panStat != 1) goto cancel; | if (panStat != 1) goto cancel; | |||
CEF->Fmods++; // done | CEF->Fmods++; // done | |||
CEF->Fsaved = 0; | CEF->Fsaved = 0; | |||
edit_done(0); | edit_done(0); | |||
goto cleanup; | goto cleanup; | |||
cancel: // failed or canceled | cancel: // failed or canceled | |||
edit_cancel(0); | edit_cancel(0); | |||
if (Fescape > 1) // user cancel | if (Fescape) // user cancel | |||
zmessage_post_bold(Mwin,"parent",3,"function canceled"); | zmessage_post_bold(Mwin,"parent",3,"function canceled"); | |||
cleanup: | cleanup: | |||
cim_free_memory(); // free memory for input files | cim_free_memory(); // free memory for input files | |||
*paneltext = 0; | *paneltext = 0; | |||
Fescape = 0; | Fwatchescape = Fescape = 0; | |||
return; | return; | |||
} | } | |||
// perform manual pre-align of all images | // perform manual pre-align of all images | |||
// returns alignment data in cimOffs[*] | // returns alignment data in cimOffs[*] | |||
// lens_mm may also be altered | // lens_mm may also be altered | |||
void vpano_prealign() | void vpano_prealign() | |||
{ | { | |||
int vpano_prealign_event(zdialog *zd, cchar *event); // dialog event function | int vpano_prealign_event(zdialog *zd, ch *event); // dialog event function | |||
void vpano_prealign_mousefunc(); | void vpano_prealign_mousefunc(); | |||
int imx, hh, err = 0; | int imx, hh, err = 0; | |||
cchar *exifkey[2] = { exif_focal_length_35_key, exif_focal_length_key } | ch *metakey[2] = { meta_focal_length_35_key, meta_focal_length_key } | |||
; | ; | |||
char *pp[2] = { 0, 0 }; | ch *pp[2] = { 0, 0 }; | |||
cchar *lens_source; | ch *lens_source; | |||
float temp; | float temp; | |||
cchar *align_mess = "Drag images into rough alignment.\n" | ch *align_mess = "Drag images into rough alignment.\n" | |||
"To rotate, drag from right edge."; | "To rotate, drag from right edge."; | |||
cchar *scan_mess = "no curve (scanned image)"; | ch *scan_mess = "no curve (scanned image)"; | |||
cchar *search_mess = "Search for lens mm"; | ch *search_mess = "Search for lens mm"; | |||
cchar *save_mess = "Save lens mm → image EXIF"; | ch *save_mess = "Save lens mm → image metadata"; | |||
err = 1; | err = 1; | |||
lens_source = "NO EXIF"; | lens_source = "no metadata"; | |||
exif_get(curr_file,exifkey,pp,2); | meta_get1(curr_file,(ch **) metakey,pp,2); | |||
// get lens mm from EXIF if available | // get lens mm from metadata if available | |||
if (pp[0]) err = convSF(pp[0], temp, 20, 1000); // try both keys | if (pp[0]) err = convSF(pp[0], temp, 20, 1000); // try both keys | |||
else if (pp[1]) err = convSF(pp[1], temp, 20, 1000); | else if (pp[1]) err = convSF(pp[1], temp, 20, 1000); | |||
if (! err) { | if (! err) { | |||
lens_mm = temp; | lens_mm = temp; | |||
lens_source = "(EXIF)"; | lens_source = "(metadata)"; | |||
} | } | |||
for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 | for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 | |||
memset(&cimOffs[imx],0,sizeof(cimoffs)); | memset(&cimOffs[imx],0,sizeof(cimoffs)); | |||
for (imx = hh = 0; imx < cimNF; imx++) // sum image heights | for (imx = hh = 0; imx < cimNF; imx++) // sum image heights | |||
hh += cimPXMf[imx]->hh; | hh += cimPXMf[imx]->hh; | |||
cimScale = 1.4 * panPreAlignSize / hh; // set alignment image scale | cimScale = 1.4 * panPreAlignSize / hh; // set alignment image scale | |||
if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) | if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) | |||
skipping to change at line 4341 | skipping to change at line 4353 | |||
cimBlend = panPreAlignBlend * cimPXMw[1]->hh; // overlap in align window | cimBlend = panPreAlignBlend * cimPXMw[1]->hh; // overlap in align window | |||
cim_show_Vimages(1,0); // combine and show images in main window | cim_show_Vimages(1,0); // combine and show images in main window | |||
/* | /* | |||
_________________________________________ | _________________________________________ | |||
| Pre-align Images | | | Pre-align Images | | |||
| | | | | | |||
| Drag images into rough alignment. | | | Drag images into rough alignment. | | |||
| To rotate, drag from right edge. | | | To rotate, drag from right edge. | | |||
| | | | | | |||
| [ 35.5 ] lens mm (EXIF) | | | [ 35.5 ] lens mm (metadata) | | |||
| [x] no curve (scanned image) | | | [x] no curve (scanned image) | | |||
| [x] no auto warp | | | [x] no auto warp | | |||
| [x] manual align | | | [x] manual align | | |||
| [Resize] resize window | | | [Resize] resize window | | |||
| [Search] Search for lens mm | | | [Search] Search for lens mm | | |||
| [Save] Save lens mm -> image EXIF | | | [Save] Save lens mm -> image metadata | | |||
| | | | | | |||
| [Proceed] [Cancel] | | | [Proceed] [Cancel] | | |||
|_________________________________________| | |_________________________________________| | |||
*/ | */ | |||
panozd = zdialog_new("Pre-align Images",Mwin,"Proceed","Cancel",null); // start pre-align dialog | panozd = zdialog_new("Pre-align Images",Mwin,"Proceed","Cancel",null); // start pre-align dialog | |||
zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=3"); | zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=3"); | |||
zdialog_add_widget(panozd,"hbox","hb1","dialog",0); | zdialog_add_widget(panozd,"hbox","hb1","dialog",0); | |||
zdialog_add_widget(panozd,"zspin","spmm","hb1","20|999|0.1|35","space=5"); | zdialog_add_widget(panozd,"zspin","spmm","hb1","20|999|0.1|35","space=5"); | |||
skipping to change at line 4396 | skipping to change at line 4408 | |||
zdialog_run(panozd,vpano_prealign_event,"save"); // start dialog | zdialog_run(panozd,vpano_prealign_event,"save"); // start dialog | |||
takeMouse(vpano_prealign_mousefunc,dragcursor); // connect mouse | takeMouse(vpano_prealign_mousefunc,dragcursor); // connect mouse | |||
zdialog_wait(panozd); // wait for dialog completion | zdialog_wait(panozd); // wait for dialog completion | |||
zdialog_free(panozd); // free dialog | zdialog_free(panozd); // free dialog | |||
freeMouse(); | freeMouse(); | |||
return; | return; | |||
} | } | |||
// pre-align dialog event function | // pre-align dialog event function | |||
int vpano_prealign_event(zdialog *zd, cchar *event) | int vpano_prealign_event(zdialog *zd, ch *event) | |||
{ | { | |||
void vpano_autolens(); | void vpano_autolens(); | |||
int imx, fchange = 0; | int imx, fchange = 0; | |||
float overlap; | float overlap; | |||
cchar *exifkey[1] = { exif_focal_length_35_key }; | ch *metakey[1] = { meta_focal_length_35_key }; | |||
cchar *exifdata[1]; | ch *metadata[1]; | |||
char lensdata[8]; | ch lensdata[8]; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"spmm")) { | if (strmatch(event,"spmm")) { | |||
zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data | zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data | |||
fchange = 1; | fchange = 1; | |||
} | } | |||
if (strmatch(event,"nocurve")) { | if (strmatch(event,"nocurve")) { | |||
zdialog_fetch(zd,"nocurve",cimPanoNC); // get "no-curve" option | zdialog_fetch(zd,"nocurve",cimPanoNC); // get "no-curve" option | |||
skipping to change at line 4449 | skipping to change at line 4461 | |||
if (strmatch(event,"search")) { // search for optimal lens parms | if (strmatch(event,"search")) { // search for optimal lens parms | |||
if (cimNF != 2) zmessageACK(Mwin,"use two images only"); | if (cimNF != 2) zmessageACK(Mwin,"use two images only"); | |||
else vpano_autolens(); | else vpano_autolens(); | |||
return 1; | return 1; | |||
} | } | |||
if (strmatch(event,"save")) { // put lens data into dialog | if (strmatch(event,"save")) { // put lens data into dialog | |||
zdialog_stuff(zd,"spmm",lens_mm); | zdialog_stuff(zd,"spmm",lens_mm); | |||
snprintf(lensdata,8,"%d",int(lens_mm)); | snprintf(lensdata,8,"%d",int(lens_mm)); | |||
exifdata[0] = lensdata; | metadata[0] = lensdata; | |||
for (imx = 0; imx < cimNF; imx++) | for (imx = 0; imx < cimNF; imx++) | |||
// save lens mm in EXIF data | // save lens mm in metadata | |||
exif_put(cimFile[imx],exifkey,exifdata,1); | meta_put(cimFile[imx],(ch **) metakey,metadata,1); | |||
} | } | |||
if (zd->zstat) // dialog complete | if (zd->zstat) // dialog complete | |||
{ | { | |||
if (zd->zstat != 1) { // cancel or other | if (zd->zstat != 1) { // cancel or other | |||
panStat = 0; | panStat = 0; | |||
return 1; | return 1; | |||
} | } | |||
m_zoom(0,"fit"); // reset poss. user zoom-in | m_zoom(0,"fit"); // reset poss. user zoom-in | |||
skipping to change at line 4486 | skipping to change at line 4498 | |||
return 1; | return 1; | |||
} | } | |||
// pre-align mouse function | // pre-align mouse function | |||
// convert mouse and KB events into image movements | // convert mouse and KB events into image movements | |||
void vpano_prealign_mousefunc() | void vpano_prealign_mousefunc() | |||
{ | { | |||
cimoffs offstemp; | cimoffs offstemp; | |||
PXM *pxmtemp; | PXM *pxmtemp; | |||
char *ftemp; | ch *ftemp; | |||
static int im1, im2, imm, imx; | static int im1, im2, imm, imx; | |||
static int mx0, my0, mx, my; // mouse drag origin, position | static int mx0, my0, mx, my; // mouse drag origin, position | |||
static int xoff, yoff, loy, hiy; | static int xoff, yoff, loy, hiy; | |||
static int ww, rotate, midy; | static int ww, rotate, midy; | |||
int sepy, minsep = 9999; | int sepy, minsep = 9999; | |||
float dx, dy, t1, t2, dt; | float dx, dy, t1, t2, dt; | |||
cimBlend = 0; // full blend during pre-align | cimBlend = 0; // full blend during pre-align | |||
if (! Mxdrag && ! Mydrag) // no drag underway | if (! Mxdrag && ! Mydrag) // no drag underway | |||
skipping to change at line 4622 | skipping to change at line 4634 | |||
zmessageACK(Mwin,"Too little overlap, cannot align"); | zmessageACK(Mwin,"Too little overlap, cannot align"); | |||
return; | return; | |||
} | } | |||
if (cimNF != 2) { | if (cimNF != 2) { | |||
zmessageACK(Mwin,"use 2 images only"); | zmessageACK(Mwin,"use 2 images only"); | |||
return; | return; | |||
} | } | |||
zadd_locked(Ffuncbusy,+1); | zadd_locked(Ffuncbusy,+1); | |||
Fwatchescape = 1; | ||||
Fescape = 0; | ||||
cimSampSize = 5000; | cimSampSize = 5000; | |||
cimNsearch = 0; | cimNsearch = 0; | |||
mm_range = 0.1 * lens_mm; // set initial search ranges | mm_range = 0.1 * lens_mm; // set initial search ranges | |||
xf_range = 7; | xf_range = 7; | |||
yf_range = 7; | yf_range = 7; | |||
tf_range = 0.01; | tf_range = 0.01; | |||
xf_rfinal = 0.3; // final xf range - when to quit | xf_rfinal = 0.3; // final xf range - when to quit | |||
skipping to change at line 4686 | skipping to change at line 4700 | |||
if (cim_sigdiff(matchlev,matchB,0.00001) > 0) { | if (cim_sigdiff(matchlev,matchB,0.00001) > 0) { | |||
matchB = matchlev; // save new best fit | matchB = matchlev; // save new best fit | |||
lens_mmB = lens_mm; // alignment is better | lens_mmB = lens_mm; // alignment is better | |||
offsetsB = cimOffs[1]; | offsetsB = cimOffs[1]; | |||
cim_show_Vimages(0,0); | cim_show_Vimages(0,0); | |||
squeeze = 1; // keep same search range as long | squeeze = 1; // keep same search range as long | |||
break; // as improvements are found | break; // as improvements are found | |||
} | } | |||
if (panStat != -1) goto done; // user kill | if (panStat != -1) goto done; // user kill | |||
if (Fescape > 1) goto done; // kill via escape key | if (Fescape) goto done; // kill via escape key | |||
zmainloop(); | zmainloop(); | |||
} | } | |||
if (xf_range < xf_rfinal) goto done; // finished | if (xf_range < xf_rfinal) goto done; // finished | |||
snprintf(paneltext,200,"align: %d match: %.5f lens: %.1f", | snprintf(paneltext,200,"align: %d match: %.5f lens: %.1f", | |||
cimNsearch, matchB, lens_mmB); | cimNsearch, matchB, lens_mmB); | |||
mm_range = squeeze * mm_range; // reduce search range if no | mm_range = squeeze * mm_range; // reduce search range if no | |||
if (mm_range < 0.02 * lens_mmB) mm_range = 0.02 * lens_mmB; // improvements were found | if (mm_range < 0.02 * lens_mmB) mm_range = 0.02 * lens_mmB; // improvements were found | |||
xf_range = squeeze * xf_range; | xf_range = squeeze * xf_range; | |||
yf_range = squeeze * yf_range; | yf_range = squeeze * yf_range; | |||
tf_range = squeeze * tf_range; | tf_range = squeeze * tf_range; | |||
zmainloop(); | zmainloop(); | |||
} | } | |||
done: | done: | |||
Fescape = 0; // keep Fwatchchescape | ||||
zfree(cimRedpix); | zfree(cimRedpix); | |||
cimRedpix = 0; | cimRedpix = 0; | |||
lens_mm = lens_mmB; // save best lens params found | lens_mm = lens_mmB; // save best lens params found | |||
cimSampSize = panSampSize; // restore | cimSampSize = panSampSize; // restore | |||
zadd_locked(Ffuncbusy,-1); | zadd_locked(Ffuncbusy,-1); | |||
cim_show_Vimages(1,0); // images are left color-matched | cim_show_Vimages(1,0); // images are left color-matched | |||
return; | return; | |||
} | } | |||
skipping to change at line 4816 | skipping to change at line 4831 | |||
goto fail; | goto fail; | |||
} | } | |||
if (cim_manualalign) cim_show_Vimages(0,0); | if (cim_manualalign) cim_show_Vimages(0,0); | |||
else { | else { | |||
cim_get_redpix(im1); // get high-contrast pixels | cim_get_redpix(im1); // get high-contrast pixels | |||
cim_show_Vimages(0,0); // show with 50/50 blend in overlaps | cim_show_Vimages(0,0); // show with 50/50 blend in overlaps | |||
cim_align_image(im1,im2); // search for best offsets and warps | cim_align_image(im1,im2); // search for best offsets and warps | |||
zfree(cimRedpix); // clear red pixels | zfree(cimRedpix); // clear red pixels | |||
cimRedpix = 0; | cimRedpix = 0; | |||
if (Fescape > 1) goto fail; // user kill | if (Fescape) goto fail; // user kill | |||
} | } | |||
dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets | dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets | |||
dy = cimOffs[im2].yf - offsets0.yf; | dy = cimOffs[im2].yf - offsets0.yf; | |||
dt = cimOffs[im2].tf - offsets0.tf; | dt = cimOffs[im2].tf - offsets0.tf; | |||
for (imx = im2+1; imx < cimNF; imx++) // propagate to following images | for (imx = im2+1; imx < cimNF; imx++) // propagate to following images | |||
{ | { | |||
cimOffs[imx].xf += dx; | cimOffs[imx].xf += dx; | |||
cimOffs[imx].yf += dy; | cimOffs[imx].yf += dy; | |||
skipping to change at line 4880 | skipping to change at line 4895 | |||
zadd_locked(Ffuncbusy,-1); | zadd_locked(Ffuncbusy,-1); | |||
cimBlend = 1; // tiny blend (increase in adjust if wanted) | cimBlend = 1; // tiny blend (increase in adjust if wanted) | |||
cim_show_Vimages(0,0); | cim_show_Vimages(0,0); | |||
return; | return; | |||
} | } | |||
// get user inputs for RGB changes and blend width, update cimPXMw[*] | // get user inputs for RGB changes and blend width, update cimPXMw[*] | |||
void vpano_adjust() | void vpano_adjust() | |||
{ | { | |||
int vpano_adjust_event(zdialog *zd, cchar *event); // dialog event function | int vpano_adjust_event(zdialog *zd, ch *event); // dialog event function | |||
cchar *adjusttitle = "Match Brightness and Color"; | ch *adjusttitle = "Match Brightness and Color"; | |||
char imageN[8] = "imageN"; | ch imageN[8] = "imageN"; | |||
int ww, hh, cc, imx; | int ww, hh, cc, imx; | |||
for (imx = 0; imx < cimNF; imx++) { // neutral color adjustments | for (imx = 0; imx < cimNF; imx++) { // neutral color adjustments | |||
pano_adjust_RGB[imx][0] = 100; | pano_adjust_RGB[imx][0] = 100; | |||
pano_adjust_RGB[imx][1] = 100; | pano_adjust_RGB[imx][1] = 100; | |||
pano_adjust_RGB[imx][2] = 100; | pano_adjust_RGB[imx][2] = 100; | |||
} | } | |||
for (imx = 0; imx < cimNF; imx++) { // allocate warp memory | for (imx = 0; imx < cimNF; imx++) { // allocate warp memory | |||
ww = cimPXMw[imx]->ww; | ww = cimPXMw[imx]->ww; | |||
skipping to change at line 4973 | skipping to change at line 4988 | |||
panStat = -1; // busy status | panStat = -1; // busy status | |||
zdialog_run(panozd,vpano_adjust_event,"save"); // run dialog, parallel | zdialog_run(panozd,vpano_adjust_event,"save"); // run dialog, parallel | |||
zdialog_wait(panozd); // wait for dialog completion | zdialog_wait(panozd); // wait for dialog completion | |||
zdialog_free(panozd); // free dialog | zdialog_free(panozd); // free dialog | |||
return; | return; | |||
} | } | |||
// dialog event function | // dialog event function | |||
int vpano_adjust_event(zdialog *zd, cchar *event) | int vpano_adjust_event(zdialog *zd, ch *event) | |||
{ | { | |||
char imageN[8] = "imageN"; | ch imageN[8] = "imageN"; | |||
float R, G, B, R1, G1, B1, F; | float R, G, B, R1, G1, B1, F; | |||
float max$; | float max$; | |||
int imS, imx, im1, im2; | int imS, imx, im1, im2; | |||
int ww, hh, px, py, nn; | int ww, hh, px, py, nn; | |||
float bright, bright2, *pixel; | float bright, bright2, *pixel; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) // dialog complete | if (zd->zstat) // dialog complete | |||
{ | { | |||
skipping to change at line 5193 | skipping to change at line 5208 | |||
Fpaint2(); | Fpaint2(); | |||
} | } | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// show files selected for present or last combine edit function | // show files selected for present or last combine edit function | |||
void m_cim_show_files(GtkWidget *, cchar *) | void m_cim_show_files(GtkWidget *, ch *) | |||
{ | { | |||
F1_help_topic = "show CIM files"; | F1_help_topic = "show CIM files"; | |||
zdialog *zd; | zdialog *zd; | |||
if (! cimNF) { | if (! cimNF) { | |||
zmessageACK(Mwin,"no input files available"); | zmessageACK(Mwin,"no input files available"); | |||
return; | return; | |||
} | } | |||
skipping to change at line 5229 | skipping to change at line 5244 | |||
int im; | int im; | |||
cimNF = 0; | cimNF = 0; | |||
for (im = 0; im < 10; im++) // clear previous file list | for (im = 0; im < 10; im++) // clear previous file list | |||
{ | { | |||
if (cimFile[im]) zfree(cimFile[im]); | if (cimFile[im]) zfree(cimFile[im]); | |||
cimFile[im] = 0; | cimFile[im] = 0; | |||
} | } | |||
///gallery_select_clear(); // clear selected file list remove 22.40 | ||||
gallery_select(); // get new list | gallery_select(); // get new list | |||
if (GScount == 0) return 0; | if (GScount == 0) return 0; | |||
if (GScount < min || GScount > max) { | if (GScount < min || GScount > max) { | |||
zmessageACK(Mwin,"Select %d to %d files",min,max); | zmessageACK(Mwin,"Select %d to %d files",min,max); | |||
return 0; | return 0; | |||
} | } | |||
cimNF = GScount; // file count | cimNF = GScount; // file count | |||
skipping to change at line 5786 | skipping to change at line 5800 | |||
// flag high-contrast pixels to use in each image compare region | // flag high-contrast pixels to use in each image compare region | |||
void cim_get_redpix(int im1) | void cim_get_redpix(int im1) | |||
{ | { | |||
int ww, hh, samp, xzone, yzone; | int ww, hh, samp, xzone, yzone; | |||
int pxL, pxH, pyL, pyH; | int pxL, pxH, pyL, pyH; | |||
int px, py, ii, jj, npix; | int px, py, ii, jj, npix; | |||
int ov1xlo, ov1xhi, ov1ylo, ov1yhi; | int ov1xlo, ov1xhi, ov1ylo, ov1yhi; | |||
int Hdist[256], Vdist[256], Hmin, Vmin; | int Hdist[256], Vdist[256], Hmin, Vmin; | |||
float zsamp[16] = { 5,5,5,5, 7,8,8,7, 7,8,8,7, 5,5,5,5 }; // % sample per zone, sum = 100 | float zsamp[16] = { 5,5,5,5, 7,8,8,7, 7,8,8,7, 5,5,5,5 }; // % sample per zone, sum = 100 | |||
uchar *Hcon, *Vcon; | uch *Hcon, *Vcon; | |||
float *pix1, *pix2; | float *pix1, *pix2; | |||
PXM *pxm; | PXM *pxm; | |||
pxm = cimPXMs[im1]; | pxm = cimPXMs[im1]; | |||
ww = pxm->ww; | ww = pxm->ww; | |||
hh = pxm->hh; | hh = pxm->hh; | |||
if (cimRedpix) zfree(cimRedpix); // clear prior | if (cimRedpix) zfree(cimRedpix); // clear prior | |||
cimRedpix = (char *) zmalloc(ww*hh,"cim redpix"); | cimRedpix = (ch *) zmalloc(ww*hh,"cim redpix"); | |||
cimRedImage = im1; // image with red pixels | cimRedImage = im1; // image with red pixels | |||
ov1xlo = cimOv1xlo + cimSearchRange; // stay within x/y search range | ov1xlo = cimOv1xlo + cimSearchRange; // stay within x/y search range | |||
ov1xhi = cimOv1xhi - cimSearchRange; // so that red pixels persist | ov1xhi = cimOv1xhi - cimSearchRange; // so that red pixels persist | |||
ov1ylo = cimOv1ylo + cimSearchRange; // over offset changes | ov1ylo = cimOv1ylo + cimSearchRange; // over offset changes | |||
ov1yhi = cimOv1yhi - cimSearchRange; | ov1yhi = cimOv1yhi - cimSearchRange; | |||
for (yzone = 0; yzone < 4; yzone++) // loop 16 zones | for (yzone = 0; yzone < 4; yzone++) // loop 16 zones | |||
for (xzone = 0; xzone < 4; xzone++) | for (xzone = 0; xzone < 4; xzone++) | |||
{ | { | |||
pxL = ov1xlo + 0.25 * xzone * (ov1xhi - ov1xlo); // px and py zone limits | pxL = ov1xlo + 0.25 * xzone * (ov1xhi - ov1xlo); // px and py zone limits | |||
pxH = ov1xlo + 0.25 * (xzone+1) * (ov1xhi - ov1xlo); | pxH = ov1xlo + 0.25 * (xzone+1) * (ov1xhi - ov1xlo); | |||
pyL = ov1ylo + 0.25 * yzone * (ov1yhi - ov1ylo); | pyL = ov1ylo + 0.25 * yzone * (ov1yhi - ov1ylo); | |||
pyH = ov1ylo + 0.25 * (yzone+1) * (ov1yhi - ov1ylo); | pyH = ov1ylo + 0.25 * (yzone+1) * (ov1yhi - ov1ylo); | |||
npix = (pxH - pxL) * (pyH - pyL); // zone pixels | npix = (pxH - pxL) * (pyH - pyL); // zone pixels | |||
if (npix < 1) continue; | if (npix < 1) continue; | |||
Hcon = (uchar *) zmalloc(npix,"cim redpix"); | Hcon = (uch *) zmalloc(npix,"cim redpix"); | |||
// horizontal pixel contrast 0-255 | // horizontal pixel contrast 0-255 | |||
Vcon = (uchar *) zmalloc(npix,"cim redpix"); | Vcon = (uch *) zmalloc(npix,"cim redpix"); | |||
// vertical pixel contrast 0-255 | // vertical pixel contrast 0-255 | |||
ii = 4 * yzone + xzone; | ii = 4 * yzone + xzone; | |||
samp = cimSampSize * 0.01 * zsamp[ii]; // sample size for zone | samp = cimSampSize * 0.01 * zsamp[ii]; // sample size for zone | |||
if (samp > 0.1 * npix) samp = 0.1 * npix; // limit to 10% of zone pixels | if (samp > 0.1 * npix) samp = 0.1 * npix; // limit to 10% of zone pixels | |||
if (samp > 500) samp = 500; | if (samp > 500) samp = 500; | |||
for (py = pyL; py < pyH; py++) // scan image pixels in zone | for (py = pyL; py < pyH; py++) // scan image pixels in zone | |||
for (px = pxL; px < pxH; px++) | for (px = pxL; px < pxH; px++) | |||
{ | { | |||
ii = (py-pyL) * (pxH-pxL) + (px-pxL); | ii = (py-pyL) * (pxH-pxL) + (px-pxL); | |||
skipping to change at line 6336 | skipping to change at line 6350 | |||
match = cim_match_images(im1,im2); // get match level | match = cim_match_images(im1,im2); // get match level | |||
if (cim_sigdiff(match,matchB,0.00001) > 0) { | if (cim_sigdiff(match,matchB,0.00001) > 0) { | |||
matchB = match; // save best match | matchB = match; // save best match | |||
offsetsB = cimOffs[im2]; | offsetsB = cimOffs[im2]; | |||
} | } | |||
snprintf(paneltext,200,"align: %d match: %.5f",cimNsearch++,matchB); | snprintf(paneltext,200,"align: %d match: %.5f",cimNsearch++,matchB); | |||
zmainloop(); | zmainloop(); | |||
if (Fescape > 1) return; // user kill | if (Fescape) return; // user kill | |||
} | } | |||
cimOffs[im2] = offsetsB; // restore best match | cimOffs[im2] = offsetsB; // restore best match | |||
if (cim_manualwarp) continue; // skip auto warp | if (cim_manualwarp) continue; // skip auto warp | |||
// warp corners and search for best match | // warp corners and search for best match | |||
wrange = cimWarpRange; // corner warp range and step | wrange = cimWarpRange; // corner warp range and step | |||
wstep = cimWarpStep; | wstep = cimWarpStep; | |||
skipping to change at line 6392 | skipping to change at line 6406 | |||
match = cim_match_images(im1,im2); // get match level | match = cim_match_images(im1,im2); // get match level | |||
if (cim_sigdiff(match,matchB,0.00001) > 0) { | if (cim_sigdiff(match,matchB,0.00001) > 0) { | |||
matchB = match; // save best match | matchB = match; // save best match | |||
offsetsB = cimOffs[im2]; | offsetsB = cimOffs[im2]; | |||
} | } | |||
snprintf(paneltext,200,"warp: %d match: %.5f",cimNsearch++,matchB); | snprintf(paneltext,200,"warp: %d match: %.5f",cimNsearch++,matchB); | |||
zmainloop(); | zmainloop(); | |||
if (Fescape > 1) return; // user kill | if (Fescape) return; // user kill | |||
} | } | |||
cimOffs[im2] = offsetsB; // restore best match | cimOffs[im2] = offsetsB; // restore best match | |||
if (cimPano) cim_warp_image_pano(im2,1); // apply corner warps | if (cimPano) cim_warp_image_pano(im2,1); // apply corner warps | |||
else if (cimPanoV) cim_warp_image_Vpano(im2,1); | else if (cimPanoV) cim_warp_image_Vpano(im2,1); | |||
else cim_warp_image(im2); | else cim_warp_image(im2); | |||
} | } | |||
} | } | |||
skipping to change at line 7172 | skipping to change at line 7186 | |||
} | } | |||
PXM_free(E3pxm); // replace input with output PXM | PXM_free(E3pxm); // replace input with output PXM | |||
E3pxm = pxmout; | E3pxm = pxmout; | |||
return; | return; | |||
} | } | |||
// dump offsets to stdout - diagnostic tool | // dump offsets to stdout - diagnostic tool | |||
void cim_dump_offsets(cchar *label) | void cim_dump_offsets(ch *label) | |||
{ | { | |||
Plog(1,"\n offsets: %s \n",label); | Plog(1,"\n offsets: %s \n",label); | |||
for (int imx = 0; imx < cimNF; imx++) | for (int imx = 0; imx < cimNF; imx++) | |||
{ | { | |||
Plog(1," imx %d x/y/t: %.1f %.1f %.4f w0: %.1f %.1f w1: %.1f %.1f w2: %.1f %.1f w3: %.1f %.1f \n", | Plog(1," imx %d x/y/t: %.1f %.1f %.4f w0: %.1f %.1f w1: %.1f %.1f w2: %.1f %.1f w3: %.1f %.1f \n", | |||
imx, cimOffs[imx].xf, cimOffs[imx].yf, cimOffs[imx].tf, | imx, cimOffs[imx].xf, cimOffs[imx].yf, cimOffs[imx].tf, | |||
cimOffs[imx].wx[0], cimOffs[imx].wy[0], cimOffs[imx].wx[1], cimOf fs[imx].wy[1], | cimOffs[imx].wx[0], cimOffs[imx].wy[0], cimOffs[imx].wx[1], cimOf fs[imx].wy[1], | |||
cimOffs[imx].wx[2], cimOffs[imx].wy[2], cimOffs[imx].wx[3], cimOf fs[imx].wy[3]); | cimOffs[imx].wx[2], cimOffs[imx].wy[2], cimOffs[imx].wx[3], cimOf fs[imx].wy[3]); | |||
} | } | |||
End of changes. 109 change blocks. | ||||
140 lines changed or deleted | 155 lines changed or added |