什么是OpenCV模板匹配Max Min值范围? 需要用作theshold / c ++ / java

我正在使用模板匹配创建一个简单的openCV应用程序,我需要比较在大图像中查找小图像并返回结果为true(如果匹配找到)或false(未找到匹配项)。

Imgproc.matchTemplate(largeImage, smallImage, result, matchMethod); Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat()); MinMaxLocResult mmr = Core.minMaxLoc(result); double minMaxValue = 1; if (matchMethod== Imgproc.TM_SQDIFF || matchMethod== Imgproc.TM_SQDIFF_NORMED) { minMaxValue = mmr.minVal; useMinThreshold = true; } else { minMaxValue = mmr.maxVal; } 

现在的问题是使用这个minMaxValue做出决定(真/假)。 我知道上面两种方法TM_SQDIFF和TM_SQDIFF_NORMED返回低值,而其他方法返回高值,所以我可以有2个不同的阈值并比较一个阈值(取决于模板方法类型)。

因此,如果有人可以解释MinMaxLocResult返回的minVal和maxVal范围是多么好。

是0到1范围?

如果是,对于Max类型模板方法,值1是完美匹配?

MinMaxLocResult不返回minValmaxVal范围。 minValmaxVal只是最小和最大匹配分数,可以在链接中看到。

结构MinMaxLocResult还有minLocmaxLoc属性,它们是Point类型,给出匹配的位置。 鉴于您使用TM_SQDIFFTM_SQDIFF_NORMED作为匹配条件,最佳匹配位置将为mmr.minLoc

为了设置检测阈值,您可以声明变量double thresholdMatch并通过实验设置其值。 如果minVal

不规范化结果,然后它会给出正确的值,我的意思是删除这一行

  Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat()); 

faithk的答案非常好,但这里有一些实际的代码实现它。 使用0.1作为阈值我得到了很好的结果:

 import lombok.val; import org.opencv.core.*; import org.springframework.core.io.ClassPathResource; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import static javax.imageio.ImageIO.read; import static javax.imageio.ImageIO.write; import static javax.swing.SwingUtilities.invokeAndWait; import static org.opencv.core.CvType.CV_32FC1; import static org.opencv.highgui.HighGui.imshow; import static org.opencv.highgui.HighGui.waitKey; import static org.opencv.imgcodecs.Imgcodecs.CV_LOAD_IMAGE_UNCHANGED; import static org.opencv.imgcodecs.Imgcodecs.imdecode; import static org.opencv.imgproc.Imgproc.*; public class TemplateMatcher { static { // loadNativeOpenCVLibrary(); } private static final int MATCH_METHOD = TM_SQDIFF_NORMED; private static Mat BufferedImage2Mat(BufferedImage image) throws IOException { try (val byteArrayOutputStream = new ByteArrayOutputStream()) { write(image, "jpg", byteArrayOutputStream); byteArrayOutputStream.flush(); val matOfByte = new MatOfByte(byteArrayOutputStream.toByteArray()); return imdecode(matOfByte, CV_LOAD_IMAGE_UNCHANGED); } } public static Point performTemplateMatching(BufferedImage bigImage, BufferedImage templateImage, double detectionThreshold, boolean showMatch) throws IOException { val image = BufferedImage2Mat(bigImage); val template = BufferedImage2Mat(templateImage); // Create the result matrix val result_cols = image.cols() - template.cols() + 1; val result_rows = image.rows() - template.rows() + 1; val result = new Mat(result_rows, result_cols, CV_32FC1); // Do the matching matchTemplate(image, template, result, MATCH_METHOD); // Localize the best match val minMaxLocResult = Core.minMaxLoc(result); // / Show me what you got val matchedLocation = minMaxLocResult.minLoc; rectangle(image, matchedLocation, new Point(matchedLocation.x + template.cols(), matchedLocation.y + template.rows()), new Scalar(0, 255, 0)); if (showMatch) { try { invokeAndWait(() -> imshow("Image Search", image)); } catch (InterruptedException | InvocationTargetException exception) { exception.printStackTrace(); } waitKey(); } // Determine whether this sub image has been found val minVal = minMaxLocResult.minVal; if (minVal < detectionThreshold) { return minMaxLocResult.maxLoc; } return null; } public static BufferedImage getBufferedImage(String classpathFile) throws IOException { val classPathResource = new ClassPathResource(classpathFile); val filePath = classPathResource.getFile(); return read(filePath); } }