imgageJ开发【Java】

55 篇文章 5 订阅
7 篇文章 1 订阅

一.ImageJ简介

 

ImageJ是一款由NIH(National Institutes of Health,美国国家卫生研究院)发起,可用于Windows,Mac,OSX和Linux等操作系统的图像处理开元软件,ImageJ小巧,只有5MB左右,界面简洁,容易上手。

 

二.ImageJ软件安装

1.下载ImageJ软件

   在百度搜ImageJ,进入官网

 

2.点击Downlaod,进入下载界面

   

3.下载后解压,解压目录下的ImageJ.exe文件便可以运行软件,打开后的软件界面如下:

                                       

三. ImageJ的二次开发

1.     配置java的运行环境

(1)在ORACL官网上下载jdk:

我这里的版本是jdk-6u10-rc2-bin-b32-windows-i586-p-12_set_2008

(2)双击此exe文件,进入安装向导,安装路径可以修改,这里就安装在默认路径下:C:\Program Files\Java\jdk1.6.0_10目录下

 

(3)点击“下一步”,直到完成安装

(4)安装完毕后还要进行jdk运行环境配置,首先在系统属性中打开到如下界面:

 

在系统变量中新建第一个变量名:JAVA_HOME,变量值为前面jdk的安装路径,这里是C:\Program Files\Java\jdk1.6.0_10

新建第二个变量名:CLASSPATH,变量值为 .:%JAVA_HOME%\lib,注意符号添加正确,.:不要缺少

添加path变量,注意path变量如果已经有了,不要新建了。在变量值后面添加一个分号;隔开,在后面加入%JAVA_HOME%\lib,不然他会覆盖之前的值

(5)到此jdk环境配置结束

 

 

2.     java的开发工具Eclipse的使用

(1)在官网上下载开发工具Eclipse,这里用的版本是eclipse-sdk-3.3-win32

(2)下载好后直接运行,出现默认工作空间路径选择,可以手动改变路径,设置后生成的项目都会保存在此目录下,本文的路径为D:\java3

(3)配置好后出现此界面

 

 

3.     验证实验小程序(验证前面的JDK和Eclipse已经安装配置好)

(1)选择菜单File下New选项,选择java projec,打开如下对话框

输入工程名,例如test1,输入完毕点击下一步直至完成

(2)  右击刚才新建的工程,创建一个包

输入包名,例如com.test1

(3)  右击com.test1,在弹跳出的选项中新建类

输入类名,例如shiyan1

(4)  类名新建好后,会出现带有头文件的java程序

 

(5)  编辑程序如下:

 

(6)  如果程序能正常运行,则在console窗口中会显示如下果:

4.     调用imagej源程序包中的图像处理函数

(1)  在imagej官网上下载imageJ源码包,这里我用的版本是ij148r-src

(2)  按照上述方法新建一个工程project1

(3)  打开ij148r-src的子文件夹source,里面包含的文件如下图:

 

(4)  打开工程project1文件夹,里面包含的文件如下:

 

(5)  将source中的plugins,macros,images文件夹和IJ_Props.txt文件拷贝到project1文件夹中,再把source中的ij文件夹拷贝到project1的子文件夹src中

(6)  右击eclipse中project1工程,在弹跳窗口中选择”Refresh”选项进行刷新,便能在src中看到imagej源码包

 

 

(7)  再按照上述方法新建一个包com.project1和类inverse

(8)  为了验证imagej源码包按上述操作后,可以成功调用,编辑一份java程序,此程序中调用了imagej的源码函数,实现了图像的打开,显示,以及反转操作

运行结果如下:

 

源码如下:

package com.project1;
import ij.process.ImageProcessor;
import ij.io.OpenDialog;
import ij.ImagePlus;
public class inverse {
public static void main(String args[]) {
OpenDialog wo=new OpenDialog("");
System.out.println("你打开的图像的路径是:");
String we=wo.getPath();
System.out.println(we);
//--------图像显示
ImagePlus ming=new ImagePlus(we);
ming.setTitle("原图像");
ming.show();

ImageProcessor ip1=ming.getProcessor();
ImageProcessor ip2=ip1.duplicate();
ip2.invert();
ImagePlus ming2=new ImagePlus("平滑后的图像",ip2);//图像有标题
ming2.show();

}
}

