I was playing around with PIL and transformation matrices to understand what's behind simple 2D image manipulation.
In my attempt to rotate an image as "low level" as possible (that is, not using any rotate(degrees)
function, but doing the math) I decided to rotate every pixel of the image using a clockwise rotation matrix:
The rotation went fine, but the image now looks like it's missing some pixels.
Original image, painted on a 435x353 black background:
Rotated 45° clockwise and moved to the right by 300 pixels:
Oddly enough, the issue doesn't occur when rotating the picture 90° clockwise (and moving 400 px to the right):
What could be causing this? Using Image.Image.rotate
works just fine, so I guess the issue resides on my code. It's worth mentioning the original picture has a transparent background, which was lost in the compression when uploaded here. However, I've done the exact same operation to a jpeg (non-transparent) image and the result was the same.
Code used to do the rotation:
import Image, ImageDraw
from scipy import misc
import math
WHITE = (255,255,255)
BLACK = (0,0,0)
W, H = 435, 353
im = Image.new('RGBA', (W, H), BLACK)
draw = ImageDraw.Draw(im)
bitmap = misc.imread('Image.png')
def affine_t(x, y, a, b, c, d, e, f):
"""Returns ((a, b), (c, d))*((x), (y)) + ((e), (f))."""
return a*x + b*y + e, c*x + d*y + f
def crotate(x, y, r):
"""Rotate (x, y) clockwise by r radians."""
# And move 300 px to the right for this example
return affine_t(
x, y, math.cos(-r), math.sin(-r), -math.sin(-r), math.cos(-r), 300, 0
)
x, y = 0, 0
angle = math.pi/4
for row in bitmap:
for pt in row:
draw.point([crotate(x, y, angle),],fill=tuple(pt))
x+= 1
x = 0
y += 1
im.save('out.png')
For each destination pixel you need to calculate the source pixel, but NOT the vice versa. Due to roundings you have several source pixels mapped into the same destination pixel. That's why you cannot actually obtain good 45° rotation without interpolation. My suggestion is actually a nearest neighbour interpolation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With