Что такое шаблон OpenCV, соответствующий диапазону значений Max Min? Необходимо использовать как основу / c++/java

Я создаю простое приложение openCV, используя сопоставление шаблонов, где мне нужно сравнить, найти маленькое изображение в большом изображении и вернуть результат как истинный (если совпадение найдено) или ложный (совпадения не найдены).

    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 разных пороговых значения и сравнивать одно из пороговых значений (в зависимости от типа метода шаблона).

Так что было бы здорово, если бы кто-нибудь мог объяснить, что такое диапазон minVal и maxVal, который возвращает MinMaxLocResult.

Это диапазон от 0 до 1?

Если да, то для метода шаблона типа Max значение 1 идеально подходит?


person Emily Webb    schedule 22.07.2013    source источник


Ответы (4)


MinMaxLocResult не возвращает диапазоны minVal и maxVal. minVal и maxVal — это просто минимальные и максимальные оценки соответствия, что можно увидеть в ссылка.

Структура MinMaxLocResult также имеет свойства minLoc и maxLoc типа Point, дающие совпадающие местоположения. Учитывая, что вы используете TM_SQDIFF или TM_SQDIFF_NORMED в качестве критерия соответствия, наиболее подходящим местом будет mmr.minLoc.

Чтобы установить порог обнаружения, вы можете объявить переменнуюdouble thresholdMatch и экспериментально установить ее значение. если minVal ‹ thresholdMatch, то можно сказать, что целевой объект обнаружен

person fatihk    schedule 22.07.2013
comment
Спасибо, Томас, значит, вы имели в виду, что решение (истина/ложь) может быть принято с использованием minLoc или maxLoc вместо minVal/maxVal? - person Emily Webb; 22.07.2013
comment
@ Нет, сопоставление шаблонов не дает информации о том, нашли ли вы точный объект или нет. Скорее, это говорит о том, что наиболее подходящий (потенциальный) объект находится в этом месте, и в данном конкретном случае это minLoc. - person fatihk; 22.07.2013
comment
Хорошо, в этом конкретном примере я могу игнорировать проблемы с перекосом вращения шкалы. Тем не менее, сопоставление с шаблоном не самое лучшее решение для этой цели (вернуть true/false)? Я понимаю, что вы подчеркнули, т. Е. В нем говорится, что наиболее подходящий (потенциальный) объект находится в этом месте. Но все же мне нужно знать, существует ли пороговый подход, чтобы прийти к выводу, найден ли объект. Не может быть с MinMaxLocResult, но есть ли альтернативы? НЕ ЗНАЧИТ, ДАЖЕ ЕСЛИ ЭТО МЕТОД ИЗВЛЕЧЕНИЯ ОПИСАНИЯ ПРИЗНАКОВ - person Emily Webb; 22.07.2013
comment
@Эмили Уэбб, вы можете установить порог, как видно из отредактированного ответа. - person fatihk; 22.07.2013
comment
спасибо, именно это я и сделал, как объяснил в исходном посте, но я не был уверен в возможном диапазоне значений minVal/maxVal . Я думаю, это 0 - 1, я думаю. Итак, в зависимости от метода сопоставления шаблонов я выбираю minVal ‹ thresholdMatchForMin или maxVal › thresholdMatchForMax, верно? - person Emily Webb; 22.07.2013
comment
@Emily Webb, конечно, если метод TM_SQDIFF_NORMED minVal - диапазон maxVal будет 0-1 - person fatihk; 22.07.2013
comment
Наконец, решил эту проблему в соответствии с последними комментариями, но удалил нормализацию, чтобы получить лучшие результаты. - person Emily Webb; 27.07.2013
comment
@Tom_Crusoe У меня та же проблема, я также хочу, чтобы в конце было найдено изображение true/false или нет. Но мои значения Minval для 3 разных тестов: 4,54..., 0, -1,86. Они не находятся в диапазоне 0-1, все 3 теста были успешно найдены на исходном изображении. Я действительно не могу решить, какой установить порог... - person Anarkie; 10.09.2014
comment
@Anarkie, вы нормализовали математический результат с помощью Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat()); ? здесь 0 и 1 — нижняя и верхняя границы нормализации - person fatihk; 11.09.2014
comment
@Tom_Crusoe да, вот мой код pastebin.com/PpY8zhHk с использованием Imgproc.TM_SQDIFF - person Anarkie; 11.09.2014

Не нормализуйте результат, тогда он даст правильное значение, я имею в виду удалить эту строку

   Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
person Mehul Thakkar    schedule 17.12.2013
comment
как я понимаю, если это правильное значение ?? @Мехул Таккар - person Fay007; 25.11.2015

Ответ 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);
    }
}
person BullyWiiPlaza    schedule 11.08.2018

УСЛОВИЯ

  • template = изображение, которое мы пытаемся найти
  • стог сена = изображение, которое мы ищем
  • region = область в стоге сена, которую мы сейчас сопоставляем с шаблоном

Минимальные и максимальные значения будут иметь разные возможные диапазоны в зависимости от типа соответствия шаблона. Результат сравнения для каждого местоположения в стоге сена определяется этими формулами (взятыми из opencv docs; T() — шаблон, I() — стог сена):

алгоритмы сопоставления шаблонов

Как вы заметили, методы квадратичной разности (SQDIFF) увеличиваются по мере увеличения разницы между шаблоном и регионом, поэтому наилучшее совпадение будет иметь наименьшее значение. Для других методов (взаимная корреляция, коэффициент корреляции) наилучшее совпадение будет иметь наибольшее значение.

Сам диапазон сложно определить, если вы не понимаете математику (как и я), но, глядя на разность квадратов, я думаю, что диапазон будет следующим (при условии, что изображения представляют собой 1-байтовые оттенки серого):

0 ... (255 * 255 * template.width * template.height)

А для нормализованных версий диапазон должен быть:

0 ... 1

person owengall    schedule 07.04.2020