目录

RGB

图像处理算法

        RGB转灰度图像

        二值图像

        负片

         马赛克

        复古

         锐化


        在说Java数字图像处理之前,需要知道以下知识:RGB

RGB

        一幅RGB图像有三个通道,也就是RGB,分别代表红、绿、蓝三个通道的颜色,这三个通道颜色的信息组合起来,就成为了多种多样的颜色,比如0,0,0代表的是黑色

        在数字图像中,每一个像素点都有一个RGB数值,Java可以用getRGB来获取

        这里我给出获取像素RGB信息的一种Java方法

        1. 确定图片路径

        2. 使用BufferedImage读取确定路径下的图像数据

BufferedImage buf_im= ImageIO.read(new FileInputStream(im_path));

        3. 可以使用getWidth等函数读取相关信息

im_width=buf_im.getWidth();
im_height=buf_im.getHeight();

        4. 遍历每一个像素点,用getRGB函数获取对应的像素信息

int[][] red = new int[im_width][im_height];
int[][] green = new int[im_width][im_height];
int[][] blue = new int[im_width][im_height];
for(int i=0;i<im_width;i++){
      for (int j =0;j<im_height;j++){
             red[i][j] = (buf_im.getRGB(i,j)>>16) &0xFF;
             green[i][j] = (buf_im.getRGB(i,j)>>8) &0xFF;
             blue[i][j] = (buf_im.getRGB(i,j)) &0xFF;
      }
}

        当然,Java还有很多封装好的包可以直接提供给用户实现读取,这里给出了最基本的逐像素法来读取,因为后面我会用到这些单个的像素进行图像处理

图像处理算法

        拿到一幅图像的大小和RGB数据后就能对他们进行处理,通过合适的处理能够给这副图像加上一个滤镜

 

java图片二值化 java数字图像处理_java图片二值化

        RGB转灰度图像

        RGB抓灰度图像的算法很简单,利用一些已经经过时间检验的公式就能够得出灰度值,将Color的三个通道设置成同样的灰度值即可实现灰度图像

int im_width = info.getIm_width();
        int im_height = info.getIm_height();
        for(int i=0;i<im_width;i++){
            for (int j =0;j<im_height;j++){
                int red = info.getIm_red()[i][j];
                int green = info.getIm_green()[i][j];
                int blue = info.getIm_blue()[i][j];
                int grayscale = (red*38+green*75+blue*15)>>7;
                g.setColor(new Color(grayscale,grayscale,grayscale));
                g.drawLine(i,j,i,j);
            }
        }

        效果如下

java图片二值化 java数字图像处理_灰度图像_02

        二值图像

        二值图像说白了就是只有黑色和白色,实现也很简单,对灰度图像的灰度值进行判断,如果小于某一个值则设置成黑0,大于某个值就设置成白255

int im_width = info.getIm_width();
        int im_height = info.getIm_height();
        for(int i=0;i<im_width;i++){
            for (int j =0;j<im_height;j++){
                int red = info.getIm_red()[i][j];
                int green = info.getIm_green()[i][j];
                int blue = info.getIm_blue()[i][j];
                int grayscale = (red*38+green*75+blue*15)>>7;
                int binary = 255;
                if(grayscale < 70){
                    binary = 0;
                }
                g.setColor(new Color(binary,binary,binary));
                g.drawLine(i,j,i,j);
            }
        }

        效果如下

java图片二值化 java数字图像处理_i++_03

         通过设置不同的阈值,可以实现不同的结果,比如阈值很低时,可以勾勒出描边!

        负片

        负片的实现也很简单,将得到的RGB数据对应反转即可(255-x)

int im_width = info.getIm_width();
        int im_height = info.getIm_height();
        for(int i=0;i<im_width;i++){
            for (int j =0;j<im_height;j++){
                int red = info.getIm_red()[i][j];
                int green = info.getIm_green()[i][j];
                int blue = info.getIm_blue()[i][j];
                red=255-red;
                green=255-green;
                blue=255-blue;
                g.setColor(new Color(red,green,blue));
                g.drawLine(i,j,i,j);
            }
        }

        实现效果如下

java图片二值化 java数字图像处理_灰度图像_04

         马赛克

        马赛克效果的实现会比前面几种稍复杂些,但是也是基于对像素的处理

        马赛克效果说白了就是模糊边界,将一个区域的像素都填充为同一个,做到了涂抹的效果

int im_width = info.getIm_width();
        int im_height = info.getIm_height();
        for(int i=0;i<im_width-10;i=i+10){
            for (int j =0;j<im_height-10;j=j+10){
                int red = info.getIm_red()[i][j];
                int green = info.getIm_green()[i][j];
                int blue = info.getIm_blue()[i][j];
                g.setColor(new Color(red,green,blue));
                g.fillRect(i,j,10,10);
            }
        }

        单是上面的处理还不够,对于边界还有一部分余量不满足处理步长(上例中为10)的,需要额外进行处理,我采用的是填充左上角的像素颜色

