Ask Your Question
0

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

asked 2014-05-17 02:59:56 -0500

niboshi gravatar image

updated 2014-05-17 03:07:31 -0500

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)     # 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

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
1

answered 2014-05-19 09:08:53 -0500

kbarni gravatar image

There is no shift, the first output is the expected behavior. After a 8x scaling you get the following pixel center coordinates:

(0,0) -> (0,0)
(0,1) -> (0,8)
(1,1) -> (8,8)
(1,0) -> (8,0)

You can check on the resulting image that they are correct.

But, if you want to get the second image, you have to translate the original coordinates by (0.5,0.5) pixels, exactly as you did.

edit flag offensive delete link more

Comments

OK, it's clear now. In cv2.warpAffine(), pixel values are considered located at grid cross-points (which is more mathematically consistent), not at the centers of grid squares (visually consistent). I was confused with cv2.resize() whose behaviour is more like the latter.

niboshi gravatar imageniboshi ( 2014-05-20 09:04:05 -0500 )edit
Login/Signup to Answer

Question Tools

Stats

Asked: 2014-05-17 02:59:56 -0500

Seen: 881 times

Last updated: May 19 '14