Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
ByteProcessor.java
1 package ij.process;
2 
3 import java.util.*;
4 import java.awt.*;
5 import java.awt.image.*;
6 import ij.gui.*;
7 
12 public class ByteProcessor extends ImageProcessor {
13 
14  protected byte[] pixels;
15  protected byte[] snapshotPixels;
16  private int bgColor = 255; //white
17  private int min=0, max=255;
18  private boolean brokenNewPixels = ij.IJ.isMacintosh()&&!ij.IJ.isJava2()
19  || System.getProperty("java.version").startsWith("1.4");
20 
22  public ByteProcessor(Image img) {
23  width = img.getWidth(null);
24  height = img.getHeight(null);
25  resetRoi();
26  pixels = new byte[width * height];
27  PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, false);
28  try {
29  pg.grabPixels();
30  } catch (InterruptedException e) {
31  System.err.println(e);
32  };
33  cm = pg.getColorModel();
34  if (cm instanceof IndexColorModel)
35  pixels = (byte[])(pg.getPixels());
36  else
37  System.err.println("ByteProcessor: not 8-bit image");
38  }
39 
41  public ByteProcessor(int width, int height) {
42  this(width, height, new byte[width*height], null);
43  }
44 
46  public ByteProcessor(int width, int height, byte[] pixels, ColorModel cm) {
47  if (pixels!=null && width*height!=pixels.length)
48  throw new IllegalArgumentException(WRONG_LENGTH);
49  this.width = width;
50  this.height = height;
51  resetRoi();
52  this.pixels = pixels;
53  this.cm = cm;
54  }
55 
56  public Image createImage() {
57  if (cm==null)
58  makeDefaultColorModel();
59  if (source==null || brokenNewPixels) {
60  source = new MemoryImageSource(width, height, cm, pixels, 0, width);
61  source.setAnimated(true);
62  source.setFullBufferUpdates(true);
63  img = Toolkit.getDefaultToolkit().createImage(source);
64  } else if (newPixels) {
65  source.newPixels(pixels, cm, 0, width);
66  newPixels = false;
67  } else
68  source.newPixels();
69  return img;
70  }
71 
73  public ImageProcessor createProcessor(int width, int height) {
74  ImageProcessor ip2;
75  ip2 = new ByteProcessor(width, height, new byte[width*height], getColorModel());
76  if (baseCM!=null)
77  ip2.setMinAndMax(min, max);
78  return ip2;
79  }
80 
81  public ImageProcessor crop() {
82  ImageProcessor ip2 = createProcessor(roiWidth, roiHeight);
83  byte[] pixels2 = (byte[])ip2.getPixels();
84  for (int ys=roiY; ys<roiY+roiHeight; ys++) {
85  int offset1 = (ys-roiY)*roiWidth;
86  int offset2 = ys*width+roiX;
87  for (int xs=0; xs<roiWidth; xs++)
88  pixels2[offset1++] = pixels[offset2++];
89  }
90  return ip2;
91  }
92 
94  public void snapshot() {
95  snapshotWidth=width;
96  snapshotHeight=height;
97  if (snapshotPixels==null || (snapshotPixels!=null && snapshotPixels.length!=pixels.length))
98  snapshotPixels = new byte[width * height];
99  System.arraycopy(pixels, 0, snapshotPixels, 0, width*height);
100  newSnapshot = true;
101  //double sum = 0;
102  //for (int i=0; i<width*height; i++)
103  // sum += pixels[i]&0xff;
104  //ij.IJ.write("snapshot: "+(sum/(width*height)));
105  }
106 
108  public void reset() {
109  if (snapshotPixels==null)
110  return;
111  System.arraycopy(snapshotPixels,0,pixels,0,width*height);
112  newSnapshot = true;
113  }
114 
116  public void reset(ImageProcessor mask) {
117  if (mask==null || snapshotPixels==null)
118  return;
119  if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
120  throw new IllegalArgumentException(maskSizeError(mask));
121  byte[] mpixels = (byte[])mask.getPixels();
122  for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
123  int i = y * width + roiX;
124  int mi = my * roiWidth;
125  for (int x=roiX; x<(roiX+roiWidth); x++) {
126  if (mpixels[mi++]==0)
127  pixels[i] = snapshotPixels[i];
128  i++;
129  }
130  }
131  }
132 
136  public void fill(ImageProcessor mask) {
137  if (mask==null)
138  {fill(); return;}
139  if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
140  throw new IllegalArgumentException(maskSizeError(mask));
141  byte[] mpixels = (byte[])mask.getPixels();
142  for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
143  int i = y * width + roiX;
144  int mi = my * roiWidth;
145  for (int x=roiX; x<(roiX+roiWidth); x++) {
146  if (mpixels[mi++]!=0)
147  pixels[i] = (byte)fgColor;
148  i++;
149  }
150  }
151  }
152 
153  public int getPixel(int x, int y) {
154  if (x>=0 && x<width && y>=0 && y<height)
155  return pixels[y*width+x]&0xff;
156  else
157  return 0;
158  }
159 
160  static double oldx, oldy;
161 
163  public double getInterpolatedPixel(double x, double y) {
164  if (x<0.0) x = 0.0;
165  if (x>=width-1.0) x = width-1.001;
166  if (y<0.0) y = 0.0;
167  if (y>=height-1.0) y = height-1.001;
168  return getInterpolatedPixel(x, y, pixels);
169  }
170 
173  public double getInterpolatedValue(double x, double y) {
174  if (cTable==null)
175  return getInterpolatedPixel(x, y);
176  if (x<0.0) x = 0.0;
177  if (x>=width-1.0) x = width-1.001;
178  if (y<0.0) y = 0.0;
179  if (y>=height-1.0) y = height-1.001;
180  int xbase = (int)x;
181  int ybase = (int)y;
182  double xFraction = x - xbase;
183  double yFraction = y - ybase;
184  int offset = ybase * width + xbase;
185  double lowerLeft = cTable[pixels[offset]&255];
186  //if ((xbase>=(width-1))||(ybase>=(height-1)))
187  // return lowerLeft;
188  double lowerRight = cTable[pixels[offset + 1]&255];
189  double upperRight = cTable[pixels[offset + width + 1]&255];
190  double upperLeft = cTable[pixels[offset + width]&255];
191  double upperAverage = upperLeft + xFraction * (upperRight - upperLeft);
192  double lowerAverage = lowerLeft + xFraction * (lowerRight - lowerLeft);
193  return lowerAverage + yFraction * (upperAverage - lowerAverage);
194  }
195 
196  public float getPixelValue(int x, int y) {
197  if (x>=0 && x<width && y>=0 && y<height) {
198  if (cTable==null)
199  return pixels[y*width + x]&0xff;
200  else
201  return cTable[pixels[y*width + x]&0xff];
202  } else
203  return 0f;
204  }
205 
207  public void setColor(Color color) {
208  //if (ij.IJ.altKeyDown()) throw new IllegalArgumentException("setColor: "+color);
209  drawingColor = color;
210  fgColor = getBestIndex(color);
211  }
212 
214  public void setValue(double value) {
215  fgColor = (int)value;
216  if (fgColor<0) fgColor = 0;
217  if (fgColor>255) fgColor = 255;
218  }
219 
223  public void putPixelValue(int x, int y, double value) {
224  if (x>=0 && x<width && y>=0 && y<height) {
225  if (value>255.0)
226  value = 255.0;
227  else if (value<0.0)
228  value = 0.0;
229  pixels[y*width + x] = (byte)(value+0.5);
230  }
231  }
232 
236  public void putPixel(int x, int y, int value) {
237  if (x>=0 && x<width && y>=0 && y<height)
238  if (value>255) value = 255;
239  if (value<0) value = 0;
240  pixels[y*width + x] = (byte)value;
241  }
242 
244  public void drawPixel(int x, int y) {
245  if (x>=clipXMin && x<=clipXMax && y>=clipYMin && y<=clipYMax)
246  pixels[y*width + x] = (byte)fgColor;
247  }
248 
252  public Object getPixels() {
253  return (Object)pixels;
254  }
255 
258  public Object getPixelsCopy() {
259  if (snapshotPixels!=null && newSnapshot)
260  return snapshotPixels;
261  else {
262  byte[] pixels2 = new byte[width*height];
263  System.arraycopy(pixels, 0, pixels2, 0, width*height);
264  return pixels2;
265  }
266  }
267 
268  public void setPixels(Object pixels) {
269  if (pixels!=null && this.pixels!=null && (((byte[])pixels).length!=this.pixels.length))
270  throw new IllegalArgumentException("");
271  this.pixels = (byte[])pixels;
272  resetPixels(pixels);
273  snapshotPixels = null;
274  }
275 
276  /*
277  public void getRow(int x, int y, int[] data, int length) {
278  int j = y*width+x;
279  for (int i=0; i<length; i++)
280  data[i] = pixels[j++];
281  }
282 
283  public void putRow(int x, int y, int[] data, int length) {
284  int j = y*width+x;
285  for (int i=0; i<length; i++)
286  pixels[j++] = (byte)data[i];
287  }
288  */
289 
291  public double getMin() {
292  return min;
293  }
294 
296  public double getMax() {
297  return max;
298  }
299 
301  public void setMinAndMax(double min, double max) {
302  if (max<min)
303  return;
304  this.min = (int)min;
305  this.max = (int)max;
306 
307  if (rLUT1==null) {
308  if (cm==null)
309  makeDefaultColorModel();
310  baseCM = cm;
311  IndexColorModel m = (IndexColorModel)cm;
312  rLUT1 = new byte[256]; gLUT1 = new byte[256]; bLUT1 = new byte[256];
313  m.getReds(rLUT1); m.getGreens(gLUT1); m.getBlues(bLUT1);
314  rLUT2 = new byte[256]; gLUT2 = new byte[256]; bLUT2 = new byte[256];
315  }
316  int index;
317  for (int i=0; i<256; i++) {
318  if (i<min) {
319  rLUT2[i] = rLUT1[0];
320  gLUT2[i] = gLUT1[0];
321  bLUT2[i] = bLUT1[0];
322  } else if (i>max) {
323  rLUT2[i] = rLUT1[255];
324  gLUT2[i] = gLUT1[255];
325  bLUT2[i] = bLUT1[255];
326  } else {
327  index = i-this.min;
328  index = (int)(256.0*index/(max-min));
329  if (index < 0)
330  index = 0;
331  if (index > 255)
332  index = 255;
333  rLUT2[i] = rLUT1[index];
334  gLUT2[i] = gLUT1[index];
335  bLUT2[i] = bLUT1[index];
336  }
337  }
338  cm = new IndexColorModel(8, 256, rLUT2, gLUT2, bLUT2);
339  newPixels = true;
340  minThreshold = NO_THRESHOLD;
341  }
342 
344  public void resetMinAndMax() {
345  setMinAndMax(0, 255);
346  }
347 
350  public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode) {
351  if (!(ip instanceof ByteProcessor || ip instanceof ColorProcessor))
352  throw new IllegalArgumentException("8-bit or RGB image required");
353  new ByteBlitter(this).copyBits(ip, xloc, yloc, mode);
354  }
355 
356  /* Filters start here */
357 
358  public void applyTable(int[] lut) {
359  int lineStart, lineEnd;
360  for (int y=roiY; y<(roiY+roiHeight); y++) {
361  lineStart = y * width + roiX;
362  lineEnd = lineStart + roiWidth;
363  for (int i=lineEnd; --i>=lineStart;)
364  pixels[i] = (byte)lut[pixels[i]&0xff];
365  }
366  }
367 
369  public void convolve3x3(int[] kernel) {
370  int p1, p2, p3,
371  p4, p5, p6,
372  p7, p8, p9;
373  int k1=kernel[0], k2=kernel[1], k3=kernel[2],
374  k4=kernel[3], k5=kernel[4], k6=kernel[5],
375  k7=kernel[6], k8=kernel[7], k9=kernel[8];
376 
377  int scale = 0;
378  for (int i=0; i<kernel.length; i++)
379  scale += kernel[i];
380  if (scale==0) scale = 1;
381  int inc = roiHeight/25;
382  if (inc<1) inc = 1;
383 
384  byte[] pixels2 = (byte[])getPixelsCopy();
385  int offset, sum;
386  int rowOffset = width;
387  for (int y=yMin; y<=yMax; y++) {
388  offset = xMin + y * width;
389  p1 = 0;
390  p2 = pixels2[offset-rowOffset-1]&0xff;
391  p3 = pixels2[offset-rowOffset]&0xff;
392  p4 = 0;
393  p5 = pixels2[offset-1]&0xff;
394  p6 = pixels2[offset]&0xff;
395  p7 = 0;
396  p8 = pixels2[offset+rowOffset-1]&0xff;
397  p9 = pixels2[offset+rowOffset]&0xff;
398 
399  for (int x=xMin; x<=xMax; x++) {
400  p1 = p2; p2 = p3;
401  p3 = pixels2[offset-rowOffset+1]&0xff;
402  p4 = p5; p5 = p6;
403  p6 = pixels2[offset+1]&0xff;
404  p7 = p8; p8 = p9;
405  p9 = pixels2[offset+rowOffset+1]&0xff;
406 
407  sum = k1*p1 + k2*p2 + k3*p3
408  + k4*p4 + k5*p5 + k6*p6
409  + k7*p7 + k8*p8 + k9*p9;
410  sum /= scale;
411 
412  if(sum>255) sum= 255;
413  if(sum<0) sum= 0;
414 
415  pixels[offset++] = (byte)sum;
416  }
417  if (y%inc==0)
418  showProgress((double)(y-roiY)/roiHeight);
419  }
420  hideProgress();
421  }
422 
424  public void filter(int type) {
425  int p1, p2, p3, p4, p5, p6, p7, p8, p9;
426  int inc = roiHeight/25;
427  if (inc<1) inc = 1;
428 
429  byte[] pixels2 = (byte[])getPixelsCopy();
430  int offset, sum1, sum2=0, sum=0;
431  int[] values = new int[10];
432  if (type==MEDIAN_FILTER) values = new int[10];
433  int rowOffset = width;
434  int count = 0;
435  for (int y=yMin; y<=yMax; y++) {
436  offset = xMin + y * width;
437  p2 = pixels2[offset-rowOffset-1]&0xff;
438  p3 = pixels2[offset-rowOffset]&0xff;
439  p5 = pixels2[offset-1]&0xff;
440  p6 = pixels2[offset]&0xff;
441  p8 = pixels2[offset+rowOffset-1]&0xff;
442  p9 = pixels2[offset+rowOffset]&0xff;
443 
444  for (int x=xMin; x<=xMax; x++) {
445  p1 = p2; p2 = p3;
446  p3 = pixels2[offset-rowOffset+1]&0xff;
447  p4 = p5; p5 = p6;
448  p6 = pixels2[offset+1]&0xff;
449  p7 = p8; p8 = p9;
450  p9 = pixels2[offset+rowOffset+1]&0xff;
451 
452  switch (type) {
453  case BLUR_MORE:
454  sum = (p1+p2+p3+p4+p5+p6+p7+p8+p9)/9;
455  break;
456  case FIND_EDGES: // 3x3 Sobel filter
457  sum1 = p1 + 2*p2 + p3 - p7 - 2*p8 - p9;
458  sum2 = p1 + 2*p4 + p7 - p3 - 2*p6 - p9;
459  sum = (int)Math.sqrt(sum1*sum1 + sum2*sum2);
460  if (sum> 255) sum = 255;
461  break;
462  case MEDIAN_FILTER:
463  values[1]=p1; values[2]=p2; values[3]=p3; values[4]=p4; values[5]=p5;
464  values[6]=p6; values[7]=p7; values[8]=p8; values[9]=p9;
465  sum = findMedian(values);
466  break;
467  case MIN:
468  sum = p5;
469  if (p1<sum) sum = p1;
470  if (p2<sum) sum = p2;
471  if (p3<sum) sum = p3;
472  if (p4<sum) sum = p4;
473  if (p6<sum) sum = p6;
474  if (p7<sum) sum = p7;
475  if (p8<sum) sum = p8;
476  if (p9<sum) sum = p9;
477  break;
478  case MAX:
479  sum = p5;
480  if (p1>sum) sum = p1;
481  if (p2>sum) sum = p2;
482  if (p3>sum) sum = p3;
483  if (p4>sum) sum = p4;
484  if (p6>sum) sum = p6;
485  if (p7>sum) sum = p7;
486  if (p8>sum) sum = p8;
487  if (p9>sum) sum = p9;
488  break;
489  }
490 
491  pixels[offset++] = (byte)sum;
492  }
493  if (y%inc==0)
494  showProgress((double)(y-roiY)/roiHeight);
495  }
496  hideProgress();
497  }
498 
499  public void erode() {
500  if (isInvertedLut())
501  filter(MIN);
502  else
503  filter(MAX);
504  }
505 
506  public void dilate() {
507  if (isInvertedLut())
508  filter(MAX);
509  else
510  filter(MIN);
511  }
512 
513  public void outline() {
514  new BinaryProcessor(this).outline();
515  }
516 
517  public void skeletonize() {
518  new BinaryProcessor(this).skeletonize();
519  }
520 
521  private final int findMedian (int[] values) {
522  //Finds the 5th largest of 9 values
523  for (int i = 1; i <= 4; i++) {
524  int max = 0;
525  int mj = 1;
526  for (int j = 1; j <= 9; j++)
527  if (values[j] > max) {
528  max = values[j];
529  mj = j;
530  }
531  values[mj] = 0;
532  }
533  int max = 0;
534  for (int j = 1; j <= 9; j++)
535  if (values[j] > max)
536  max = values[j];
537  return max;
538  }
539 
540  public void medianFilter() {
541  filter(MEDIAN_FILTER);
542  }
543 
544  public void noise(double range) {
545  Random rnd=new Random();
546  int v;
547 
548  for (int y=roiY; y<(roiY+roiHeight); y++) {
549  int i = y * width + roiX;
550  for (int x=roiX; x<(roiX+roiWidth); x++) {
551  int RandomBrightness = (int)Math.round(rnd.nextGaussian()*range);
552  v = (pixels[i] & 0xff) + RandomBrightness;
553  if (v < 0)
554  v = 0;
555  if (v > 255)
556  v = 255;
557  pixels[i] = (byte)v;
558  i++;
559  }
560  if (y%10==0)
561  showProgress((double)(y-roiY)/roiHeight);
562  }
563  hideProgress();
564  }
565 
569  public void scale(double xScale, double yScale) {
570  double xCenter = roiX + roiWidth/2.0;
571  double yCenter = roiY + roiHeight/2.0;
572  int xmin, xmax, ymin, ymax;
573  if (isInvertedLut()) bgColor = 0;
574 
575  if ((xScale>1.0) && (yScale>1.0)) {
576  //expand roi
577  xmin = (int)(xCenter-(xCenter-roiX)*xScale);
578  if (xmin<0) xmin = 0;
579  xmax = xmin + (int)(roiWidth*xScale) - 1;
580  if (xmax>=width) xmax = width - 1;
581  ymin = (int)(yCenter-(yCenter-roiY)*yScale);
582  if (ymin<0) ymin = 0;
583  ymax = ymin + (int)(roiHeight*yScale) - 1;
584  if (ymax>=height) ymax = height - 1;
585  } else {
586  xmin = roiX;
587  xmax = roiX + roiWidth - 1;
588  ymin = roiY;
589  ymax = roiY + roiHeight - 1;
590  }
591  byte[] pixels2 = (byte[])getPixelsCopy();
592  boolean checkCoordinates = (xScale < 1.0) || (yScale < 1.0);
593  int index1, index2, xsi, ysi;
594  double ys, xs;
595  double xlimit = width-1.0, xlimit2 = width-1.001;
596  double ylimit = height-1.0, ylimit2 = height-1.001;
597  for (int y=ymin; y<=ymax; y++) {
598  ys = (y-yCenter)/yScale + yCenter;
599  ysi = (int)ys;
600  if (ys<0.0) ys = 0.0;
601  if (ys>=ylimit) ys = ylimit2;
602  index1 = y*width + xmin;
603  index2 = width*(int)ys;
604  for (int x=xmin; x<=xmax; x++) {
605  xs = (x-xCenter)/xScale + xCenter;
606  xsi = (int)xs;
607  if (checkCoordinates && ((xsi<xmin) || (xsi>xmax) || (ysi<ymin) || (ysi>ymax)))
608  pixels[index1++] = (byte)bgColor;
609  else {
610  if (interpolate) {
611  if (xs<0.0) xs = 0.0;
612  if (xs>=xlimit) xs = xlimit2;
613  pixels[index1++] =(byte)((int)(getInterpolatedPixel(xs, ys, pixels2)+0.5)&255);
614  } else
615  pixels[index1++] = pixels2[index2+xsi];
616  }
617  }
618  if (y%20==0)
619  showProgress((double)(y-ymin)/height);
620  }
621  hideProgress();
622  }
623 
625  private final double getInterpolatedPixel(double x, double y, byte[] pixels) {
626  int xbase = (int)x;
627  int ybase = (int)y;
628  double xFraction = x - xbase;
629  double yFraction = y - ybase;
630  int offset = ybase * width + xbase;
631  int lowerLeft = pixels[offset]&255;
632  //if ((xbase>=(width-1))||(ybase>=(height-1)))
633  // return lowerLeft;
634  int lowerRight = pixels[offset + 1]&255;
635  int upperRight = pixels[offset + width + 1]&255;
636  int upperLeft = pixels[offset + width]&255;
637  double upperAverage = upperLeft + xFraction * (upperRight - upperLeft);
638  double lowerAverage = lowerLeft + xFraction * (lowerRight - lowerLeft);
639  return lowerAverage + yFraction * (upperAverage - lowerAverage);
640  }
641 
645  public ImageProcessor resize(int dstWidth, int dstHeight) {
646  if (roiWidth==dstWidth && roiHeight==dstHeight)
647  return crop();
648  double srcCenterX = roiX + roiWidth/2.0;
649  double srcCenterY = roiY + roiHeight/2.0;
650  double dstCenterX = dstWidth/2.0;
651  double dstCenterY = dstHeight/2.0;
652  double xScale = (double)dstWidth/roiWidth;
653  double yScale = (double)dstHeight/roiHeight;
654  if (interpolate) {
655  dstCenterX += xScale/2.0;
656  dstCenterY += yScale/2.0;
657  }
658  ImageProcessor ip2 = createProcessor(dstWidth, dstHeight);
659  byte[] pixels2 = (byte[])ip2.getPixels();
660  double xs, ys;
661  double xlimit = width-1.0, xlimit2 = width-1.001;
662  double ylimit = height-1.0, ylimit2 = height-1.001;
663  int index1, index2;
664  for (int y=0; y<=dstHeight-1; y++) {
665  ys = (y-dstCenterY)/yScale + srcCenterY;
666  if (interpolate) {
667  if (ys<0.0) ys = 0.0;
668  if (ys>=ylimit) ys = ylimit2;
669  }
670  index1 = width*(int)ys;
671  index2 = y*dstWidth;
672  for (int x=0; x<=dstWidth-1; x++) {
673  xs = (x-dstCenterX)/xScale + srcCenterX;
674  if (interpolate) {
675  if (xs<0.0) xs = 0.0;
676  if (xs>=xlimit) xs = xlimit2;
677  pixels2[index2++] = (byte)((int)(getInterpolatedPixel(xs, ys, pixels)+0.5)&255);
678  } else
679  pixels2[index2++] = pixels[index1+(int)xs];
680  }
681  if (y%20==0)
682  showProgress((double)y/dstHeight);
683  }
684  hideProgress();
685  return ip2;
686  }
687 
691  public void rotate(double angle) {
692  if (angle%360==0)
693  return;
694  byte[] pixels2 = (byte[])getPixelsCopy();
695  double centerX = roiX + (roiWidth-1)/2.0;
696  double centerY = roiY + (roiHeight-1)/2.0;
697  int xMax = roiX + this.roiWidth - 1;
698  if (isInvertedLut()) bgColor = 0;
699 
700  double angleRadians = -angle/(180.0/Math.PI);
701  double ca = Math.cos(angleRadians);
702  double sa = Math.sin(angleRadians);
703  double tmp1 = centerY*sa-centerX*ca;
704  double tmp2 = -centerX*sa-centerY*ca;
705  double tmp3, tmp4, xs, ys;
706  int index, ixs, iys;
707  double dwidth=width, dheight=height;
708  double xlimit = width-1.0, xlimit2 = width-1.001;
709  double ylimit = height-1.0, ylimit2 = height-1.001;
710 
711  for (int y=roiY; y<(roiY + roiHeight); y++) {
712  index = y*width + roiX;
713  tmp3 = tmp1 - y*sa + centerX;
714  tmp4 = tmp2 + y*ca + centerY;
715  for (int x=roiX; x<=xMax; x++) {
716  xs = x*ca + tmp3;
717  ys = x*sa + tmp4;
718  if ((xs>=-0.01) && (xs<dwidth) && (ys>=-0.01) && (ys<dheight)) {
719  if (interpolate) {
720  if (xs<0.0) xs = 0.0;
721  if (xs>=xlimit) xs = xlimit2;
722  if (ys<0.0) ys = 0.0;
723  if (ys>=ylimit) ys = ylimit2;
724  pixels[index++] = (byte)((int)(getInterpolatedPixel(xs, ys, pixels2)+0.5)&255);
725  } else {
726  ixs = (int)(xs+0.5);
727  iys = (int)(ys+0.5);
728  if (ixs>=width) ixs = width - 1;
729  if (iys>=height) iys = height -1;
730  pixels[index++] = pixels2[width*iys+ixs];
731  }
732  } else
733  pixels[index++] = (byte)bgColor;
734  }
735  if (y%30==0)
736  showProgress((double)(y-roiY)/roiHeight);
737  }
738  hideProgress();
739  }
740 
741  public void flipVertical() {
742  int index1,index2;
743  byte tmp;
744  for (int y=0; y<roiHeight/2; y++) {
745  index1 = (roiY+y)*width+roiX;
746  index2 = (roiY+roiHeight-1-y)*width+roiX;
747  for (int i=0; i<roiWidth; i++) {
748  tmp = pixels[index1];
749  pixels[index1++] = pixels[index2];
750  pixels[index2++] = tmp;
751  }
752  }
753  newSnapshot = false;
754  }
755 
756  public int[] getHistogram() {
757  if (mask!=null)
758  return getHistogram(mask);
759  int[] histogram = new int[256];
760  for (int y=roiY; y<(roiY+roiHeight); y++) {
761  int i = y * width + roiX;
762  for (int x=roiX; x<(roiX+roiWidth); x++) {
763  int v = pixels[i++] & 0xff;
764  histogram[v]++;
765  }
766  }
767  return histogram;
768  }
769 
770  public int[] getHistogram(ImageProcessor mask) {
771  if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
772  throw new IllegalArgumentException(maskSizeError(mask));
773  int v;
774  int[] histogram = new int[256];
775  byte[] mpixels = (byte[])mask.getPixels();
776  for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
777  int i = y * width + roiX;
778  int mi = my * roiWidth;
779  for (int x=roiX; x<(roiX+roiWidth); x++) {
780  if (mpixels[mi++]!=0) {
781  v = pixels[i] & 0xff;
782  histogram[v]++;
783  }
784  i++;
785  }
786  }
787  return histogram;
788  }
789 
791  public void threshold(int level) {
792  for (int i=0; i<width*height; i++) {
793  if ((pixels[i] & 0xff) <= level)
794  pixels[i] = 0;
795  else
796  pixels[i] = (byte)255;
797  }
798  newSnapshot = false;
799  }
800 
801  public void applyLut() {
802  if (rLUT2==null)
803  return;
804  if (isInvertedLut())
805  for (int i=0; i<width*height; i++)
806  pixels[i] = (byte)(255 - rLUT2[pixels[i]&0xff]);
807  else
808  for (int i=0; i<width*height; i++)
809  pixels[i] = rLUT2[pixels[i] & 0xff];
810  setMinAndMax(0, 255);
811  }
812 
814  public void convolve(float[] kernel, int kernelWidth, int kernelHeight) {
816  ip2.setRoi(getRoi());
817  new ij.plugin.filter.Convolver().convolve(ip2, kernel, kernelWidth, kernelHeight);
818  ip2 = ip2.convertToByte(false);
819  byte[] pixels2 = (byte[])ip2.getPixels();
820  System.arraycopy(pixels2, 0, pixels, 0, pixels.length);
821  }
822 
823 }
824