这样你就能够使用ImageJ中的图像处理函数了!深入的东西还要读者自己去挖掘!

 

 ImageJ的源码函数众多,可以在imagej官网上查找每个类所包含的成员函数和成员变量:

注意

安装插件
在ImageJ的安装包里,有一个”plugins”的文件夹,ImageJ中所有的插件都是放在”plugins”文件夹中。”plugins”文件夹中允许创建与某个插件有关的子文件夹,此文件夹中存放的是与此插件相关的编译好的类文件以及配置文件。ImageJ的插件机制可以自行识别满足以下要求的插件
1)插件类按着规定必须继承以下三个类中的某一个 “PlugIn”,此类在运行时不需要输入图像,”PlugInFilter”,此类在运行时需要输入图像,以及”PlugInFrame”。
2)插件类的命名中必须至少有一个下划线。
3)插件类中不允许有包申明,它必须放在默认的包中。
4)编写好插件后,编译得到class文件,再按照相关要求写此插件的”plugins.config”文件,将所有class文件和config文件打包后放在ImageJ的plugin文件夹中即可。
重新运行ImageJ就能在Plugin中找到自己编写的插件。

开发环境
开发所使用的环境必须和ImageJ的环境对应,若用eclipse开发,ImageJ是x64则,eclipse必须是先x64,编译的class文件所对应的jdk应该与ImageJ的jdk对应

插件类编写
插件类若继承” PlugInFilter” 在插件类的构造函数中,若要传递参数需要写配置文件中写明,其setup函数需要返回输入图像的类型,否则在ImageJ中运行会出现”requires an image of type”,按照图像处理的需求指定相应的类型。

Java package

 

一些人用了一阵子的Java,可是对于 Java 的 package 跟 import 还是不太了解。很多人以为原始码 .java 文件中的 import 会让编译器把所 import 的程序通通写到编译好的 .class 档案中,或是认为 import 跟 C/C++ 的 #include 相似,实际上,这是错误的观念。

  让我们先了解一下,Java 的 package 到底有何用处。

  其实,package 名称就像是我们的姓,而 class 名称就像是我们的名字。package 名称有很多 . 的,就好像是复姓。比如说 java.lang.String,就是复姓 java.lang,名字为 String 的类别;java.io.InputStream 则是复姓java.io,名字为 InputStream 的类别。

  Java 会使用 package 这种机制的原因也非常明显,就像我们取姓名一样,光是一间学校的同一届同学中,就有可能会出现不少同名的同学,如果不取姓的话,那学校在处理学生数据,或是同学彼此之间的称呼,就会发生很大的困扰。相同的,全世界的 Java 类别数量,恐怕比台湾人口还多,而且还不断的在成长当中,如果类别不使用套件名称,那在用到相同名称的不同类别时,就会产生极大的困扰。幸运的是,Java 的套件名称我们可以自己取,不像人的姓没有太大的选择 ( 所以有很多同名同姓的 ),如果依照 Sun 的规范来取套件名称,那理论上不同人所取的套件名称不会相同 ( 请参阅 "命名惯例"的相关文章 ),也就不会发生名称冲突的情况。

  可是问题来了,因为很多套件的名称非常的长,在写程序时,会多打好多字,花费不少时间,比如说在A.B.C文件下有Point和Circle两个类,现在在程序中要调用:

     A.B.C.Point  P1=new A.B.C.Point();

     A.B.C.Circle  C1=new A.B.C.Circle();

实在是不美观又麻烦.于是,Sun 想了一个办法,就是 import. 就是在程序一开头的时候,说明程序中会用到那些类的路径.首先,在档案开头写:

     import A.B.C.Point;

     import A.B.C.Circle;

