1 package ij.plugin.filter;
17 private static int radius = 50;
18 private static boolean whiteBackground =
true;
20 private boolean canceled;
22 private boolean invert;
36 public void run(ImageProcessor ip) {
43 subtractRGBBackround((ColorProcessor)ip, radius);
48 public void showDialog() {
49 GenericDialog gd =
new GenericDialog(
"Subtract Background");
50 gd.addNumericField(
"Rolling Ball Radius:", radius, 0);
51 gd.addCheckbox(
"White Background", whiteBackground);
56 radius = (int)gd.getNextNumber();
57 whiteBackground = gd.getNextBoolean();
60 invert = (invertedLut && !whiteBackground) || (!invertedLut && whiteBackground);
63 public void subtractRGBBackround(
ColorProcessor ip,
int ballRadius) {
66 byte[] H =
new byte[width*height];
67 byte[] S =
new byte[width*height];
68 byte[] B =
new byte[width*height];
70 ByteProcessor brightness =
new ByteProcessor(width, height, B, null);
72 ip.
setHSB(H, S, (byte[])brightness.getPixels());
86 ip.setProgressBar(null);
90 RollingBall ball =
new RollingBall(ballRadius);
93 ImageProcessor smallImage = shrinkImage(ip, ball.shrinkfactor);
96 IJ.
showStatus(
"Rolling ball ("+ball.shrinkfactor+
")...");
97 ImageProcessor background = rollBall(ball, ip, smallImage);
98 interpolateBackground(background, ball);
99 extrapolateBackground(background, ball);
103 ip.copyBits(background, 0, 0, Blitter.SUBTRACT);
121 ImageProcessor rollBall(RollingBall ball, ImageProcessor image, ImageProcessor smallImage) {
124 int ptsbelowlastpatch;
138 int left, right, top, bottom;
139 byte[] pixels = (byte[])smallImage.getPixels();
140 byte[] patch = ball.data;
141 int width = image.getWidth();
142 int height = image.getHeight();
143 int swidth = smallImage.getWidth();
144 int sheight = smallImage.getHeight();
145 ImageProcessor background =
new ByteProcessor(width, height);
146 byte[] backgroundpixels = (byte[])background.getPixels();
147 int shrinkfactor = ball.shrinkfactor;
149 int rightroll = width/shrinkfactor-1;
151 int bottomroll = height/shrinkfactor-1;
154 right = rightroll - leftroll - 1;
156 bottom = bottomroll - toproll - 1;
157 smallimagewidth = swidth;
158 int patchwidth = ball.patchwidth;
159 halfpatchwidth = patchwidth / 2;
160 ybackgrinc = shrinkfactor*width;
162 for (
int ypt=top; ypt<=(bottom+patchwidth); ypt++) {
163 for (
int xpt=left; xpt<=(right+patchwidth); xpt++) {
168 ypt2 = ypt - patchwidth;
169 imgpt = ypt2*smallimagewidth + xpt - patchwidth;
171 xpt2 = xpt-patchwidth;
174 if ((xpt2>=left) && (xpt2<=right) && (ypt2>=top) && (ypt2<=bottom)) {
177 zdif = (pixels[p2]&255) - (zctr + (patch[p1]&255));
193 imgpt = imgpt - patchwidth - 1 + smallimagewidth;
198 ptsbelowlastpatch = halfpatchwidth;
200 ptsbelowlastpatch = 0;
202 yval = ypt - patchwidth;
205 ybackgrpt = (yval - top + 1) * ybackgrinc;
206 while (ypt2<=patchwidth) {
207 xval = xpt - patchwidth + ptsbelowlastpatch;
208 xpt2 = ptsbelowlastpatch;
209 ballpt += ptsbelowlastpatch;
210 backgrpt = ybackgrpt + (xval - left + 1) * shrinkfactor;
211 while (xpt2<=patchwidth) {
212 if ((xval >= left) && (xval <= right) && (yval >= top) && (yval <= bottom)) {
214 zadd = zctr + (patch[p1]&255);
217 if (zadd>(backgroundpixels[p1]&255))
218 backgroundpixels[p1] = (byte)zadd;
223 backgrpt += shrinkfactor;
227 ybackgrpt += ybackgrinc;
231 IJ.showProgress(0.2+0.6*ypt/(bottom+patchwidth));
237 ImageProcessor shrinkImage(ImageProcessor ip,
int shrinkfactor) {
238 int width = ip.getWidth();
239 int height = ip.getHeight();
240 int swidth = width/shrinkfactor;
241 int sheight = height/shrinkfactor;
242 ImageProcessor ip2 = ip.duplicate();
244 IJ.showProgress(0.1);
245 ImageProcessor smallImage =
new ByteProcessor(swidth, sheight);
246 byte[] pixels = (byte[])ip2.getPixels();
247 byte[] spixels = (byte[])smallImage.getPixels();
248 int xmaskmin, ymaskmin, min, nextrowoffset, paddr, thispixel;
249 for (
int i=0; i<(swidth*sheight); i++) {
250 xmaskmin = shrinkfactor*(i%swidth);
251 ymaskmin = shrinkfactor*(i/swidth);
253 nextrowoffset = width-shrinkfactor;
254 paddr = ymaskmin*width+xmaskmin;
255 for (
int j=1; j<=shrinkfactor; j++) {
256 for (
int k=1; k<=shrinkfactor; k++) {
257 thispixel = pixels[paddr++]&255;
261 paddr += nextrowoffset;
263 spixels[i] = (byte)min;
274 void interpolateBackground(ImageProcessor background, RollingBall ball) {
277 int lastvalue, nextvalue;
279 int bglastptr, bgnextptr;
281 int width = background.getWidth();
282 int height = background.getHeight();
283 int shrinkfactor = ball.shrinkfactor;
285 int rightroll = width/shrinkfactor-1;
287 int bottomroll = height/shrinkfactor-1;
288 byte[] pixels = (byte[])background.getPixels();
291 for (
int j=1; j<=(bottomroll-toproll-1); j++) {
293 vloc += shrinkfactor;
294 for (
int i=1; i<=(rightroll-leftroll); i++) {
295 hloc += shrinkfactor;
296 bgnextptr = vloc*width + hloc;
297 bglastptr = bgnextptr - shrinkfactor;
298 nextvalue = pixels[bgnextptr]&255;
299 lastvalue = pixels[bglastptr]&255;
300 for (
int ii=1; ii<=(shrinkfactor-1); ii++) {
302 pixels[p] = (byte)(lastvalue+(shrinkfactor-ii)*(nextvalue-lastvalue)/shrinkfactor);
304 for (
int ii=0; ii<=(shrinkfactor-1); ii++) {
305 bglastptr = (vloc-shrinkfactor)*width+hloc-ii;
306 bgnextptr = vloc*width+hloc-ii;
307 lastvalue = pixels[bglastptr]&255;
308 nextvalue = pixels[bgnextptr]&255;
310 for (
int jj=1; jj<=(shrinkfactor-1); jj++) {
313 pixels[p] = (byte)(lastvalue+(shrinkfactor-jj)*(nextvalue-lastvalue)/shrinkfactor);
328 void extrapolateBackground(ImageProcessor background, RollingBall ball) {
332 int lastvalue, nextvalue;
334 int bglastptr, bgnextptr;
336 int width = background.getWidth();
337 int height = background.getHeight();
338 int shrinkfactor = ball.shrinkfactor;
340 int rightroll = width/shrinkfactor-1;
342 int bottomroll = height/shrinkfactor-1;
343 byte[] pixels = (byte[])background.getPixels();
345 for (
int hloc=shrinkfactor; hloc<=(shrinkfactor*(rightroll-leftroll)-1); hloc++) {
347 bglastptr = shrinkfactor*width+hloc;
348 bgnextptr = (shrinkfactor+1)*width+hloc;
349 lastvalue = pixels[bglastptr]&255;
350 nextvalue = pixels[bgnextptr]&255;
351 edgeslope = nextvalue-lastvalue;
354 for (
int jj=1; jj<=shrinkfactor; jj++) {
356 pvalue = pvalue-edgeslope;
360 pixels[p] = (byte)255;
362 pixels[p] = (byte)pvalue;
364 bglastptr = (shrinkfactor*(bottomroll-toproll-1)-1)*width+hloc;
365 bgnextptr = shrinkfactor*(bottomroll-toproll-1)*width+hloc;
366 lastvalue = pixels[bglastptr]&255;
367 nextvalue = pixels[bgnextptr]&255;
368 edgeslope = nextvalue-lastvalue;
371 for (
int jj=1; jj<=((height-1)-shrinkfactor*(bottomroll-toproll-1)); jj++) {
377 pixels[p] = (byte)255;
379 pixels[p] = (byte)pvalue;
382 for (
int vloc=0; vloc<height; vloc++) {
384 bglastptr = vloc*width+shrinkfactor;
385 bgnextptr = bglastptr+1;
386 lastvalue = pixels[bglastptr]&255;
387 nextvalue = pixels[bgnextptr]&255;
388 edgeslope = nextvalue-lastvalue;
391 for (
int ii=1; ii<=shrinkfactor; ii++) {
393 pvalue = pvalue - edgeslope;
397 pixels[p] = (byte)255;
399 pixels[p] = (byte)pvalue;
401 bgnextptr = vloc*width+shrinkfactor*(rightroll-leftroll-1)-1;
402 bglastptr = bgnextptr-1;
403 lastvalue = pixels[bglastptr]&255;
404 nextvalue = pixels[bgnextptr]&255;
405 edgeslope = nextvalue-lastvalue;
408 for (
int ii=1; ii<=((width-1)-shrinkfactor*(rightroll-leftroll-1)+1); ii++) {
410 pvalue = pvalue+edgeslope;
414 pixels[p] = (byte)255;
416 pixels[p] = (byte)pvalue;
430 RollingBall(
int radius) {
435 }
else if (radius<=30) {
438 }
else if (radius<=100) {
445 buildRollingBall(radius, arcTrimPer);
453 void buildRollingBall(
int ballradius,
int arcTrimPer) {
457 int smallballradius, diam;
462 this.shrinkfactor = shrinkfactor;
463 smallballradius = ballradius/shrinkfactor;
464 if (smallballradius<1)
466 rsquare = smallballradius*smallballradius;
467 diam = smallballradius*2;
468 xtrim = (arcTrimPer*diam)/100;
469 patchwidth = diam - xtrim - xtrim;
470 halfpatchwidth = smallballradius - xtrim;
471 ballsize = (patchwidth+1)*(patchwidth+1);
472 data =
new byte[ballsize];
474 for (
int i=0; i<ballsize; i++) {
475 xval = i % (patchwidth+1) - halfpatchwidth;
476 yval = i / (patchwidth+1) - halfpatchwidth;
477 temp = rsquare - (xval*xval) - (yval*yval);
479 data[i] = (byte)Math.round(Math.sqrt(temp));