Home > database >  [cv2.filter2D() on Python]: why does it return these specific values?
[cv2.filter2D() on Python]: why does it return these specific values?

Time:11-06

The following Python script computes the 2D convolution of the blue color channel of a .jpg image:

  1. It reads a 6x6 BGR image: image to convolve
  2. It extracts the channel 0. In cv2 this corresponds to color channel blue.
  3. I print the values of the channel
  4. Input data type is uint8. Therefore, we making cv2.filter2D() and setting ddepth=-1, the output will have data type uint8 too and hence values >255 cannot be represented. Hence, I decided to convert the image from uint8 to, for example, short to have a wider numeric range and be able to represent the values at the output of the filter.
  5. I define a kernel of size 3x3 (see the values of the kernel in the code below).
  6. I filter the blue channel with the kernel and I obtain a filtered image of the same size due to the padding
  7. The filtered values given by the function filter2D() don't correspond to what I would expect. For example, for the top left value the functions returns 449, however I would have expected 425 instead since 71*0 60*0 65*1 69*1 58*3 61*1 89*0 66*0 56*1=425.

Does anyone have any idea about how the filtered image is being calculated by filter2D() function? Is there anything wrong with my proposed calculation?

    import cv2
    import numpy as np
    image = cv2.imread('image.jpg')
    # Read image 6x6x3 (BGR)
    blue_channel=image[:,:,0]
    # Obtain blue channel
    print(blue_channel)
    # Result is:
    #[[71 60 65 71 67 67]
    # [69 58 61 69 69 67]
    # [89 66 56 55 45 37]
    # [65 37 27 32 31 30]
    # [46 23 22 38 43 45]
    # [55 36 44 60 60 47]]
    blue_channel=np.short(blue_channel)
    # Convert image from uint8 to short. Otherwise, output of the filter will have the same   data type as the
    # input when using ddepth=-1 and hence filtered values >255 won't be able to be represented
    print(blue_channel)
    # Result is (same as before, ok...):
    # 71 60 65 71 67 67
    # 69 58 61 69 69 67
    # 89 66 56 55 45 37
    # 65 37 27 32 31 30
    # 46 23 22 38 43 45
    # 55 36 44 60 60 47
    kernel=np.array([ [0, 0, 1], [1, 3, 1], [0, 0, 1] ])
    # Kernel is of size 3x3
    # [0 0 1]
    # [1 3 1]
    # [0 0 1]
    filtered_image = cv2.filter2D(blue_channel, -1, kernel)
    # Blue channel is filtered with the kernel and the result gives:
    # 449 438 464 483 473 473
    # 449 425 436 449 447 451
    # 494 431 390 366 324 301
    # 358 281 243 242 237 240
    # 257 208 219 270 289 312
    # 283 251 304 370 377 347
    print(filtered_image)
    # Why top left filtered value is 449?
    # I would expect this:
    # 71*0 60*0 65*1 69*1 58*3 61*1 89*0 66*0 56*1=425
    # In short, I would expect 425 instead of 449, how is that 449 computed?

CodePudding user response:

Your calculation is not wrong, but you have actually written convolution for value at [2,2], which match with your result 425.

To calculate value e.g. [1,1] you need values outside of the image, you have to handle surrounding edges. And by default in function filter2D they are handled as reflect 101 , in wiki its shifted mirror edge handling by 1.

To understand diffrence between mirror(reflect) and reflect 101:

Mirror (reflect)

left edge |  image  | right edge
          |         | 
     b  a | a  b  c | c  b

Reflect 101

left edge |  image  | right edge
          |         | 
     c  b | a  b  c | b  a

So calculation for [1,1] with default edge handling in filder2D would be:

0*58   0*69   1*58   1*60   3*71   1*60   0*58   0*69   1*58 = 449
  • Related