Performing sobel filters on rgb color components

Question:

I’m trying to separate an image into it’s rgb color components, and then trying to perform sobel h and v filters on each of the color component images. I’m not really sure what the problem is, but I’m getting the following divide by 0 error. I think it might be because my u and v are turning out to be the exact same array.

Error

/Users/Sam/PycharmProjects/temp/A2.py:51: RuntimeWarning: divide by zero encountered in true_divide
  theta = 0.5 * np.arctan(2 * gxy / (gxx - gyy))
/Users/Sam/PycharmProjects/temp/A2.py:51: RuntimeWarning: invalid value encountered in true_divide
  theta = 0.5 * np.arctan(2 * gxy / (gxx - gyy))
/Users/Sam/PycharmProjects/temp/A2.py:54: RuntimeWarning: invalid value encountered in sqrt
  fTheta = np.sqrt(0.5 * ((gxx + gyy) + (gxx - gyy) * np.cos(2 * theta) + (2 * gxy * np.sin(2 * theta))))
Traceback (most recent call last):
  File "/Users/Sam/PycharmProjects/A1/venv/lib/python3.6/site-packages/numpy/core/fromnumeric.py", line 51, in _wrapfunc
    return getattr(obj, method)(*args, **kwds)

Code

import skimage.filters as filt
import numpy as np
def color_dot_product(A, B):
    return np.sum(A.conj() * B, axis=2)


mushroom = io.imread('mushroom.jpg')
I = util.img_as_float(mushroom)
  red = I[:, :, 0]  # Zero out contribution from green
  blue = I[:,:,1]
  green = I[:,:,2]

  # Compute horizontal and vertical derivatives of red, blue and green channels through applying sobel filters
  u = I.copy()
  u[:, :, 0] = filt.sobel_h(red)
  u[:, :, 1] = filt.sobel_h(green)
  u[:, :, 2] = filt.sobel_h(blue)
  v = I.copy()
  v[:, :, 0] = filt.sobel_v(red)
  v[:, :, 1] = filt.sobel_v(green)
  v[:, :, 2] = filt.sobel_v(blue)
  gxx = color_dot_product(u, u)
  gyy = color_dot_product(v, v)
  gxy = color_dot_product(u, v)

  # Calculate gradient direction (direction of the largest colour change)
  theta = 0.5 * np.arctan(2 * gxy / (gxx - gyy))

  # Calculate the magnitude of the rate of change
  fTheta = np.sqrt(0.5 * ((gxx + gyy) + (gxx - gyy) * np.cos(2 * theta) + (2 * gxy * np.sin(2 * theta))))
Asked By: Sam

||

Answers:

When dividing by an image like this, it is very likely that some pixel has a value of zero, and thus you get a division by zero.

This is typically avoided by explicitly testing each pixel for zero before dividing, or if the divisor is non-negative, adding a very small value.

But in this case you don’t need to divide at all. The function atan2 takes two input arguments, such that atan2(y,x) is equivalent to atan(y/x). Except that it returns an angle in the range (-π,π] (i.e. it gives you the full 360 degree range of angles). I linked to Wikipedia above because atan2 is a generic function that exists in all languages. Except in NumPy it is called arctan2 (weird desire to be different, I guess?). So replace:

theta = 0.5 * np.arctan(2 * gxy / (gxx - gyy))

with:

theta = 0.5 * np.arctan2(2 * gxy, gxx - gyy)

The gxx, gyy, gxy triplet you compute looks a lot like the structure tensor. If this is what you intend to compute, you need to add an additional blurring to each of these three components. This causes the gradient information to be averaged locally, yielding fewer locations with a zero gradient.

Answered By: Cris Luengo