Frei-Chen Edge Detector

1,078 views
Skip to first unread message

Umesh Sharma

unread,
Apr 24, 2013, 4:18:25 AM4/24/13
to scikit...@googlegroups.com
Hi,
I am working on implementation of Frei-Chen Edge detector ( http://rastergrid.com/blog/2011/01/frei-chen-edge-detector/ ) , i have almost completed it but i have one doubt regarding the last mask it is using for computing average .
I don't know why it is using this mask and after applying this mask i am getting an image which looks like original image and the difference can't be detected and if that mask is not used then edges are clearly visible .
so can you please tell me where is problem ?



Thanks,
Umesh

Stéfan van der Walt

unread,
Apr 24, 2013, 5:12:07 AM4/24/13
to scikit-image
Hi Umesh
Can you show us your code?

Stéfan

Umesh Sharma

unread,
Apr 24, 2013, 5:43:20 AM4/24/13
to scikit...@googlegroups.com

Hi Stefan,
Here is my code which i have written in edges.py

##############

def freiChen(image,mask=None):
    """Find the edge magnitude using FreiChen Filter.

    Parameters
----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen edge .
    """
    return np.sqrt(freiChen_edge1(image, mask)**2 +\
                   freiChen_edge2(image, mask)**2 +\
          freiChen_edge3(image, mask)**2 +\
                   freiChen_edge4(image, mask)**2 +\
                   freiChen_line1(image, mask)**2 +\
                   freiChen_line2(image, mask)**2 +\
                   freiChen_line3(image, mask)**2 +\
                   freiChen_line4(image, mask)**2 )
                   #freiChen_average(image, mask)**2)


def freiChen_edge1(image, mask):
    """Find the horizontal edges of an image using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen horizontal edge.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

      1  sqrt(2)  1
      0       0   0
-1 -sqrt(2) -1

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[ 1, sqrt(2), 1],
                                       [ 0,       0, 0],
                                       [-1,-sqrt(2),-1]]).\
astype(float) / sqrt(8)))
    return _mask_filter_result(result, mask)


def freiChen_edge2(image, mask):
    """Find the vertical edges of an image using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChan edges .

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

         1   0       -1
    sqrt(2)  0  -sqrt(2)
1 0 -1
    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[      1, 0,      -1 ],
                                       [sqrt(2), 0, -sqrt(2)],
                                       [      1, 0,      -1]]).\
astype(float) / sqrt(8)))
    return _mask_filter_result(result, mask)

def freiChen_edge3(image, mask):
    """Find the edges in an image having slope 135 degree FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen edges.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

          0   -1   sqrt(2)
          1    0       -1
-sqrt(2)   1        0

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[       0,-1, sqrt(2)],
                                       [       1, 0,      -1],
                                       [-sqrt(2), 1,       0]]).\
astype(float) / sqrt(8)))
    return _mask_filter_result(result, mask)


def freiChen_edge4(image, mask):
    """Find the edges of an image having slope 45 degree using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The Freichen edges.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

      sqrt(2)   -1         0
          -1     0         1
  0     1   -sqrt(2)

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[sqrt(2), -1,        0],
                                       [     -1,  0,        1],
                                       [      0,  1, -sqrt(2)]]).\
astype(float) / sqrt(8)))
    return _mask_filter_result(result, mask)


def freiChen_line1(image, mask):
    """Find the edge intersection in an image using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen lines.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

      0   1   0
     -1   0  -1
      0   1   0

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[ 0, 1,  0],
                                       [-1, 0, -1],
                                       [ 0, 1,  0]]).astype(float) / 2.0))
    return _mask_filter_result(result, mask)


def freiChen_line2(image, mask):
    """Find the intersection of edges in an image using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen lines.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

      -1   0   1
       0   0   0
       1   0  -1

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[-1, 0,  1 ],
                                       [ 0, 0,  0],
                                       [ 1, 0, -1]]).astype(float) / 2.0))
    return _mask_filter_result(result, mask)

