Я создаю простое приложение 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;
}
Теперь проблема заключается в принятии решения (true / false) с использованием этого minMaxValue. Я знаю, что два вышеупомянутых метода TM_SQDIFF и TM_SQDIFF_NORMED возвращают низкие значения, в то время как другие возвращают высокие значения, поэтому я могу иметь 2 разных порога и сравнить один из порогов (в зависимости от типа метода шаблона).
Поэтому было бы здорово, если бы кто-нибудь смог объяснить, что такое minVal и maxVal, которые возвращает MinMaxLocResult.
Это диапазон от 0 до 1?
Если да, то для метода шаблона типа Max значение 1 идеально подходит?
MinMaxLocResult
не возвращается minVal
а также maxVal
спектр. minVal
а также maxVal
это только минимальные и максимальные баллы соответствия, которые можно увидеть в ссылка на сайт.
Структура MinMaxLocResult
также имеет minLoc
а также maxLoc
свойства, которые имеют тип Point
, давая соответствующие места. Учитывая, что вы используете TM_SQDIFF
или же TM_SQDIFF_NORMED
в качестве критерия соответствия наилучшим местом сопоставления будет mmr.minLoc
,
Чтобы установить порог для обнаружения, вы можете объявить переменнуюdouble thresholdMatch
и установить его значение экспериментально. если minVal < thresholdMatch, то можно сказать, что целевой объект обнаружен
Не нормализуйте результат, тогда он даст правильное значение, я имею в виду удалить эту строку
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);
}
}