(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值為基准,處理效果更好,但加權法更常用。

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

這幾天處理圖片獲取到知識,在此總結一下。

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM