二值图像分析笔记(7)—— 开闭操作

it2022-05-07  14

1 开操作

主要应用在二值图像分析,灰度图像也可以;开操作 = 腐蚀 + 膨胀, 输入图像 + 结构元素
有利于消除图像中的噪声点分离不同的对象结构,基于不同的结构元素

2 闭操作

闭操作 = 膨胀 + 腐蚀输入 : 图像 + 结构元素不同的结构元素得到不同的效果;
有利于消除图像中的噪声点;分离不同的对象结构;

3 开操作测试

腐蚀 ErosionFilter package binimage.erosion; import binimage.binary.BinaryFilter; import java.awt.image.BufferedImage; public class ErosionFilter extends BinaryFilter { // 前景像素值 private int fcolor; public ErosionFilter() { fcolor = 255; } @Override public BufferedImage process(BufferedImage image) { BufferedImage binImage = super.process(image); int width = binImage.getWidth(); int height = binImage.getHeight(); int[] pixels = new int[width * height]; int[] output = new int[width * height]; getRGB(binImage, 0, 0, width, height, pixels); System.arraycopy(pixels, 0, output, 0, pixels.length); int p1 = 0, p2 = 0, p3 = 0; int p4 = 0, p5 = 0, p6 = 0; int p7 = 0, p8 = 0, p9 = 0; int offset = 0; for (int row = 1; row < height - 1; row++) { offset = row * width; for (int col = 1; col < width - 1; col++) { p1 = (pixels[offset - width + col - 1] >> 16) & 0xff; p2 = (pixels[offset - width + col] >> 16) & 0xff; p3 = (pixels[offset - width + col + 1] >> 16) & 0xff; p4 = (pixels[offset + col - 1] >> 16) & 0xff; p5 = (pixels[offset + col] >> 16) & 0xff; p6 = (pixels[offset + col + 1] >> 16) & 0xff; p7 = (pixels[offset + width + col - 1] >> 16) & 0xff; p8 = (pixels[offset + width + col] >> 16) & 0xff; p9 = (pixels[offset + width + col + 1] >> 16) & 0xff; // 周围全是前景像素 int sum = p1 + p2 + p3 + p4 + p6 + p7 + p8 + p9; int total = fcolor * 8; // 255 * 8 = 2040 if (p5 == fcolor && sum != total) { // 说明周围有一个是背景色,即黑色 int bc = 255 - fcolor; output[offset + col] = (0xff << 24) | ((bc & 0xff) << 16) | ((bc & 0xff) << 8) | (bc & 0xff); } } } BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); setRGB(bi, 0, 0, width, height, output); return bi; } public int getFcolor() { return fcolor; } public void setFcolor(int fcolor) { this.fcolor = fcolor; } } 膨胀 DilationFilter package binimage.dilation; import binimage.binary.BinaryFilter; import java.awt.image.BufferedImage; public class DilationFilter extends BinaryFilter { // 前景像素值 private int fcolor; public DilationFilter() { fcolor = 255; } @Override public BufferedImage process(BufferedImage image) { BufferedImage binImage = super.process(image); int width = binImage.getWidth(); int height = binImage.getHeight(); int[] pixels = new int[width * height]; int[] output = new int[width * height]; getRGB(binImage, 0, 0, width, height, pixels); System.arraycopy(pixels, 0, output, 0, pixels.length); int p1 = 0, p2 = 0, p3 = 0; int p4 = 0, p5 = 0, p6 = 0; int p7 = 0, p8 = 0, p9 = 0; int offset = 0; for (int row = 1; row < height - 1; row++) { offset = row * width; for (int col = 1; col < width - 1; col++) { p1 = (pixels[offset - width + col - 1] >> 16) & 0xff; p2 = (pixels[offset - width + col] >> 16) & 0xff; p3 = (pixels[offset - width + col + 1] >> 16) & 0xff; p4 = (pixels[offset + col - 1] >> 16) & 0xff; p5 = (pixels[offset + col] >> 16) & 0xff; p6 = (pixels[offset + col + 1] >> 16) & 0xff; p7 = (pixels[offset + width + col - 1] >> 16) & 0xff; p8 = (pixels[offset + width + col] >> 16) & 0xff; p9 = (pixels[offset + width + col + 1] >> 16) & 0xff; // 中心像素是背景像素 int sum = p1 + p2 + p3 + p4 + p6 + p7 + p8 + p9; int bc = 255 - fcolor; int total = bc * 8; if (p5 == bc && sum != total) { // 说明周围有一个是前景色,中心像素要设置为前景 output[offset + col] = (0xff << 24) | ((fcolor & 0xff) << 16) | ((fcolor & 0xff) << 8) | (fcolor & 0xff); } } } BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); setRGB(bi, 0, 0, width, height, output); return bi; } public int getFcolor() { return fcolor; } public void setFcolor(int fcolor) { this.fcolor = fcolor; } }
开操作 OpenFilter package binimage.openclose; import binimage.dilation.DilationFilter; import binimage.erosion.ErosionFilter; import binimage.utils.AbstractImageOptionFilter; import java.awt.image.BufferedImage; public class OpenFilter extends AbstractImageOptionFilter { private int fcolor; public int getFcolor() { return fcolor; } public void setFcolor(int fcolor) { this.fcolor = fcolor; } @Override public BufferedImage process(BufferedImage image) { ErosionFilter ef = new ErosionFilter(); ef.setFcolor(fcolor); BufferedImage eimage = ef.process(image); DilationFilter df = new DilationFilter(); df.setFcolor(fcolor); BufferedImage result = df.process(eimage); return result; } } ImagePanel package binimage.openclose; import binimage.erosion.ErosionFilter; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class ImagePanel extends JComponent implements ActionListener { private BufferedImage image; private BufferedImage resultImage; private JButton processBtn; public ImagePanel(BufferedImage image) { this.image = image; } public JButton getButton() { processBtn = new JButton("按钮"); processBtn.addActionListener(this); return processBtn; } @Override protected void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; if (null != image) { g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); } if (resultImage != null) { g2d.drawImage(resultImage, image.getWidth() + 10, 0, resultImage.getWidth(), resultImage.getHeight(), null); } } public void process() { OpenFilter filter = new OpenFilter(); filter.setFcolor(0); // 前景是黑色 resultImage = filter.process(image); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == processBtn) { this.process(); this.repaint(); } } public static void main(String[] args) { File file = new File("resource/num.png"); try { BufferedImage image = ImageIO.read(file); ImagePanel imp = new ImagePanel(image); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(imp, BorderLayout.CENTER); frame.getContentPane().add(imp.getButton(), BorderLayout.SOUTH); frame.setSize(1000, 600); frame.setTitle("图像显示测试"); frame.setVisible(true); } catch (IOException e) { e.printStackTrace(); } } }


最新回复(0)