I have written a piece of code in C++. I took the first part from
  search engine results.
Are you serious? Not sure how to understand that. It's not a debugging site. You're supposed to do the effort first.
Anyway, your code is mostly C. The only piece of code reminding me of C++ is the console output. So let me try if I can help... because I like.
1) What is the meaning of defining a function using double **filter_2d? Can we define a function using a pointer?
This means that the result of the function is a pointer to a pointer of type double. Break it down like this:
- **filt_outis of type- double- used to access a double value; popular use in 2D arrays to access the 2nd dimension, i.e. the row and the column of a 2D array.
 
- *filt_outis of type- double *- used to access a pointer to a double value; popular use in 2D arrays to access the 1st dimension, i.e. the row of a 2D array.
 
- filt_outis of type- double **- used to access a pointer to a pointer to a double value; popular use in 2D arrays to access the array, i.e. the allocated memory address for the 2D array.
 
You can define a function using a simple pointer, but it is not suitable for 2D arrays. Read the items above.
2) I am confused about the following line:
double **filt_out = filter_2d(A, 3, 3, B, 2, 1); It is not working
  properly, and I do not understand why.
Does not make sense to me. filter_2d's return type is voidand thus I don't see why would want to assign the returned value to a pointer to a pointer to a double
It is not working properly, and I do not understand why.
Me neither, yet. But to be honest, it sounds more like a debugging request than a question that merits votes. In particular you give us the impression that you did not do your homework learning C/C++ first of all, and secondly copied code from a search engine and ask the community to solve that for you.
Some flaws I believe you want to have a closer look at:
(I'll use mostly C syntax)
OutImage = (double **)malloc(sizeof(double *)*(3 * 3));
It does not look right to me. Please verify.
I think OutImage is supposed to be a 2D array (the image) and thus **OutImage points to an element (2nd dimension, you want to access row and column) of the 2D array.
Also since it is a 2D array, you need to initialize the 1st dimension first (i.e. the rows) and then the 2nd dimension (i.e. the columns).
So I would suggest something like this:
//three rows of size for type double*
OutImage = (double **) malloc(sizeof(double *) * 3);
//three columns of size of type double
for (int i=0; i<3; i++)
    OutImage[i] = (double *) malloc(sizeof(double) * 4);
This way you can access using OutImage[row][column]. I believe it's less error prone. I put the size of the columns to 4 according to the calculation in the function filter_2d which calculates the widths and the heights (The width remains the same with parameters given, the height increases by one dimension).
Also (see below) later in the function filter_2d I'd remove the memory allocation, since it is already done here.
Not sure what you want to achieve with this, but I think that...
double *A_ptr[9];
for (int i = 0; i < 10; i++)
    {
        A_ptr[i] = A[i];
    }
is just wrong on so many levels.
- 10 does not make sense; indices go from 0 to 8
- A[i] has size 3 while A_ptr[i] has size 9
- what were you thinking Sam?
Considering the use of A_ptr (and the way you access it) in the function filter_2d above I would think you want to do something analogue to above 2D array.
double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
for (int i = 0; i < 3; i++)
    A_ptr[i] = (double *) malloc(sizeof (double) * 3);
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        A_ptr[i][j] = A[i][j];
    }
}
double B[1][2] = { 1, 2 };
double *B_ptr[2];
for (int i = 0; i < 2; i++)
{
    B_ptr[i] = B[i];
}
Similar to above.
- B[i] is of size 1, so only index 0 makes sense
- Damn Sam, what were you thinking again?
You call filter with following parameters:
- A_ptr: a 2D array copy of A (image)
- 3: size of 1st dimension of image
- 3: size of 2nd dimension of image
- B_ptr: a 2D array copy of B (kernel)
- 2: size of 1st dimension of kernel - Should be switched with the next one
- 1: size of 2nd dimension of kernel - Should be switched with the previous one
- &OutImage: address of the pointer to the resulting filtered image (the parameter is a pointer to - **OutImageactually)? I think you want to preserve the pointer after the function call, isn't it? Sounds OK to me.
 - filter_2d(A_ptr, 3, 3, B_ptr, 2, 1, &OutImage); 