这两行说明了类的路径,所以当程序中提到Point就是指A.B.C.Point,而Circle就是指A.B.C.Circle,依此类推。于是原来的程序就变成:

     Point  P1=new Point();

     Circle  C1=new Circle();  

这样看起来是不是清爽多了呢?如果这些类别用的次数很多,那就更能体会到import 的好处了。可是这样还是不够,因为懒是人的天性,还是会有人觉得打太多 import 了也很浪费时间,于是 Sun 又提供了一个方法:

    import A.B.C.*; 意思就是,等一下程序中提到的没有姓名的类别,全都包含在A.B.C这个目录中。

  注意点:但我们在程序中经常使用System.out这个类,为什么没有import System.out呢,因为java.lang 这个套件实在是太常太常太常用到了,几乎没有程序不用它的,所以不管你有没有写 import java.lang;,编译器都会自动帮你补上,也就是说编译器只要看到没有姓的类别,它就会自动去 java.lang 里面找找看,看这个类别是不是属于这个套件的。所以我们就不用特别去import java.lang 了。

   为甚么我一开始说 import 跟 #include 不同呢?因为 import 的功能到此为止,它不像 #include 一样,会将档案内容载入进来。import 只是请编译器帮你打字,让编译器把没有姓的类别加上姓,并不会把别的文件的程式码写进来。如果你想练习打字,可以不要使用 import,只要在用到类别的时候,用它的全部姓名来称呼它就行了(就像例子一开始那样),跟使用 import 完全没有甚么两样。

 

                                 先介绍Java的Package机制

基本原则:需要将类文件切实安置到其所归属之Package所对应的相对路径下。

例如:以下面程序为例:假设此Hello.java文件在D:\Java\下
package  A;
public class Hello{
  public static void main(String args[]){   
     System.out.println("Hello World!");
  }
}

D:\Java>javac  Hello.java  此程序可以编译通过.接着执行。
D:\Java>java  Hello       但是执行时,却提示以下错误!
Exception in thread "main" java.lang.NoClassDefFoundError: hello (wrong name: A/Hello)
        at java.lang.ClassLoader.defineClass0(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:537)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)

原因是我们把生成的Hello.class规定打包在D:\Java\A文件中,必须在A文件中才能去运行。所以应该在D:\Java目录下建立一个A目录,然后把把Hello.class放在它下面,执行时,可正常通过!
D:\Java\>java A.hello   就会输出:Hello world!

 

                              现在介绍Java的import机制

我们在D:\Java目录下建立一个JInTian.java文件,其内容如下:
import  A.Hello;
public class JInTian{
   public static void main(String[] args){
       Hello  Hello1=new Hello();
     }
}

D:\Java\>javac JInTian.java   编译成功!

D:\Java\>java  JInTian      运行成功!

也就是你在JInTian.class中成功的引用了Hello.class这个类,是通过import A.Hello来实现的,如果你没有这句话,就会提示不能找到Hello这个类。

提示1:如果你在D:\Java目录下仍保留一个Hello.java文件的话,执行对主程序的编译命令时仍会报错!你自己可以试试呀!
提示2:如果你删除D:\Java\A\Hello.java文件的话,只留Hello.class文件,执行对主程序的编译命令时是可以通过,此时可以不需要子程序的源代码。
提出一个问题:如果把目录A剪切到其它目录,如D盘根目录下,在A目录如果执行编译和执行命令呢?
很明显,会报以下错误!当然了,前提条件是你没有设置classpath路径,其实只要没把类搜索路径设置到我这个位置就会出错的!你试试吧

imageJ 小例子

Java图像处理最快技术:ImageJ 学习第一篇 ImageJ是世界上最快的纯Java的图像处理程序。它可以过滤一个2048x2048的图像在0.1秒内(*)。这是每秒40万像素!ImageJ的扩展通过使用内置的文本编辑器和Java编译器的ImageJ的开发插件。500多插件可用。

数据类型:8位灰度或索引色,16位无符号整数,32位浮点和RGB色彩。

文件格式:读写所有支持的数据类型为TIFF(非压缩)或原始数据。打开和保存GIF,JPEG,BMP,PNG,PGM,FITS和ASCII。打开DICOM。使用URL打开的TIFF、GIF文件、JPEG文件、DICOMs和原始数据。也可以扩展许多其他格式 的插件。

图像增强:支持平滑,锐化,边缘检测,中值滤波和阈值的8位灰度和RGB彩色图像。交互方式调整亮度和8位,16位和32位图像的对比度。

几何操作:裁剪,缩放,调整大小和旋转。翻转垂直或水平。

分析:测量面积,平均值,标准偏差,最小的选择和最大或整个图像。测量长度和角度。使用现实世界中的度量单位,如毫米。校准使用密度标准。生成柱状图和剖面图。

色彩处理:分裂一个32位彩色图像转换成RGB或HSV分量。合并8位组件成彩色图像。RGB图像转换为8位索引颜色。应用伪彩色调色板为灰度图像。

 

基于ImageJ的项目有、CellProfiler(细胞图像分析)、idoimaging(医学影像)、ImageSurfer(3D可视化和分析)、MIPAV(3D成像和可视化)、NITRC(神经影像学工具和资源)等。

下面对ImageJ的编程基础介绍一下。

一、ImageJ的图像剖析

ImageJ的 图像由三个部分组成:

1、ImageProcessor对象实例:持有并提供了访问像素的方法。

2、Image对象实例:即java.awt.Image画在屏幕上。

3、ImagePlus对象实例:包括所有的元数据(标题,属性)、ImageProcessor和Image。

ImageJ的 图像堆栈由四部分组成:

1、ImageStack对象实例:持有像素阵列的阵列(LUT变化通过临时实例StackProcessor)

2、Image对象实例:即java.awt.Image画在屏幕上。

3、ImageProcessor对象实例:提供访问当前切片像素。

4、ImagePlus对象实例:持有ImageStack、ImageProcessor和Image。

 

使用堆栈时,要谨记以下几点:

1、ImagePlus的ImageProcessor实例在任何调用setSlice(INT)时都由它的像素替换对象。

2、ImageStack.getProcessor(int)在每次调用时都返回一个新的ImageProcessor,是 一个消耗大的操作。

3、ImagePlus的java.awt.Image中在每次调用setSlice(int)时被更新。

 

当ImagePlus调用updateAndDraw()时重新创建 java.awt.Image对象。如果你想改变被反映当前显示在屏幕上的图像,必须修改的像素之后调用updateAndDraw()。

 

二、创建图像

    1、创建一个图像(详细)

int width = 400;  
int height = 400;  
ImageProcessor ip = new ByteProcessor(width, height);  
String title = "My new image";  
ImagePlus imp = new ImagePlus(title, ip);  
imp.show();  

 

    有几个ImageProcessor类,每个都有自己专门的构造函数。ByteProcessor,ShortProcessor,FloatProcessor和ColorProcessor。

    2、创建一个图像(简单方式)

 

        new ImagePlus("My new image", new ByteProcessor(400, 400)).show(); 

 

    3、创建任意数量任何类型的

         A、一个简单的8位的400x400像素的灰度图像

ImagePlus imp = IJ.createImage("My new image", "8-bit black", 400, 400, 1);
imp.show();
// or, without getting back a reference:
IJ.newImage("My new image", "8-bit black", 400, 400, 1);

B、堆栈的400×400像素的10色图片

ImagePlus imp = IJ.createImage("My new image", "RGB white", 400, 400, 10);  
imp.show();  
// again, without getting back a reference:  
IJ.newImage("My new image", "RGB white", 400, 400, 10); 

三、销毁图像

调用flush()将释放所使用的ImagePlus所有内存资源。

ImagePlus imp = ...  
imp.flush();  

 