int w=im_width%10;
        int h=im_height%10;
        //补齐底部余量
        for(int i=0;i<im_width-10;i=i+10){
            int red = info.getIm_red()[i][im_height-h];
            int green = info.getIm_green()[i][im_height-h];
            int blue = info.getIm_blue()[i][im_height-h];
            g.setColor(new Color(red,green,blue));
            g.fillRect(i,im_height-h,10,h);
        }
        //补齐右侧余量
        for(int j=0;j<im_height-10;j=j+10){
            int red = info.getIm_red()[im_width-w][j];
            int green = info.getIm_green()[im_width-w][j];
            int blue = info.getIm_blue()[im_width-w][j];
            g.setColor(new Color(red,green,blue));
            g.fillRect(im_width-w,j,w,10);
        }

         实现效果如下

        

java图片二值化 java数字图像处理_图像处理_05

        另外,通过修改执行马赛克算法的步长,可以修改马赛克模糊的大小,比如我修改为50,马赛克会变大,当然,图片的内容也就更加模糊了!

java图片二值化 java数字图像处理_灰度图像_06

        复古

        复古滤镜也有特定算法,直接给出代码和结果

int im_width = info.getIm_width();
        int im_height = info.getIm_height();
        for(int i=0;i<im_width;i++){
            for (int j =0;j<im_height;j++){
                int red = info.getIm_red()[i][j];
                int green = info.getIm_green()[i][j];
                int blue = info.getIm_blue()[i][j];
                int R = (int) (0.393 * red + 0.469 * green + 0.049 * blue);
                int G = (int) (0.349 * red + 0.586 * green + 0.068 * blue);
                int B = (int) (0.272 * red + 0.534 * green + 0.031 * blue);
                g.setColor(new Color(R,G,B));
                g.drawLine(i,j,i,j);
            }
        }

        实现效果如下

java图片二值化 java数字图像处理_灰度图像_07

         锐化

        锐化效果实际上就是增加不同像素颜色之间的差异,也就是边缘增强效果,这里可以用到卷积来处理,不了解卷积原理的同学可以参照这篇 - 文章

        比较简单和常见的卷积核是3*3的只有中心为9,其它为-1的核,我使用的就是这种卷积核,但是要注意卷积边界问题,需要额外处理留下的卷积核大小-1的空隙

        这里常见的有两种方法:1. 直接对空出来的地方进行额外处理,填充像素即可;2. 在原始图像补一圈或者多圈‘0’,就能做到全卷积了。

        我这里采用直接处理的方法

int im_width = info.getIm_width();
        int im_height = info.getIm_height();

        for(int i=0;i<im_width-kernel_size+1;i++){
            for(int j =0;j<im_height-kernel_size+1;j++){
                int red=0,green=0,blue=0;
                for(int x=0;x<kernel_size;x++){
                    for(int y=0;y<kernel_size;y++){
                        red=red+info.getIm_red()[i+x][j+y]*kernel_sharp[x][y];
                        green=green+info.getIm_green()[i+x][j+y]*kernel_sharp[x][y];
                        blue=blue+info.getIm_blue()[i+x][j+y]*kernel_sharp[x][y];
                    }
                }
                red=red>255?255:Math.max(0,red);
                green=green>255?255:Math.max(0,green);
                blue=blue>255?255:Math.max(0,blue);
                g.setColor(new Color(red,green,blue));
                g.drawLine(i,j,i,j);
                //补充底层缺失像素 - 也可以图像外圈使用补0的方法
                if(j==(im_height-kernel_size)){
                    for(int m=0;m<kernel_size-1;m++){
                        red=info.getIm_red()[i][j+m+1];
                        green=info.getIm_green()[i][j+m+1];
                        blue=info.getIm_green()[i][j+m+1];
                        g.setColor(new Color(red,green,blue));
                        g.drawLine(i,j+m+1,i,j+m+1);
                    }
                }
            }
            //补充右侧缺失像素
            if(i==(im_width-kernel_size)){
                for(int n=0;n<kernel_size-1;n++){
                    for(int j =0;j<im_height;j++){
                        int red=info.getIm_red()[i+n+1][j];
                        int green=info.getIm_green()[i+n+1][j];
                        int blue=info.getIm_green()[i+n+1][j];
                        g.setColor(new Color(red,green,blue));
                        g.drawLine(i+n+1,j,i+n+1,j);
                    }
                }
            }

        }

        实现效果如下

java图片二值化 java数字图像处理_java_08