I have a few questions related to moving a particle ( a round particle with gaussian distribution of intensities) by rotation. When I rotate an image , I would like the particle intensity to be redistributed correctly when the particle ends up in a subpixel position. lets say I have a particle at 2,2 and I rotate it about 4,3 ( NOTE : Not the geometric center of the image ) by 12 degrees and it ends up at 3.2,4.6 .
I have tried to dig something up , and I found this and this
I am not very convinced though. I am attaching the pictures I have made synthetically by this code here
#from random import randrange, uniform
import math
#import matplotlib as mpl
#import matplotlib.pyplot as plt
#import trackpy as tp
#import pims
import numpy as np
from PIL import Image
""" Class to specify the location of a particle """
class Particles(object):
def __init__(self,n=200):
self.pointsxy = np.zeros((200,2))
#""" Initial location of particles. We use floating point ( not integer) to specify random location """
def randomloc(self) :
for i in range(1,200) :
self.pointsxy[i][0] = np.random.uniform(0,1280)
self.pointsxy[i][1] = np.random.uniform(0,1024)
frame.add_spot((self.pointsxy[i][0], self.pointsxy[i][1]), 200, 5)
return self.pointsxy
#""" Function to displace or translate the particles from initial location to the specified value """
def displacement(self,xdisp=0,ydisp=10,n=100):
newxy = np.zeros((200,2))
for i in range(1,200) :
newxy[i][0]=self.pointsxy[i][0]+xdisp
newxy[i][1]=self.pointsxy[i][1]+ydisp
frame2.add_spot((newxy[i][0], newxy[i][1]), 200, 5)
return newxy
#"""function to rotate the image by a specified angle in degrees as provided in main function """
def rotate(self, origin,angle, n=10):
"""
Rotate a point counterclockwise by a given angle around a given origin.
note : The angle should be given in radians.
"""
ox, oy = origin
xynew = np.zeros((200,2))
for i in range(1,200) :
px = self.pointsxy[i][0]
py = self.pointsxy[i][1]
xynew[i][0] = ox + math.cos(angle) * (self.pointsxy[i][0] - ox) - math.sin(angle) * (self.pointsxy[i][1] - oy)
xynew[i][1] = oy + math.sin(angle) * (self.pointsxy[i][0] - ox) + math.cos(angle) * (self.pointsxy[i][1] - oy)
frame3.add_spot((xynew[i][0],xynew[i][1]), 255, 5)
return xynew
# def make_image(self):
#
# for i in range(1,100) :
# frame.add_spot((pointsxy[i][0], pointsxy[i][1]), 200, 5)
#""" class to create image of particles in the specified location as per the class MakeParticles"""
class SimulatedFrame(object):
def __init__(self, shape, dtype=np.int8):
self.image = np.zeros(shape, dtype=dtype)
self._saturation = np.iinfo(dtype).max
self.shape = shape
self.dtype =dtype
#""" A gaussian distribution of intensities is obtained. Eccentricity (ecc) means how much the particle is elongated . """
def add_spot(self, pos, amplitude, r, ecc=0):
"Add a Gaussian spot to the frame."
x, y = np.meshgrid(*np.array(list(map(np.arange, self.shape))) - np.asarray(pos))
spot = amplitude*np.exp(-((x/(1 - ecc))**2 + (y*(1 - ecc))**2)/(2*r**2)).T
self.image += np.clip(spot, 0, self._saturation).astype(self.dtype)
def save_frame(self, filename='frame.jpg'):
img = Image.fromarray(self.image.astype(np.uint8))
img.save(filename)
#class MakeImage(object):
# def blob(self,array):
#""" the values in brackets say the size of the background to be created. Use np.int so that the particle overlap does not cause regions of black spots """
frame = SimulatedFrame((1280, 1024), dtype=np.int)
frame2 = SimulatedFrame((1280, 1024), dtype=np.int)
frame3 = SimulatedFrame((1280, 1024), dtype=np.int)
coordinates=Particles()
xy=coordinates.randomloc()
nee=coordinates.displacement()
origin=640,512
new=coordinates.rotate(origin,angle=math.radians(5))
fname = "initial_image.jpg"
frame.save_frame(filename=fname)
fname1 = "translated_image.jpg"
frame2.save_frame(filename=fname1)
fname3 = "rotat ed_image.jpg"
frame3.save_frame(filename=fname3)
Right now , I create the new particles for each of the new frames ( Translated, rotated and so on ) , but I would like to manipulate the initial image .
thanks Arun
I used the following code and it works.