1

When using gocv package it is possible, for example, to perform template matching of a pattern within an image. The package also provide the MinMaxLoc function to retrieve locations of minimums and maximums within the matrix.

However, in below python example, the writer uses numpy.Where to threshold the matrix and get locations of multiple maximums. The python zip function is used to glue values together so they are like a slice [][2]int, the inner slice being xs and ys of the matches found.

The syntax loc[::-1] reverses the array.

The star operator in zip(*loc..) is being used to unpack the slices given to zip.

https://docs.opencv.org/master/d4/dc6/tutorial_py_template_matching.html

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img_rgb = cv.imread('mario.png')
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread('mario_coin.png',0)
w, h = template.shape[::-1]
res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)

for pt in zip(*loc[::-1]):
    cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
cv.imwrite('res.png',img_rgb)

How do I implement the same np.where algorithm in Go to get the multiple locations after the threshold is applied?

alkasm
  • 20,395
  • 4
  • 73
  • 90
mh-cbon
  • 6,683
  • 2
  • 27
  • 51

1 Answers1

4

OpenCV has a built-in (semi-)equivalent function to np.where(), which is findNonZero(). As implied by the name, it finds the non-zero elements in an image, which is what np.where() does when called with a single argument, as the numpy docs state.

And this is available in the golang bindings as well. From the gocv docs on FindNonZero:

func FindNonZero(src Mat, idx *Mat)

FindNonZero returns the list of locations of non-zero pixels.

For further details, please see: https://docs.opencv.org/master/d2/de8/group__core__array.html#gaed7df59a3539b4cc0fe5c9c8d7586190

Note: np.where() returns indexes in array order, that is, (row, col) or (i, j) which is opposite to typical image indexing (x, y). That is why loc is reversed in Python. When using findNonZero() you won't need to do that, since OpenCV always uses (x, y) for points.

alkasm
  • 20,395
  • 4
  • 73
  • 90
  • can you also explain the advantage of using numpy version over opencv version of this algorithm ? if any! i m not clear about to why the two exist... – mh-cbon Nov 09 '19 at 08:22
  • 1
    @mh-cbon people can use either; you'll see numpy functions a lot because OpenCV uses numpy for matrix representation in Python instead of the native `cv::Mat` (there's a lot of good reasons for this), and that means you can just use numpy functions on images directly---and a lot of people know numpy better than OpenCV. There's no general reason to prefer it (one might be a little faster on certain platforms, you can test the timing if you like). – alkasm Nov 09 '19 at 22:21
  • something is not clear about findNonZero output format. Using the c++ library it appears people do `nonZeroCoordinates.at(i).x `. But with gocv i don t find the equivalent Point method. Meanwhile, `findNonZero` returns a mat type `cv32sc2` with 9 rows, 1 col, 2 channels. I have not found how to turn those values into locations yet. I have read about https://stackoverflow.com/questions/19242662/opencv-find-all-non-zero-coordinates-of-a-binary-mat-image and understand the second method. But i would like o stick to method 1, and try to exploit findNonZero return matrix. Can you help again? – mh-cbon Nov 14 '19 at 15:56
  • I mean, i m unclear about the format output of findNonZero, especially like how many various format can it return, and how to handle them all. I guess... – mh-cbon Nov 14 '19 at 15:58
  • Also, if i were to take xs from channels 0 and ys from channel 1 because channel length == 2, i found a lot of similar values off by 1 pixel, how can i flatten this ? are those questions out of topic ? – mh-cbon Nov 14 '19 at 16:03
  • @mh-cbon you are correct that each channel corresponds to each dimension of the data (channel 0 is x, channel 1 is y), this is a common output format for OpenCV. Can you please edit your original post with code showing the off by one issues? I can edit my answer accordingly. – alkasm Nov 14 '19 at 21:16