注意:如果你持有一个从ImagePlus.getProcessor()方法获得ImageProcessor。即ImageProcessor的像素数组指针将被设置为null。你应该改为调用ImageProcessor的duplicate(),或直接通过getPixels()得到它的像素,并把它们存储在相同的尺寸的新ImageProcessor。

 

同样,java.awt.Image中获取自己的flush()方法调用也是如此。

四、打开图像

    所有方法都围绕着ij.io.Opener类展开。

    1、高层次的方式,从文件或URL

 

ImagePlus imp = IJ.openImage("/path/to/image.tif");  
imp.show();  
  
ImagePlus imp = IJ.openImage("http://www.example.org/path/to/image.tif");  
imp.show();  
  
// Without getting back a pointer, and automatically showing it:  
IJ.open("/path/to/image.tif");  
// Same but from an URL  
IJ.open("http://www.example.org/path/to/image.tif"); 

 

    2、从文件打开

Opener opener = new Opener();  
ImagePlus imp = opener.openImage("/path/to/image.tif");  
imp.show();  

    3、从URL打开

Opener opener = new Opener();  
ImagePlus imp = opener.openImage("http://www.example.org/path/to/image.tif");  
imp.show(); 

 

以上注意URL 包含http://如何的自动检测并正确解析。如果需要,可以直接调用:

ImagePlus imp = opener.openURL("http://www.example.org/path/to/image.tif");  

 

五、编辑像素

1、运行ImageJ命令方式,这是一个高层次的方法,像素可以通过调用ImageJ的命令编辑图像:

ImagePlus imp = ...  
// Making a binary image  
IJ.run(imp, "Convert to Mask", ""); // "" means no arguments  
  
// Resizing, opens a copy in a new window (the 'create' command keyword)  
IJ.run(imp, "Scale...", "x=0.5 y=0.5 width=344 height=345 interpolate create title=[Scaled version of " +imp.getTitle() + "]");  
  ...  

任何ImageJ命令可能被应用。你可以找出哪些命令来使用,哪些参数通过运行插件,并手动调用的ImageJ打开的图像上的菜单命令。

2、中级层次编辑方式:ImageProcessor(ROIs/selections)

在图像上绘制或填充ROI(感兴趣区域):

ImagePlus imp = ...  
ImageProcessor ip = imp.getProcessor();  
  
// Assuming 8-bit image  
  
// fill a rectangular region with 255 (on grayscale this is white color):  
Roi roi = new Roi(30, 40, 100, 100); // x, y, width, height of the rectangle  
ip.setRoi(roi);  
ip.setValue(255);  
ip.fill();  
  
// fill an oval region with 255 (white color when grayscale LUT):  
OvalRoi oroi = new OvalRoi(50, 60, 100, 150); // x, y, width, height of the oval  
ip.setRoi(oroi);  
ip.setValue(255);  
ip.fill(ip.getMask()); // notice different fill method  
                       // regular fill() would fill the entire bounding box rectangle of the OvalRoi  
// The method above is valid at least for PolygonRoi and ShapeRoi as well.  
  
  
// draw the contour of any region with 255 pixel intensity  
Roi roi = ...  
ip.setValue(255);  
ip.draw();  
  
// update screen view of the image  
imp.updateAndDraw();  

 

3、ROIs的一些事情:

A、有很多selection/ROI类型:Roi(矩形之一,也是所有其它类型的父类),Line, OvalRoi, PolygonRoi, PointRoi, FreehandRoi, ShapeRoi, TextRoi。另外有一些子类型,如PolygonRoi里的POLYGON、POLYLINE 类型。

B、大部分的ROI是用于编辑图像非常有用; 一些用于图像分析(Line,PointRoi,TextRoi)。

C、最强大的ROI是ShapeRoi:java.awt.geom.GeneralPath支持它,它能够存储任意数量的任何形状的不连续区域的。

D、ip.fill(ip.getMask())方法是最安全的,可在各种场合使用,只需要检查ImageProcessor的mask通过getMask()返回的不为null。

 

旋转,翻转和缩放图像(或者ROI)

