zoukankan      html  css  js  c++  java
  • (java)图片像素的操作

    因为做个游戏,需要一些图片资源,而获取到的图片资源都是jpg格式的,不是透明的,例如下面样式的:

    为了取出其中的蓝光部分,透明化黑色背景,我开始了图片处理探索之路。

    这篇文章的内容包含以下部分:

    1.RGB是什么?

    2.获取图片指定位置的RGB值

    3.图片的灰化处理

    4.修改图片的透明通道alpha

    ————————————————————————————————————————————————————————————————————

    RGB是什么?

    可以查看一下RGB的百度百科

    这里简单说一下,RGB即是red,green,blue的缩写,即红绿蓝三种颜色。可以通过这三种颜色按一定比例混合,可以形成任何颜色。

    图片是由许许多多个像素组成,每一像素是一种颜色,有rgb按一定比例混合而成,平常rbg的取值范围为0~255,当red,green,blue的值都为0时,这个像素的颜色就为黑色,都为255时就是白色,当他们的值相同时,混合色变相为灰色。所以,一个像素点可以表示的颜色的个数为 255 * 255 * 255个,是非常多的。

    这里不多做介绍,百科还是很详细的。

    获取图片指定位置的RGB值

    使用java获取一个像素的RGB,需要使用BufferedImage这个类,这个类提供修改图片数据的方法。

     1 /**
     2      * 读取一张图片的RGB值
     3      */
     4     public void getImagePixel(String image) {
     5         
     6         int[] rgb = new int[3];
     7         File file = new File(image);
     8         BufferedImage bi = null;
     9         try {
    10             bi = ImageIO.read(file);
    11         } catch (IOException e) {
    12         
    13             e.printStackTrace();
    14         }
    15         int width = bi.getWidth();
    16         int height = bi.getHeight();
    17         int minX = bi.getMinX();
    18         int minY = bi.getMinY();
    19         for(int y = minY; y < height; y++) {
    20             for(int x = minX; x < width; x++) {
    21                 //获取包含这个像素的颜色信息的值, int型
    22                 int pixel = bi.getRGB(x, y);
    23                 //从pixel中获取rgb的值
    24                 rgb[0] = (pixel & 0xff0000) >> 16; //r
    25                 rgb[1] = (pixel & 0xff00) >> 8; //g
    26                 rgb[2] = (pixel & 0xff); //b
    27                 System.out.print("("+rgb[0] + "," + rgb[1] + "," + rgb[2] + ")");
    28             }
    29             System.out.println();
    30         }
    31         
    32     }

    表示一个像素的颜色数据的格式有很多,不过常见格式就是4byte形式,即32位数据。看下图

    如果支持alpha通道,则最高的8位表示alpha的值,剩下的分别表示r,g,b的值,分别8位。还有其他的数据格式,这里不做介绍啦。

    现在应该可以看懂上边的代码了吧。

    rgb[0]即是r的值,在24~16之间,所以pixel取此区间的值,再右移16位就取得了其值。g,b的值同理。

    图片的灰化处理

    图片的灰化处理,很常用,在图片识别之前,最常用。图像灰化,直观上看就是把多彩的图像黑白化,本来用r,g,b三个值来表示一个pixel的颜色,现在用一个值来表示pixel的颜色,这样,检测图片中图形的边界就方便许多啦。现在,介绍几种灰化方法。

    1,以r,g,b中的其中一个值,作为灰度值

    2. 以r,g,b中的最大值或最小值,作为灰度值

    3.以r,g,b的平均值作为灰度值

    4.以rgb的加权值作为灰度值

    5.用java本身的灰化类型

    下面写个以r值为灰度值的代码:

    /**
         * @param imagePath 要灰化图像的名字
         * @param path 生成的图像的名字
         * 
         */
        public void transformGray_R(String imagePath, String path) {
            BufferedImage image;
            try {
                image = ImageIO.read(new File(imagePath));
                for(int y = image.getMinY(); y  < image.getHeight(); y++) {
                    for(int x = image.getMinX(); x < image.getWidth(); x ++) {
                        int pixel = image.getRGB(x, y);
                        int r = (pixel >> 16) & 0x00ff;
                        pixel = (r & 0x000000ff) | (pixel & 0xffffff00); //用r的值设置b的值
                        pixel = ((r<<8) & 0x0000ff00) | (pixel & 0xffff00ff);//用r的值设置g的值
                        image.setRGB(x, y, pixel);
                    }
                }
                try {
                    ImageIO.write(image, "jpg", new File(path));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            
        }

    看一下效果:

    效果还可以,与ps的红色通道图片一模一样啊。

    2,3方法就不演示啦。2方法还是很好使的,特别是处理像开头那种颜色单一的图片时。

    下面说一下4方法

    //加权法
        public void transformGrayJiaQuan (String imagePath, String path) {
            try {
                BufferedImage image = ImageIO.read(new File(imagePath));
                int width = image.getWidth();
                int height = image.getHeight();
                for(int y = image.getMinY(); y < height; y++) {
                    for(int x = image.getMinX(); x < width ; x ++) {
                        int pixel = image.getRGB(x, y);
                        int r = (pixel >> 16) & 0xff;
                        int g = (pixel >> 8) & 0xff;
                        int b = pixel & 0xff;
                        //加权法的核心,加权法是用图片的亮度作为灰度值的
                        int grayValue = (int) (0.30f * r + 0.59f * g + 0.11f * b ); 
                        //int grayValue = (int) (0.21f * 4 + 0.71f * g + 0.08f * b); //还可以使用这个系数的加权法
                        pixel = (grayValue << 16) & 0x00ff0000 | (pixel & 0xff00ffff);
                        pixel = (grayValue << 8) & 0x0000ff00 | (pixel & 0xffff00ff    );
                        pixel = (grayValue) & 0x000000ff | (pixel & 0xffffff00);
                        image.setRGB(x, y, pixel);
                    }
                }
                
                ImageIO.write(image, "jpg", new File(path));
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }

    效果:

    相对于r值灰化的效果,清晰了好多,但亮度明显小了。

     第5种方法:

    public void transformGray(String imagePath, String path) {
            File file = new File(imagePath);
            try {
                BufferedImage image = ImageIO.read(file);
                int width = image.getWidth();
                int height = image.getHeight();
                BufferedImage grayImage = new BufferedImage(width, height,BufferedImage.TYPE_BYTE_GRAY);//这里的图像类型换了
                for(int y = image.getMinY(); y < height; y++) {
                    for(int x = image.getMinX(); x < width; x++) {
                        int rgb = image.getRGB(x, y);
                        grayImage.setRGB(x, y, rgb);
                    }
                }
                File newFile = new File(path);
                ImageIO.write(grayImage, "jpg", newFile);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }

    看效果

    可以下载下来自己比对一番

    修改图片的透明通道alpha

     上面说了那么多,是为了我的终极目的,就是把黑色的背景透明化,保留我想要的颜色。

    alpha的值也是在0~255之间,当alpha为0时,则图片完全透明,为255时不透明,所以其值越小越透明,由此可知,保留想要的颜色,透明掉不想要的颜色是很简单的。

    处理方法和灰化方法一样,这次修改的是alpha值。通用的方法是加权法,也可以根据图片颜色的类型选择合适的方法。

    下面代码以加权值为alpha值,加权值得到的图片的亮度,所以,越黑的地方,亮度越小,其alpha值最小,越透明。所以,此方法是可行的。

    public void clearBackground(String imagePath, String dstPath) {
            ImageIcon icon = new ImageIcon(imagePath);
            Image srcImage = icon.getImage();
            BufferedImage dstImage = new BufferedImage(srcImage.getWidth(icon.getImageObserver()), srcImage.getHeight(icon.getImageObserver()), BufferedImage.TYPE_4BYTE_ABGR);
            Graphics gr = dstImage.getGraphics();
            gr.drawImage(srcImage, 0,0,icon.getImageObserver());
            int height = dstImage.getHeight();
            int width = dstImage.getWidth();
            for(int y = dstImage.getMinY(); y < height; y++) {
                for(int x = dstImage.getMinX(); x < width; x++) {
                    int pixel = dstImage.getRGB(x, y);
                    int r = (pixel & 0x00ff0000) >> 16;
                    int g = (pixel >> 8) & 0xff;
                    int b = pixel & 0xff;
                    int liangDu = (int)(0.21f * 4 + 0.71f * g + 0.08f * b);//获取亮度
                    //以亮度作为alpha值
                    pixel = (liangDu << 24) & 0xff000000 | (pixel & 0x00ffffff); //alpha值在24~32
                    dstImage.setRGB(x, y, pixel);
                }
            }
            
            try {
                ImageIO.write(dstImage, "png", new File(dstPath));//不要忘记更改图片格式为png格式,jpg不支持透明
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }

    看第一张图处理后的效果:

    其实这张图以b值为基准,处理效果更好,但加权法更常用。

    ————————————————————————————————————————————————————————————————————————————

    这几天处理图片获取到知识,在此总结一下。

  • 相关阅读:
    命名空间“Aspose”中不存在类型或命名空间名称“Slides”。
    项目平台不同修改方法
    手机端自动跳转
    KindEditor得不到textarea值的解决方法
    正则表达式常用
    Log4Net不生成日志文件
    python笔记03-----文件操作
    python笔记04-----字典、元组、集合操作
    python笔记02-----字符串操作
    python笔记01-----列表操作
  • 原文地址:https://www.cnblogs.com/wangjunxiao/p/6700920.html
Copyright © 2011-2022 走看看