我的SWT与数字图像处理总结(1)—重点Image类的介绍

1.ImageData
重要字段:
byte[] data
The pixel data of the image.(图像的像素值)
int scanlinePad
The scanline padding.
(图像的扫描行的宽度,经常与图像的宽度值相同)
int type
The type of file from which the image was read.
(读取图像时图像的类型)
int depth
The color depth of the image, in bits per pixel.
(图像每个像素的位数,例如8位,16位,32位)
PaletteData palette
The color table for the image.(图像的颜色表)
int width
The width of the image, in pixels.
(图像的宽度,以像素为单位),同理有height高度
RGB[] getRGBs
Returns an array of RGBs which comprise the indexed color table of the receiver, or null if the receiver has a direct color model.
(如果是索引图像的话返回的是color table,如果是直接RGB颜色模型的话返回null)
 
在一个默认的颜色模式中,一个像素实际上就是一个带有 alpha,red,green,blue 的整形数。
Alpha代表了像素的透明度,完全透明用0表示,相反用255表示
 
参考:
 
width 和 height 指定图像的宽和高。
depth 指定图像的颜色深度。可能的值为 1、2、4、8、16、24 或者 32,指定编码每一个像素的值所使用的比特数。
alpha 与 alphaData 定义图像的透明度。alpha 定义了图象的全局透明度值,默认值为 -1,否则 alphaData 域将被忽略。
当 alpha 不等于 -1 时, alphaData 存储了图象的透明度缓冲区,每个像素可以有一个在 0~255 之间的透明度值,数值越大,表示越不透明。
值得注意的是,只有部分图象格式具有透明度,例如 GIF 和 PNG。 【alpha:图像的透明度】
palette 包含一个 PaletteData 对象,它存储有关图像的颜色模型的信息。SWT 的颜色模型可以是索引或者直接的,由其域 isDirect 来指定。
如果颜色模型是索引的,那么 PaletteData 包含颜色索引,可以通过方法 getRGBs() 来获取 RGB 信息。如果不是就会返回null
如果它是直接的,那么它包含转换信息,表明应当如何从像素的整数值中提取出颜色 RGB 成分。 【palette:画板,调色板】
data 包含像素值的字节缓冲区。字节编码的方法取决于所使用的颜色深度。
对于一个 8 位的图像,数组中的一个字节正好表示图像中一个像素的值。
对于 16 位图像,每一个像素值编码为缓冲区中的两个字节。这两个字节以最低有效字节顺序存储。
对于 24 或者 32 位图像,每一个像素值以最高有效位字节顺序编码为缓冲区中的三个或者四个字节。
bytesPerLine 表明缓冲区中有多少字节用于表示图像中一行像素的所有像素值。由于一个像素可能有多个字节表示,所以 bytesPerLine 可能是字段 width 值的若干倍。
 
[这里的data和bytesPerLine不好理解!我的理解如下:
8位的图像,每个像素值是占8位,也就是一个字节,对应到data(byte数组)中就是一个元素,同理,对于16位的图像,那么就是2个元素
还有就是如果是16位的话存储时从左到右是低位到高位,但是24位和32位是从高位到低位
bytesPerLine就是指图像中的一行像素所需的字节数,由于一个像素可能有多个字节,所以它可能是width的多位]
对于直接图像,可以有办法通过三个mask得到实际的颜色(或者RGB)
 
构造方法:
 
 
 
注意:一般图像处理时都是在原有的图像上进行处理,处理的都是源图像的ImageData.data,所以之后要得到处理了之后的图像一般都是调用第三种构造方法
其中,前面的五个参数保持不变,调用原来的值,最后一个是处理了之后的data
例如:
ImageData imageData = new ImageData(oldData.width, oldData.height, oldData.depth, oldData.palette, oldData.bytesPerLine, newdata);
imgdst = new Image(getDisplay(), imageData);
 
但是,并非总是这样,还有可能是修改了ImageData中的其他的部分,例如bytesPerLine,但是大致的处理方法还是不变的
ImageData imageData = new ImageData(oldData.width, oldData.height, oldData.depth, oldData.palette, oldData.bytesPerLine, newdata);
imgdst = new Image(getDisplay(), imageData);
 
