redistributing intensities of round particles upon rotation at subpixel level using python

146 views Asked by At

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

1

There are 1 answers

0
Arun Subraminion On

I used the following code and it works.

import cv2
import matplotlib.pyplot as plt
img = cv2.imread('1.jpg',0)
rows,cols = img.shape
M = cv2.getRotationMatrix2D((cols/2,rows/2),-40,1) # the format is cv2.getRotationMatrix2D(center, angle, scale) 
dst = cv2.warpAffine(img,M,(cols,rows),flags=cv2.INTER_CUBIC)
plt.imshow(dst)