Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

cv2.warpAffine() results in an image shifted by 0.5 pixel

Warping an image with cv2.warpAffine() results in an image shifted by 0.5 pixel.

Is this behaviour expected? If so, what's the reasons behind?

Code

Below is a simple example where an image is scaled with affine transform.

import cv2
import numpy as np

def warpScale(im, scale):
    affine = np.array([
        [scale, 0, 0],
        [0, scale, 0],
        [0, 0, 1],
    ], np.float32)
    return cv2.warpAffine(im, affine[:2, :], (int(im.shape[1]*scale), int(im.shape[0]*scale)))

im = cv2.imread("0-in.png")     # 2x2
scale = 8

# Scale up
im1 = warpScale(im, scale)
cv2.imwrite("1.png", im1)     # 8x8

# Scale down
im2 = warpScale(im1, 1. / scale)
cv2.imwrite("2.png", im2)     # 2x2

Input 2x2 image:

image description

Output-1 (scaled up by a factor of 8):

image description

Output-2 (scaled down back to the original):

image description

Workaround

When I rewrite the warpScale() function as blow, it becomes as I expected. It's like doing the following operations in order:

  • Shift the original image by (+0.5, +0.5)
  • Apply the intended affine transform
  • Shift the transformed image by (-0.5, -0.5)

:

def warpScale(im, scale):
    affine = np.dot(
        np.array([
            [1, 0, -0.5],
            [0, 1, -0.5],
            [0, 0, 1],
        ], np.float32),
        np.dot(
            np.array([
                [scale, 0, 0],
                [0, scale, 0],
                [0, 0, 1],
            ], np.float32),
            np.array([
                [1, 0, 0.5],
                [0, 1, 0.5],
                [0, 0, 1],
            ], np.float32)
        )
    )
    return cv2.warpAffine(im, affine[:2, :], (int(im.shape[1]*scale), int(im.shape[0]*scale)))

Output-1 (scaled up by a factor of 8):

image description

Output-2 (scaled down back to the original):

image description

cv2.warpAffine() results in an image shifted by 0.5 pixel

Warping an image with cv2.warpAffine() results in an image shifted by 0.5 pixel.

Is this behaviour expected? If so, what's the reasons behind?

Code

Below is a simple example where an image is scaled with affine transform.

import cv2
import numpy as np

def warpScale(im, scale):
    affine = np.array([
        [scale, 0, 0],
        [0, scale, 0],
        [0, 0, 1],
    ], np.float32)
    return cv2.warpAffine(im, affine[:2, :], (int(im.shape[1]*scale), int(im.shape[0]*scale)))

im = cv2.imread("0-in.png")     # 2x2
scale = 8

# Scale up
im1 = warpScale(im, scale)
cv2.imwrite("1.png", im1)     # 8x8
16x16

# Scale down
im2 = warpScale(im1, 1. / scale)
cv2.imwrite("2.png", im2)     # 2x2

Input 2x2 image:

image description

Output-1 (scaled up by a factor of 8):

image description

Output-2 (scaled down back to the original):

image description

Workaround

When I rewrite the warpScale() function as blow, it becomes as I expected. It's like doing the following operations in order:

  • Shift the original image by (+0.5, +0.5)
  • Apply the intended affine transform
  • Shift the transformed image by (-0.5, -0.5)

:

def warpScale(im, scale):
    affine = np.dot(
        np.array([
            [1, 0, -0.5],
            [0, 1, -0.5],
            [0, 0, 1],
        ], np.float32),
        np.dot(
            np.array([
                [scale, 0, 0],
                [0, scale, 0],
                [0, 0, 1],
            ], np.float32),
            np.array([
                [1, 0, 0.5],
                [0, 1, 0.5],
                [0, 0, 1],
            ], np.float32)
        )
    )
    return cv2.warpAffine(im, affine[:2, :], (int(im.shape[1]*scale), int(im.shape[0]*scale)))

Output-1 (scaled up by a factor of 8):

image description

Output-2 (scaled down back to the original):

image description