Changeset 28998
- Timestamp:
- Aug 20, 2010, 11:47:48 AM (16 years ago)
- Location:
- trunk/psLib
- Files:
-
- 8 edited
- 3 copied
-
src/fft/psImageFFT.c (modified) (1 diff)
-
src/fft/psImageFFT.h (modified) (2 diffs)
-
src/jpeg/psImageJpeg.c (modified) (2 diffs)
-
src/math/psMinimizeLMM.c (modified) (9 diffs)
-
src/math/psMinimizeLMM.h (modified) (3 diffs)
-
src/math/psMinimizePowell.c (modified) (4 diffs)
-
src/math/psStats.c (modified) (1 diff)
-
test/math/Makefile.am (modified) (1 diff)
-
test/math/data/polyMD.dat (copied) (copied from branches/eam_branches/ipp-20100621/psLib/test/math/data/polyMD.dat )
-
test/math/data/polyMD.pro (copied) (copied from branches/eam_branches/ipp-20100621/psLib/test/math/data/polyMD.pro )
-
test/math/tap_psPolynomialMD_sampleDark.c (copied) (copied from branches/eam_branches/ipp-20100621/psLib/test/math/tap_psPolynomialMD_sampleDark.c )
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/fft/psImageFFT.c
r21183 r28998 532 532 return out; 533 533 } 534 535 void psKernelFFTFree(psKernelFFT *kernel) { 536 537 if (!kernel->fft) return; 538 539 bool threaded = psThreadPoolSize(); // Are we running threaded? 540 541 FFTW_LOCK; 542 fftwf_free(kernel->fft); 543 FFTW_UNLOCK; 544 545 return; 546 } 547 548 psKernelFFT *psKernelFFTAlloc(const psKernel *input) { 549 550 psKernelFFT *kernel = psAlloc(sizeof(psKernelFFT)); 551 psMemSetDeallocator(kernel, (psFreeFunc)psKernelFFTFree); 552 553 kernel->fft = NULL; 554 555 kernel->xMin = input->xMin; 556 kernel->xMax = input->xMax; 557 kernel->yMin = input->yMin; 558 kernel->yMax = input->yMax; 559 560 kernel->paddedCols = 0; 561 kernel->paddedRows = 0; 562 563 return kernel; 564 } 565 566 // generate the FFTed kernel image appropriate to be used for convolution of the given input image 567 psKernelFFT *psImageConvolveKernelInit(const psImage *in, const psKernel *kernel) 568 { 569 PS_ASSERT_IMAGE_NON_NULL(in, NULL); 570 PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL); 571 PS_ASSERT_KERNEL_NON_NULL(kernel, NULL); 572 573 bool threaded = psThreadPoolSize(); // Are we running threaded? 574 575 int numCols = in->numCols, numRows = in->numRows; // Size of image 576 int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Kernel sizes 577 578 // Need to pad the kernel (and later the input image) to protect from wrap-around effects 579 if (xMax - xMin > numCols || yMax - yMin > numRows) { 580 // Cannot pad the image if the kernel is larger. 581 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 582 _("Kernel cannot extend further than input image size (%dx%d vs %dx%d)."), 583 xMax, yMax, numCols, numRows); 584 return NULL; 585 } 586 587 int paddedCols = numCols + PS_MAX(-xMin, xMax); // Number of columns in padded image 588 int paddedRows = numRows + PS_MAX(-yMin, yMax); // Number of rows in padded image 589 590 #if CONVOLVE_FFT_BINARY_SIZE 591 // Make the size an integer power of two 592 { 593 int twoCols, twoRows; // Size that is a factor of two 594 for (twoCols = 1; twoCols <= paddedCols && twoCols < INT_MAX - 1; twoCols <<= 1); // No action 595 for (twoRows = 1; twoRows <= paddedRows && twoRows < INT_MAX - 1; twoRows <<= 1); // No action 596 if (paddedCols > twoCols || paddedRows > twoRows) { 597 psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Unable to scale size (%dx%d) up to factor of two", 598 paddedCols, paddedRows); 599 return NULL; 600 } 601 paddedCols = twoCols; 602 paddedRows = twoRows; 603 } 604 #endif 605 606 int numPadded = paddedCols * paddedRows; // Number of pixels in padded image 607 608 // Create data array containing the padded kernel 609 FFTW_LOCK; 610 psF32 *data = fftwf_malloc(numPadded * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Data for FFTW 611 FFTW_UNLOCK; 612 613 // Generate the padded kernel image. We could generate the padded kernel image using 614 // memcpy, but by going pixel by pixel we can apply the normalisation that corrects for the 615 // FFT renormalisation. By applying it to the kernel here, we save applying it to the 616 // output image(s). 617 618 // copy kernel into data array 619 psF32 *dataPtr = data; // Pointer into FFTW data 620 float norm = 1.0 / (float)(paddedRows * paddedCols); // Normalisation to correct for FFT 621 622 int xNegMin = PS_MIN(-1, xMin), xNegMax = PS_MIN(-1, xMax); // Min and max for x when negative 623 int xPosMin = PS_MAX(0, xMin), xPosMax = PS_MAX(0, xMax); // Min and max for x when positive 624 int yNegMin = PS_MIN(-1, yMin), yNegMax = PS_MIN(-1, yMax); // Min and max for x when negative 625 int yPosMin = PS_MAX(0, yMin), yPosMax = PS_MAX(0, yMax); // Min and max for x when positive 626 int blankCols = xNegMin + paddedCols - xPosMax - 1; // Number of columns between kernel extrema 627 int blankRows = (yNegMin + paddedRows - yPosMax - 1) * paddedCols; // Rows between kernel extrema 628 size_t blankColBytes = blankCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes in blankCols 629 for (int y = yPosMin; y <= yPosMax; y++) { 630 // y is positive 631 for (int x = xPosMin; x <= xPosMax; x++, dataPtr++) { 632 // x is positive 633 *dataPtr = kernel->kernel[y][x] * norm; 634 } 635 // Columns between kernel extrema 636 memset(dataPtr, 0, blankColBytes); 637 dataPtr += blankCols; 638 for (int x = xNegMin; x <= xNegMax; x++, dataPtr++) { 639 // x is negative 640 *dataPtr = kernel->kernel[y][x] * norm; 641 } 642 } 643 // Rows between kernel extrema 644 memset(dataPtr, 0, blankRows * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); 645 dataPtr += blankRows; 646 for (int y = yNegMin; y <= yNegMax; y++) { 647 // y is negative 648 for (int x = xPosMin; x <= xPosMax; x++, dataPtr++) { 649 // x is positive 650 *dataPtr = kernel->kernel[y][x] * norm; 651 } 652 // Columns between kernel extrema 653 memset(dataPtr, 0, blankColBytes); 654 dataPtr += blankCols; 655 for (int x = xNegMin; x <= xNegMax; x++, dataPtr++) { 656 // x is negative 657 *dataPtr = kernel->kernel[y][x] * norm; 658 } 659 } 660 661 #if 0 662 { 663 // Use this for inspecting the result of copying the kernel 664 psImage *test = psImageAlloc(paddedCols, paddedRows, PS_TYPE_F32); 665 psFree(test->p_rawDataBuffer); 666 test->p_rawDataBuffer = data; 667 test->data.V[0] = test->p_rawDataBuffer; 668 for (int y = 1; y < paddedRows; y++) { 669 test->data.V[y] = (psPtr)((int8_t *)test->data.V[y - 1] + paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); 670 } 671 // View image here or write to disk 672 test->p_rawDataBuffer = NULL; 673 psFree(test); 674 } 675 #endif 676 677 // Do the forward FFT 678 // Note that the FFT images have different size from the input 679 FFTW_LOCK; 680 fftwf_complex *fft = fftwf_malloc((paddedCols/2 + 1) * paddedRows * sizeof(fftwf_complex)); // FFT 681 FFTW_UNLOCK; 682 683 FFTW_LOCK; 684 fftwf_plan plan = fftwf_plan_dft_r2c_2d(paddedRows, paddedCols, data, fft, FFTW_PLAN_RIGOR); 685 FFTW_UNLOCK; 686 687 fftwf_execute(plan); 688 689 FFTW_LOCK; 690 fftwf_destroy_plan(plan); 691 fftwf_free(data); 692 FFTW_UNLOCK; 693 694 psKernelFFT *output = psKernelFFTAlloc(kernel); 695 output->fft = fft; 696 output->paddedCols = paddedCols; 697 output->paddedRows = paddedRows; 698 699 return output; 700 } 701 702 psImage *psImageConvolveKernel(psImage *out, const psImage *in, const psImage *mask, psImageMaskType maskVal, const psKernelFFT *kernel) 703 { 704 PS_ASSERT_IMAGE_NON_NULL(in, NULL); 705 PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL); 706 PS_ASSERT_PTR_NON_NULL(kernel, NULL); 707 PS_ASSERT_PTR_NON_NULL(kernel->fft, NULL); 708 if (mask) { 709 PS_ASSERT_IMAGE_NON_NULL(mask, NULL); 710 PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_IMAGE_MASK, NULL); 711 PS_ASSERT_IMAGES_SIZE_EQUAL(mask, in, NULL); 712 } 713 714 bool threaded = psThreadPoolSize(); // Are we running threaded? 715 716 int numCols = in->numCols, numRows = in->numRows; // Size of image 717 int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Kernel sizes 718 719 // Need to pad the input image to protect from wrap-around effects 720 if (xMax - xMin > numCols || yMax - yMin > numRows) { 721 // Cannot pad the image if the kernel is larger. 722 psError(PS_ERR_BAD_PARAMETER_SIZE, true, _("Kernel cannot extend further than input image size (%dx%d vs %dx%d)."), xMax, yMax, numCols, numRows); 723 return NULL; 724 } 725 726 int paddedCols = numCols + PS_MAX(-xMin, xMax); // Number of columns in padded image 727 int paddedRows = numRows + PS_MAX(-yMin, yMax); // Number of rows in padded image 728 729 #if CONVOLVE_FFT_BINARY_SIZE 730 // Make the size an integer power of two 731 { 732 int twoCols, twoRows; // Size that is a factor of two 733 for (twoCols = 1; twoCols <= paddedCols && twoCols < INT_MAX - 1; twoCols <<= 1); // No action 734 for (twoRows = 1; twoRows <= paddedRows && twoRows < INT_MAX - 1; twoRows <<= 1); // No action 735 if (paddedCols > twoCols || paddedRows > twoRows) { 736 psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Unable to scale size (%dx%d) up to factor of two", 737 paddedCols, paddedRows); 738 return NULL; 739 } 740 paddedCols = twoCols; 741 paddedRows = twoRows; 742 } 743 #endif 744 745 if (paddedCols != kernel->paddedCols) { 746 psError(PS_ERR_BAD_PARAMETER_SIZE, true, _("Image is inconsistent with allocated kernel")); 747 return NULL; 748 } 749 if (paddedRows != kernel->paddedRows) { 750 psError(PS_ERR_BAD_PARAMETER_SIZE, true, _("Image is inconsistent with allocated kernel")); 751 return NULL; 752 } 753 754 int numPadded = paddedCols * paddedRows; // Number of pixels in padded image 755 756 // Create data array containing the padded image 757 FFTW_LOCK; 758 psF32 *data = fftwf_malloc(numPadded * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Data for FFTW 759 FFTW_UNLOCK; 760 psF32 *dataPtr = data; // Pointer into FFTW data 761 psF32 **imageData = in->data.F32; // Pointer into image data 762 763 // Copy image into data array 764 size_t goodBytes = numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes per image row 765 size_t padBytes = (paddedCols - numCols) * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to pad 766 for (int y = 0; y < numRows; y++, dataPtr += paddedCols, imageData++) { 767 memcpy(dataPtr, *imageData, goodBytes); 768 memset(dataPtr + numCols, 0, padBytes); 769 } 770 memset(dataPtr, 0, (paddedRows - numRows) * paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); 771 772 #if 0 773 { 774 // Use this for inspecting the result of copying the image 775 psImage *test = psImageAlloc(paddedCols, paddedRows, PS_TYPE_F32); 776 psFree(test->p_rawDataBuffer); 777 test->p_rawDataBuffer = data; 778 test->data.V[0] = test->p_rawDataBuffer; 779 for (int y = 1; y < paddedRows; y++) { 780 test->data.V[y] = (psPtr)((int8_t *)test->data.V[y - 1] + 781 paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); 782 } 783 // View image here 784 test->p_rawDataBuffer = NULL; 785 psFree(test); 786 } 787 #endif 788 789 // Mask bad pixels (which may be NANs), lest they infect everything 790 if (mask && maskVal) { 791 for (int y = 0; y < numRows; y++) { 792 for (int x = 0; x < numCols; x++) { 793 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) { 794 data[x + paddedCols * y] = 0; 795 } 796 } 797 } 798 } 799 800 // Do the forward FFT 801 // Note that the FFT images have different size from the input 802 FFTW_LOCK; 803 fftwf_complex *fft = fftwf_malloc((paddedCols/2 + 1) * paddedRows * sizeof(fftwf_complex)); // FFT 804 FFTW_UNLOCK; 805 806 int fftCols = paddedCols/2 + 1, fftRows = paddedRows; // Size of FFT images 807 int fftPixels = fftCols * fftRows; // Number of pixels in FFT image 808 809 FFTW_LOCK; 810 fftwf_plan forward = fftwf_plan_dft_r2c_2d(paddedRows, paddedCols, data, fft, FFTW_PLAN_RIGOR); 811 FFTW_UNLOCK; 812 813 fftwf_execute(forward); 814 815 FFTW_LOCK; 816 fftwf_destroy_plan(forward); 817 FFTW_UNLOCK; 818 819 fftwf_complex *kernelFFT = kernel->fft; 820 821 // Multiply the two transforms 822 for (int i = 0; i < fftPixels; i++) { 823 // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i 824 #if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 825 // C99 complex support 826 fft[i] *= kernelFFT[i]; 827 #else 828 // FFTW's backup complex support 829 float imageReal = fft[i][0], imageImag = fft[i][1]; 830 float kernelReal = kernelFFT[i][0], kernelImag = kernelFFT[i][1]; 831 fft[i][0] = imageReal * kernelReal - imageImag * kernelImag; 832 fft[i][1] = imageImag * kernelReal + imageReal * kernelImag; 833 #endif 834 } 835 836 // Do the backward FFT 837 FFTW_LOCK; 838 fftwf_plan backward = fftwf_plan_dft_c2r_2d(paddedRows, paddedCols, fft, data, FFTW_PLAN_RIGOR); 839 FFTW_UNLOCK; 840 841 fftwf_execute(backward); 842 843 FFTW_LOCK; 844 fftwf_destroy_plan(backward); 845 fftwf_free(fft); 846 FFTW_UNLOCK; 847 848 // Copy into the target, without the padding 849 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F32); 850 psF32 **outData = out->data.F32; // Pointer into output 851 dataPtr = data; // Reset to start 852 for (int y = 0; y < numRows; y++, outData++, dataPtr += paddedCols) { 853 memcpy(*outData, dataPtr, goodBytes); 854 } 855 856 FFTW_LOCK; 857 fftwf_free(data); 858 FFTW_UNLOCK; 859 860 return out; 861 } -
trunk/psLib/src/fft/psImageFFT.h
r21183 r28998 15 15 #include "psImage.h" 16 16 #include "psImageConvolve.h" 17 18 typedef struct { 19 void *fft; 20 int xMin; ///< Most negative x index 21 int yMin; ///< Most negative y index 22 int xMax; ///< Most positive x index 23 int yMax; ///< Most positive y index 24 int paddedCols; 25 int paddedRows; 26 } psKernelFFT; 17 27 18 28 /// @addtogroup MathOps Mathematical Operations … … 71 81 const psImage *mask, ///< Corresponding mask 72 82 psImageMaskType maskVal, ///< Value to mask 73 const psKernel *kernel ///< kernel to colvolve with 83 const psKernel *kernel ///< kernel to convolve with 84 ); 85 86 /// Allocate an the psKernelFFT structure 87 psKernelFFT *psKernelFFTAlloc( 88 const psKernel *input ///< kernel to convolve with 74 89 ); 90 91 /// Generate an FFT'ed kernel suitable for convolution with the given image 92 psKernelFFT *psImageConvolveKernelInit( 93 const psImage *in, ///< representative image to convolve 94 const psKernel *kernel ///< kernel to convolve with 95 ); 96 97 /// Convolve the given image with the pre-FFT'ed kernel 98 psImage *psImageConvolveKernel( 99 psImage *out, ///< Output image, or NULL 100 const psImage *in, ///< Image to convolve 101 const psImage *mask, ///< Corresponding mask 102 psImageMaskType maskVal, ///< Value to mask 103 const psKernelFFT *kernel ///< kernel to convolve with 104 ); 75 105 76 106 /// @} -
trunk/psLib/src/jpeg/psImageJpeg.c
r27145 r28998 7 7 #include <string.h> 8 8 9 #include <kapa.h> 9 10 #include "psMemory.h" 10 11 #include "psImage.h" … … 134 135 return psImageJpegColormapSet (map, "greyscale"); 135 136 } 137 138 // XXX need to fix library references for this (psLib does not depend on libkapa) 139 # if (0) 140 // XXX Add colormap bar with scale (min -> max) 141 // XXX Add option to plot the source overlay (pass in bDrawBuffer populated with points?) 142 // XXX need to update bDraw APIs to pass in/out structure and avoid the local static 143 bool psImageJpegNew(const psImageJpegColormap *map, const psImage *image, const char *filename, 144 float min, float max) 145 { 146 PS_ASSERT_PTR_NON_NULL(map, false); 147 PS_ASSERT_IMAGE_NON_NULL(image, false); 148 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 149 PS_ASSERT_VECTOR_NON_NULL(map->red, false); 150 PS_ASSERT_VECTOR_NON_NULL(map->green, false); 151 PS_ASSERT_VECTOR_NON_NULL(map->blue, false); 152 PS_ASSERT_PTR_NON_NULL(filename, false); 153 PS_ASSERT_INT_POSITIVE(strlen(filename), false); 154 PS_ASSERT_FLOAT_REAL(min, false); 155 PS_ASSERT_FLOAT_REAL(max, false); 156 157 float zero, scale; 158 struct jpeg_compress_struct cinfo; 159 struct jpeg_error_mgr jerr; 160 161 long pixel; 162 JSAMPLE *jpegLine; // Points to data for current line 163 JSAMPROW jpegLineList[1]; // pointer to JSAMPLE row[s] 164 JSAMPLE *jpegImage; 165 JSAMPLE *outPix; 166 167 /* JPEG init calls */ 168 cinfo.err = jpeg_std_error (&jerr); 169 jpeg_create_compress (&cinfo); 170 171 /* open file, prep for jpeg */ 172 FILE *f = fopen(filename, "w"); 173 if (!f) { 174 psError(PS_ERR_IO, true, "failed to open %s for output\n", filename); 175 return false; 176 } 177 jpeg_stdio_dest(&cinfo, f); 178 179 /* set up color jpeg buffers */ 180 int quality = 75; 181 cinfo.image_width = image->numCols; // image width and height, in pixels 182 cinfo.image_height = image->numRows; 183 cinfo.input_components = 3; 184 cinfo.in_color_space = JCS_RGB; 185 jpeg_set_defaults (&cinfo); 186 jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values 187 jpeg_start_compress (&cinfo, true); 188 189 psU8 *Rpix = map->red->data.U8; 190 psU8 *Gpix = map->green->data.U8; 191 psU8 *Bpix = map->blue->data.U8; 192 193 if (max == min) { 194 zero = min - 0.1; 195 scale = 256.0/0.2; 196 } else { 197 zero = min; 198 scale = 256.0/(max - min); 199 } 200 201 int dx = image->numCols; 202 int dy = image->numRows; 203 204 // output image buffer and line buffer 205 jpegLine = psAlloc (3*dx*sizeof(JSAMPLE)); 206 jpegImage = psAlloc (3*dx*dy*sizeof(JSAMPLE)); 207 208 // first copy the image data into the output buffer 209 for (int j = 0; j < dy; j++) { 210 psF32 *row = image->data.F32[j]; 211 212 outPix = jpegLine; 213 for (int i = 0; i < dx; i++, outPix += 3) { 214 if (isfinite(row[i])) { 215 pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale); 216 outPix[0] = Rpix[pixel]; 217 outPix[1] = Gpix[pixel]; 218 outPix[2] = Bpix[pixel]; 219 } else { 220 // XXX NAN value should be set per-color map 221 outPix[0] = 0x00; 222 outPix[1] = 0xff; 223 outPix[2] = 0x00; 224 } 225 } 226 memcpy (&jpegImage[j*3*dx], jpegLine, 3*dx); 227 } 228 229 bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy); 230 bDrawSetBuffer(bdbuf); 231 bDrawColor red = KapaColorByName("red"); 232 bDrawSetStyle (red, 1, 0); 233 bDrawCircle(40.0, 20.0, 3.0); 234 235 { 236 int Npalette; 237 png_color *palette = KapaPNGPalette (&Npalette); 238 bDrawColor white = KapaColorByName ("white"); 239 for (int j = 0; j < dy; j++) { 240 for (int i = 0; i < dx; i++) { 241 bDrawColor color = bdbuf[0].pixels[j][i]; 242 if (color == white) continue; 243 jpegImage[j*3*dx + 3*i + 0] = palette[color].red; 244 jpegImage[j*3*dx + 3*i + 1] = palette[color].green; 245 jpegImage[j*3*dx + 3*i + 2] = palette[color].blue; 246 } 247 } 248 } 249 bDrawBufferFree (bdbuf); 250 251 // write out the image buffer 252 for (int j = 0; j < image->numRows; j++) { 253 jpegLineList[0] = &jpegImage[j*3*dx]; 254 if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) { 255 psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j); 256 psFree(jpegLine); 257 psFree(jpegImage); 258 fclose(f); 259 return false; 260 } 261 } 262 263 jpeg_finish_compress(&cinfo); 264 if (fclose(f) == EOF) { 265 psError(PS_ERR_IO, true, "Failed to close %s", filename); 266 psFree(jpegLine); 267 psFree(jpegImage); 268 return false; 269 } 270 jpeg_destroy_compress(&cinfo); 271 272 psFree(jpegLine); 273 psFree(jpegImage); 274 return true; 275 } 276 # endif 136 277 137 278 bool psImageJpeg(const psImageJpegColormap *map, const psImage *image, const char *filename, -
trunk/psLib/src/math/psMinimizeLMM.c
r26951 r28998 441 441 } 442 442 443 // number of degrees of freedom for this fit 444 int nDOF = dy->n - params->n; 445 443 446 // calculate initial alpha and beta, set chisq (min->value) 444 447 min->value = psMinLM_SetABX(alpha, beta, params, paramMask, x, y, dy, func); … … 456 459 } 457 460 458 // iterate until the tolerance is reached, or give up 459 while ((min->iter < min->maxIter) && ((min->lastDelta > min->tol) || !isfinite(min->lastDelta))) { 461 // iterate until: (a) nIter = min->iter or (b) (chisq / ndof) < maxChisq and deltaChisq < minTol (but don't stop unless Chisq is finite) 462 bool done = (min->iter >= min->maxIter); 463 while (!done) { 460 464 psTrace("psLib.math", 5, "Iteration number %d. (max iterations is %d).\n", min->iter, min->maxIter); 461 psTrace("psLib.math", 5, "Last delta is %f. Min->tol is %f.\n", min->lastDelta, min->tol);465 psTrace("psLib.math", 5, "Last delta is %f. stop if < %f, accept if < %f\n", min->lastDelta, min->minTol, min->maxTol); 462 466 463 467 // set a new guess for Alpha, Beta, Params 464 468 if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda, &dLinear)) { 465 469 min->iter ++; 470 if (min->iter >= min->maxIter) break; 466 471 lambda *= 10.0; 467 472 continue; … … 482 487 if (isnan(Chisq)) { 483 488 min->iter ++; 489 if (min->iter >= min->maxIter) break; 484 490 lambda *= 10.0; 485 491 continue; … … 492 498 psF32 rho = (min->value - Chisq) / dLinear; 493 499 494 psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value, 495 Chisq, min->lastDelta, dLinear, rho, lambda); 496 497 psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value, 498 Chisq, min->lastDelta, dLinear, rho, lambda); 500 psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f, nDOF: %d\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda, nDOF); 501 502 psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda); 499 503 500 504 // dump some useful info if trace is defined … … 506 510 /* rho is positive if the new chisq is smaller; allow for some insignificant change (slight negative rho) */ 507 511 if (rho >= -1e-6) { 508 min->lastDelta = (min->value - Chisq) / (dy->n - params->n);512 min->lastDelta = (min->value - Chisq) / nDOF; 509 513 min->value = Chisq; 510 514 alpha = psImageCopy(alpha, Alpha, PS_TYPE_F32); … … 516 520 } 517 521 min->iter++; 522 523 done = (min->iter >= min->maxIter); 524 525 // check for convergence: 526 float chisqDOF = Chisq / nDOF; 527 if (!isfinite(min->maxChisqDOF) || ((chisqDOF < min->maxChisqDOF) && isfinite(min->lastDelta))) { 528 done |= (min->lastDelta < min->minTol); 529 } 518 530 } 519 531 psTrace("psLib.math", 5, "chisq: %f, last delta: %f, Niter: %d\n", min->value, min->lastDelta, min->iter); … … 549 561 psFree(dy); 550 562 } 551 if (min->iter == min->maxIter) { 552 psTrace("psLib.math", 3, "---- end (false) ----\n"); 553 return(false); 554 } 555 psTrace("psLib.math", 3, "---- end (true) ----\n"); 556 return(true); 563 564 // if the last improvement was at least as good as maxTol, accept the fit: 565 if (min->lastDelta <= min->maxTol) { 566 psTrace("psLib.math", 6, "---- end (true) ----\n"); 567 return(true); 568 } 569 psTrace("psLib.math", 6, "---- end (false) ----\n"); 570 return(false); 557 571 } 558 572 … … 588 602 } 589 603 590 psMinimization *psMinimizationAlloc(int maxIter, 591 float tol) 604 psMinimization *psMinimizationAlloc(int maxIter, float minTol, float maxTol) 592 605 { 593 606 PS_ASSERT_INT_NONNEGATIVE(maxIter, NULL); … … 595 608 psMinimization *min = psAlloc(sizeof(psMinimization)); 596 609 psMemSetDeallocator(min, (psFreeFunc)minimizationFree); 610 597 611 P_PSMINIMIZATION_SET_MAXITER(min,maxIter); 598 P_PSMINIMIZATION_SET_TOL(min,tol); 612 P_PSMINIMIZATION_SET_MIN_TOL(min,minTol); 613 P_PSMINIMIZATION_SET_MAX_TOL(min,maxTol); 614 599 615 min->value = 0.0; 600 616 min->iter = 0; 601 617 min->lastDelta = NAN; 618 min->maxChisqDOF = NAN; 602 619 603 620 return(min); -
trunk/psLib/src/math/psMinimizeLMM.h
r23486 r28998 33 33 #define PS_MAX_LMM_ITERATIONS 100 34 34 #define PS_MAX_MINIMIZE_ITERATIONS 100 35 #define P_PSMINIMIZATION_SET_MAXITER(m,val) *(int*)&m->maxIter = val 36 #define P_PSMINIMIZATION_SET_TOL(m,val) *(float*)&m->tol = val 35 #define P_PSMINIMIZATION_SET_MAXITER(m,val) { *(int*)&m->maxIter = val; } 36 #define P_PSMINIMIZATION_SET_MIN_TOL(m,val) { *(float*)&m->minTol = val; } 37 #define P_PSMINIMIZATION_SET_MAX_TOL(m,val) { *(float*)&m->maxTol = val; } 37 38 38 39 typedef enum { … … 75 76 typedef struct 76 77 { 77 const int maxIter; ///< Convergence limit 78 const float tol; ///< Error Tolerance 78 const int maxIter; ///< Convergence limit 79 const float minTol; ///< Convergence Tolerance (stop if we reach this value) 80 const float maxTol; ///< Max Tolerance (accept fit if last improvement was this good) 79 81 float value; ///< Value of function at minimum 80 82 int iter; ///< Number of iterations to date 81 83 float lastDelta; ///< The last difference for the fit 84 float maxChisqDOF; ///< for Chisq minimization, require that we reach here before checking tolerance 82 85 } 83 86 psMinimization; … … 102 105 psMinimization *psMinimizationAlloc( 103 106 int maxIter, ///< Number of minimization iterations to perform. 104 float tol ///< Requested error tolerance 107 float minTol, ///< stop if tolerance is less than this 108 float maxTol ///< accept fit if tolerance is less than this 105 109 ) PS_ATTR_MALLOC; 106 110 -
trunk/psLib/src/math/psMinimizePowell.c
r28635 r28998 457 457 458 458 mul = bracket->data.F32[1]; 459 if ((fabs(a-b) < min-> tol) && (fabs(b-c) < min->tol)) {459 if ((fabs(a-b) < min->minTol) && (fabs(b-c) < min->minTol)) { 460 460 PS_VECTOR_ADD_MULTIPLE(params, paramMask, line, params, mul); 461 461 min->value = func(params, coords); … … 524 524 psTrace("psLib.math", 4, "---- psMinimizePowell() begin ----\n"); 525 525 psTrace("psLib.math", 6, "min->maxIter is %d\n", min->maxIter); 526 psTrace("psLib.math", 6, "min-> tol is %f\n", min->tol);526 psTrace("psLib.math", 6, "min->minTol is %f\n", min->minTol); 527 527 528 528 if (paramMask == NULL) { … … 573 573 for (i=0;i<numDims;i++) { 574 574 if (myParamMask->data.PS_TYPE_VECTOR_MASK_DATA[i] == 0) { 575 575 576 P_PSMINIMIZATION_SET_MAXITER((&dummyMin),PS_MINIMIZE_POWELL_LINEMIN_MAX_ITERATIONS); 576 *(float*)&dummyMin.tol = PS_MINIMIZE_POWELL_LINEMIN_ERROR_TOLERANCE; 577 P_PSMINIMIZATION_SET_MIN_TOL((&dummyMin),PS_MINIMIZE_POWELL_LINEMIN_ERROR_TOLERANCE); 578 577 579 mul = LineMin(&dummyMin, Q, ((psVector *) v->data[i]), 578 580 myParamMask, coords, func); … … 677 679 678 680 // 8: Go to step 3 until the change is less than some tolerance. 679 if (fabs(baseFuncVal - currFuncVal) <= min-> tol) {681 if (fabs(baseFuncVal - currFuncVal) <= min->minTol) { 680 682 psFree(v); 681 683 psFree(pQP); -
trunk/psLib/src/math/psStats.c
r27334 r28998 1211 1211 1212 1212 // Fit a Gaussian to the data. 1213 psMinimization *minimizer = psMinimizationAlloc(100, 0.01 ); // The minimizer information1213 psMinimization *minimizer = psMinimizationAlloc(100, 0.01, 1.0); // The minimizer information 1214 1214 psVector *params = psVectorAlloc(2, PS_TYPE_F32); // Parameters for the Gaussian 1215 1215 // Initial guess for the mean (index 0) and var (index 1). -
trunk/psLib/test/math/Makefile.am
r24321 r28998 49 49 tap_psMinimizePowell \ 50 50 tap_psSpline1D \ 51 tap_psPolynomialMD 51 tap_psPolynomialMD \ 52 tap_psPolynomialMD_sampleDark 52 53 53 54 # tap_psRandom
Note:
See TracChangeset
for help on using the changeset viewer.