def freiChen_line3(image, mask):
    """Find the lines of an image using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen lines.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

      1   -2   1
     -2    4  -2
      1   -2   1

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[ 1, -2,  1 ],
                                       [-2,  4, -2 ],
                                       [ 1, -2,  1]]).astype(float) / 6.0))
    return _mask_filter_result(result, mask)


def freiChen_line4(image, mask):
    """Find the lines of an image using the FreiChen operator.

    The kernel is applied to the input image, to produce separate measurements
    of the gradient component one orientation.

    Parameters
    ----------
    image : 2-D array
        Image to process.
    mask : 2-D array, optional
        An optional mask to limit the application to a certain area.
        Note that pixels surrounding masked regions are also masked to
        prevent masked regions from affecting the result.

    Returns
    -------
    output : ndarray
        The FreiChen lines.

    Notes
    -----
    We use the following kernel and return the absolute value of the
    result at each point::

      -2   1   -2
       1   4    1
      -2   1   -2

    """
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[ -2, 1, -2 ],
                                       [  1, 4,  1 ],
                                       [ -2, 1, -2 ]]).astype(float) / 6.0))
    return _mask_filter_result(result, mask)


def freiChen_average(image, mask):
    image = img_as_float(image)
    result = np.abs(convolve(image,
                             np.array([[ 1, 1, 1 ],
                                       [ 1, 1, 1 ],
                                       [ 1, 1, 1 ]]).astype(float) / 3.0))
    return _mask_filter_result(result, mask)
##############



Should i commit and upload to Git because it is easy to read ???



Regards ,

Umesh

Chintak Sheth

unread,
Apr 24, 2013, 5:48:00 AM4/24/13
to scikit...@googlegroups.com
Hi Umesh,

Yes. You could create a new branch, commit and push it, and provide a link to it maybe ?

Chintak



Umesh

--
You received this message because you are subscribed to the Google Groups "scikit-image" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scikit-image...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Umesh Sharma

unread,
Apr 24, 2013, 6:08:31 AM4/24/13
to scikit...@googlegroups.com
Hi,

Here is my code one Git



Umesh

Chintak Sheth

unread,
Apr 24, 2013, 6:48:52 AM4/24/13
to scikit...@googlegroups.com
Hi Umesh,

As stated in the subject I'm presuming you want to implement an edge detector, right ? As it says on the blog :
When we are using the Frei-Chen masks for edge detection we are searching for the cosine defined above and we use the first four masks as the elements of importance so the first sum above goes from one to four.

But in your implementation you are summing all the elements including the 4 line masks. As can be seen from the function definition, M is the sum of square of the convolution of relevant masks and S is the sum of square of the convolution of all the masks. If you take all the masks as "relevant", the ratio essentially works out to be 1.

In short, you have to return the sqrt((mask1 + mask2 + mask3 + mask4) / ( mask1 + mask2 + mask3 + mask4 + mask5 + mask6 + mask7 + mask8 + mask9))
Where, mask : refers to the square of the convolution between the corresponding mask and the image

Also just one more note, before you submit a PR, clean up the whitespace noise. You can use Sublime Text 2, with 4 white spaces for indentation as Josh suggested. This is something I learned the hard way. To cross check if the noise is actually cleared out, you can view it on the GitHub editor.

I hope this sorts out the issue.

This is the link you should provide : https://github.com/umesh563/scikit-image/blob/master/skimage/filter/edges.py. Always assume people are lazy. ;)
Thanks,
Chintak

Umesh Sharma

unread,
Apr 24, 2013, 6:56:50 AM4/24/13
to scikit...@googlegroups.com
Thanks Chintak,
I was confused by that S = sum(all mask).



Regrads
Umesh

Ankit Agrawal

unread,
Apr 24, 2013, 7:09:11 AM4/24/13
to scikit...@googlegroups.com
Hi Umesh,

                 Currently, your code returns np.sqrt(S) where S is the corresponding quantity in the article. The answer given by Chintak is almost perfect, just that the algorithm can be used for detecting lines too. Also, you would have to do some sort of scaling(which may not be linear) on sqrt(S/M),(maybe using rescale_intensity in exposure.py would help) to highlight the edges/lines in the output image. For eg: If you want to detect only the lines, then you would calculate M for k = 5, 6, 7, 8 and then calculate sqrt(S/M) . If you want to show all the edges and lines at once, you will calculate M for k = 1....8. Also, almost all the editors have the option of indenting tabs as spaces. But still you should give a try to Sublime Text 2, as it gives (atleast to me) an aesthetic feel while programming. Hope this solves your problem.

Regards,
Ankit Agrawal,
Communication and Signal Processing,
IIT Bombay.

Umesh Sharma

unread,
Apr 24, 2013, 12:24:14 PM4/24/13
to scikit...@googlegroups.com
Hi ,

I have implemented the frei-chen edge detector , it works fine for normal images but for some special cases , like half of the image is black and rest is white ,
in these type of cases , there are some problems.
In this implementation first all the 9 masks are applied to image m1,m2,...m9 (after applying mask).
so after that there is one step      (m1+..m4)/sum(m)   
there are cases in which sum(m) is not singular so inverse of sum(m) can't be calculated . So how should i handle those cases ??


Thanks,
Umesh

Michael Aye

unread,
Apr 24, 2013, 2:56:48 PM4/24/13
to scikit...@googlegroups.com
Concerning removal of whitespace noise, one could setup pre-commit git hooks to do that:

Umesh Sharma

unread,
Apr 25, 2013, 12:45:52 AM4/25/13
to scikit...@googlegroups.com
Hi ,

I have  implemented  frei-chen edge detector .

I am working on testing of this algorithm . 
Please review the code and tell me if i need to make any other changes on this part .


Regrads,
Umesh 
Reply all
Reply to author
Forward
0 new messages