You defined B_ptr as a copy of B which has dimensions [1][2], but you pass 2 as 1st dimension and 1 as 2nd dimension to the function. Either switch the dimensions of B/B_ptr or switch the two parameters.
In that function I would remove the following code
for (i = 0; i<width_image + width_kernel - 1; i++)
{
    output[i] = (double *)malloc(sizeof(double)*(height_image + height_kernel - 1));
}
(See last remark in first bug above when allocating memory for OutImage).
Replace the loop to print the result. Make it look like that:
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++)
        cout << OutImage[i][j] << endl;
}
I kept the C++ style printing, but actually you could do it simply with C's printf function as well. No need to include iostream really.
So that's it. I compiled your code and run it. Not sure what to expect, but according to your comment it should be 
2 5 8 3 8 14 17 6 14 23 26 9
Guess what? I got
1 4 7 6 4 13 16 12 7 22 25 18
Well, I guess at this point, it's your turn now.
Please remember, check where you want to do the memory allocation in
  order to have it take into account the new dimensions. I hard
  coded it in your example to make it work, more or less.
I would probably allocate a dummy address and then use realloc to increase the size to whatever is needed depending on the parameters.
Remember that in general you would want to free the allocated memory.
  I skip it here, since it is a short program.
The program could look like so:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
void filter_2d(double** image, int width_image, int height_image, double** kernel, int width_kernel, int height_kernel, double *** OutImg) {
    double **output = *OutImg;
    int i, j, p, q;
    int rows = width_image + width_kernel - 1;
    int cols = height_image + height_kernel - 1;
    //rows of size for type double*
    output = (double **) realloc(output, sizeof (double *) * rows);
    //columns of size of type double
    for (int i = 0; i < rows; i++)
        output[i] = (double *) malloc(sizeof (double) * cols);
    //for each point in the output
    for (i = 0; i < width_image + width_kernel - 1; i++) {
        for (j = 0; j < height_image + height_kernel - 1; j++) {
            output[i][j] = 0;
            //kernel(p,q)*image(i-p, j-q) 
            for (p = 0; p < width_kernel; p++) {
                //avoid unnecessary comparisons
                if (i - p < 0) {
                    break;
                } else if (i - p < width_image) {
                    for (q = 0; q < height_kernel; q++) {
                        //idem as above
                        if (j - q < 0) {
                            break;
                        } else if (j - q < width_image) {
                            output[i][j] += kernel[p][q] * image[i - p][j - q];
                        }
                    }
                }
            }
        }
    }
}
int main() {
    //allocate dummy memory of size for type double*
    double ** OutImage = (double **) malloc(sizeof (double *));
    // define image matrix
    double A[3][3] = {
        { 1, 2, 3},
        { 4, 5, 6},
        { 7, 8, 9}
    };
    // copy image matrix
    double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
    for (int i = 0; i < 3; i++)
        A_ptr[i] = (double *) malloc(sizeof (double) * 3);
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            A_ptr[i][j] = A[i][j];
            printf(" %f ", A_ptr[i][j]);
        }
    }
    printf("\n");
    //define kernel matrix
    double B[1][2] = {
        { 1, 2}
    };
    //copy kernel matrix
    double ** B_ptr = (double **) malloc(sizeof (double *));
    B_ptr[0] = (double *) malloc(sizeof (double)*2);
    for (int i = 0; i < 1; i++) {
        for (int j = 0; j < 2; j++) {
            B_ptr[i][j] = B[i][j];
            printf(" %f ", B_ptr[i][j]);
        }
    }
    printf("\n");
    //call filter
    filter_2d(A_ptr, 3, 3, B_ptr, 1, 2, &OutImage);
    //print result
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++)
            cout << OutImage[i][j] << endl;
    }
    // No idea what that is
    //system("PAUSE");
    return 0;
}
P.S.: I just saw that Valy had a good solution.