关闭

基于Java的图像象素处理(2)

标签: java图像处理tutorialsbyte算法框架
3047人阅读 评论(1) 收藏 举报
分类:
讨论和代码
先讨论这个ImgMod02.java
我们设计的初衷是: 展示如何在象素级别修改一个图片 , 同时展示修改的结果, 并且和原始图像对比
解压图像, 并且以象素方式来保存
 
这个程序将象素以三维的方式来保存
int[纵坐标][ 横坐标][颜色]
第一, 二个数值代表了这个象素在图像上的位置, 每个象素都不一样, 底3个表示他的颜色, 用一个4byte表示了:
 
0 alpha
1 red
2 green
3 blue
 
数据类型
注意:这个数据是以整数显示的, 这样比无符号位更适合。
这个整数类型的选用可以排除很多因为JAVA不支持有符号的算法而引起的麻烦。
 
支持的文件类型
 
这个程序支持jpg gif格式, 当然你也可以尝试其他的格式, 如果这个程序不支持你所提供的格式, 他会抛出异常的
程序框架
这个程序你也可以改成一个怎么获取图像象素的框架程序。换句话说, 这个程序做到了把图像以象素的方式解开, 并且把它放进一个易于处理的格式里面, 当然, 他也真实地操作了象素。
这些被改过的象素又返回程序, 和原始图像一起展示给你, 如图5所示
 
 
有用的信息
 
你可以这样执行这个程序
java ImgMod02 ProcessingProgramName ImageFileName
 
用于测试, 源文件包含了一个处理象素方法的类: ProgramTest.
 
默认文件是junk.gif
第二个参数是可选的, 默认值是在程序当前目录寻找一个叫junk.gif的文件
 
默认的图像处理类是 ProgramTest
 
如果两个参数都不写, 就是用ProgramTest和junk.gif
【题外话】这个老外可真罗索,不知道这个文档有人看没有,感觉像唐僧。
 
图像文件是必须由客户提供的
如果你没有这个junk.gif文件, 程序也会抛出异常
图像显示格式
当程序启动之后, 原始图像和处理之后的图像都显示在一个Frame里面, 上面是原始图像, 下面是处理之后的图像。
Replot按钮是用来重新加载的按钮, 当您按下这个按钮新的图像将被加载。
processImg 方法
图像象素程序必须实现ImgIntfc02接口, 这个接口只有一个方法:
int[][][] processImg(int[][][] threeDPix, int imgRows, int imgCols);
第一个参数是上文提到的3维象素数组,第二个和第三个表示这个图像中需要处理的行数和列数。
 
这个图像处理的类的构造器是不支持有参数的构造函数的。之所以这样做, 是因为在这个程序里面, 图像处理实例是通过ClassForName来获得的,他的实例名来自命令行参数,这个决定了不适合用有参数的构造器。 这个图像处理的类必须实现processImg方法
 
More on the processImg method
 
这个processImg 方法接受到一个3维数组,我们将这个数组做一个拷贝, 然后处理, 并且返回一个修改后的3维数组。
小心数值范围
 processImg方法可以随意地对象素的数组进行修改, 但是原始象素数据是由无符号位字节组成的, 如果您的处理方法是的这些数值成了一个负数或者>255的正数, 这个据要你处理一下了, 否则无论你做了什么, 程序只是返回8位BIT的值, 而截断你的其他位BIT, 显示的效果肯定不是您所期望的。一个简单的做法是:假设<0使之=0, >255使之=255.
 
操作细节
这个程序从文件读取图像数据,然后保存在一个rawImg内存对象里面,然后被转换成足够大的int[] 数组里面, 每个象素占一个int[]值。这个一维数组叫做oneDPix. 程序实例化了一个 PixelGrabber对象, 用来获得这个一维数组。
将一维的数组转换成三维
 
两个原因让我们这样做:
1)  便于做象素处理程序的调用
2)  将数据从无符号类型转换成可以便于算法的有符号类型, 这点我以后在解释
处理象素
【oldjavaman翻译的时候的补充】
对于一个图像文件来说, 假设我们是一个10pis*10pix的图像, 当然这么小的图像基本没有作用, 一般我们的程序的ICON的大小是32x32,为了方便解释1维》》3维的过程, 我们举个例子来解释, 下面的表格我们可以看成是放大的10x10的图片, 计算机将他转换成一个长度为100的int[]数组, 他们分别对应了下面的格子。
0
1
2
3
4
5
6
7
8
9
10
 
 
 
 
 
 
 
 
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
 
 
 
 
 
 
 
99
 
 
 
 
 
 
 
 
 
 
 
 
那么转换成3维图像是怎么样的?对应上图中的红色的pix将转换成下面这个值
Pix[1][1][0]alpha
Pix[1][1][1]=red
Pix[1][1][2]=green
Pix[1][1][3]=blue
而绿色的pix 的值对应3维数组里面的
Pix[8][3][0]alpha
Pix[8][3][1]=red
Pix[8][3][2]=green
Pix[8][3][3]=blue
之所以这样操作, 目的是为了未来做特殊效果, 如高亮这个象素做准备, 这样更利于算法处理。我也开始成为唐僧了。不知道您看到这里懂了没有。
主要代码
获取一维的象素点数据
 
try{
     PixelGrabber pgObj = new PixelGrabber( rawImg,0,0,imgCols,imgRows,
                              oneDPix,0,imgCols);
     if(pgObj.grabPixels()&&((pgObj.getStatus()& ImageObserver.ALLBITS)!= 0)){
threeDPix = convertToThreeDim( oneDPix,imgCols,imgRows);
     }
 
 
这个方法主要利用了PixelGrabber对象, 在PixelGrabber. grabPixels()方法执行后, 会把数据存储在oneDPix数组中。
 
一维数据转换成三维
int[][][] convertToThreeDim(
          int[] oneDPix,int imgCols,int imgRows){
       int[][][] data =
                    new int[imgRows][imgCols][4];
 
第一步先初始化一个3维数组, 如上所言, 第一个维数是行的象素值, 第二个是列的象素值, 第三个的长度=4
先获得某一行的数组
for(int row = 0;row < imgRows;row++){
      int[] aRow = new int[imgCols];
      for(int col = 0; col < imgCols;col++){
        int element = row * imgCols + col;
        aRow[col] = oneDPix[element];
      }
在将这行的数据拆成4个整数, 用移位运算和与运算
for(int col = 0;col < imgCols;col++){
         data[row][col][0] = (aRow[col] >> 24) & 0xFF;
         data[row][col][1] = (aRow[col] >> 16) & 0xFF;
        data[row][col][2] = (aRow[col] >> 8) & 0xFF;
          data[row][col][3] = (aRow[col]) & 0xFF;
                                         
      }/
}
    return data;
 }
 
象素处理方法
在找个例子里面, 我们找出所有的对角线位置的象素, 并将他置为白色r=255, g=255 , b=255, 将apha值置为255, 不透明。
int[][][] temp3D =
                    new int[imgRows][imgCols][4];
//第一步把获得的3维数组做一个copy
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        temp3D[row][col][0] =
                          threeDPix[row][col][0];
        temp3D[row][col][1] =
                          threeDPix[row][col][1];
        temp3D[row][col][2] =
                          threeDPix[row][col][2];
        temp3D[row][col][3] =
                          threeDPix[row][col][3];
      }
    }
for(int col = 0;col < imgCols;col++){
      int row = col;
      if(row > imgRows -1)break;
//设置成不透,明
      temp3D[row][col][0] = (byte)0xff;
      temp3D[row][col][1] = (byte)0xff;
      temp3D[row][col][2] = (byte)0xff;
      temp3D[row][col][3] = (byte)0xff;
    }
 
 
所有的程序下载: http://www.developer.com/java/other/article.php/3403921
总结
我展示了任何修改象素的方式来修改图像,也提供了一个简单的图像象素修改程序
接下来的课程
接下来我们的课程将告诉你如何使用常规和非常规算法来实现一下功能:
  • 高亮一个图像的某些区域.
  • 模糊一个图像
  • 锐化一个图像
  • 检测一个图像的边缘
  • 过滤一个颜色
  • 让图像的颜色反转
  • 让两个图像融合
  • 旋转一个图像
  • 放大缩小一个图像
  • 使用线性和非线性的方式来调整亮度
  • 其他的一些图像处理效果
OldJavaMan的补充
    尽管这个程序运行的时候看起来平淡无偿, 但是, 我们可以清晰的看到图像象素的处理手段, 接下来我们只要对ImgIntfc02接口编写实现类, 用算法来处理processImg方法, 就能获得让人心动的效果, 相信大家都用过PohtoShop, 我们一样可以自己编写程序来实现PS里面的特效。
关于原始作者
Richard Baldwin 是德州的一名教授,他是一位私人顾问, 致力于C# , Java和XML技术的研究。 由于Java的平台无关性, 他相信未来的web程序主要是用C#, Java 和XML来实现。 作者在很多美国德州的高科技企业担任技术顾问,他是《Baldwin's Programming Tutorials》这本书的作者。他也经常在《JavaPro》杂志撰写文章。
 
Richard 有 Southern Methodist University学位,他有许多年的将计算机科技应用在现实世界的经验。
 
关于译者
OldJavaMan,长期致力于Java相关领域的技术工作, 主要参与J2EE相关程序的设计, 目前在南京的一家软件企业就职,他希望和广大的Java爱好者结交朋友。大家可以通过mail联系他 。
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:140051次
    • 积分:1882
    • 等级:
    • 排名:千里之外
    • 原创:39篇
    • 转载:4篇
    • 译文:6篇
    • 评论:47条
    最新评论
    友情Blog(征集中)