簡體   English   中英

如何在openCV(java)中調整模板匹配的閾值?

[英]How to adjust the threshold for template matching in openCV (java)?

我正在使用 openCV 3.4.7 Android SDK (java) 運行模板匹配。 代碼幾乎完美運行; 當模板匹配時,它在匹配區域上繪制一個矩形。 問題是,即使沒有匹配項,它也會繪制一個隨機矩形。 我認為這是因為閾值設置不正確。 如果是這樣,有人可以幫我嗎?

這是代碼:

public static void run(String inFile, String templateFile, String outFile,
                    int match_method) {
        Mat img = Imgcodecs.imread(inFile);
        Mat templ = Imgcodecs.imread(templateFile);

        // / Create the result matrix
        int result_cols = img.cols() - templ.cols() + 1;
        int result_rows = img.rows() - templ.rows() + 1;
        Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

        // / Do the Matching and Normalize
        Imgproc.matchTemplate(img, templ, result, match_method);
        Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());

        // / Localizing the best match with minMaxLoc
        Core.MinMaxLocResult mmr = Core.minMaxLoc(result);

        Point matchLoc;
        if (match_method == Imgproc.TM_SQDIFF
                || match_method == Imgproc.TM_SQDIFF_NORMED) {
            matchLoc = mmr.minLoc;
        } else {
            matchLoc = mmr.maxLoc;
        }

        // / Show me what you got
        Imgproc.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(),
                matchLoc.y + templ.rows()), new Scalar(0, 0, 128));

        // Save the visualized detection.
        System.out.println("Writing " + outFile);
        Imgcodecs.imwrite(outFile, img);
}

使用規范匹配方法來確保您的匹配值為 [0..1]。

替換這一行

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

與閾值操作。 否則 0.9 的最佳匹配將通過第二次標准化變為 1,並且您將丟失實際匹配“質量”信息。

規范化模板匹配的結果將始終導致您的最佳匹配為 1,從而無法丟棄壞匹配。

您可以使用 Imgproc.TM_CCOEFF_NORMED 或 Imgproc.TM_CCORR_NORMED 和 mmr.maxVal >= 0.8。 它應該處理您的大部分誤報。

示例代碼:

import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.io.File;
import java.nio.file.Files;

public class templateMatchingTester {

    private static String str = null;

    static {
        if (str == null) {
            str = "initialised";
            nu.pattern.OpenCV.loadShared();
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        }

    }

    private static Mat createMatrixFromImage(String imagePath) {
        Mat imageMatrix = Imgcodecs.imread(imagePath);
        Mat greyImage = new Mat();
        Imgproc.cvtColor(imageMatrix, greyImage, Imgproc.COLOR_BGR2GRAY);
        return greyImage;
    }

    private static boolean matchTemplate(String pathToInputImage,String pathToTemplate){

        Mat inputImage = createMatrixFromImage(pathToInputImage);
        Mat templateImage = createMatrixFromImage(pathToTemplate);

        // Create the result matrix
        int result_cols = inputImage.cols() - templateImage.cols() + 1;
        int result_rows = inputImage.rows() - templateImage.rows() + 1;
        Mat result = new Mat(result_rows, result_cols, CvType.CV_8UC1);
        int match_method;
        match_method = Imgproc.TM_CCOEFF_NORMED;//Imgproc.TM_CCORR_NORMED;
        Imgproc.matchTemplate(inputImage, templateImage, result, match_method);
        Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
        double minMatchQuality = 0.85; 
        System.out.println(mmr.maxVal);
        if (mmr.maxVal >= minMatchQuality){
            return true;
        } else
        return false;
    }

    public static void main(String args[]) {

        String template = "path/to/your/templateImage";
        final File folder = new File("path/to/your/testImagesFolder/");
        int matchCount = 0;
        for (final File fileEntry : folder.listFiles()){
            if (matchTemplate(fileEntry.getPath(),template)){
                matchCount+=1;
            }else
                System.out.println(fileEntry.getPath());
        }
        System.out.println(matchCount);

    }
}

我寫了一個應用程序,它可以截取游戲守望先鋒的屏幕截圖,並試圖告訴每個團隊都有誰。 使用模板匹配和打開簡歷。 項目需要迭代結果圖像並檢查值。

OpenCVUtils.getPointsFromMatAboveThreshold(result, 0.90f)

public static void scaleAndCheckAll(String guid){       
    Mat source = imread(IMG_PROC_PATH + guid);  //load the source image
    Mat scaledSrc = new Mat(defaultScreenshotSize, source.type());
    resize(source, scaledSrc, defaultScreenshotSize);
    Mat sourceGrey = new Mat(scaledSrc.size(), CV_8UC1);
    cvtColor(scaledSrc, sourceGrey, COLOR_BGR2GRAY);        

    for (String hero : getCharacters()) {
        Mat template = OpenCVUtils.matFromJar(TEMPLATES_FOLDER + hero + ".png", 0); //load a template
        Size size = new Size(sourceGrey.cols()-template.cols()+1, sourceGrey.rows()-template.rows()+1);
        Mat result = new Mat(size, CV_32FC1);
        matchTemplate(sourceGrey, template, result, TM_CCORR_NORMED);// get results
        Scalar color =  OpenCVUtils.randColor();
        List<Point> points = OpenCVUtils.getPointsFromMatAboveThreshold(result, 
0.90f);
        for (Point point : points) {
            //rectangle(scaledSrc, new Rect(point.x(),point.y(),template.cols(),template.rows()), color, -2, 0, 0);
            putText(scaledSrc, hero, point, FONT_HERSHEY_PLAIN, 2, color);
        }
    }
    String withExt = IMG_PROC_PATH + guid +".png";
    imwrite(withExt,  scaledSrc);
    File noExt = new File(IMG_PROC_PATH + guid);
    File ext = new File(withExt);
    noExt.delete();
    ext.renameTo(noExt);                
}

另一種方法。

public static List<Point> getPointsFromMatAboveThreshold(Mat m, float t){
    List<Point> matches = new ArrayList<Point>();
    FloatIndexer indexer = m.createIndexer();
    for (int y = 0; y < m.rows(); y++) {
        for (int x = 0; x < m.cols(); x++) {
            if (indexer.get(y,x)>t) {
                System.out.println("(" + x + "," + y +") = "+ indexer.get(y,x));
                matches.add(new Point(x, y));                   
            }
        }           
    }       
    return matches;
}

您可以從列表中獲取第一個,或者如果您期望多個匹配項,則查看它們的接近程度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM