基於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+" width: "+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+" width: "+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();
        }
    }

}


免責聲明!

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



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