• 基于Java BufferedImage实现识别图片中的黑色矩形


    基于Java BufferedImage实现识别图片中的黑色矩形

    前言:在项目中需要实现将图片中的黑色矩形替换为其他图形,其中的难点在于图片中存在其他黑点或者黑色小方块。

    实现思路:

    • 二值化,将纯黑的区域保留下来,其他区域编程白色。
    • 去噪:去除噪点
    • 转为矩阵,将黑色像素点的位置的值设为1,其他位置的值设为0
    • 求极大全为1的子矩阵,使用悬吊法求极大全为1的子矩阵

    二值化代码:

    public static void binaryImage(String filePath,double threshold){
            try {
                BufferedImage image = ImageIO.read(new File(filePath));
                int minX = 0;//图片起始点X
                int minY = 0;//图片起始点Y
                int width = image.getWidth();//图片的宽度
                m = width;
                int height = image.getHeight();//图片的高度
                n = height;
                //将黑色区域化为1,其他为0
                for (int i = minX; i < width; i++) {
                        for (int j = minY; j < height; j++) {
                        Object data = image.getRaster().getDataElements(i, j, null);//获取该点像素,并以object类型表示
                        int red = image.getColorModel().getRed(data);
                        int blue = image.getColorModel().getBlue(data);
                        int green = image.getColorModel().getGreen(data);
                        if(red==0&&green==0&&blue==0){
                            a[i+1 ][j+1 ] = 1;
                        }
                    }
                }
            }catch (IOException e) {
                    e.printStackTrace();
            }
        }
    

    去噪:

     public static void removeNoise(int whiteThreshold,int blackThreshold){
            int i,j,nValue,nCount,m,n;
            int nWidth=Calculate.maxn;
            int nHeight=Calculate.maxn;
            //对图像上下边缘去噪
            for(i=0;i<nWidth;i++){
                a[i][0]=0;
                a[i][nHeight-1]=0;
            }
            //对图像上下边缘去噪
            for( i=0;i<nHeight;i++){
                a[0][i]=0;
                a[0][nWidth-1]=0;
            }
    
            //根据周围点的颜色去噪
        //遍历所有的点     //j是y,  i是x
            for(i=1;i<nWidth-1;i++){
                for( j=1;j<nHeight-1;j++){
                    nValue=a[i][j];
                    if(nValue==1&&whiteThreshold!=0){//如果一点是黑点
                        nCount=0;
                        //遍历他周围的八个点,如果他
                        for(m=j-1;m<=j+1;m++){
                            for(n=i-1;n<=i+1;n++){
                                if(a[n][m]==0){//周围白点的个数
                                    nCount++;
                                }
                            }
                        }
                        if(nCount>=whiteThreshold){//周围白点的个数大于阈值则变为白色
                            a[i][j]=0;
                        }
                    }else{//如果一个点是白色的点,周围的点是黑色
                        nCount=0;
                        for(m=j-1;m<=j+1;m++){
                            for(n=i-1;n<=i+1;n++){
                                if(a[n][m]==1){
                                    nCount++;
                                }
                            }
                        }
                        if(nCount>=blackThreshold){//周围黑点的个数大于阈值就变成黑色
                            a[i][j]=1;
                        }
                    }
                }
            }
        }
    

    找到极大全为1的矩形矩阵:

    public static void findMaxBlackRect(){
            int ans = 0;
            //初始化
            for(int i=1;i<=m;++i) {
                l[0][i] = 1;
                r[0][i] = m;
            }
    
            for(int i=1; i<=n; i++){
                int maxl=1, maxr=m;
                //计算h和l
                for(int j=1; j<=m; j++){
                    if(a[i][j]==0){
                        h[i][j] = 0;
                        l[i][j] = 1;
                        maxl = j+1;
                    }else{
                        l[i][j] = Math.max(l[i-1][j],maxl);
                        h[i][j] = h[i-1][j]+1;
                    }
                }
                //计算r
                for(int j=m; j>=1; j--){
                    if(a[i][j]==0){
                        r[i][j] = m;
                        maxr = j-1;
                    }else{
                        r[i][j] = Math.min(r[i-1][j],maxr);
                        int temp=ans;
                        ans = Math.max(ans,(r[i][j]-l[i][j]+1)*h[i][j]);
                        if(temp!=ans){
                            y1=l[i][j];
                            x1=i-h[i][j]+1;
                            rwidth=r[i][j]-l[i][j]+1;
                            rheight=h[i][j];
                           // System.out.println("i: "+i+" j:"+j+" l:"+l[i][j]+" r:"+r[i][j]+" h:"+h[i][j]);
                        }
                    }
                }
            }
            //由于在二值化时将所有的点横纵坐标都加了1,找到矩形起点时要减去1
            x1=x1-1;
            y1=y1-1;
            System.out.println("x1: "+x1+" y1: "+y1+"  "+rwidth+" height: "+rheight);
        }
    

    粘贴图片:

        public static void stickImage(String bigImagePath,String smallImagePath,String outImagePath) {
            try {
                BufferedImage bigImage = ImageIO.read(new File(bigImagePath));
                BufferedImage smallImage = ImageIO.read(new File(smallImagePath));
                Graphics2D gh=bigImage.createGraphics();
                gh.drawImage(smallImage,null,x1,y1);
                gh.dispose();
                ImageIO.write(bigImage,"jpg",new File(outImagePath));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
    
        }
    

    没有输出路劲就随机产生一个:

     public static void stickImage(String bigImagePath,String smallImagePath) {
            try {
                BufferedImage bigImage = ImageIO.read(new File(bigImagePath));
                BufferedImage smallImage = ImageIO.read(new File(smallImagePath));
                Graphics2D gh=bigImage.createGraphics();
                gh.drawImage(smallImage,null,x1,y1);
                gh.dispose();
                ImageIO.write(bigImage,"jpg",new File(Generate.randomOutPutPath()));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
    
        }
    

    全文程序:

    package com.edupt;
    
    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    
    
    public class Calculate {
        static int maxn = 2000;
         static int n,m;
         static  int[][]a=new int[maxn][maxn]; //二值化结果
        // static int[][]pixels;
         static int[][]h=new int[maxn][maxn]; //高度
         static int[][]l=new int[maxn][maxn];//向左能移动到的终点
         static int[][]r=new  int [maxn][maxn];//向右能移动到的终点
         static  int x1;
         static  int y1;
         static  int x2;
         static  int y2;
         static  int rwidth;
         static  int rheight;
         static final int FZ=130;
        public static void main(String[] args) {
            String filePath="C:\Users\86130\Desktop\素材\2019-12-30-17-56.jpg";
            String filePath2="C:\Users\86130\Desktop\素材\BigHead.jpg";
          //  String outPath="C:\Users\86130\Desktop\素材\result1.jpg";
            binaryImage(filePath,7);
    
          //  removeNoise(0,3);
            print();
           // findMaxBlackRect();
            //stickImage(filePath,filePath2);
        }
    
        //二值化图像
        public static void binaryImage(String filePath,double threshold){
            try {
                BufferedImage image = ImageIO.read(new File(filePath));
                int minX = 0;//图片起始点X
                int minY = 0;//图片起始点Y
                int width = image.getWidth();//图片的宽度
                m = width;
                int height = image.getHeight();//图片的高度
                n = height;
                //pixels=new int[height][width];
                //将黑色区域化为1,其他为0
                for (int i = minX; i < width; i++) {
                        for (int j = minY; j < height; j++) {
                        Object data = image.getRaster().getDataElements(i, j, null);//获取该点像素,并以object类型表示
                        int red = image.getColorModel().getRed(data);
                        int blue = image.getColorModel().getBlue(data);
                        int green = image.getColorModel().getGreen(data);
                        if(red==0&&green==0&&blue==0){
                            a[i+1 ][j+1 ] = 1;
                        }
    
                    }
                }
            }catch (IOException e) {
                    e.printStackTrace();
            }
    
    
        }
    
        /**
         *
         * @param whiteThreshold 默认为0
         * @param blackThreshold
         */
        public static void removeNoise(int whiteThreshold,int blackThreshold){
            int i,j,nValue,nCount,m,n;
            int nWidth=Calculate.maxn;
            int nHeight=Calculate.maxn;
            //对图像上下边缘去噪
            for(i=0;i<nWidth;i++){
                a[i][0]=0;
                a[i][nHeight-1]=0;
            }
            //对图像上下边缘去噪
            for( i=0;i<nHeight;i++){
                a[0][i]=0;
                a[0][nWidth-1]=0;
            }
    
            //根据周围点的颜色去噪
            //遍历所有的点     //j是y,  i是x
            for(i=1;i<nWidth-1;i++){
                for( j=1;j<nHeight-1;j++){
                    nValue=a[i][j];
                    if(nValue==1&&whiteThreshold!=0){//如果一点是黑点
                        nCount=0;
                        //遍历他周围的八个点,如果他
                        for(m=j-1;m<=j+1;m++){
                            for(n=i-1;n<=i+1;n++){
                                if(a[n][m]==0){//周围白点的个数
                                    nCount++;
                                }
                            }
                        }
                        if(nCount>=whiteThreshold){//周围白点的个数大于阈值则变为白色
                            a[i][j]=0;
                        }
                    }else{//如果一个点是白色的点,周围的点是黑色
                        nCount=0;
                        for(m=j-1;m<=j+1;m++){
                            for(n=i-1;n<=i+1;n++){
                                if(a[n][m]==1){
                                    nCount++;
                                }
                            }
                        }
                        if(nCount>=blackThreshold){//周围黑点的个数大于阈值就变成黑色
                            a[i][j]=1;
                        }
                    }
                }
            }
        }
    
        //找到极大全为1的矩形矩阵
        public static void findMaxBlackRect(){
            int ans = 0;
            //初始化
            for(int i=1;i<=m;++i) {
                l[0][i] = 1;
                r[0][i] = m;
            }
    
            for(int i=1; i<=n; i++){
                int maxl=1, maxr=m;
                //计算h和l
                for(int j=1; j<=m; j++){
                    if(a[i][j]==0){
                        h[i][j] = 0;
                        l[i][j] = 1;
                        maxl = j+1;
                    }else{
                        l[i][j] = Math.max(l[i-1][j],maxl);
                        h[i][j] = h[i-1][j]+1;
                    }
                }
                //计算r
                for(int j=m; j>=1; j--){
                    if(a[i][j]==0){
                        r[i][j] = m;
                        maxr = j-1;
                    }else{
                        r[i][j] = Math.min(r[i-1][j],maxr);
                        int temp=ans;
                        ans = Math.max(ans,(r[i][j]-l[i][j]+1)*h[i][j]);
                        if(temp!=ans){
                            y1=l[i][j];
                            x1=i-h[i][j]+1;
                            rwidth=r[i][j]-l[i][j]+1;
                            rheight=h[i][j];
                           // System.out.println("i: "+i+" j:"+j+" l:"+l[i][j]+" r:"+r[i][j]+" h:"+h[i][j]);
                        }
                    }
                }
            }
            //由于在二值化时将所有的点横纵坐标都加了1,找到矩形起点时要减去1
            x1=x1-1;
            y1=y1-1;
            System.out.println("x1: "+x1+" y1: "+y1+"  "+rwidth+" height: "+rheight);
        }
    
        //粘贴图片
        public static void stickImage(String bigImagePath,String smallImagePath,String outImagePath) {
            try {
                BufferedImage bigImage = ImageIO.read(new File(bigImagePath));
                BufferedImage smallImage = ImageIO.read(new File(smallImagePath));
                Graphics2D gh=bigImage.createGraphics();
                gh.drawImage(smallImage,null,x1,y1);
                gh.dispose();
                ImageIO.write(bigImage,"jpg",new File(outImagePath));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
    
        }
        //没有输出路劲就随机产生一个
        public static void stickImage(String bigImagePath,String smallImagePath) {
            try {
                BufferedImage bigImage = ImageIO.read(new File(bigImagePath));
                BufferedImage smallImage = ImageIO.read(new File(smallImagePath));
                Graphics2D gh=bigImage.createGraphics();
                gh.drawImage(smallImage,null,x1,y1);
                gh.dispose();
                ImageIO.write(bigImage,"jpg",new File(Generate.randomOutPutPath()));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
    
        }
    
        public static void print(){
            String filePath="C:\Users\86130\Desktop\素材\2019-12-30-14-30.jpg";
            try {
                BufferedImage image=ImageIO.read(new File(filePath));
                for(int i=501;i<=1000;i++){
                    for(int j=501;j<=1000;j++){
                        if(a[i][j]==0){
                            Object data = image.getRaster().getDataElements(i-1, j-1, null);//获取该点像素,并以object类型表示
                        int red = image.getColorModel().getRed(data);
                        int blue = image.getColorModel().getBlue(data);
                        int green = image.getColorModel().getGreen(data);
                        System.out.print("[ red "+red+" blue "+blue+" green "+green+" ]");
                        }
                    }
                    System.out.println();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    
  • 相关阅读:
    NET基础课--NET的一些概念0
    项目异常及处理方法记录
    个人总结
    NuGet学习笔记(4)—— 实践
    NuGet学习笔记(3)——搭建属于自己的NuGet服务器(转)
    NuGet学习笔记(2)——使用图形化界面打包自己的类库(转)
    NuGet学习笔记(1)——初识NuGet及快速安装使用(转)
    关系数据库SQL之基本数据查询:子查询、分组查询、模糊查询
    <iOS>UIImage变为NSData并进行压缩
    iOS 将NSArray、NSDictionary转换为JSON格式进行网络传输
  • 原文地址:https://www.cnblogs.com/c-lover/p/12131704.html
Copyright © 2020-2023  润新知