二值图像分析笔记(7)—— 开闭操作
程序员文章站
2023-12-27 08:24:27
...
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();
}
}
}
推荐阅读