Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Fast 2D Separable Symmetric/Anti-Symmmetric Convolution

0.00/5 (No votes)
17 Aug 2014CPOL2 min read 12K  
In the article we will look at algorithm for Fast 2D Convolution.

Introduction

In the article we will look at algorithm for Fast 2D Convolution.

Separable Symmetric/Anti-Symmetric Convolution

  • This article presents a convolution algorithm involving a separable symmetric/anti symmetric kernel.
  • Such kernels are common in image processing like blurring,edge detection etc
  • This optimization helps in speeding up many routines .
  • Another requirement being addressed is we may have multiple kernels that need to be applied to the same image in application such as computing the basis representation of rectangular path of the image.
  • since we are traversing the image,we can perform computation of all these kernels simultaneously instead of independent traversals.
  • It is to be noted that this optimization is specific to symmetric/antisymmetric separable filters.
  • We will be assuming that all the kernel are of the same size as well
  • Since kernels are separable we will perform vertical convolution followed by horizontal convolution.
  • One of the considerations is to minimize the row accesses .
  • Another consideration is to perform a single pass over the entire source image
  • Let (n*2+1) be the kernel size.
  • The convolution filter is initialized by accepting all the row and column filter coefficients as well as the information if the filter is symmetric or not
  • A class called SeperableSConvolution implemented this algorithm
01	class SeperableSConvolution
02	{
03	public:
04	    SeperableSConvolution();
05	    vector<mat> rowk;//vector of row filter
06	    vector<mat> colk;//vector of column filters
07	    vector<bool> symmetric; //info if filter is symmetric or not
08	    int N;//number of channels in the output image
09	    //function to set the filter parameters
10	    void setKernel(Mat row,Mat col,bool symm);
11	    //function to clear the filter parameters
12	    void clearKernel();
13	    //apply a set of separable symmetric/anti-symmetric filters on
14	    //the source image and return a multi channel destination image
15	    ////function to perform separable filtering
16	    void apply(Mat &src,Mat &dst);
17	};

Vertical Convolution

  • First vertical convolution is considered
  • If kernel size is (2N+1) ,we need to access same number of rows
  • This if we are applying the filter at row j,we need to access elements from rows from \(j-k\) to \(j+k\) where \(k \in 0..N\)
    $\begin{eqnarray} dst(x,y) = \sum_{i,k=-N}^{k=N} g(k+N)I(x,y+k) \end{eqnarray}$
  • The above needs to be processed for each \(x,y\)
  • Since we need to reduce the number of row access,access rows from \(j-N,j+N\) are performed for each j,compute the convolution for each x.
  • Since with change in x no new rows are being accessed,hence we compute convolution for each element of the present row.
  • Each of the rows need to be multiplied with suitable filter coefficients.
  • since the filter is symmetric or anti symmetric the filter coefficients \(g_k\) is multiplied with elements of rows \(j-k\) and \(j+k\)
  • The resultant sum of accumulated,this is performed for all the rows.
01	for(int y=0;y<s.height;y++)
02	{
03	    //pointer to the source and destination
04	    float *srow0 = (float*)(src.data + src.step*y),*srow1=0;
05	    float *drow = (float*)(dst.data + dst.step*y);
06	 
07	 
08	     //performing vertical convolution
09	     //using the row kernel
10	     //computing g[0]*f(x,y)
11	     for( x = 0; x < s.width; x++ )
12	     {
13	         for(int l=0;l<ch;l++)
14	         {
15	         row[x*ch+l] = srow0[x]*rowk[l].at<float>(n);
16	         }
17	 
18	     }
19	      
20	    //computing g[-n/2]*f(x,y-n/2)
21	   //performing vertical convolution accessing n rows about current row
22	   //accessing a 2 rows at a time,performing computation
23	   for(int k=1;k<=n;k++)
24	   {
25	 
26	    //accessing the vertical abouts about the current row
27	    srow0 = (float*)(src.data + src.step*std::max(y-k,0));
28	    srow1 = (float*)(src.data + src.step*std::min(y+k,s.height-1));
29	    for(int x=0;x<s.width;x++)
30	    {
31	    //applying different vertical kernels
32	    //accumulating the sum
33	        for(int l=0;l<ch;l++)
34	        {
35	        float p=srow0[x]+(1*(symmetric[l]?1:-1))*srow1[x];
36	        row[x*ch+l]+=rowk[l].at<float>(k)*(p);
37	        }
38	    }
39	   }

Horizontal Convolution

  • Once vertical convolution is done we proceed to perform horizontal convolution
  • Since in horizontal convolution there is only a single row access ,it is relatively simple process.
  • The output image is a multi channel image,containing number of channels as desired number of input kernels being applied to the source image.
01	for(x=0;x<s.width;x++)
02	{
03	 
04	//apply horizontal kernels
05	//g[0]*f(x,y)
06	    for(int l=0;l<ch;l++)
07	    {
08	        res[l]=row[x*ch+l]*colk[l].at<float>(n);
09	    }
10	 
11	    //accumulating the sum for g[-N/2+k]f(x-n/2+k)
12	    for(int k=1;k<=n;k++)
13	    {
14	 
15	        for(int l=0;l<ch;l++)
16	        {
17	            float p=(row[(x+k)]+(1*symmetric[l]?1:-1)
18	            *row[(x-k)])*colk[l].at<float>(k);
19	             res[l]=res[l]+p;
20	        }
21	    }
22	    //storing the result of convolution
23	    //output image contains number of channels as different input filters
24	    for(int l=0;l<ch;l++)
25	    {
26	        drow[x*ch+l]=res[l];
27	    }
28	}

Code

  • The class SeperableSConvolution defines a class for performing separable symmetric/ant-symmetric convolution/ Code is available in repository https://github.com/pi19404/OpenVision/ at Improper/convolution.hpp and ImgProc/convolution.cpp files.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)