Advertisement
Guest User

Untitled

a guest
Aug 6th, 2024
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 7.89 KB | None | 0 0
  1. package org.whatever;
  2.  
  3. import java.io.File;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import nu.pattern.OpenCV;
  7. import org.opencv.core.Core;
  8. import org.opencv.core.CvType;
  9. import org.opencv.core.Mat;
  10. import org.opencv.core.Point;
  11. import org.opencv.core.Scalar;
  12. import org.opencv.imgcodecs.Imgcodecs;
  13.  
  14. import org.apache.logging.log4j.Logger;
  15. import org.apache.logging.log4j.LogManager;
  16. import org.opencv.imgproc.Imgproc;
  17.  
  18. public class Main {
  19.     private static final Logger l = LogManager.getLogger(Main.class);
  20.  
  21.     private static Mat readImage(String imageName, int codec) {
  22.         Mat img = Imgcodecs.imread(new File(Main.class.getClassLoader().getResource("images/" + imageName + ".png").getFile()).getAbsolutePath(), codec);
  23.         l.info("Read image '{}' using codec {}, result Mat: {}", imageName, codec, img);
  24.         return img;
  25.     }
  26.  
  27.     private static void writeImage(String prefix, String imageName, Mat img) {
  28.         String imageFilename = prefix + imageName + ".png";
  29.         Imgcodecs.imwrite(imageFilename, img);
  30.         l.info("Wrote image '{}'", imageFilename);
  31.     }
  32.  
  33.     public static Mat createMask(String imageName) {
  34.         Mat img = readImage(imageName, Imgcodecs.IMREAD_UNCHANGED);
  35.  
  36.         Mat mask = new Mat(img.size(), CvType.CV_8UC1);
  37.         for (int y = 0; y < img.rows(); y++) {
  38.             for (int x = 0; x < img.cols(); x++) {
  39.                 // OpenCV uses BGR order, so the alpha channel is the 4th channel
  40.                 double alphaValue = img.get(y, x)[3];
  41.                 if (alphaValue > 0) {
  42.                     mask.put(y, x, 255); // Consider this pixel
  43.                 } else {
  44.                     mask.put(y, x, 0); // Ignore this pixel
  45.                 }
  46.             }
  47.         }
  48.         return mask;
  49.     }
  50.  
  51.     private static String tryMatch(String needle, String haystack, int matchMethod) {
  52.         double minimumMatchThreshold = 0.99;
  53.  
  54.         String prefix = "method_" + matchMethod + "_find_" + needle + "_in_" + haystack + "_";
  55.  
  56.         // note that we ignore transparency here (4th alpha channel), we read as 3 channels
  57.         Mat needleImg = readImage(needle, Imgcodecs.IMREAD_COLOR);
  58.         writeImage(prefix, "01_needle", needleImg);
  59.  
  60.         Mat haystackImg = readImage(haystack, Imgcodecs.IMREAD_COLOR);
  61.         writeImage(prefix, "02_haystack", haystackImg);
  62.  
  63.         // this uses the 4th alpha channel
  64.         Mat mask = createMask(needle);
  65.         writeImage(prefix, "03_mask", mask);
  66.  
  67.         // try to match
  68.         Mat matchResult = new Mat();
  69.         Imgproc.matchTemplate(haystackImg, needleImg, matchResult, matchMethod, mask);
  70.         l.info("matchResult:           {}", matchResult);
  71.  
  72.         Mat normalizedMatchResult = new Mat();
  73.         Core.normalize(matchResult, normalizedMatchResult, 0, 100, Core.NORM_MINMAX, CvType.CV_32F);
  74.         l.info("normalizedMatchResult: {}", matchResult);
  75.  
  76.         Mat heatmap = new Mat();
  77.         Core.normalize(matchResult, heatmap, 0, 255, Core.NORM_MINMAX, CvType.CV_8U);
  78.         writeImage(prefix, "04_heatmap", heatmap);
  79.  
  80.         // find the min/max in the histogram
  81.         Core.MinMaxLocResult mmr = Core.minMaxLoc(matchResult);
  82.         l.info("minMaxLoc matchResult:           maxVal {}, maxLoc {}, minVal {}, minLoc {}", mmr.maxVal, mmr.maxLoc, mmr.minVal, mmr.minLoc);
  83.         Core.MinMaxLocResult mmr2 = Core.minMaxLoc(normalizedMatchResult);
  84.         l.info("minMaxLoc normalizedMatchResult: maxVal {}, maxLoc {}, minVal {}, minLoc {}", mmr2.maxVal, mmr2.maxLoc, mmr2.minVal, mmr2.minLoc);
  85.  
  86.         for (int y = 0; y < matchResult.rows(); y++) {
  87.             String line = String.format("  y %2d: ", y);
  88.             for (int x = 0; x < matchResult.cols(); x++) {
  89.                 double value = matchResult.get(y, x)[0];
  90.                 String strVal = "";
  91.                 if (value == Double.POSITIVE_INFINITY) {
  92.                     strVal = " +In ";
  93.                 } else if (value == Double.NEGATIVE_INFINITY) {
  94.                     strVal = " -In ";
  95.                 } else if (Double.isNaN(value)) {
  96.                     strVal = " nan ";
  97.                 } else if (value > 99) {
  98.                     strVal = " >99 (" + value + ")";
  99.                 } else if (value < -99) {
  100.                     strVal = " <-99(" + value + ")";
  101.                 } else if (value == 0) {
  102.                     strVal = String.format("  0  ", value);
  103.                 } else if (value < 0) {
  104.                     strVal = String.format("%.2f", value);
  105.                 } else {
  106.                     strVal = String.format(" %.2f", value);
  107.                 }
  108.                 line += strVal + " ";
  109.             }
  110.             l.info(line);
  111.         }
  112.  
  113.         Point matchLocationTopLeft;
  114.         double matchPercentage = -1;
  115.         // depending on the matchMethod, we are looking for the maximum or minimum
  116.         if (matchMethod == Imgproc.TM_SQDIFF || matchMethod == Imgproc.TM_SQDIFF_NORMED) {
  117.             matchLocationTopLeft = mmr.minLoc;
  118.             matchPercentage = mmr.minVal * 100;
  119.         } else {
  120.             matchLocationTopLeft = mmr.maxLoc;
  121.             matchPercentage = mmr.maxVal * 100;
  122.         }
  123.  
  124.         // a value of +Infinity is not a match, it should be 1.0 maximum or something is wrong
  125.         boolean matchFound = mmr.maxVal >= (minimumMatchThreshold) && mmr.maxVal <= 1;
  126.  
  127.         l.info("Matches {}%, best match top-left {}", matchPercentage, matchLocationTopLeft);
  128.  
  129.         // draw a red rectangle around the best match if it's better than a certain threshold
  130.         if (matchFound) {
  131.             Mat haystackWithRect = haystackImg.clone();
  132.             // make sure we draw AROUND the needle/template, don't worry about the fact this might be out of bounds, it's not for the test images
  133.             Point rectTopLeft = new Point(matchLocationTopLeft.x - 1, matchLocationTopLeft.y - 1);
  134.             Point rectBottomRight = new Point(rectTopLeft.x + needleImg.cols() + 1, rectTopLeft.y + needleImg.rows() + 1);
  135.             Scalar color = new Scalar(0, 255, 255); // yellow
  136.  
  137.             Imgproc.rectangle(haystackWithRect, rectTopLeft, rectBottomRight, color, 1);
  138.             writeImage(prefix, "05_haystack_with_rect", haystackWithRect);
  139.         } else {
  140.             l.warn("not match found, matchPercentage {} is below minimumMatchThreshold {} or is +Infinity", matchPercentage, minimumMatchThreshold);
  141.         }
  142.         return "method " + matchMethod + " needle " + needle + " haystack " + haystack + " match percentage: " + matchPercentage + "%, top left location: " + matchLocationTopLeft;
  143.     }
  144.  
  145.     public static void main(String[] args) {
  146.         OpenCV.loadLocally();
  147.  
  148.         List<String> results = new ArrayList<>();
  149.  
  150.         //for (int matchMethod : new int[] { Imgproc.TM_CCORR_NORMED, Imgproc.TM_CCOEFF_NORMED, Imgproc.TM_SQDIFF_NORMED }) {
  151.         for (int matchMethod : new int[] { Imgproc.TM_CCORR_NORMED }) {
  152.             l.info("");
  153.             l.info("Match method: {}", matchMethod);
  154.             for (String haystack : new String[] {
  155.                 "haystack_blue_needle_on_all",
  156.                 "haystack_blue_needle_on_black",
  157.                 "haystack_blue_needle_on_green",
  158.                 "haystack_blue_needle_on_red",
  159.                 "haystack_blue_needle_on_white" }) {
  160.                 String needle = "needle_blue";
  161.                 results.add(tryMatch(needle, haystack, matchMethod));
  162.             }
  163.             for (String haystack : new String[] {
  164.                 "haystack_white_needle_on_all",
  165.                 "haystack_white_needle_on_black",
  166.                 "haystack_white_needle_on_green",
  167.                 "haystack_white_needle_on_purple",
  168.                 "haystack_white_needle_on_red",
  169.                 "haystack_white_needle_on_red_bottom_right" }) {
  170.                 String needle = "needle_white";
  171.                 results.add(tryMatch(needle, haystack, matchMethod));
  172.             }
  173.         }
  174.  
  175.         results.forEach(l::info);
  176.     }
  177. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement