Understanding correlation in image processing using examples
As it was already posted multiple times: The problem comes from an inaccurate definition of correlation in your application. 

The Pearson correlation coefficient does require the data to be 


centered, ie the mean must be subtracted
normalized, ie the data must be divided by the standard deviation


This centering and normalization must be done for the mask as well for each sub-matrix of your larger matrix.

In your example, you would end up with a correlation matrix as:

$\left(
\begin{matrix}
0.0&amp;0.0&amp;0.0\\
-1.0&amp;-0.577&amp;0.0\\
1.0&amp;0.577&amp;0.0
\end{matrix}
\right)
$

Lets have a look at the matrix entries:


0.0 They are there, since there are sub-matrices with all ones in them. The mean of such a matrix is 1 and therefore it is centered to the corresponding matrix with only zeros. Hence the correlation is zero.
1.0 is the correlation that you would like to see. The corresponding sub-matrix fits the mask perfectly, hence full correlation, i.e. 1
-1.0 is the correlation of the sub-matrix that fits the mask, but the sub-matrix entries are switched (i.e. the sub-matrix is 0 where the mask is 1 and vice versa). This is a perfect anti-correlation, i.e. -1
The 0.577 cases: They occur where the sub-matrix deviates from the mask by one number (i.e. there is a 1 where the mask has a 0 and vice versa). It also happens to be a symmetric case in your example, therefore there is a pair that correlates positively with one switch and one that correlates negatively with a corresponding switch.  


Here is a pretty ugly brute-force code to illustrate it. It is neither optimized in any way, nor tested for any other case than yours. I hope it is somewhat correct ;)

import numpy as np
In [2]:

img = np.ones([4,4])
img[2,0:2] = 0.0
print(img)
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [0. 0. 1. 1.]
 [1. 1. 1. 1.]]
In [3]:

mask = np.ones([2,2])
mask[0,0:2] = 0.0
print(mask)
[[0. 0.]
 [1. 1.]]
In [4]:

def simple_convolve(img, mask):
    max_row    = img.shape[0] - mask.shape[0] + 1
    max_col    = img.shape[1] - mask.shape[1] + 1

    output = np.zeros([max_row, max_col])

    for curr_row in range(0, max_row):
        for curr_col in range(0, max_col):
            for curr_mask_row in range(0, mask.shape[0]):
                for curr_mask_col in range(0, mask.shape[1]):
                    output[curr_row, curr_col] += img[curr_row + curr_mask_row, curr_col + curr_mask_col] * mask[curr_mask_row, curr_mask_col]
    return output
​
def better_convolve(img, mask):
    max_row    = img.shape[0] - mask.shape[0] + 1
    max_col    = img.shape[1] - mask.shape[1] + 1

    output = np.zeros([max_row, max_col])

    mask_mean  = mask.mean()
    mask_sigma = (((mask - mask_mean)**2).sum())**0.5
    mask = mask - mask_mean
    mask = mask/mask_sigma

    curr_img_mean  = 0.0
    curr_img_sigma = 0.0

    for curr_row in range(0, max_row):
        for curr_col in range(0, max_col):

            curr_img_mean  = 0.0
            curr_img_sigma = 0.0

            # Compute the mean value of the sub-image of img
            ctr = 0.0
            for curr_mask_row in range(0, mask.shape[0]):
                for curr_mask_col in range(0, mask.shape[1]):
                    ctr = ctr + 1.0
                    curr_img_mean += img[curr_row + curr_mask_row, curr_col + curr_mask_col]
            curr_img_mean = curr_img_mean / ctr

            # Compute the std value of the sub-image of img
            ctr = 0.0
            for curr_mask_row in range(0, mask.shape[0]):
                for curr_mask_col in range(0, mask.shape[1]):
                    ctr = ctr + 1.0
                    curr_img_sigma += (img[curr_row + curr_mask_row, curr_col + curr_mask_col] - curr_img_mean)**2.0
            curr_img_sigma = curr_img_sigma**0.5

            for curr_mask_row in range(0, mask.shape[0]):
                for curr_mask_col in range(0, mask.shape[1]):         
                    x = (img[curr_row + curr_mask_row, curr_col + curr_mask_col] - curr_img_mean)
                    if curr_img_sigma == 0.0:
                        x = 0.0
                    else:
                        x = x/curr_img_sigma

                    output[curr_row, curr_col] += x * mask[curr_mask_row, curr_mask_col]
    return output
In [5]:

simple_convolve(img, mask)
Out[5]:
array([[2., 2., 2.],
       [0., 1., 2.],
       [2., 2., 2.]])
In [6]:

better_convolve(img, mask)
Out[6]:
array([[ 0.        ,  0.        ,  0.        ],
       [-1.        , -0.57735027,  0.        ],
       [ 1.        ,  0.57735027,  0.        ]])