2.双缓冲
 
暂时没有深入研究....
 
3.实现Canvas的图像的变化
一个实例:来自《Eclipse_SWT_JFace开发实战精解》
import org.eclipse.swt.*
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;

/**
 * 画布Canvas的使用实例
 */

public class CanvasExample {
  static Image image;

  public CanvasExample() {
    final Display display = Display.getDefault();
    final Shell shell = new Shell(SWT.SHELL_TRIM);
    shell.setSize(300, 400);
    shell.setText("Canvas实例");
    shell.setLayout(new GridLayout(4, false));
    final Canvas canvas = new Canvas(shell, SWT.BORDER);
    GridData gridA = new GridData();
    gridA.horizontalIndent = 15;
    gridA.widthHint = 250;
    gridA.heightHint = 120;
    gridA.horizontalSpan = 4;
    gridA.verticalIndent = 15;
    canvas.setLayoutData(gridA);
    // 监听canvas重绘事件
    canvas.addPaintListener(new PaintListener() {
      public void paintControl(final PaintEvent event) {
        if (image != null)//一定要首先判断一下图像是否为null
          // 将其图像显示在canvas上,图像显示在canvas上的坐标为(0,0)
          event.gc.drawImage(image, 0, 0);
          //image = null;//注释掉这一句就可以避免下面的问题
      }
    });
    final List list = new List(shell, SWT.BORDER | SWT.V_SCROLL);
    list.setItems(new String[] { "黄颜色", "蓝颜色", "红颜色", "绿颜色", "黑颜色", "青颜色", "CSU", "皮卡丘", "箭头" });
    GridData gridB = new GridData();
    gridB.horizontalIndent = 15;
    gridB.widthHint = 100;
    gridB.horizontalSpan = 4;
    gridB.verticalIndent = 10;
    list.setLayoutData(gridB);
    Button buttonB = new Button(shell, SWT.NONE);
    buttonB.setText("浏览");
    GridData gridD = new GridData();
    gridD.horizontalIndent = 90;
    gridD.widthHint = 80;
    gridD.horizontalSpan = 3;
    gridD.verticalIndent = 10;
    buttonB.setLayoutData(gridD);
    buttonB.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        int selectionIndex = list.getSelectionIndex();
        if (selectionIndex == 0) {
          canvas.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
        } else if (selectionIndex == 1) {
          canvas.setBackground(display.getSystemColor(SWT.COLOR_BLUE));
        } else if (selectionIndex == 2) {
          canvas.setBackground(display.getSystemColor(SWT.COLOR_RED));
        } else if (selectionIndex == 3) {
          canvas.setBackground(display.getSystemColor(SWT.COLOR_GREEN));
        } else if (selectionIndex == 4) {
          canvas.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
        } else if (selectionIndex == 5) {
          canvas.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
        } else if (selectionIndex == 6) {
          image = new Image(display, "images/csu.jpg");
          canvas.redraw();
        } else if (selectionIndex == 7) {
          image = new Image(display, "images/psu.jpg");
          canvas.redraw();
        } else if (selectionIndex == 8) {
          image = new Image(display, "ico/current.ico");
          canvas.redraw();
        }
      }
    });
    Button buttonC = new Button(shell, SWT.NONE);
    buttonC.setText("退出");
    GridData gridE = new GridData();
    gridE.horizontalIndent = 15;
    gridE.widthHint = 80;
    gridE.verticalIndent = 10;
    buttonC.setLayoutData(gridE);
    buttonC.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        shell.dispose();
      }
    });
    shell.open();
    shell.layout();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
  }

  public static void main(String[] args) {
    new CanvasExample();
  }
}
效果:
 
 
点击其他的选项并点击浏览可以看到其他的图像,并且不会出现图像的重叠现象!
但是还是有一个bug,如果是点击了最小化(如果可以的话)然后重新查看窗体,会发现图像不见了!
解决办法就是删掉一句  image=null
 
