图像处理之应用篇-大米计数续

简介: 图像处理之应用篇-大米计数续

图像处理之应用篇-大米计数续


背景介绍:


请看博客文章《图像处理之简单综合实例(大米计数)》


其实拍出来的照片更多的是含有大米颗粒相互接触,甚至于有点重叠的照片


要准确计算大米的颗粒数非常困难,通过图像形态学开闭操作,腐蚀等手


段尝试以后效果不是很好。最终发现一种简单明了但是有微小误差的计数


方法。照相机图片:

1342538469_7927.png


算法思想:


主要是利用连通区域发现算法,发现所有连通区域,使用二分法,截取较小


部分的连通区域集合,求取平均连通区域面积,根据此平均连通区域面积,


作为单个大米大小,从而求取出粘连部分的大米颗粒数,完成对整个大米


数目的统计:


缺点:


平均连通区域面积的计算受制于两个因素,一个是最小连通区域集合的选取算法,


二个样本数量。算法结果跟实际结果有一定的误差,但是误差在1%左右。



程序算法代码详解


将输入图像转换为黑白二值图像,求得连通区域的算法代码如下:


src = super.filter(src, null);


getRGB(src, 0, 0, width,height, inPixels );


FastConnectedComponentLabelAlgfccAlg = new FastConnectedComponentLabelAlg();


fccAlg.setBgColor(0);


int[] outData = fccAlg.doLabel(inPixels, width, height);



获取平均大米颗粒连通区域的代码如下:


Integer[] values =labelMap.values().toArray(new Integer[0]);


Arrays.sort(values);


int minRiceNum = values.length/4;


float sum = 0;


for(int v= offset; v<minRiceNum + offset; v++) {


sum += values[v].intValue();


}


float minMeans = sum / (float)minRiceNum;


System.out.println(" minMeans = " + minMeans);



程序时序图如下:

1342538494_5263.png


程序运行效果如下:


1342538600_4197.png

实际大米颗粒数目为202,正确率为99%


完成大米数目统计的源代码如下(其它相关代码见以前的图像处理系列文章):

public class FindRiceFilter extends BinaryFilter {
  
  private int sumRice;
  private int offset = 10;
  
  public int getSumRice() {
    return this.sumRice;
  }
  
  public void setOffset(int pos) {
    this.offset = pos;
  }
 
  @Override
  public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    int width = src.getWidth();
        int height = src.getHeight();
        if ( dest == null )
            dest = createCompatibleDestImage( src, null );
 
        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        src = super.filter(src, null);
        getRGB(src, 0, 0, width, height, inPixels );
        FastConnectedComponentLabelAlg fccAlg = new FastConnectedComponentLabelAlg();
    fccAlg.setBgColor(0);
    int[] outData = fccAlg.doLabel(inPixels, width, height);
    
    // labels statistic
    HashMap<Integer, Integer> labelMap = new HashMap<Integer, Integer>();
    for(int d=0; d<outData.length; d++) {
      if(outData[d] != 0) {
        if(labelMap.containsKey(outData[d])) {
          Integer count = labelMap.get(outData[d]);
          count+=1;
          labelMap.put(outData[d], count);
        } else {
          labelMap.put(outData[d], 1);
        }
      }
    }
    
    Integer[] values = labelMap.values().toArray(new Integer[0]);
    Arrays.sort(values);
    int minRiceNum = values.length/4;
    float sum = 0;
    for(int v= offset; v<minRiceNum + offset; v++) {
      sum += values[v].intValue();
    }
    float minMeans = sum / (float)minRiceNum;
    System.out.println(" minMeans = " + minMeans);
    
    // try to find the max connected component
    Integer[] keys = labelMap.keySet().toArray(new Integer[0]);
    Arrays.sort(keys);
    int threshold = 10;
    ArrayList<Integer> listKeys = new ArrayList<Integer>();
    for(Integer key : keys) {
      if(labelMap.get(key) <=threshold){
        listKeys.add(key);
      } else {
        float xx = labelMap.get(key);
        float intPart = (float)Math.floor(xx / minMeans + 0.5f);
        sumRice += intPart;
      }
    }
    System.out.println( "Number of rice  = " + sumRice);
    // sumRice = keys.length - listKeys.size();
    
        // calculate means of pixel  
        int index = 0;    
        for(int row=0; row<height; row++) {  
            int ta = 0, tr = 0, tg = 0, tb = 0;  
            for(int col=0; col<width; col++) {  
                index = row * width + col;  
                ta = (inPixels[index] >> 24) & 0xff;  
                tr = (inPixels[index] >> 16) & 0xff;  
                tg = (inPixels[index] >> 8) & 0xff;  
                tb = inPixels[index] & 0xff;
                if(outData[index] != 0 && validRice(outData[index], listKeys)) {
                  tr = tg = tb = 255;
                } else {
                  tr = tg = tb = 0;
                }
                outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
            }
        }
        setRGB( dest, 0, 0, width, height, outPixels );
        return dest;
  }
 
  private boolean validRice(int i, ArrayList<Integer> listKeys) {
    for(Integer key : listKeys) {
      if(key == i) {
        return false;
      }
    }
    return true;
  }
 
}

转载文章请务必注明出处

相关文章
|
6月前
|
计算机视觉 Python
Yolov5双目测距-双目相机计数及测距教程(附代码)
Yolov5双目测距-双目相机计数及测距教程(附代码)
|
6月前
|
机器学习/深度学习 编解码 监控
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-1
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-1
|
6月前
|
机器学习/深度学习 算法 计算机视觉
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A路径规划+单目测距与测速+行人车辆计数等)
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A路径规划+单目测距与测速+行人车辆计数等)
112 2
|
19天前
|
传感器 存储 小程序
跳绳计数小程序开发
跳绳计数小程序旨在通过智能设备(如手机或智能手表)记录用户在跳绳过程中的次数、时间、速度等关键数据,为用户提供便捷的运动记录和数据分析服务
|
6月前
|
机器学习/深度学习 算法 计算机视觉
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
|
6月前
|
机器学习/深度学习 编解码 算法
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)-2
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)-2
|
6月前
|
机器学习/深度学习 监控 算法
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)-1
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)-1
|
5月前
|
算法 计算机视觉
图像处理之简单综合实例(大米计数)
图像处理之简单综合实例(大米计数)
22 0
|
6月前
|
机器学习/深度学习 算法
应用规则学习算法识别有毒的蘑菇
应用规则学习算法识别有毒的蘑菇
|
6月前
|
机器学习/深度学习 存储 编解码
彩票开奖彩票开奖BCFPL:基于二元分类的低分辨率图像快速停车位识别
彩票开奖BCFPL:基于二元分类的低分辨率图像快速停车位识别
75 0