5 import java.awt.image.*;
14 protected byte[] pixels;
15 protected byte[] snapshotPixels;
16 private int bgColor = 255;
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");
23 width = img.getWidth(null);
24 height = img.getHeight(null);
26 pixels =
new byte[width * height];
27 PixelGrabber pg =
new PixelGrabber(img, 0, 0, width, height,
false);
30 }
catch (InterruptedException e) {
31 System.err.println(e);
33 cm = pg.getColorModel();
34 if (cm instanceof IndexColorModel)
35 pixels = (byte[])(pg.getPixels());
37 System.err.println(
"ByteProcessor: not 8-bit image");
42 this(width, height,
new byte[width*height], null);
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);
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);
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++];
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);
109 if (snapshotPixels==null)
111 System.arraycopy(snapshotPixels,0,pixels,0,width*height);
117 if (mask==null || snapshotPixels==null)
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];
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;
154 if (x>=0 && x<width && y>=0 && y<height)
155 return pixels[y*width+x]&0xff;
160 static double oldx, oldy;
165 if (x>=width-1.0) x = width-1.001;
167 if (y>=height-1.0) y = height-1.001;
177 if (x>=width-1.0) x = width-1.001;
179 if (y>=height-1.0) y = height-1.001;
182 double xFraction = x - xbase;
183 double yFraction = y - ybase;
184 int offset = ybase * width + xbase;
185 double lowerLeft = cTable[pixels[offset]&255];
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);
197 if (x>=0 && x<width && y>=0 && y<height) {
199 return pixels[y*width + x]&0xff;
201 return cTable[pixels[y*width + x]&0xff];
209 drawingColor = color;
215 fgColor = (int)value;
216 if (fgColor<0) fgColor = 0;
217 if (fgColor>255) fgColor = 255;
224 if (x>=0 && x<width && y>=0 && y<height) {
229 pixels[y*width + x] = (byte)(value+0.5);
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;
245 if (x>=clipXMin && x<=clipXMax && y>=clipYMin && y<=clipYMax)
246 pixels[y*width + x] = (byte)fgColor;
253 return (Object)pixels;
259 if (snapshotPixels!=null && newSnapshot)
260 return snapshotPixels;
262 byte[] pixels2 =
new byte[width*height];
263 System.arraycopy(pixels, 0, pixels2, 0, width*height);
269 if (pixels!=null && this.pixels!=null && (((byte[])pixels).length!=this.pixels.length))
270 throw new IllegalArgumentException(
"");
271 this.pixels = (byte[])pixels;
273 snapshotPixels = null;
309 makeDefaultColorModel();
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];
317 for (
int i=0; i<256; i++) {
323 rLUT2[i] = rLUT1[255];
324 gLUT2[i] = gLUT1[255];
325 bLUT2[i] = bLUT1[255];
328 index = (int)(256.0*index/(max-min));
333 rLUT2[i] = rLUT1[index];
334 gLUT2[i] = gLUT1[index];
335 bLUT2[i] = bLUT1[index];
338 cm =
new IndexColorModel(8, 256, rLUT2, gLUT2, bLUT2);
352 throw new IllegalArgumentException(
"8-bit or RGB image required");
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];
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];
378 for (
int i=0; i<kernel.length; i++)
380 if (scale==0) scale = 1;
381 int inc = roiHeight/25;
386 int rowOffset = width;
387 for (
int y=yMin; y<=yMax; y++) {
388 offset = xMin + y * width;
390 p2 = pixels2[offset-rowOffset-1]&0xff;
391 p3 = pixels2[offset-rowOffset]&0xff;
393 p5 = pixels2[offset-1]&0xff;
394 p6 = pixels2[offset]&0xff;
396 p8 = pixels2[offset+rowOffset-1]&0xff;
397 p9 = pixels2[offset+rowOffset]&0xff;
399 for (
int x=xMin; x<=xMax; x++) {
401 p3 = pixels2[offset-rowOffset+1]&0xff;
403 p6 = pixels2[offset+1]&0xff;
405 p9 = pixels2[offset+rowOffset+1]&0xff;
407 sum = k1*p1 + k2*p2 + k3*p3
408 + k4*p4 + k5*p5 + k6*p6
409 + k7*p7 + k8*p8 + k9*p9;
412 if(sum>255) sum= 255;
415 pixels[offset++] = (byte)sum;
418 showProgress((
double)(y-roiY)/roiHeight);
425 int p1, p2, p3, p4, p5, p6, p7, p8, p9;
426 int inc = roiHeight/25;
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;
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;
444 for (
int x=xMin; x<=xMax; x++) {
446 p3 = pixels2[offset-rowOffset+1]&0xff;
448 p6 = pixels2[offset+1]&0xff;
450 p9 = pixels2[offset+rowOffset+1]&0xff;
454 sum = (p1+p2+p3+p4+p5+p6+p7+p8+p9)/9;
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;
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);
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;
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;
491 pixels[offset++] = (byte)sum;
494 showProgress((
double)(y-roiY)/roiHeight);
513 public void outline() {
517 public void skeletonize() {
518 new BinaryProcessor(
this).skeletonize();
521 private final int findMedian (
int[] values) {
523 for (
int i = 1; i <= 4; i++) {
526 for (
int j = 1; j <= 9; j++)
527 if (values[j] > max) {
534 for (
int j = 1; j <= 9; j++)
545 Random rnd=
new Random();
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;
561 showProgress((
double)(y-roiY)/roiHeight);
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;
575 if ((xScale>1.0) && (yScale>1.0)) {
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;
587 xmax = roiX + roiWidth - 1;
589 ymax = roiY + roiHeight - 1;
592 boolean checkCoordinates = (xScale < 1.0) || (yScale < 1.0);
593 int index1, index2, xsi, ysi;
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;
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;
607 if (checkCoordinates && ((xsi<xmin) || (xsi>xmax) || (ysi<ymin) || (ysi>ymax)))
608 pixels[index1++] = (byte)bgColor;
611 if (xs<0.0) xs = 0.0;
612 if (xs>=xlimit) xs = xlimit2;
615 pixels[index1++] = pixels2[index2+xsi];
619 showProgress((
double)(y-ymin)/height);
628 double xFraction = x - xbase;
629 double yFraction = y - ybase;
630 int offset = ybase * width + xbase;
631 int lowerLeft = pixels[offset]&255;
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);
646 if (roiWidth==dstWidth && roiHeight==dstHeight)
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;
655 dstCenterX += xScale/2.0;
656 dstCenterY += yScale/2.0;
659 byte[] pixels2 = (byte[])ip2.
getPixels();
661 double xlimit = width-1.0, xlimit2 = width-1.001;
662 double ylimit = height-1.0, ylimit2 = height-1.001;
664 for (
int y=0; y<=dstHeight-1; y++) {
665 ys = (y-dstCenterY)/yScale + srcCenterY;
667 if (ys<0.0) ys = 0.0;
668 if (ys>=ylimit) ys = ylimit2;
670 index1 = width*(int)ys;
672 for (
int x=0; x<=dstWidth-1; x++) {
673 xs = (x-dstCenterX)/xScale + srcCenterX;
675 if (xs<0.0) xs = 0.0;
676 if (xs>=xlimit) xs = xlimit2;
679 pixels2[index2++] = pixels[index1+(int)xs];
682 showProgress((
double)y/dstHeight);
695 double centerX = roiX + (roiWidth-1)/2.0;
696 double centerY = roiY + (roiHeight-1)/2.0;
697 int xMax = roiX + this.roiWidth - 1;
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;
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;
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++) {
718 if ((xs>=-0.01) && (xs<dwidth) && (ys>=-0.01) && (ys<dheight)) {
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;
728 if (ixs>=width) ixs = width - 1;
729 if (iys>=height) iys = height -1;
730 pixels[index++] = pixels2[width*iys+ixs];
733 pixels[index++] = (byte)bgColor;
736 showProgress((
double)(y-roiY)/roiHeight);
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;
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;
772 throw new IllegalArgumentException(maskSizeError(mask));
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;
792 for (
int i=0; i<width*height; i++) {
793 if ((pixels[i] & 0xff) <= level)
796 pixels[i] = (byte)255;
801 public void applyLut() {
805 for (
int i=0; i<width*height; i++)
806 pixels[i] = (byte)(255 - rLUT2[pixels[i]&0xff]);
808 for (
int i=0; i<width*height; i++)
809 pixels[i] = rLUT2[pixels[i] & 0xff];
814 public void convolve(
float[] kernel,
int kernelWidth,
int kernelHeight) {
817 new ij.plugin.filter.Convolver().convolve(ip2, kernel, kernelWidth, kernelHeight);
819 byte[] pixels2 = (byte[])ip2.
getPixels();
820 System.arraycopy(pixels2, 0, pixels, 0, pixels.length);