最近,我一直在开发一个需要能够找到X& X的小型项目。另一图像中子图像的Y坐标。图像可能具有不同的分辨率,但总体而言图像分辨率相似且颜色应相同。我已经研究过OpenCV,但似乎OpenCV只返回一个匹配。我需要在超级图像中找到子图像的所有出现/实例。我已经拥有了所有要搜索的子图像,因此我只需要一种方法来查找超级图像中子图像的坐标。
这是我的意思的一个例子:
如果我们有red_circle.png
:
和shapes.png
:
我需要得到X& Y坐标为各种形状(red_circle.png
;超级图像)中红色圆圈(shapes.png
;子图像)的全部。
理想情况下,我希望能够做到这样的事情:
/* code to read in red_cirlce.png and shapes.png as BufferedImages */
ArrayList<Point> instancesOfRedCircle = new ArrayList<>();
findAllSubimageInstances( shapesObj, // Super-Image
redCircleObj, // Subimage
instancesOfRedCircle // ArrayList to put points in
);
有没有人知道这样做的方法(例如,库,函数等)?
答案 0 :(得分:12)
我无法入睡那个......
我已经在java中编写了tuorial中的代码,并围绕它构建了一个小gui。
package opencv.test;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.Scalar;
import org.opencv.features2d.DMatch;
import org.opencv.features2d.DescriptorExtractor;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.FeatureDetector;
import org.opencv.features2d.Features2d;
import org.opencv.highgui.Highgui;
public class MatchDetection {
public static BufferedImage detectMatches(File file, File file2) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat img_1 = Highgui.imread(file.getAbsolutePath(), Highgui.CV_LOAD_IMAGE_GRAYSCALE);
Mat img_2 = Highgui.imread(file2.getAbsolutePath(), Highgui.CV_LOAD_IMAGE_GRAYSCALE);
if (img_1.empty() || img_2.empty()) {
System.out.println(" --(!) Error reading images ");
return null;
}
// -- Step 1: Detect the keypoints using SURF Detector
//I am not sure where to use it
int minHessian = 400;
FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
MatOfKeyPoint keypoints_1 = new MatOfKeyPoint();
MatOfKeyPoint keypoints_2 = new MatOfKeyPoint();
detector.detect(img_1, keypoints_1);
detector.detect(img_2, keypoints_2);
// -- Step 2: Calculate descriptors (feature vectors)
DescriptorExtractor extractor = DescriptorExtractor
.create(DescriptorExtractor.SURF);
Mat descriptors_1 = new Mat();
Mat descriptors_2 = new Mat();
extractor.compute(img_1, keypoints_1, descriptors_1);
extractor.compute(img_2, keypoints_2, descriptors_2);
// -- Step 3: Matching descriptor vectors using FLANN matcher
DescriptorMatcher matcher = DescriptorMatcher
.create(DescriptorExtractor.SURF);
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors_1, descriptors_2, matches);
DMatch[] matchesArr = matches.toArray();
double max_dist = 0;
double min_dist = 100;
// -- Quick calculation of max and min distances between keypoints
for (int i = 0; i < matchesArr.length; i++) {
double dist = matchesArr[i].distance;
if (dist < min_dist)
min_dist = dist;
if (dist > max_dist)
max_dist = dist;
}
System.out.printf("-- Max dist : %f \n", max_dist);
System.out.printf("-- Min dist : %f \n", min_dist);
// -- Draw only "good" matches (i.e. whose distance is less than
// 2*min_dist,
// -- or a small arbitary value ( 0.02 ) in the event that min_dist is
// very
// -- small)
// -- PS.- radiusMatch can also be used here.
MatOfDMatch good_matches = new MatOfDMatch();
for (int i = 0; i < matchesArr.length; i++) {
if (matchesArr[i].distance <= Math.max(2 * min_dist, 0.02)) {
good_matches.push_back(matches.row(i));
}
}
// -- Draw only "good" matches
Mat img_matches = new Mat();
Features2d.drawMatches(img_1, keypoints_1, img_2, keypoints_2,
good_matches, img_matches);//, Scalar.all(-1), Scalar.all(-1),
//null, Features2d.NOT_DRAW_SINGLE_POINTS);
// ----Here i had to Patch around a little----
MatOfByte matOfByte = new MatOfByte();
Highgui.imencode(".jpg", img_matches, matOfByte);
byte[] byteArray = matOfByte.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
} catch (Exception e) {
e.printStackTrace();
return null;
}
for (int i = 0; i < (int) good_matches.rows(); i++) {
System.out.printf(
"-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n",
i, good_matches.toArray()[i].queryIdx,
good_matches.toArray()[i].trainIdx);
}
return bufImage;
}
}
和GUI
package opencv.test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
public class OpenCVMyGui {
private JFrame frame;
ImageResultPanel panel_bot;
ImageChoosePanel panel_left;
ImageChoosePanel panel_right;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
OpenCVMyGui window = new OpenCVMyGui();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public OpenCVMyGui() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[]{0, 0, 0};
gridBagLayout.rowHeights = new int[]{0, 0, 0};
gridBagLayout.columnWeights = new double[]{1.0, 1.0, Double.MIN_VALUE};
gridBagLayout.rowWeights = new double[]{1.0, 1.0, Double.MIN_VALUE};
frame.getContentPane().setLayout(gridBagLayout);
panel_left = new ImageChoosePanel();
GridBagConstraints gbc_panel_2 = new GridBagConstraints();
gbc_panel_2.insets = new Insets(0, 0, 5, 5);
gbc_panel_2.fill = GridBagConstraints.BOTH;
gbc_panel_2.gridx = 0;
gbc_panel_2.gridy = 0;
frame.getContentPane().add(panel_left, gbc_panel_2);
panel_right = new ImageChoosePanel();
GridBagConstraints gbc_panel_1 = new GridBagConstraints();
gbc_panel_1.insets = new Insets(0, 0, 5, 0);
gbc_panel_1.fill = GridBagConstraints.BOTH;
gbc_panel_1.gridx = 1;
gbc_panel_1.gridy = 0;
frame.getContentPane().add(panel_right, gbc_panel_1);
panel_bot = new ImageResultPanel(this);
GridBagConstraints gbc_panel = new GridBagConstraints();
gbc_panel.gridwidth = 2;
gbc_panel.fill = GridBagConstraints.BOTH;
gbc_panel.gridx = 0;
gbc_panel.gridy = 1;
frame.getContentPane().add(panel_bot, gbc_panel);
}
private class ImageChoosePanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 2207576827793103205L;
public BufferedImage image;
public File file;
public ImageChoosePanel() {
setFocusable(true);
addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setFileFilter(new FileNameExtensionFilter("Images",
"jpg", "png")); // maybe more? dont know what OpenCV
// likes
chooser.showOpenDialog(ImageChoosePanel.this);
ImageChoosePanel icp = ((ImageChoosePanel) e.getSource());
icp.file = chooser.getSelectedFile();
try {
image = ImageIO.read(icp.file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
@Override
public void paint(Graphics arg0) {
if (image != null) {
arg0.drawImage(image, 0, 0, null);
} else{
arg0.fillRect(0, 0, getWidth(), getHeight());
}
}
}
private class ImageResultPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 8948107638933808175L;
public BufferedImage image;
OpenCVMyGui gui;
public ImageResultPanel(OpenCVMyGui gui) {
this.gui = gui;
setFocusable(true);
addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent arg0) {
}
@Override
public void mousePressed(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {
}
@Override
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseClicked(MouseEvent arg0) {
try {
OpenCVMyGui gui = ((ImageResultPanel) arg0.getSource()).gui;
image = MatchDetection.detectMatches(
gui.panel_right.file, gui.panel_left.file);
} catch (Exception e2) {
e2.printStackTrace();
}
}
});
}
@Override
public void paint(Graphics arg0) {
if (image != null) {
arg0.drawImage(image, 0, 0, null);
}else{
arg0.fillRect(0, 0, getWidth(), getHeight());
}
}
}
}
你应该使用算法来定义...但结果atm应该可以帮助你实现目标。
我可能会再读一遍。明天。
答案 1 :(得分:2)
看一下本教程:
它的C ++代码,但你可以猜到它是如何工作的,而OpenCV有一个非常接近C ++ Api的java Api。
我希望能帮助你。
如果你认为这射击远远超过目标,你可以尝试迭代像素x。但是不同尺寸会很复杂。