zoukankan      html  css  js  c++  java
  • Java基于opencv实现图像数字识别(四)—图像降噪

    Java基于opencv实现图像数字识别(四)—图像降噪

    我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类

    这个工具类呢,就一个成员变量Mat,非常的简单,这里给出代码

    public class ImageUtils {
    	private static final int BLACK = 0;
    	private static final int WHITE = 255;
    
    	private Mat mat;
    
    	/**
    	 * 空参构造函数
    	 */
    	public ImageUtils() {
    
    	}
    
    	/**
    	 * 通过图像路径创建一个mat矩阵
    	 * 
    	 * @param imgFilePath
    	 *            图像路径
    	 */
    	public ImageUtils(String imgFilePath) {
    		mat = Imgcodecs.imread(imgFilePath);
    	}
    
    	public void ImageUtils(Mat mat) {
    		this.mat = mat;
    	}
    
    	/**
    	 * 加载图片
    	 * 
    	 * @param imgFilePath
    	 */
    	public void loadImg(String imgFilePath) {
    		mat = Imgcodecs.imread(imgFilePath);
    	}
    
    	/**
    	 * 获取图片高度的函数
    	 * 
    	 * @return
    	 */
    	public int getHeight() {
    		return mat.rows();
    	}
    
    	/**
    	 * 获取图片宽度的函数
    	 * 
    	 * @return
    	 */
    	public int getWidth() {
    		return mat.cols();
    	}
    
    	/**
    	 * 获取图片像素点的函数
    	 * 
    	 * @param y
    	 * @param x
    	 * @return
    	 */
    	public int getPixel(int y, int x) {
    		// 我们处理的是单通道灰度图
    		return (int) mat.get(y, x)[0];
    	}
    
    	/**
    	 * 设置图片像素点的函数
    	 * 
    	 * @param y
    	 * @param x
    	 * @param color
    	 */
    	public void setPixel(int y, int x, int color) {
    		// 我们处理的是单通道灰度图
    		mat.put(y, x, color);
    	}
    
    	/**
    	 * 保存图片的函数
    	 * 
    	 * @param filename
    	 * @return
    	 */
    	public boolean saveImg(String filename) {
    		return Imgcodecs.imwrite(filename, mat);
    	}
    }
    

    灰度化和二值化的代码我没有贴出来,因为代码实在有点长

    我们接着上一步的成果,来开始我们的降噪

    一、8邻域降噪

    我感觉9宫格降噪更形象一点;即9宫格中心被异色包围,则同化
    8邻域降噪

    降噪效果还是蛮好的,这个方法对小噪点比较好

    /**
    	 * 8邻域降噪,又有点像9宫格降噪;即如果9宫格中心被异色包围,则同化
    	 * @param pNum 默认值为1
    	 */
    	public void navieRemoveNoise(int pNum) {
    		int i, j, m, n, nValue, nCount;
    		int nWidth = getWidth(), nHeight = getHeight();
    
    		// 对图像的边缘进行预处理
    		for (i = 0; i < nWidth; ++i) {
    			setPixel(i, 0, WHITE);
    			setPixel(i, nHeight - 1, WHITE);
    		}
    
    		for (i = 0; i < nHeight; ++i) {
    			setPixel(0, i, WHITE);
    			setPixel(nWidth - 1, i, WHITE);
    		}
    
    		// 如果一个点的周围都是白色的,而它确是黑色的,删除它
    		for (j = 1; j < nHeight - 1; ++j) {
    			for (i = 1; i < nWidth - 1; ++i) {
    				nValue = getPixel(j, i);
    				if (nValue == 0) {
    					nCount = 0;
    					// 比较以(j ,i)为中心的9宫格,如果周围都是白色的,同化
    					for (m = j - 1; m <= j + 1; ++m) {
    						for (n = i - 1; n <= i + 1; ++n) {
    							if (getPixel(m, n) == 0) {
    								nCount++;
    							}
    						}
    					}
    					if (nCount <= pNum) {
    						// 周围黑色点的个数小于阀值pNum,把该点设置白色
    						setPixel(j, i, WHITE);
    					}
    				} else {
    					nCount = 0;
    					// 比较以(j ,i)为中心的9宫格,如果周围都是黑色的,同化
    					for (m = j - 1; m <= j + 1; ++m) {
    						for (n = i - 1; n <= i + 1; ++n) {
    							if (getPixel(m, n) == 0) {
    								nCount++;
    							}
    						}
    					}
    					if (nCount >= 7) {
    						// 周围黑色点的个数大于等于7,把该点设置黑色;即周围都是黑色
    						setPixel(j, i, BLACK);
    					}
    				}
    			}
    		}
    
    	}
    
    
    二、连通域降噪

    floodFill函数

    我们先介绍一个函数(floodFill)

    floodFill就是把一个点x的所有相邻的点都涂上x点的颜色,一直填充下去,直到这个区域内所有的点都被填充完为止

    在计算的过程中,每扫描到一个黑色(灰度值为0)的点,就将与该点连通的所有点的灰度值都改为1,因此这一个连通域的点都不会再次重复计算了。下一个灰度值为0的点所有连通点的颜色都改为2,这样依次递加,直到所有的点都扫描完。接下来再次扫描所有的点,统计每一个灰度值对应的点的个数,每一个灰度值的点的个数对应该连通域的大小,并且不同连通域由于灰度值不同,因此每个点只计算一次,不会重复。这样一来就统计到了每个连通域的大小,再根据预设的阀值,如果该连通域大小小于阀值,则其就为噪点。这个算法比较适合检查大的噪点,与上个算法正好相反。

    连通域降噪

    因为我找的图像关系,效果可能不咋明显;

    /**
    	 * 连通域降噪
    	 * @param pArea 默认值为1
    	 */
    	public void contoursRemoveNoise(double pArea) {
    		int i, j, color = 1;
    		int nWidth = getWidth(), nHeight = getHeight();
    
    		for (i = 0; i < nWidth; ++i) {
    			for (j = 0; j < nHeight; ++j) {
    				if (getPixel(j, i) == BLACK) {
    					//用不同颜色填充连接区域中的每个黑色点
    					//floodFill就是把一个点x的所有相邻的点都涂上x点的颜色,一直填充下去,直到这个区域内所有的点都被填充完为止
    					Imgproc.floodFill(mat, new Mat(), new Point(i, j), new Scalar(color));
    					color++;
    				}
    			}
    		}
    		
    		//统计不同颜色点的个数
    		int[] ColorCount = new int[255];
    
    		for (i = 0; i < nWidth; ++i) {
    			for (j = 0; j < nHeight; ++j) {
    				if (getPixel(j, i) != 255) {
    					ColorCount[getPixel(j, i) - 1]++;
    				}
    			}
    		}
    		
    		//去除噪点
    		for (i = 0; i < nWidth; ++i) {
    			for (j = 0; j < nHeight; ++j) {
    
    				if (ColorCount[getPixel(j, i) - 1] <= pArea) {
    					setPixel(j, i, WHITE);
    				}
    			}
    		}
    
    		for (i = 0; i < nWidth; ++i) {
    			for (j = 0; j < nHeight; ++j) {
    				if (getPixel(j, i) < WHITE) {
    					setPixel(j, i, BLACK);
    				}
    			}
    		}
    
    	}
    

    注:
    本文章参考了很多博客,感谢;主要是跟着一个博客来实现的https://blog.csdn.net/ysc6688/article/category/2913009(也是基于opencv来做的,只不过他是用c++实现的)感谢

  • 相关阅读:
    faster with MyISAM tables than with InnoDB or NDB tables
    w-BIG TABLE 1-toSMALLtable @-toMEMORY
    Indexing and Hashing
    MEMORY Storage Engine MEMORY Tables TEMPORARY TABLE max_heap_table_size
    controlling the variance of request response times and not just worrying about maximizing queries per second
    Variance
    Population Mean
    12.162s 1805.867s
    situations where MyISAM will be faster than InnoDB
    1920.154s 0.309s 30817
  • 原文地址:https://www.cnblogs.com/qjmnong/p/9191076.html
Copyright © 2011-2022 走看看