图像处理之简单综合实例(大米计数)
来源:互联网 发布:windows打开dos快捷键 编辑:程序博客网 时间:2024/04/27 17:05
图像处理之简单综合实例(大米计数)
一位网友给我发了几张灰度图像,说是他们单位的工业相机拍摄的,画质非常的清楚,他们
单位是农业科研单位,特别想知道种子的数量,他想知道的是每次工业相机拍摄种子图片中
有多少颗粒种子,想到了用图像处理的办法解决他们的问题,看了他给我照片,以大米种子
为例。实现了一个简单的算法流程,可以得到种子的数目。
大致算法分为以下三个步骤:
1. 将灰度图像二值化,二值化方法可以参考以前的文章,求取像素平均值,灰度直方图都
可以
2. 去掉二值化以后的图像中干扰噪声。
3. 得到种子数目,用彩色标记出来。
源图像如下:
程序处理中间结果及最终效果如下:
二值化处理参见以前的文章 - http://blog.csdn.net/jia20003/article/details/7392325
大米计数与噪声块消去算法基于连通组件标记算法,源代码如下:
package com.gloomyfish.rice.analysis;import java.awt.image.BufferedImage;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import com.gloomyfish.face.detection.AbstractBufferedImageOp;import com.gloomyfish.face.detection.FastConnectedComponentLabelAlg;public class FindRiceFilter extends AbstractBufferedImageOp {private int sumRice;public int getSumRice() {return this.sumRice;}@Overridepublic 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]; getRGB(src, 0, 0, width, height, inPixels ); FastConnectedComponentLabelAlg fccAlg = new FastConnectedComponentLabelAlg();fccAlg.setBgColor(0);int[] outData = fccAlg.doLabel(inPixels, width, height);// labels statisticHashMap<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);}}}// try to find the max connected componentInteger[] 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);}System.out.println( "Number of " + key + " = " + labelMap.get(key));}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;}}大米着色处理很简单,只是简单RGB固定着色,源码如下:
package com.gloomyfish.rice.analysis;import java.awt.image.BufferedImage;import com.gloomyfish.face.detection.AbstractBufferedImageOp;public class ColorfulRiceFilter extends AbstractBufferedImageOp {@Overridepublic 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]; getRGB(src, 0, 0, width, height, inPixels ); int index = 0, srcrgb; for(int row=0; row<height; row++) { int ta = 255, 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; srcrgb = inPixels[index] & 0x000000ff; if(srcrgb > 0 && row < 140) { tr = 0; tg = 255; tb = 0; } else if(srcrgb > 0 && row >= 140 && row <=280) { tr = 0; tg = 0; tb = 255; } else if(srcrgb > 0 && row >=280) { tr = 255; tg = 0; tb = 0; } else { tr = tg = tb = 0; } outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb; } } setRGB( dest, 0, 0, width, height, outPixels ); return dest;}}测试程序UI代码如下:
package com.gloomyfish.rice.analysis;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Image;import java.awt.MediaTracker;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;import javax.imageio.ImageIO;import javax.swing.JButton;import javax.swing.JComponent;import javax.swing.JFileChooser;import javax.swing.JFrame;import javax.swing.JPanel;public class MainFrame extends JComponent implements ActionListener {/** * */private static final long serialVersionUID = 1518574788794973574L;public final static String BROWSE_CMD = "Browse...";public final static String NOISE_CMD = "Remove Noise";public final static String FUN_CMD = "Colorful Rice";private BufferedImage rawImg;private BufferedImage resultImage;private MediaTracker tracker;private Dimension mySize;// JButtonsprivate JButton browseBtn;private JButton noiseBtn;private JButton colorfulBtn;// rice number....private int riceNum = -1;public MainFrame() {JPanel btnPanel = new JPanel();btnPanel.setLayout(new FlowLayout(FlowLayout.LEFT));browseBtn = new JButton("Browse...");noiseBtn = new JButton("Remove Noise");colorfulBtn = new JButton("Colorful Rice");browseBtn.setToolTipText("Please select image file...");noiseBtn.setToolTipText("find connected region and draw red rectangle");colorfulBtn.setToolTipText("Remove the minor noise region pixels...");// buttonsbtnPanel.add(browseBtn);btnPanel.add(noiseBtn);btnPanel.add(colorfulBtn);// setup listener...browseBtn.addActionListener(this);noiseBtn.addActionListener(this);colorfulBtn.addActionListener(this);browseBtn.setEnabled(true);noiseBtn.setEnabled(true);colorfulBtn.setEnabled(true);//minX = minY = 10000;//maxX = maxY = -1;mySize = new Dimension(500, 300);JFrame demoUI = new JFrame("Rice Detection Demo");demoUI.getContentPane().setLayout(new BorderLayout());demoUI.getContentPane().add(this, BorderLayout.CENTER);demoUI.getContentPane().add(btnPanel, BorderLayout.SOUTH);demoUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);demoUI.pack();demoUI.setVisible(true);}public void paint(Graphics g) {Graphics2D g2 = (Graphics2D) g;if(rawImg != null) {Image scaledImage = rawImg.getScaledInstance(200, 200, Image.SCALE_FAST);g2.drawImage(scaledImage, 0, 0, 200, 200, null);}if(resultImage != null) {Image scaledImage = resultImage.getScaledInstance(200, 200, Image.SCALE_FAST);g2.drawImage(scaledImage, 210, 0, 200, 200, null);}g2.setPaint(Color.RED);if(riceNum > 0) {g2.drawString("Number of Rice : " + riceNum, 100, 300);} else {g2.drawString("Number of Rice : Unknown", 100, 300);}}public Dimension getPreferredSize() {return mySize;}public Dimension getMinimumSize() {return mySize;}public Dimension getMaximumSize() {return mySize;}public static void main(String[] args) {new MainFrame();}@Overridepublic void actionPerformed(ActionEvent e) {if(BROWSE_CMD.equals(e.getActionCommand())) {JFileChooser chooser = new JFileChooser();chooser.showOpenDialog(null);File f = chooser.getSelectedFile();BufferedImage bImage = null;if(f == null) return;try {bImage = ImageIO.read(f);} catch (IOException e1) {e1.printStackTrace();}tracker = new MediaTracker(this);tracker.addImage(bImage, 1);// blocked 10 seconds to load the image datatry {if (!tracker.waitForID(1, 10000)) {System.out.println("Load error.");System.exit(1);}// end if} catch (InterruptedException ine) {ine.printStackTrace();System.exit(1);} // end catchBinaryFilter bfilter = new BinaryFilter();rawImg = bfilter.filter(bImage, null);repaint();} else if(NOISE_CMD.equals(e.getActionCommand())) {FindRiceFilter frFilter = new FindRiceFilter();resultImage = frFilter.filter(rawImg, null);riceNum = frFilter.getSumRice();repaint();} else if(FUN_CMD.equals(e.getActionCommand())) {ColorfulRiceFilter cFilter = new ColorfulRiceFilter();resultImage = cFilter.filter(resultImage, null);repaint();} else {// do nothing...}}}关于连通组件标记算法,我实现一个优化过的快速版本,可以参见
http://blog.csdn.net/jia20003/article/details/7596443
- 图像处理------简单综合实例(大米计数)
- 图像处理之简单综合实例(大米计数)
- 图像处理之应用篇-大米计数续
- 图像处理之应用篇-大米计数续
- vue.js之简单综合实例
- 图像处理实例之绘图板
- Qt Quick 图像处理实例之美图秀秀
- 图像处理与matlab实例之图像平滑(一)
- 图像处理之图像分割之Snake算法简单梳理
- Python之简单的图像处理
- 图像处理之简单脸谱检测算法
- OpenCV入门:简单图像处理实例——平滑滤波
- iOS图像处理之Core Image 之二 实例运用
- java图像处理--连通区域计数bwlable
- Struts2之Crud综合实例
- shiro框架之综合实例
- 图像的简单处理
- 简单的图像处理
- setsockopt
- 2012-04-14 C#基础学习笔记(11)
- linux下用rpm 安装jdk
- Java之extends implement
- hibernate批量处理数据
- 图像处理之简单综合实例(大米计数)
- ssh整合jar包的导入
- 对1-9三个数组成1:2:3的自己理解
- 当 IDENTITY_INSERT 设置为 OFF 时,不能向表 'OrderList' 中的标识列插入显式值
- 自写随机生成十个随机数,使他们总和为100的小程序
- VB控件随窗体最大化变化的方法
- Platform-independent is Nothing
- vs2008 技巧
- playing with dacapo using aspectj [the series about program instrumentation is done]