ImagePlus imp = ...  
ImageProcessor ip = imp.getProcessor();  
  
ip.flipHorizontal();  
  
ip.flipVertical();  
  
ip.rotateLeft();  
  
ip.rotateRight();  
  
// rotate WITHOUT enlarging the canvas to fit  
double angle = 45;  
ip.setInterpolate(true); // bilinear  
ip.rotate(45);  
  
// rotate ENLARGING the canvas and filling the new areas with background color  
double angle = 45;  
IJ.run(imp, "Arbitrarily...", "angle=" + angle + " grid=1 interpolate enlarge");  
  
// scale WITHOUT modifying the canvas dimensions  
ip.setInterpolate(true); // bilinear  
ip.scale(2.0, 2.0); // in X and Y  
  
// scale ENLARGING or SHRINKING the canvas dimensions  
double sx = 2.0;  
double sy = 0.75;  
int new_width = (int)(ip.getWidth() * sx);  
int new_height = (int)(ip.getHeight() * sy);  
ip.setInterpolate(true); // bilinear  
ImageProcesor ip2 = ip.resize(new_width, new_height); // of the same type as the original  
imp.setProcessor(imp.getTitle(), ip2); // UPDATE the original ImagePlus  
  
// update screen view of the image  
imp.updateAndDraw();  

ImageProcessor类提供了绘制线条、文字和点等。看看在ImageProcessor的API。

 

4、低层次的编辑方式:像素数组

ImagePlus imp = ...  
ImageProcessor ip = imp.getProcessor();  
  
// Editing the pixel array  
if (imp.getType() == ImagePlus.GRAY8) {  
    byte[] pixels = (byte[])ip.getPixels();  
    // ... do whatever operations directly on the pixel array  
}  
  
// Replacing the pixel array: ONLY if same size  
if (imp.getType() == ImagePlus.GRAY8) {  
    int width = ip.getWidth();  
    int height = ip.getHeight();  
    byte[] new_pixels = new byte[width * height];  
    // set each pixel value to whatever, between -128 and 127  
    for (int y=0; y<height; y++) {  
        for (int x=0; x<width; x++) {  
            // Editing pixel at x,y position  
            new_pixels[y * width + x] = ...;  
        }  
    }  
    // update ImageProcessor to new array  
    ip.setPixels(new_pixels);  
}  
  
// Replacing the pixel array but of different length: for example, to resize 2.5 times in width and height  
int new_width = (int)(ip.getWidth() * 2.5);  
int new_height = (int)(ip.getHeight() * 2.5);  
ImageProcessor ip2 = ip.createProcessor(new_width, new_height); // of same type  
imp.setProcessor(imp.getTitle(), ip2);  
  
if (imp.getType() == ImagePlus.GRAY8) {  
    byte[] pix = (byte[])imp.getProcessor().getPixels(); // or ip2.getPixels();  
    // .. process pixels ...  
    for (int y=0; y<height; y++) {  
        for (int x=0; x<width; x++) {  
            // Editing pixel at x,y position  
            new_pixels[y * width + x] = ...;  
        }  
    }  
}  
  
// DON'T forget to update the screen image!  
imp.updateAndDraw();  

如果要显示的ImagePlus,更新图像只有必须的,

 

六、保存图像

1、高层次的方式

ImagePlus imp = ...  
IJ.saveAs(imp, "tif", "/path/to/image.tif");  
  
// or by using the file format extension:  
IJ.save(imp, "/path/to/image.tif");

    

很多格式都支持。在IJ类里搜索方法"saveAs"

2、通过FileSaver类

ImagePlus imp = ...  
new FileSaver(imp).saveAsTiff("/path/to/image.tif"); 

该FileSaver类有更多的选择:saveAsTiffStack,saveAsJpeg,saveAsPng,saveAsGif ...等。

Writing ImageJ Plugins—A Tutorial

https://imagingbook.com/imagej-tutorial/

Java 图像处理类库

https://blog.csdn.net/zlxtk/article/details/54890789

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值