public MatchResult match(Mat scene, Mat templ, Method method, Mat img) { int result_cols = scene.cols() - templ.cols() + 1; int result_rows = scene.rows() - templ.rows() + 1; Mat result = new Mat(result_rows, result_cols, CV_32FC1); Imgproc.matchTemplate(scene, templ, result, method.ordinal()); //Core.normalize(result, result, 0, 1, 32,-1,new Mat()); MinMaxLocResult mmr = Core.minMaxLoc(result); Point matchLoc; double maxVal; if (method.ordinal() == Imgproc.TM_SQDIFF || method.ordinal() == Imgproc.TM_SQDIFF_NORMED) { matchLoc = mmr.minLoc; maxVal = mmr.minVal; } else { matchLoc = mmr.maxLoc; maxVal = mmr.maxVal; } MatchResult currResult = new MatchResult(matchLoc.x +(templ.cols()/2),matchLoc.y +(templ.rows()/2),0,maxVal); return currResult; }
private boolean minMaxLocResultIsValid(MinMaxLocResult minMaxLocRes) { if (minMaxLocRes.minVal == 1 && minMaxLocRes.maxVal == 1 && minMaxLocRes.maxLoc.x == 0 && minMaxLocRes.maxLoc.y == 0 && minMaxLocRes.minLoc.x == 0 && minMaxLocRes.minLoc.y == 0) { return false; } else { return true; } }
private ImageFinderResult findImage(Mat sourceMat, Mat templateMat, double desiredAccuracy) { if (sourceMat.width() < templateMat.width() || sourceMat.height() < templateMat.height()) { throw new UnsupportedOperationException("The template image is larger than the source image. Ensure that the width and/or height of the image you are trying to find do not exceed the dimensions of the source image."); } Mat result = new Mat(sourceMat.rows() - templateMat.rows() + 1, sourceMat.rows() - templateMat.rows() + 1, CvType.CV_32FC1); int intMatchingMethod; switch (this.matchingMethod) { case MM_CORELLATION_COEFF: intMatchingMethod = Imgproc.TM_CCOEFF_NORMED; break; case MM_CROSS_CORELLATION: intMatchingMethod = Imgproc.TM_CCORR_NORMED; break; default: intMatchingMethod = Imgproc.TM_SQDIFF_NORMED; } Imgproc.matchTemplate(sourceMat, templateMat, result, intMatchingMethod); MinMaxLocResult minMaxLocRes = Core.minMaxLoc(result); double accuracy = 0; Point location = null; if (this.matchingMethod == MatchingMethod.MM_SQUARE_DIFFERENCE) { accuracy = 1 - minMaxLocRes.minVal; location = minMaxLocRes.minLoc; } else { accuracy = minMaxLocRes.maxVal; location = minMaxLocRes.maxLoc; } if (accuracy < desiredAccuracy) { throw new ImageNotFoundException( String.format( "Failed to find template image in the source image. The accuracy was %.2f and the desired accuracy was %.2f", accuracy, desiredAccuracy), new Rectangle((int) location.x, (int) location.y, templateMat.width(), templateMat.height()), accuracy); } if (!minMaxLocResultIsValid(minMaxLocRes)) { throw new ImageNotFoundException( "Image find result (MinMaxLocResult) was invalid. This usually happens when the source image is covered in one solid color.", null, null); } Rectangle foundRect = new Rectangle( (int) location.x, (int) location.y, templateMat.width(), templateMat.height()); return new ImageFinderResult(foundRect, accuracy); }
/** * Checks if the pattern can be found in the given area of interest and sets up feedback. * @param match_method Match Methods supported by OpenCV. * @param res ID of the resource pattern in the res directory. * @param resName Name of the resource to be returned. * @param thresh Threshold the best detection has to pass in order to be a successful detection. */ public void templateMatching(int match_method, int res, String resName, double thresh) { // Pattern Matching Point matchLocCode; double matchValCode; Log.i("HERE", "" + resName); Rect roiCodeArea = new Rect(new Point(showBit.cols() * card.getPattern(resName).getTl().x,showBit.rows() * card.getPattern(resName).getTl().y), new Point(showBit.cols() * card.getPattern(resName).getBr().x, showBit.rows() * card.getPattern(resName).getBr().y)); Mat cropedCodeArea = showBit.submat(roiCodeArea); Bitmap bmCode = BitmapFactory.decodeResource(getResources(), res); Mat cropedCode = new Mat ( bmCode.getHeight(), bmCode.getWidth(), CvType.CV_8U, new Scalar(4)); Utils.bitmapToMat(bmCode, cropedCode); int result_cols_code = cropedCodeArea.cols() - cropedCode.cols() + 1; int result_rows_code = cropedCodeArea.rows() - cropedCode.rows() + 1; Mat resultCode = new Mat(result_rows_code, result_cols_code, CvType.CV_32FC1); Imgproc.matchTemplate(cropedCodeArea, cropedCode, resultCode, match_method); MinMaxLocResult mmrCode = Core.minMaxLoc(resultCode); if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) { matchLocCode = mmrCode.minLoc; matchValCode = mmrCode.minVal; } else { matchLocCode = mmrCode.maxLoc; matchValCode = mmrCode.maxVal; } Log.w("matchValCode", "" + matchValCode); // Pattern passes Detection if(matchValCode >= thresh) { // If detecting card and pattern passes: get the card that pattern belongs to. if(cardType.equals("-DETECT-")) { cardType = getFoundCard(resName); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText( CardValidationActivity.this, "Card detected: " + cardType, Toast.LENGTH_LONG ).show(); } }); } else { Core.rectangle( cropedCodeArea, matchLocCode, new Point( matchLocCode.x + cropedCode.cols() , matchLocCode.y + cropedCode.rows() ), new Scalar(0, 255, 0, 255), 4 ); theText.put("Pattern: " + resName, "PASSED"); } } else { theText.put("Pattern: " + resName, "FAILED"); failureCount++; } }
public SingleScaleMatch(double fingerprintMatch, MinMaxLocResult minMaxLocResult, Rectangle.Int result) { this.fingerprintMatch = fingerprintMatch; this.minMaxLocResult = minMaxLocResult; this.result = result; }
private static ScanMatch findMatch(Mat searchImageMat, Mat templateMat, double templateStdDev, double scale, Image.Int searchImageScaled, BigDecimal s) { double templateScale = s.doubleValue() * scale; int w = (int) Math.round(templateMat.width() * templateScale); int h = (int) Math.round(templateMat.height() * templateScale); // early exit - template is bigger than search image if (templateMat.cols() * templateScale >= searchImageMat.cols() || templateMat.rows() * templateScale >= searchImageMat.rows()) { return null; } if (isTemplateTooSmall(w, h, s)) { return null; } // scale Mat scaledTemplateMat = new MatOfFloat(); resize(templateMat, scaledTemplateMat, new Size(w, h), 0, 0, CV_INTER_AREA); // normalized cross-corr Mat resultMatrix = new MatOfFloat(); matchTemplate(searchImageMat, scaledTemplateMat, resultMatrix, TM_CCORR_NORMED); MinMaxLocResult minMaxResult = minMaxLoc(resultMatrix); // compute fingerprint for scaled template Image.Int templateForFingerprint = ImageUtil.Convert.toImage(OpenCV.matToBufferedImage(scaledTemplateMat)); ImageFingerprint templateFingerprint = new ImageFingerprint(ImageUtil.toSquare(templateForFingerprint), 0xf2, 0xf1, 0xf0, FINGERPRINT_SIZE); // if template has low contrast bump it up if (templateStdDev < STDDEV_THRESHOLD) { Image.Int contrastedImage = ImageUtil.Convert.toImageInt(Contrast.autoContrast(ImageUtil.Convert.toImageByte(templateForFingerprint))); templateFingerprint = new ImageFingerprint(ImageUtil.toSquare(contrastedImage), 0xf2, 0xf1, 0xf0, FINGERPRINT_SIZE); } // cut the possible area from the image and get fingerprint probability for it Rectangle.Int resultRectangle = new Rectangle.Int((int) minMaxResult.maxLoc.x, (int) minMaxResult.maxLoc.y, w, h); SingleScaleMatch singleScaleMatch = getMatchForRectangle(searchImageScaled, templateFingerprint, templateStdDev, minMaxResult, resultRectangle); // free resultMatrix.release(); return new ScanMatch(singleScaleMatch.fingerprintMatch, scaleRectangle(singleScaleMatch.result, 1 / scale), s); }
private static SingleScaleMatch getMatchForRectangle(Image.Int searchImage, ImageFingerprint templateFingerprint, double templateStdDev, MinMaxLocResult result, Rectangle.Int resultRectangle) { Image.Int crop = ImageUtil.Cut.crop(searchImage, resultRectangle); // also increase contrast for crop of search image Image.Int contrast = applyContrast(crop, templateStdDev < STDDEV_THRESHOLD); ImageFingerprint resultFingerprint = new ImageFingerprint(ImageUtil.toSquare(contrast), 0xf2, 0xf1, 0xf0, FINGERPRINT_SIZE); double stddev1 = stddev(templateFingerprint); double stddev2 = stddev(resultFingerprint); double stddevMatch = Math.min(stddev1, stddev2) / Math.max(stddev1, stddev2); double fingerprintProbability = fingerprintMatch(templateFingerprint, resultFingerprint); double matchProbability = stddevMatch > 0.8 ? fingerprintProbability : fingerprintProbability * stddevMatch; return new SingleScaleMatch(matchProbability, result, resultRectangle); }
@Override public void execute(Raster raster, Map<Key, Serializable> params,Hints hints, ProgressListener listener) { double[] minMax = null; if(params != null){ if(params.containsKey(KEY_MINMAX)){ minMax = (double[]) params.get(KEY_MINMAX); } } final int raster_width = raster.getDimension().width(); final int raster_height = raster.getDimension().height(); final int pixelAmount = raster_width * raster_height; if(minMax == null){ final Mat srcMat = matAccordingToDatatype( raster.getBands().get(0).datatype(), raster.getData(), raster_width, raster_height); MinMaxLocResult result = Core.minMaxLoc(srcMat); minMax = new double[]{result.minVal, result.maxVal}; } int[] pixels = new int[pixelAmount]; final ByteBufferReader reader = new ByteBufferReader(raster.getData().array(), ByteOrder.nativeOrder()); // Log.d(OpenCVAmplitudeRescaler.class.getSimpleName(), "rawdata min "+minMax[0] +" max "+minMax[1]); for (int i = 0; i < pixelAmount; i++) { double d = ByteBufferReaderUtil.getValue(reader, raster.getBands().get(0).datatype()); pixels[i] = pixelValueForGrayScale(d, minMax[0], minMax[1]); } ByteBuffer buffer = ByteBuffer.allocate(pixels.length * 4); buffer.asIntBuffer().put(pixels); raster.setData(buffer); }