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值为基准,处理效果更好,但加权法更常用。

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

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

  • 相关阅读:
    37. Sudoku Solver(js)
    36. Valid Sudoku(js)
    35. Search Insert Position(js)
    34. Find First and Last Position of Element in Sorted Array(js)
    33. Search in Rotated Sorted Array(js)
    32. Longest Valid Parentheses(js)
    函数的柯里化
    俞敏洪:我和马云就差了8个字
    vue路由传值params和query的区别
    简述vuex的数据传递流程
  • 原文地址:https://www.cnblogs.com/wangjunxiao/p/6700920.html
Copyright © 2011-2022 走看看