%ffp Category: "FM Tutorial" Title: "GB Test 004" Version: "1.1" Filename: "GB Test 004" Author: "Alex Hunter" Organization:"AFH Systems" Description: "Code derived from the Gimp Gaussian Blur RLE plugin, " "which is Copyright (C) 1995 by Spencer Kimball and Peter Mattis, " "and the Gimp blur2 filter, which is Copyright (C) 1996 by " "Torsten Martinsen, with contributions by Johan Klockars." Copyright: "©1999-2001 AFH Systems" URL: "www.filtermeister.com" Dialog: color=steelblue ctl(0):"&Radius * 10", val=10 ctl(2):CHECKBOX,"Pl&ot the Curve", val=0 ctl(4):CHECKBOX,"Print the Cur&ve", val=0 ctl(6):CHECKBOX,"Print &Debug Info", val=0 ctl(8):CHECKBOX,"&Use cnvX/Y", val=0 ForEveryTile: { double radius = ctl(0)/10.0; double sigma, sigma2; double l; int n; int length; int i, j; const bool PLOT = ctl(2); const bool PRINT = ctl(4); const bool DEBUG = ctl(6); const bool USE_CNV = ctl(8); radius = radius * 2.0 + 1.0; //scale approx same as Photoshop radius = fabs(radius) + 1.0; if (radius < 2.0) { if (Warn("Sub-pixel radii yield spurious results.") != IDOK) { abort(); } } if (DEBUG) Info("X = %d\nY = %d", X, Y); if (DEBUG) Info("Radius = %g", radius); sigma = sqrt(-(radius*radius)/(2.0*log(1.0/255.0))); if (DEBUG) Info("Sigma = %g", sigma); sigma2 = 2.0 * sigma * sigma; if (DEBUG) Info("Sigma2 = %g", sigma2); l = sqrt(-sigma2 * log(1.0/255.0)); if (DEBUG) Info("l = %g", l); n = ceil(l) * 2; //round n up to an odd value. n |= 1; if (DEBUG) Info("n = %d", n); if (n > 256) { //exceeds number of put() cells... Error("Specified radius would require too many cells (%d).", n); abort(); } length = n / 2; //generate the bell-shaped Gaussian distribution curve... //curve[0] = 255; put(255, length); for (i = 1; i <= length; i++) { int temp = exp(-(i*i)/sigma2) * 255.0; //curve[-i] = curve[i] = temp; put(temp, length - i); put(temp, length + i); } if (PRINT) { // Print the curve. for (i = -length; i <= length; i++) { if (YesNo("curve[%d] = %d\n\nContinue?", i, get(length + i)) == IDNO) break; } } if (PLOT) { // Plot the Gaussian bell-shaped curve over a darkened // image background. // This updates fast, so set real-time tracking ON. setCtlProperties(0, CTP_TRACK); // Copy over a darkened version of the input image, // setting the alpha channel (if present) to fully opaque. for (y = y_start; y < y_end; y++) { if (updateProgress(y-y_start,y_end-y_start)) abort(); for (x = x_start; x < x_end; x++) { for (z = 0; z < Z; z++) { pset(x, y, z, z==3?255:src(x,y,z)/3); } } } // Draw the Y-axis. for (y = y_start; y < y_end; y++) { pset(X/2, y, 2, 255);//blue } // Draw the X-axis. for (x = x_start; x < x_end; x++) { pset(x, Y/2, 0, 255);//red } // Plot the Gaussian curve. for (i = -length; i <= length; i++) { pset(X/2 + i*10, Y/2 - get(length + i)*Y/512, 1, 255); //green } } else { // Apply Gaussian blur in the vertical and horizontal // directions. int sum, total; int xWork = x_end - x_start; int yWork = y_end - y_start; int totalWork = xWork + yWork; // This updates slowly, so set real-time tracking OFF. clearCtlProperties(0, CTP_TRACK); // Compute total weight total = 0; for (i = -length; i <= length; i++) { total += get(length + i); } if (DEBUG) Info("total = %d", total); // Apply vertical Gaussian blur... for (x = x_start; x < x_end; x++) { if (updateProgress(x-x_start, totalWork)) abort(); for (y = y_start; y < y_end; y++) { for (z = 0; z < Z; z++) { if (USE_CNV) { sum = cnvY(length, 0, total, src, x, y, z); tset(x, y, z, sum); } else { sum = 0; for (i = -length; i <= length; ++i) { sum += src(x, y+i, z)*get(length + i); } tset(x, y, z, sum/total); } } } } // Apply horizontal Gaussian blur... for (y = y_start; y < y_end; y++) { if (updateProgress(y-y_start+xWork, totalWork)) abort(); for (x = x_start; x < x_end; x++) { for (z = 0; z < Z; z++) { if (USE_CNV) { sum = cnvX(length, 0, total, tget, x, y, z); pset(x, y, z, sum); } else { sum = 0; for (i = -length; i <= length; ++i) { sum += tget(x+i, y, z)*get(length + i); } pset(x, y, z, sum/total); } } } } }//if // Reset the progress bar. updateProgress(0,100); return true; //Done! }//ForEveryTile