期间我尝试过的方法,不太记得了,貌似出了很多问题,但是现在行了!最主要的一个问题就是图片重叠的问题
一般的解决方法就是image=null,image.dispose()但是会带来其他的问题,如果没有立即看到显示效果可以使用相应控件的redraw方法
(1)使用Canvas的GC
// 监听canvas重绘事件 
canvas.addPaintListener(new PaintListener() {
  public void paintControl(final PaintEvent event) {
    if (image != null){//一定要首先判断一下图像是否为null
      gc = new GC(canvas);
        gc.drawImage(image, 0, 0);
      // 将其图像显示在canvas上,图像显示在canvas上的坐标为(0,0)
//          event.gc.drawImage(image, 0, 0);
//          image = null;
    }
  }
});
 
(2)先画背景色或者填充原来的区域
e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); 【现在加上也是可以的】
e.gc.fillRectangle(canvas.getBounds()); //效果不是很好,填充的不完全
 
4.RGB
 
 
red - the red component of the new instance
green - the green component of the new instance
blue - the blue component of the new instance 
 
hue - the hue value for the HSB color (from 0 to 360) 
saturation - the saturation value for the HSB color (from 0 to 1) 
brightness - the brightness value for the HSB color (from 0 to 1) 
 
[不知道为什么,这里的brightness却是0到1,应该是0-255才对的,貌似它是其他的转换方式,所以在绘制灰度直方图时,HSB中没有一个值是正确的,要使用自己的得到
brightness的算法]
 
重要方法:
 
float[] getHSB():Returns the hue, saturation, and brightness of the color.
 
5.Palette和PaletteData
 
实例一:索引图像
 
PaletteData paletteData = new PaletteData(new RGB[] { new RGB(255, 0, 0), new RGB(0, 255, 0) });//深度是1位的图像,只有两种颜色,red和green 
ImageData imageData = new ImageData(48, 48, 1, paletteData);// 这里构造一个ImageData,它默认的颜色是paletteData的第一个颜色RGB(这里是red)
for (int x = 11; x < 35; x++) {
    for (int y = 11; y < 35; y++) {
        imageData.setPixel(x, y, 1);// 索引图像,这里的1表示的是当前位置的像素值是1,但是它的颜色RGB是指向paletteData中的下标为1的那个颜色
    }
}
imgdst = new Image(getDisplay(), imageData);
 
 This creates the result below where the image is red with a green center.

 
 
实例二:直接图像
 
 
PaletteData palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); 
ImageData imageData = new ImageData(48, 48, 24, palette);//图像的位数是24位
for (int x = 0; x < 48; x++) {
    for (int y = 0; y < 48; y++) {
        if (y > 11 && y < 35 && x > 11 && x < 35) {//中心位置是green
            imageData.setPixel(x, y, 0xFF00); // Set the center to green
        } else {//其他地方是red
            imageData.setPixel(x, y, 0xFF); // and everything else to red
        }
    }
}
imgdst = new Image(getDisplay(), imageData);
 

This creates the result below where the image is red with a green center.

Because you can use color depths of 16, 24 and 32 bits with direct palettes, you can represent more colors than are available with an indexed palette whose maximum depth is 8. A color depth of 24 allows you to represent 16 million colors (2^24). The tradeoff however is size, because an indexed palette with a depth of 8 requires one byte per image coordinate whereas a direct palette with a depth of 24 requires three bytes per image coordinate.

[使用directed image你可以使图像包含更多的颜色值,但是它的缺点就是图像的大小增大了!一个位数为8位的索引图像只需要1byte来保存图像的坐标信息,然而,一个24位的直接图像需要3bytes才行!]

With both direct and indexed palettes you can go from an RGB to a pixel value and vice-versa using the public methods int getPixel(RGB rgb) and RGB getRGB(int pixelValue).

[不管是直接还是索引图像,为了实现RGB到pixel的转换都可以使用PaletteData的方法 public int getPixel(RGB rgb)   public RGB getRGB(int pixel) ]

例如实例一:

System.out.println(imgdst.getImageData().palette.getRGB(0).red); //255
System.out.println(imgdst.getImageData().palette.getPixel(new RGB(0,255,0)));  //1
 
 





原文地址:https://www.cnblogs.com/yinger/p/2237498.html