0

So, what I'm trying to do is take an image (let's say 100x100) and do a 5x5 kernel over the image:

kernel = np.ones((5, 5), np.float32)/25

and then output an array for each iteration of the kernel (like in cv2.filter2D) like:

kernel_vals.append(np.array([[indexOfKernelIteration], [newArrayOfEditedKernelValues]]))

What I'm missing is how to get it to iterate across the image and output the pixel values of the new "image" that would be produced by:

img = cv2.filter2D(image, -1, kernel)

I just want, for each kernel, the output that is displayed on the new image to be put into the "kernel_vals" array.

image

^NOT INTO AN IMAGE

Attached image for visual reference.

Nelewout
  • 6,281
  • 3
  • 29
  • 39
  • One way to implement the convolution, albeit a very slow one, would be traversing the image while extracting the kernel neighborhood on each iteration. For each input pixel, you could slice the `5 x 5` area, perform the linear combinations between pixels and send the resulting pixel to a new image (or “canvas”). This, of course, in Python type-checking for each loop iteration is pretty slow. I honestly don’t know if this operation could be vectorized using `numpy` functions, but you could at least use `numba` for speeding things up. Hopefully, someone numpy-savvy enough could chime in. – stateMachine Nov 16 '22 at 20:28
  • @stateMachine Thank you for the comment! This is similar to what I want to do, but I think what I was really stuck on was the problem of getting the pixels into an array in general. Couldn't see it because I was too caught up on the filter2d method lol. I do understand what you are saying though, and that's where my head was going at first, because I want to be able to find the location of the greatest concentration of white pixels in an image. I'm sure there is probably an easier way, but it was requested that I use a kernel at least to get bare functionality to work. – Zachary Partlo Nov 16 '22 at 23:05

1 Answers1

1

imread returns an np.array, so if i understand what you want to do, you have the solution in the question. For completeness sake, see the code below.

import cv2

img = cv2.imread("image.png", cv2.IMREAD_GRAYSCALE)
print(type(img))
print(img[:10, :10])

kernel = np.ones((5, 5), np.float32)/25
kernel_vals = cv2.filter2D(img, -1, kernel)
print(kernel_vals[:10, :10])

And the output is (with added newlines for readability)

<class 'numpy.ndarray'>

[[255 255 255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255 255 255]
 [255 255 255   0 255 255 255   0 255 255]
 [255 255 255   0 255 255 255   0 255 255]
 [255 255 255   0 255 255 255   0 255 255]
 [255 255 255   0 255 255 255   0 255 255]
 [255 255 255   0 255 255 255   0 255 255]
 [255 255 255   0 255 255 255   0 255 255]
 [255 255 255   0 255 255 255   0 255 255]]

[[255 255 255 255 255 255 255 255 255 255]
 [255 245 245 245 245 235 245 245 245 235]
 [255 235 235 235 235 214 235 235 235 214]
 [255 224 224 224 224 194 224 224 224 194]
 [255 214 214 214 214 173 214 214 214 173]
 [255 204 204 204 204 153 204 204 204 153]
 [255 204 204 204 204 153 204 204 204 153]
 [255 204 204 204 204 153 204 204 204 153]
 [255 204 204 204 204 153 204 204 204 153]
 [255 204 204 204 204 153 204 204 204 153]]

Now, since kernel_vals is an np.array, you can flatten it, turn it into a list, or manipulate it in any other way you want

Alex P
  • 1,105
  • 6
  • 18
  • I think OP is asking how to replicate filter2d's functionality manually, using python/numpy-based functions. – stateMachine Nov 16 '22 at 20:29
  • @stateMachine I don't see how the OP is asking about implementing a 2D convolution manually, but if that's the case (and, hopefully, they can clarify), that question has been answered [here (numpy answer)](https://stackoverflow.com/questions/43086557/convolve2d-just-by-using-numpy) and [here (less numpy-heavy)](https://stackoverflow.com/questions/2448015/2d-convolution-using-python-and-numpy) – Alex P Nov 16 '22 at 20:42
  • @AlexP Thank you for the answer! I am asking basically how to transform an image into a numerical array. I think you did essentially what I wanted to do; I wanted to traverse the image making it smaller and condensing a 5x5 area of numbers into 1 "pixel". The reason for this is to ultimately try to find the 5x5 area that has the greatest percentage of white or "255" pixels. I think this is on the right track, but I'm not sure what exactly the new array is showing. If I understand correctly, it is the image after the kernel goes over it, but does that do what I want? In terms of finding the max – Zachary Partlo Nov 16 '22 at 22:55
  • @AlexP regardless, you were very helpful! For some reason, I couldn't find the `imread` method on my own. Probably because I'm fairly new to Computer Vision and was stuck on figuring out how to modify the filter2D method. Which is something I don't need to think about because I can turn the image into a `np.array` from the beginning. – Zachary Partlo Nov 16 '22 at 23:01
  • @ZacharyPartlo The new array, at each cell, contains the result of the convolution with said cell as the center. Since your kernel is a mean (or averaging) filter, the result shows the average light intensity (since this a grayscale image) locally to each cell. If you now want to find the "whitest" 5x5 area, you simply need one, many, or all indices of the resultant matrix with the max value in the matrix, which is easy enough with numpy. So based on your comment, I'd say this is exactly what you want. Also, consider upvoting and accepting the answer if it solved your problem. – Alex P Nov 16 '22 at 23:18
  • @AlexP Okay! Thank you! I would upvote if I could. Usually I just lurk on SO but today was my first post! I will accept the answer though! – Zachary Partlo Nov 16 '22 at 23:21
  • @AlexP the other issue though is that I'm trying to pass a background subtracted image (not file name) to `cv2.imread`. It only supports direct file names correct? – Zachary Partlo Nov 16 '22 at 23:24
  • @ZacharyPartlo what do you mean "background subtracted image"? But yes, `imread` accepts the path to the image file – Alex P Nov 16 '22 at 23:35
  • @AlexP I'm using `cv2.bgsegm.createBackgroundSubtractorMOG()` to mask each frame of a video and then find the location of the greatest amount of white space. I'm not sure how to use `imread` without the file path. Or is there maybe another tool in Computer Vision? I've been looking at docs and online but can't seem to find anything. – Zachary Partlo Nov 18 '22 at 05:13
  • @ZacharyPartlo you don't need to use `imread` if it doesn't apply to your use case. When you apply the subtractor to a frame, what will the result be? Based on the code above, how can you check what the result is? And what do you want it to be? Use `type` and you'll see that it is also an `np.array`, which is exactly what you want. Always try things out for yourself and check/understand what you put in and what comes out – Alex P Nov 18 '22 at 11:32
  • @AlexP okay thank you! You were very helpful! I'll keep those questions in mind when testing in the future! – Zachary Partlo Nov 19 '22 at 03:16