Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
ColorProcessor.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 ColorProcessor extends ImageProcessor {
13 
14  protected int[] pixels;
15  protected int[] snapshotPixels = null;
16  private int bgColor = 0xffffffff; //white
17  private int min=0, max=255;
18 
19  // Weighting factors used by getPixelValue(), getHistogram() and convertToByte().
20  // For unweighted conversions, check "Unweighted Color Conversion" in <i>Edit/Options/Conversions</i>.
21  private static double rWeight=0.299, gWeight=0.587, bWeight=0.114;
22 
24  public ColorProcessor(Image img) {
25  width = img.getWidth(null);
26  height = img.getHeight(null);
27  pixels = new int[width * height];
28  PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
29  try {
30  pg.grabPixels();
31  } catch (InterruptedException e){};
32  createColorModel();
33  fgColor = 0xff000000; //black
34  resetRoi();
35  }
36 
38  public ColorProcessor(int width, int height) {
39  this(width, height, new int[width*height]);
40  }
41 
43  public ColorProcessor(int width, int height, int[] pixels) {
44  if (pixels!=null && width*height!=pixels.length)
45  throw new IllegalArgumentException(WRONG_LENGTH);
46  this.width = width;
47  this.height = height;
48  createColorModel();
49  fgColor = 0xff000000; //black
50  resetRoi();
51  this.pixels = pixels;
52  }
53 
54 
55  void createColorModel() {
56  cm = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
57  }
58 
59  public Image createImage() {
60  if (source==null || (ij.IJ.isMacintosh()&&!ij.IJ.isJava2())) {
61  source = new MemoryImageSource(width, height, cm, pixels, 0, width);
62  source.setAnimated(true);
63  source.setFullBufferUpdates(true);
64  img = Toolkit.getDefaultToolkit().createImage(source);
65  } else if (newPixels) {
66  source.newPixels(pixels, cm, 0, width);
67  newPixels = false;
68  } else
69  source.newPixels();
70  return img;
71  }
72 
73 
75  public ImageProcessor createProcessor(int width, int height) {
76  int[] pixels = new int[width*height];
77  for (int i=0; i<width*height; i++)
78  pixels[i] = -1;
79  return new ColorProcessor(width, height, pixels);
80  }
81 
82  public Color getColor(int x, int y) {
83  int c = pixels[y*width+x];
84  int r = (c&0xff0000)>>16;
85  int g = (c&0xff00)>>8;
86  int b = c&0xff;
87  return new Color(r,g,b);
88  }
89 
90 
92  public void setColor(Color color) {
93  fgColor = color.getRGB();
94  drawingColor = color;
95  }
96 
97 
99  public void setValue(double value) {
100  fgColor = (int)value;
101  }
102 
104  public double getMin() {
105  return min;
106  }
107 
108 
110  public double getMax() {
111  return max;
112  }
113 
114 
116  public void setMinAndMax(double min, double max) {
117  setMinAndMax(min, max, 7);
118  }
119 
120 
121  public void setMinAndMax(double min, double max, int channels) {
122  if (max<min)
123  return;
124  this.min = (int)min;
125  this.max = (int)max;
126  int v;
127  int[] lut = new int[256];
128  for (int i=0; i<256; i++) {
129  v = i-this.min;
130  v = (int)(256.0*v/(max-min));
131  if (v < 0)
132  v = 0;
133  if (v > 255)
134  v = 255;
135  lut[i] = v;
136  }
137  reset();
138  if (channels==7)
139  applyTable(lut);
140  else
141  applyTable(lut, channels);
142  }
143 
144  public void snapshot() {
145  snapshotWidth = width;
146  snapshotHeight = height;
147  if (snapshotPixels==null || (snapshotPixels!=null && snapshotPixels.length!=pixels.length))
148  snapshotPixels = new int[width * height];
149  System.arraycopy(pixels, 0, snapshotPixels, 0, width*height);
150  newSnapshot = true;
151  }
152 
153 
154  public void reset() {
155  if (snapshotPixels==null)
156  return;
157  System.arraycopy(snapshotPixels, 0, pixels, 0, width*height);
158  newSnapshot = true;
159  }
160 
161 
162  public void reset(ImageProcessor mask) {
163  if (mask==null || snapshotPixels==null)
164  return;
165  if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
166  throw new IllegalArgumentException(maskSizeError(mask));
167  byte[] mpixels = (byte[])mask.getPixels();
168  for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
169  int i = y * width + roiX;
170  int mi = my * roiWidth;
171  for (int x=roiX; x<(roiX+roiWidth); x++) {
172  if (mpixels[mi++]==0)
173  pixels[i] = snapshotPixels[i];
174  i++;
175  }
176  }
177  }
178 
179 
183  public void fill(ImageProcessor mask) {
184  if (mask==null)
185  {fill(); return;}
186  if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
187  throw new IllegalArgumentException(maskSizeError(mask));
188  byte[] mpixels = (byte[])mask.getPixels();
189  for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
190  int i = y * width + roiX;
191  int mi = my * roiWidth;
192  for (int x=roiX; x<(roiX+roiWidth); x++) {
193  if (mpixels[mi++]!=0)
194  pixels[i] = fgColor;
195  i++;
196  }
197  }
198  }
199 
200 
201  public Object getPixelsCopy() {
202  if (newSnapshot)
203  return snapshotPixels;
204  else {
205  int[] pixels2 = new int[width*height];
206  System.arraycopy(pixels, 0, pixels2, 0, width*height);
207  return pixels2;
208  }
209  }
210 
211 
213  public Object getSnapshotPixels() {
214  return snapshotPixels;
215  }
216 
217  public int getPixel(int x, int y) {
218  if (x>=0 && x<width && y>=0 && y<height)
219  return pixels[y*width+x];
220  else
221  return 0;
222  }
223 
224 
228  public int[] getPixel(int x, int y, int[] iArray) {
229  if (iArray==null) iArray = new int[3];
230  int c = getPixel(x, y);
231  iArray[0] = (c&0xff0000)>>16;
232  iArray[1] = (c&0xff00)>>8;
233  iArray[2] = c&0xff;
234  return iArray;
235  }
236 
239  public void putPixel(int x, int y, int[] iArray) {
240  int r=iArray[0], g=iArray[1], b=iArray[2];
241  putPixel(x, y, 0xff000000+(r<<16)+(g<<8)+b);
242  }
243 
245  public double getInterpolatedPixel(double x, double y) {
246  int ix = (int)(x+0.5);
247  int iy = (int)(y+0.5);
248  if (ix<0) ix = 0;
249  if (ix>=width) ix = width-1;
250  if (iy<0) iy = 0;
251  if (iy>=height) iy = height-1;
252  return getPixelValue(ix, iy);
253  }
254 
256  public void putPixel(int x, int y, int value) {
257  if (x>=0 && x<width && y>=0 && y<height)
258  pixels[y*width + x] = value|0xff000000;
259  }
260 
264  public void putPixelValue(int x, int y, double value) {
265  if (x>=0 && x<width && y>=0 && y<height) {
266  if (value>255.0)
267  value = 255;
268  else if (value<0.0)
269  value = 0.0;
270  int gray = (int)(value+0.5);
271  pixels[y*width + x] = 0xff000000 + (gray<<16) + (gray<<8) + gray;
272 
273  }
274  }
275 
279  public float getPixelValue(int x, int y) {
280  if (x>=0 && x<width && y>=0 && y<height) {
281  int c = pixels[y*width+x];
282  int r = (c&0xff0000)>>16;
283  int g = (c&0xff00)>>8;
284  int b = c&0xff;
285  return (float)(r*rWeight + g*gWeight + b*bWeight);
286  }
287  else
288  return 0;
289  }
290 
291 
293  public void drawPixel(int x, int y) {
294  if (x>=clipXMin && x<=clipXMax && y>=clipYMin && y<=clipYMax)
295  pixels[y*width + x] = fgColor;
296  }
297 
298 
301  public Object getPixels() {
302  return (Object)pixels;
303  }
304 
305 
306  public void setPixels(Object pixels) {
307  this.pixels = (int[])pixels;
308  resetPixels(pixels);
309  snapshotPixels = null;
310  }
311 
312 
314  public void getHSB(byte[] H, byte[] S, byte[] B) {
315  int c, r, g, b;
316  float[] hsb = new float[3];
317  for (int i=0; i < width*height; i++) {
318  c = pixels[i];
319  r = (c&0xff0000)>>16;
320  g = (c&0xff00)>>8;
321  b = c&0xff;
322  hsb = Color.RGBtoHSB(r, g, b, hsb);
323  H[i] = (byte)((int)(hsb[0]*255.0));
324  S[i] = (byte)((int)(hsb[1]*255.0));
325  B[i] = (byte)((int)(hsb[2]*255.0));
326  }
327  }
328 
329 
332  int c, r, g, b;
333  int size = width*height;
334  float[] brightness = new float[size];
335  float[] hsb = new float[3];
336  for (int i=0; i<size; i++) {
337  c = pixels[i];
338  r = (c&0xff0000)>>16;
339  g = (c&0xff00)>>8;
340  b = c&0xff;
341  hsb = Color.RGBtoHSB(r, g, b, hsb);
342  brightness[i] = hsb[2];
343  }
344  return new FloatProcessor(width, height, brightness, null);
345  }
346 
348  public void getRGB(byte[] R, byte[] G, byte[] B) {
349  int c, r, g, b;
350  for (int i=0; i < width*height; i++) {
351  c = pixels[i];
352  r = (c&0xff0000)>>16;
353  g = (c&0xff00)>>8;
354  b = c&0xff;
355  R[i] = (byte)r;
356  G[i] = (byte)g;
357  B[i] = (byte)b;
358  }
359  }
360 
361 
363  public void setRGB(byte[] R, byte[] G, byte[] B) {
364  int c, r, g, b;
365  for (int i=0; i < width*height; i++)
366  pixels[i] = 0xff000000 | ((R[i]&0xff)<<16) | ((G[i]&0xff)<<8) | B[i]&0xff;
367  }
368 
369 
371  public void setHSB(byte[] H, byte[] S, byte[] B) {
372  float hue, saturation, brightness;
373  for (int i=0; i < width*height; i++) {
374  hue = (float)((H[i]&0xff)/255.0);
375  saturation = (float)((S[i]&0xff)/255.0);
376  brightness = (float)((B[i]&0xff)/255.0);
377  pixels[i] = Color.HSBtoRGB(hue, saturation, brightness);
378  }
379  }
380 
382  public void setBrightness(FloatProcessor fp) {
383  int c, r, g, b;
384  int size = width*height;
385  float[] hsb = new float[3];
386  float[] brightness = (float[])fp.getPixels();
387  if (brightness.length!=size)
388  throw new IllegalArgumentException("fp is wrong size");
389  for (int i=0; i<size; i++) {
390  c = pixels[i];
391  r = (c&0xff0000)>>16;
392  g = (c&0xff00)>>8;
393  b = c&0xff;
394  hsb = Color.RGBtoHSB(r, g, b, hsb);
395  float bvalue = brightness[i];
396  if (bvalue<0f) bvalue = 0f;
397  if (bvalue>1.0f) bvalue = 1.0f;
398  pixels[i] = Color.HSBtoRGB(hsb[0], hsb[1], bvalue);
399  }
400  }
401 
404  public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode) {
405  if (!((ip instanceof ColorProcessor) | (ip instanceof ByteProcessor)))
406  throw new IllegalArgumentException("8-bit or RGB image required");
407  new ColorBlitter(this).copyBits(ip, xloc, yloc, mode);
408  }
409 
410  /* Filters start here */
411 
412  public void applyTable(int[] lut) {
413  int c, r, g, b;
414  for (int y=roiY; y<(roiY+roiHeight); y++) {
415  int i = y * width + roiX;
416  for (int x=roiX; x<(roiX+roiWidth); x++) {
417  c = pixels[i];
418  r = lut[(c&0xff0000)>>16];
419  g = lut[(c&0xff00)>>8];
420  b = lut[c&0xff];
421  pixels[i] = 0xff000000 + (r<<16) + (g<<8) + b;
422  i++;
423  }
424  }
425  hideProgress();
426  }
427 
428  public void applyTable(int[] lut, int channels) {
429  int c, r=0, g=0, b=0;
430  for (int y=roiY; y<(roiY+roiHeight); y++) {
431  int i = y * width + roiX;
432  for (int x=roiX; x<(roiX+roiWidth); x++) {
433  c = pixels[i];
434  if (channels==4) {
435  r = lut[(c&0xff0000)>>16];
436  g = (c&0xff00)>>8;
437  b = c&0xff;
438  } else if (channels==2) {
439  r = (c&0xff0000)>>16;
440  g = lut[(c&0xff00)>>8];
441  b = c&0xff;
442  } else if (channels==1) {
443  r = (c&0xff0000)>>16;
444  g = (c&0xff00)>>8;
445  b = lut[c&0xff];
446  } else if ((channels&6)==6) {
447  r = lut[(c&0xff0000)>>16];
448  g = lut[(c&0xff00)>>8];
449  b = c&0xff;
450  } else if ((channels&5)==5) {
451  r = lut[(c&0xff0000)>>16];
452  g = (c&0xff00)>>8;
453  b = lut[c&0xff];
454  } else if ((channels&3)==3) {
455  r = (c&0xff0000)>>16;
456  g = lut[(c&0xff00)>>8];
457  b = lut[c&0xff];
458  }
459  pixels[i] = 0xff000000 + (r<<16) + (g<<8) + b;
460  i++;
461  }
462  }
463  hideProgress();
464  }
465 
467  public void fill() {
468  for (int y=roiY; y<(roiY+roiHeight); y++) {
469  int i = y * width + roiX;
470  for (int x=roiX; x<(roiX+roiWidth); x++)
471  pixels[i++] = fgColor;
472  if (y%20==0)
473  showProgress((double)(y-roiY)/roiHeight);
474  }
475  hideProgress();
476  }
477 
478 
479  public final int RGB_NOISE=0, RGB_MEDIAN=1, RGB_FIND_EDGES=2,
480  RGB_ERODE=3, RGB_DILATE=4, RGB_THRESHOLD=5;
481 
483  public void filterRGB(int type, double arg) {
484  showProgress(0.01);
485  byte[] R = new byte[width*height];
486  byte[] G = new byte[width*height];
487  byte[] B = new byte[width*height];
488  getRGB(R, G, B);
489  Rectangle roi = new Rectangle(roiX, roiY, roiWidth, roiHeight);
490 
491  ByteProcessor r = new ByteProcessor(width, height, R, null);
492  r.setRoi(roi);
493  ByteProcessor g = new ByteProcessor(width, height, G, null);
494  g.setRoi(roi);
495  ByteProcessor b = new ByteProcessor(width, height, B, null);
496  b.setRoi(roi);
497 
498  showProgress(0.15);
499  switch (type) {
500  case RGB_NOISE:
501  r.noise(arg); showProgress(0.40);
502  g.noise(arg); showProgress(0.65);
503  b.noise(arg); showProgress(0.90);
504  break;
505  case RGB_MEDIAN:
506  r.medianFilter(); showProgress(0.40);
507  g.medianFilter(); showProgress(0.65);
508  b.medianFilter(); showProgress(0.90);
509  break;
510  case RGB_FIND_EDGES:
511  r.findEdges(); showProgress(0.40);
512  g.findEdges(); showProgress(0.65);
513  b.findEdges(); showProgress(0.90);
514  break;
515  case RGB_ERODE:
516  r.erode(); showProgress(0.40);
517  g.erode(); showProgress(0.65);
518  b.erode(); showProgress(0.90);
519  break;
520  case RGB_DILATE:
521  r.dilate(); showProgress(0.40);
522  g.dilate(); showProgress(0.65);
523  b.dilate(); showProgress(0.90);
524  break;
525  case RGB_THRESHOLD:
526  r.autoThreshold(); showProgress(0.40);
527  g.autoThreshold(); showProgress(0.65);
528  b.autoThreshold(); showProgress(0.90);
529  break;
530  }
531 
532  R = (byte[])r.getPixels();
533  G = (byte[])g.getPixels();
534  B = (byte[])b.getPixels();
535 
536  setRGB(R, G, B);
537  hideProgress();
538  }
539 
540  public void noise(double range) {
541  filterRGB(RGB_NOISE, range);
542  }
543 
544  public void medianFilter() {
545  filterRGB(RGB_MEDIAN, 0.0);
546  }
547 
548  public void findEdges() {
549  filterRGB(RGB_FIND_EDGES, 0.0);
550  }
551 
552  public void erode() {
553  filterRGB(RGB_ERODE, 0.0);
554  }
555 
556  public void dilate() {
557  filterRGB(RGB_DILATE, 0.0);
558 
559  }
560 
561  public void autoThreshold() {
562  filterRGB(RGB_THRESHOLD, 0.0);
563  }
564 
568  public void scale(double xScale, double yScale) {
569  double xCenter = roiX + roiWidth/2.0;
570  double yCenter = roiY + roiHeight/2.0;
571  int xmin, xmax, ymin, ymax;
572 
573  if ((xScale>1.0) && (yScale>1.0)) {
574  //expand roi
575  xmin = (int)(xCenter-(xCenter-roiX)*xScale);
576  if (xmin<0) xmin = 0;
577  xmax = xmin + (int)(roiWidth*xScale) - 1;
578  if (xmax>=width) xmax = width - 1;
579  ymin = (int)(yCenter-(yCenter-roiY)*yScale);
580  if (ymin<0) ymin = 0;
581  ymax = ymin + (int)(roiHeight*yScale) - 1;
582  if (ymax>=height) ymax = height - 1;
583  } else {
584  xmin = roiX;
585  xmax = roiX + roiWidth - 1;
586  ymin = roiY;
587  ymax = roiY + roiHeight - 1;
588  }
589  int[] pixels2 = (int[])getPixelsCopy();
590  boolean checkCoordinates = (xScale < 1.0) || (yScale < 1.0);
591  int index1, index2, xsi, ysi;
592  double ys, xs;
593  double xlimit = width-1.0, xlimit2 = width-1.001;
594  double ylimit = height-1.0, ylimit2 = height-1.001;
595  for (int y=ymin; y<=ymax; y++) {
596  ys = (y-yCenter)/yScale + yCenter;
597  ysi = (int)ys;
598  if (ys<0.0) ys = 0.0;
599  if (ys>=ylimit) ys = ylimit2;
600  index1 = y*width + xmin;
601  index2 = width*(int)ys;
602  for (int x=xmin; x<=xmax; x++) {
603  xs = (x-xCenter)/xScale + xCenter;
604  xsi = (int)xs;
605  if (checkCoordinates && ((xsi<xmin) || (xsi>xmax) || (ysi<ymin) || (ysi>ymax)))
606  pixels[index1++] = (byte)bgColor;
607  else {
608  if (interpolate) {
609  if (xs<0.0) xs = 0.0;
610  if (xs>=xlimit) xs = xlimit2;
611  pixels[index1++] = getInterpolatedPixel(xs, ys, pixels2);
612  } else
613  pixels[index1++] = pixels2[index2+xsi];
614  }
615  }
616  if (y%20==0)
617  showProgress((double)(y-ymin)/height);
618  }
619  hideProgress();
620  }
621 
622  public ImageProcessor crop() {
623  int[] pixels2 = new int[roiWidth*roiHeight];
624  for (int ys=roiY; ys<roiY+roiHeight; ys++) {
625  int offset1 = (ys-roiY)*roiWidth;
626  int offset2 = ys*width+roiX;
627  for (int xs=0; xs<roiWidth; xs++)
628  pixels2[offset1++] = pixels[offset2++];
629  }
630  return new ColorProcessor(roiWidth, roiHeight, pixels2);
631  }
632 
633 
635  public int getInterpolatedRGBPixel(double x, double y) {
636  if (x<0.0) x = 0.0;
637  if (x>=width-1.0) x = width-1.001;
638  if (y<0.0) y = 0.0;
639  if (y>=height-1.0) y = height-1.001;
640  return getInterpolatedPixel(x, y, pixels);
641  }
642 
644  private final int getInterpolatedPixel(double x, double y, int[] pixels) {
645  int xbase = (int)x;
646  int ybase = (int)y;
647  double xFraction = x - xbase;
648  double yFraction = y - ybase;
649  int offset = ybase * width + xbase;
650 
651  int lowerLeft = pixels[offset];
652  int rll = (lowerLeft&0xff0000)>>16;
653  int gll = (lowerLeft&0xff00)>>8;
654  int bll = lowerLeft&0xff;
655 
656  int lowerRight = pixels[offset + 1];
657  int rlr = (lowerRight&0xff0000)>>16;
658  int glr = (lowerRight&0xff00)>>8;
659  int blr = lowerRight&0xff;
660 
661  int upperRight = pixels[offset + width + 1];
662  int rur = (upperRight&0xff0000)>>16;
663  int gur = (upperRight&0xff00)>>8;
664  int bur = upperRight&0xff;
665 
666  int upperLeft = pixels[offset + width];
667  int rul = (upperLeft&0xff0000)>>16;
668  int gul = (upperLeft&0xff00)>>8;
669  int bul = upperLeft&0xff;
670 
671  int r, g, b;
672  double upperAverage, lowerAverage;
673  upperAverage = rul + xFraction * (rur - rul);
674  lowerAverage = rll + xFraction * (rlr - rll);
675  r = (int)(lowerAverage + yFraction * (upperAverage - lowerAverage)+0.5);
676  upperAverage = gul + xFraction * (gur - gul);
677  lowerAverage = gll + xFraction * (glr - gll);
678  g = (int)(lowerAverage + yFraction * (upperAverage - lowerAverage)+0.5);
679  upperAverage = bul + xFraction * (bur - bul);
680  lowerAverage = bll + xFraction * (blr - bll);
681  b = (int)(lowerAverage + yFraction * (upperAverage - lowerAverage)+0.5);
682 
683  return 0xff000000 | ((r&0xff)<<16) | ((g&0xff)<<8) | b&0xff;
684  }
685 
689  public ImageProcessor resize(int dstWidth, int dstHeight) {
690  double srcCenterX = roiX + roiWidth/2.0;
691  double srcCenterY = roiY + roiHeight/2.0;
692  double dstCenterX = dstWidth/2.0;
693  double dstCenterY = dstHeight/2.0;
694  double xScale = (double)dstWidth/roiWidth;
695  double yScale = (double)dstHeight/roiHeight;
696  double xlimit = width-1.0, xlimit2 = width-1.001;
697  double ylimit = height-1.0, ylimit2 = height-1.001;
698  if (interpolate) {
699  dstCenterX += xScale/2.0;
700  dstCenterY += yScale/2.0;
701  }
702  ImageProcessor ip2 = createProcessor(dstWidth, dstHeight);
703  int[] pixels2 = (int[])ip2.getPixels();
704  double xs, ys;
705  int index1, index2;
706  for (int y=0; y<=dstHeight-1; y++) {
707  ys = (y-dstCenterY)/yScale + srcCenterY;
708  if (interpolate) {
709  if (ys<0.0) ys = 0.0;
710  if (ys>=ylimit) ys = ylimit2;
711  }
712  index1 = width*(int)ys;
713  index2 = y*dstWidth;
714  for (int x=0; x<=dstWidth-1; x++) {
715  xs = (x-dstCenterX)/xScale + srcCenterX;
716  if (interpolate) {
717  if (xs<0.0) xs = 0.0;
718  if (xs>=xlimit) xs = xlimit2;
719  pixels2[index2++] = getInterpolatedPixel(xs, ys, pixels);
720  } else
721  pixels2[index2++] = pixels[index1+(int)xs];
722  }
723  if (y%20==0)
724  showProgress((double)y/dstHeight);
725  }
726  hideProgress();
727  return ip2;
728  }
729 
733  public void rotate(double angle) {
734  if (angle%360==0)
735  return;
736  int[] pixels2 = (int[])getPixelsCopy();
737  double centerX = roiX + (roiWidth-1)/2.0;
738  double centerY = roiY + (roiHeight-1)/2.0;
739  int xMax = roiX + this.roiWidth - 1;
740 
741  double angleRadians = -angle/(180.0/Math.PI);
742  double ca = Math.cos(angleRadians);
743  double sa = Math.sin(angleRadians);
744  double tmp1 = centerY*sa-centerX*ca;
745  double tmp2 = -centerX*sa-centerY*ca;
746  double tmp3, tmp4, xs, ys;
747  int index, ixs, iys;
748  double dwidth = width, dheight=height;
749  double xlimit = width-1.0, xlimit2 = width-1.001;
750  double ylimit = height-1.0, ylimit2 = height-1.001;
751 
752  for (int y=roiY; y<(roiY + roiHeight); y++) {
753  index = y*width + roiX;
754  tmp3 = tmp1 - y*sa + centerX;
755  tmp4 = tmp2 + y*ca + centerY;
756  for (int x=roiX; x<=xMax; x++) {
757  xs = x*ca + tmp3;
758  ys = x*sa + tmp4;
759  if ((xs>=-0.01) && (xs<dwidth) && (ys>=-0.01) && (ys<dheight)) {
760  if (interpolate) {
761  if (xs<0.0) xs = 0.0;
762  if (xs>=xlimit) xs = xlimit2;
763  if (ys<0.0) ys = 0.0;
764  if (ys>=ylimit) ys = ylimit2;
765  pixels[index++] = getInterpolatedPixel(xs, ys, pixels2);
766  } else {
767  ixs = (int)(xs+0.5);
768  iys = (int)(ys+0.5);
769  if (ixs>=width) ixs = width - 1;
770  if (iys>=height) iys = height -1;
771  pixels[index++] = pixels2[width*iys+ixs];
772  }
773  } else
774  pixels[index++] = bgColor;
775  }
776  if (y%30==0)
777  showProgress((double)(y-roiY)/roiHeight);
778  }
779  hideProgress();
780  }
781 
782  public void flipVertical() {
783  int index1,index2;
784  int tmp;
785  for (int y=0; y<roiHeight/2; y++) {
786  index1 = (roiY+y)*width+roiX;
787  index2 = (roiY+roiHeight-1-y)*width+roiX;
788  for (int i=0; i<roiWidth; i++) {
789  tmp = pixels[index1];
790  pixels[index1++] = pixels[index2];
791  pixels[index2++] = tmp;
792  }
793  }
794  newSnapshot = false;
795  }
796 
798  public void convolve3x3(int[] kernel) {
799  int p1, p2, p3, p4, p5, p6, p7, p8, p9;
800  int k1=kernel[0], k2=kernel[1], k3=kernel[2],
801  k4=kernel[3], k5=kernel[4], k6=kernel[5],
802  k7=kernel[6], k8=kernel[7], k9=kernel[8];
803 
804  int scale = 0;
805  for (int i=0; i<kernel.length; i++)
806  scale += kernel[i];
807  if (scale==0) scale = 1;
808  int inc = roiHeight/25;
809  if (inc<1) inc = 1;
810 
811  int[] pixels2 = (int[])getPixelsCopy();
812  int offset;
813  int rsum = 0, gsum = 0, bsum = 0;
814  int rowOffset = width;
815  for (int y=yMin; y<=yMax; y++) {
816  offset = xMin + y * width;
817  p1 = 0;
818  p2 = pixels2[offset-rowOffset-1];
819  p3 = pixels2[offset-rowOffset];
820  p4 = 0;
821  p5 = pixels2[offset-1];
822  p6 = pixels2[offset];
823  p7 = 0;
824  p8 = pixels2[offset+rowOffset-1];
825  p9 = pixels2[offset+rowOffset];
826 
827  for (int x=xMin; x<=xMax; x++) {
828  p1 = p2; p2 = p3;
829  p3 = pixels2[offset-rowOffset+1];
830  p4 = p5; p5 = p6;
831  p6 = pixels2[offset+1];
832  p7 = p8; p8 = p9;
833  p9 = pixels2[offset+rowOffset+1];
834 
835  rsum = k1*((p1 & 0xff0000) >> 16)
836  + k2*((p2 & 0xff0000) >> 16)
837  + k3*((p3 & 0xff0000) >> 16)
838  + k4*((p4 & 0xff0000) >> 16)
839  + k5*((p5 & 0xff0000) >> 16)
840  + k6*((p6 & 0xff0000) >> 16)
841  + k7*((p7 & 0xff0000) >> 16)
842  + k8*((p8 & 0xff0000) >> 16)
843  + k9*((p9 & 0xff0000) >> 16);
844  rsum /= scale;
845  if(rsum>255) rsum = 255;
846  if(rsum<0) rsum = 0;
847 
848  gsum = k1*((p1 & 0xff00) >> 8)
849  + k2*((p2 & 0xff00) >> 8)
850  + k3*((p3 & 0xff00) >> 8)
851  + k4*((p4 & 0xff00) >> 8)
852  + k5*((p5 & 0xff00) >> 8)
853  + k6*((p6 & 0xff00) >> 8)
854  + k7*((p7 & 0xff00) >> 8)
855  + k8*((p8 & 0xff00) >> 8)
856  + k9*((p9 & 0xff00) >> 8);
857  gsum /= scale;
858  if(gsum>255) gsum = 255;
859  else if(gsum<0) gsum = 0;
860 
861  bsum = k1*(p1 & 0xff)
862  + k2*(p2 & 0xff)
863  + k3*(p3 & 0xff)
864  + k4*(p4 & 0xff)
865  + k5*(p5 & 0xff)
866  + k6*(p6 & 0xff)
867  + k7*(p7 & 0xff)
868  + k8*(p8 & 0xff)
869  + k9*(p9 & 0xff);
870  bsum /= scale;
871  if (bsum>255) bsum = 255;
872  if (bsum<0) bsum = 0;
873 
874  pixels[offset++] = 0xff000000
875  | ((rsum << 16) & 0xff0000)
876  | ((gsum << 8 ) & 0xff00)
877  | (bsum & 0xff);
878  }
879  if (y%inc==0)
880  showProgress((double)(y-roiY)/roiHeight);
881  }
882  hideProgress();
883  }
884 
886  public void filter(int type) {
887  int p1, p2, p3, p4, p5, p6, p7, p8, p9;
888  int inc = roiHeight/25;
889  if (inc<1) inc = 1;
890 
891  int[] pixels2 = (int[])getPixelsCopy();
892  int offset, rsum=0, gsum=0, bsum=0;
893  int rowOffset = width;
894  for (int y=yMin; y<=yMax; y++) {
895  offset = xMin + y * width;
896  p1 = 0;
897  p2 = pixels2[offset-rowOffset-1];
898  p3 = pixels2[offset-rowOffset];
899  p4 = 0;
900  p5 = pixels2[offset-1];
901  p6 = pixels2[offset];
902  p7 = 0;
903  p8 = pixels2[offset+rowOffset-1];
904  p9 = pixels2[offset+rowOffset];
905 
906  for (int x=xMin; x<=xMax; x++) {
907  p1 = p2; p2 = p3;
908  p3 = pixels2[offset-rowOffset+1];
909  p4 = p5; p5 = p6;
910  p6 = pixels2[offset+1];
911  p7 = p8; p8 = p9;
912  p9 = pixels2[offset+rowOffset+1];
913  rsum = (p1 & 0xff0000) + (p2 & 0xff0000) + (p3 & 0xff0000) + (p4 & 0xff0000) + (p5 & 0xff0000)
914  + (p6 & 0xff0000) + (p7 & 0xff0000) + (p8 & 0xff0000) + (p9 & 0xff0000);
915  gsum = (p1 & 0xff00) + (p2 & 0xff00) + (p3 & 0xff00) + (p4 & 0xff00) + (p5 & 0xff00)
916  + (p6 & 0xff00) + (p7 & 0xff00) + (p8 & 0xff00) + (p9 & 0xff00);
917  bsum = (p1 & 0xff) + (p2 & 0xff) + (p3 & 0xff) + (p4 & 0xff) + (p5 & 0xff)
918  + (p6 & 0xff) + (p7 & 0xff) + (p8 & 0xff) + (p9 & 0xff);
919  pixels[offset++] = 0xff000000 | ((rsum/9) & 0xff0000) | ((gsum/9) & 0xff00) | (bsum/9);
920  }
921  if (y%inc==0)
922  showProgress((double)(y-roiY)/roiHeight);
923  }
924  hideProgress();
925  }
926 
927  public int[] getHistogram() {
928  if (mask!=null)
929  return getHistogram(mask);
930  int c, r, g, b, v;
931  int[] histogram = new int[256];
932  for (int y=roiY; y<(roiY+roiHeight); y++) {
933  int i = y * width + roiX;
934  for (int x=roiX; x<(roiX+roiWidth); x++) {
935  c = pixels[i++];
936  r = (c&0xff0000)>>16;
937  g = (c&0xff00)>>8;
938  b = c&0xff;
939  v = (int)(r*rWeight + g*gWeight + b*bWeight + 0.5);
940  histogram[v]++;
941  }
942  if (y%20==0)
943  showProgress((double)(y-roiY)/roiHeight);
944  }
945  hideProgress();
946  return histogram;
947  }
948 
949 
950  public int[] getHistogram(ImageProcessor mask) {
951  if (mask.getWidth()!=roiWidth||mask.getHeight()!=roiHeight)
952  throw new IllegalArgumentException(maskSizeError(mask));
953  byte[] mpixels = (byte[])mask.getPixels();
954  int c, r, g, b, v;
955  int[] histogram = new int[256];
956  for (int y=roiY, my=0; y<(roiY+roiHeight); y++, my++) {
957  int i = y * width + roiX;
958  int mi = my * roiWidth;
959  for (int x=roiX; x<(roiX+roiWidth); x++) {
960  if (mpixels[mi++]!=0) {
961  c = pixels[i];
962  r = (c&0xff0000)>>16;
963  g = (c&0xff00)>>8;
964  b = c&0xff;
965  v = (int)(r*rWeight + g*gWeight + b*bWeight + 0.5);
966  histogram[v]++;
967  }
968  i++;
969  }
970  if (y%20==0)
971  showProgress((double)(y-roiY)/roiHeight);
972  }
973  hideProgress();
974  return histogram;
975  }
976 
978  public void convolve(float[] kernel, int kernelWidth, int kernelHeight) {
979  int size = width*height;
980  byte[] r = new byte[size];
981  byte[] g = new byte[size];
982  byte[] b = new byte[size];
983  getRGB(r,g,b);
984  ImageProcessor rip = new ByteProcessor(width, height, r, null);
985  ImageProcessor gip = new ByteProcessor(width, height, g, null);
986  ImageProcessor bip = new ByteProcessor(width, height, b, null);
987  ImageProcessor ip2 = rip.convertToFloat();
988  Rectangle roi = getRoi();
989  ip2.setRoi(roi);
990  ip2.convolve(kernel, kernelWidth, kernelHeight);
991  ImageProcessor r2 = ip2.convertToByte(false);
992  ip2 = gip.convertToFloat();
993  ip2.setRoi(roi);
994  ip2.convolve(kernel, kernelWidth, kernelHeight);
995  ImageProcessor g2 = ip2.convertToByte(false);
996  ip2 = bip.convertToFloat();
997  ip2.setRoi(roi);
998  ip2.convolve(kernel, kernelWidth, kernelHeight);
999  ImageProcessor b2 = ip2.convertToByte(false);
1000  setRGB((byte[])r2.getPixels(), (byte[])g2.getPixels(), (byte[])b2.getPixels());
1001  }
1002 
1007  public static void setWeightingFactors(double rFactor, double gFactor, double bFactor) {
1008  rWeight = rFactor;
1009  gWeight = gFactor;
1010  bWeight = bFactor;
1011  }
1012 
1015  public static double[] getWeightingFactors() {
1016  double[] weights = new double[3];
1017  weights[0] = rWeight;
1018  weights[1] = gWeight;
1019  weights[2] = bWeight;
1020  return weights;
1021  }
1022 
1024  public boolean isInvertedLut() {
1025  return false;
1026  }
1027 
1029  public int getBestIndex(Color c) {
1030  return 0;
1031  }
1032 
1034  public void invertLut() {
1035  }
1036 
1038  public void threshold(int level) {}
1039 
1040 }
1041