Ejemplo n.º 1
0
    def reset(self):
        """
        Reset state variables. Necesary after changing or setting the filter or zero padding.
        """
        self.num_frames = 0
        self.nbin = self.nfft // 2 + 1
        self.freq = np.linspace(0,self.fs/2,self.nbin)

        if self.D==1:
            self.fft_in_buffer[:] = 0.
            self.X[:] = 0.
            self.y_p[:] = 0.
        else:
            self.fft_in_buffer[:,:] = 0.
            self.X[:,:] = 0.
            self.y_p[:,:] = 0.

        self.dft = DFT(nfft=self.nfft,fs=self.fs,num_sig=self.D,
            analysis_window=self.analysis_window,
            synthesis_window=self.synthesis_window,
            transform=self.transform)
Ejemplo n.º 2
0
    def computeFFT(self, imge):
        """Computes the FFT of a given image.
        """

        #Compute size of the given image
        N = imge.shape[0]

        #Compute the FFT for the base case (which uses the normal DFT)
        if N == 2:
            return DFT.computeForward2DDFTNoSeparability(imge)

        #Otherwise compute FFT recursively

        #Divide the original image into even and odd
        imgeEE = np.array([[imge[i, j] for i in xrange(0, N, 2)]
                           for j in xrange(0, N, 2)]).T
        imgeEO = np.array([[imge[i, j] for i in xrange(0, N, 2)]
                           for j in xrange(1, N, 2)]).T
        imgeOE = np.array([[imge[i, j] for i in xrange(1, N, 2)]
                           for j in xrange(0, N, 2)]).T
        imgeOO = np.array([[imge[i, j] for i in xrange(1, N, 2)]
                           for j in xrange(1, N, 2)]).T

        #Compute FFT for each of the above divided images
        FeeUV = FFT.computeFFT(imgeEE)
        FeoUV = FFT.computeFFT(imgeEO)
        FoeUV = FFT.computeFFT(imgeOE)
        FooUV = FFT.computeFFT(imgeOO)

        #Compute also Ws
        Wu = FFT.__computeW(N / 2, N)
        Wv = Wu.T  #Transpose
        Wuv = FFT.__computeW(N / 2, N, oneD=False)

        #Compute F(u,v) for u,v = 0,1,2,...,N/2
        imgeFuv = 0.25 * (FeeUV + (FeoUV * Wv) + (FoeUV * Wu) + (FooUV * Wuv))

        #Compute F(u, v+M) where M = N/2
        imgeFuMv = 0.25 * (FeeUV + (FeoUV * Wv) - (FoeUV * Wu) - (FooUV * Wuv))

        #Compute F(u+M, v) where M = N/2
        imgeFuvM = 0.25 * (FeeUV - (FeoUV * Wv) + (FoeUV * Wu) - (FooUV * Wuv))

        #Compute F(u+M, v+M) where M = N/2
        imgeFuMvM = 0.25 * (FeeUV - (FeoUV * Wv) - (FoeUV * Wu) +
                            (FooUV * Wuv))

        imgeF1 = np.hstack((imgeFuv, imgeFuvM))
        imgeF2 = np.hstack((imgeFuMv, imgeFuMvM))
        imgeFFT = np.vstack((imgeF1, imgeF2))

        return imgeFFT
Ejemplo n.º 3
0
def compress_image(im_fft, compression_level, originalCount):
    if compression_level < 0 or compression_level > 100:
        AssertionError('compression_level must be between 0 to 100')

    rest = 100 - compression_level
    lower = np.percentile(im_fft, rest // 2)
    upper = np.percentile(im_fft, 100 - rest // 2)
    print('non zero values for level {}% are {} out of {}'.format(
        compression_level,
        int(originalCount * ((100 - compression_level) / 100.0)),
        originalCount))

    compressed_im_fft = im_fft * \
        np.logical_or(im_fft <= lower, im_fft >= upper)
    save_npz('coefficients-{}-compression.csr'.format(compression_level),
             csr_matrix(compressed_im_fft))

    return DFT.fast_two_dimension_inverse(compressed_im_fft)
Ejemplo n.º 4
0
    def __init__(self, N, fs, hop=None, analysis_window=None, 
        synthesis_window=None, channels=1, transform='numpy'):
        """
        Constructor for STFT class.
        Parameters
        -----------
        N : int
            number of samples per frame
        fs : float
            Sampling frequency.
        hop : int
            hop size
        wA : numpy array
            analysis window
        wS : numpy array
            synthesis window
        channels : int
            number of signals
        """
        # initialize parameters
        self.N = N          # number of samples per frame
        self.fs = fs
        self.D = channels         # number of channels
        if hop is not None: # hop size
            self.hop = hop  
        else:
            self.hop = self.N/2
        self.hop = int(np.floor(self.hop))

        # analysis window
        if analysis_window is not None:
            self.analysis_window = analysis_window
        elif analysis_window is None and self.hop ==self.N/2:
            self.analysis_window = windows.hann(self.N)
        else:
            self.analysis_window = None
        # synthesis window
        if synthesis_window is not None:  
            self.synthesis_window = synthesis_window
        elif synthesis_window is None and self.hop ==self.N/2:
            self.synthesis_window = None # rectangular window
        else:
            self.synthesis_window = None

        # create DFT object
        self.transform = transform
        self.nfft = self.N
        self.nbin = self.nfft // 2 + 1
        self.freq = np.linspace(0,self.fs/2,self.nbin)
        self.dft = DFT(nfft=self.nfft,fs=self.fs,num_sig=self.D,
                analysis_window=self.analysis_window,
                synthesis_window=self.synthesis_window,
                transform=self.transform)

        self.fft_out_buffer = np.zeros(self.nbin, dtype=np.complex64)

        # initialize filter + zero padding --> use set_filter
        self.zf = 0; self.zb = 0
        self.H = None       # filter frequency spectrum

        # state variables
        self.num_frames = 0            # number of frames processed so far
        self.n_state = self.N - self.hop

        # allocate all the required buffers
        self.make_buffers()
Ejemplo n.º 5
0
class STFT:
    """
    Methods
    --------
    analysis(x_n)
        Perform STFT on most recent samples.
    process(h)
        Perform filtering in frequency domain.
    synthesis()
        Transform to time domain and use overlap-and-add to reconstruct the 
        output.
    set_filter(h, zb, zf)
        Set time-domain filter with appropriate zero-padding.
    get_prev_samples()
        Get previous reconstructed samples.
    zero_pad_front(zf)
        Set zero-padding at beginning of frame.
    zero_pad_back(zb)
        Set zero-padding at end of frame.
    reset()
        Reset state variables. Necessary after changing or setting the filter.
    visualize_frame(fmin=None,fmax=None,plot_time=False)
        Visualize frequency spectrum of current frame.
    spectogram(x, fmin=None,fmax=None,tmin=None,tmax=None,plot_time=False)
        Plot spectrogram according to object's parameters and given signal.
    """
    def __init__(self, N, fs, hop=None, analysis_window=None, 
        synthesis_window=None, channels=1, transform='numpy'):
        """
        Constructor for STFT class.
        Parameters
        -----------
        N : int
            number of samples per frame
        fs : float
            Sampling frequency.
        hop : int
            hop size
        wA : numpy array
            analysis window
        wS : numpy array
            synthesis window
        channels : int
            number of signals
        """
        # initialize parameters
        self.N = N          # number of samples per frame
        self.fs = fs
        self.D = channels         # number of channels
        if hop is not None: # hop size
            self.hop = hop  
        else:
            self.hop = self.N/2
        self.hop = int(np.floor(self.hop))

        # analysis window
        if analysis_window is not None:
            self.analysis_window = analysis_window
        elif analysis_window is None and self.hop ==self.N/2:
            self.analysis_window = windows.hann(self.N)
        else:
            self.analysis_window = None
        # synthesis window
        if synthesis_window is not None:  
            self.synthesis_window = synthesis_window
        elif synthesis_window is None and self.hop ==self.N/2:
            self.synthesis_window = None # rectangular window
        else:
            self.synthesis_window = None

        # create DFT object
        self.transform = transform
        self.nfft = self.N
        self.nbin = self.nfft // 2 + 1
        self.freq = np.linspace(0,self.fs/2,self.nbin)
        self.dft = DFT(nfft=self.nfft,fs=self.fs,num_sig=self.D,
                analysis_window=self.analysis_window,
                synthesis_window=self.synthesis_window,
                transform=self.transform)

        self.fft_out_buffer = np.zeros(self.nbin, dtype=np.complex64)

        # initialize filter + zero padding --> use set_filter
        self.zf = 0; self.zb = 0
        self.H = None       # filter frequency spectrum

        # state variables
        self.num_frames = 0            # number of frames processed so far
        self.n_state = self.N - self.hop

        # allocate all the required buffers
        self.make_buffers()

    # def make_buffers(self):

    #     # The input buffer, float32 for speed!
    #     self.fft_in_buffer = np.zeros((self.nfft, self.D), dtype=np.float32)
    #     #  a number of useful views on the input buffer
    #     self.x_p = self.fft_in_buffer[self.zf:self.zf+self.n_state,:]  # State buffer
    #     self.fresh_samples = self.fft_in_buffer[self.zf+self.n_state:self.zf+self.n_state+self.hop,:]
    #     self.old_samples = self.fft_in_buffer[self.zf+self.hop:self.zf+self.hop+self.n_state,:]

    #     self.y_p = np.zeros((self.zb, self.D), dtype=np.float32).squeeze()  # prev reconstructed samples
    #     self.X = np.zeros((self.nbin, self.D), dtype=np.complex64)       # current frame in STFT domain

    def make_buffers(self):

        if self.D==1:  # need this distinction for fftw

            # The input buffer, float32 for speed!
            self.fft_in_buffer = np.zeros(self.nfft, dtype=np.float32)
            #  a number of useful views on the input buffer
            self.x_p = self.fft_in_buffer[self.zf:self.zf+self.n_state]  # State buffer
            self.fresh_samples = self.fft_in_buffer[self.zf+self.n_state:self.zf+self.n_state+self.hop]
            self.old_samples = self.fft_in_buffer[self.zf+self.hop:self.zf+self.hop+self.n_state]

            self.y_p = np.zeros(self.zb, dtype=np.float32)  # prev reconstructed samples
            self.X = np.zeros(self.nbin, dtype=np.complex64)       # current frame in STFT domain
            self.out = np.zeros(self.hop, dtype=np.float32)

        else:

            # The input buffer, float32 for speed!
            self.fft_in_buffer = np.zeros((self.nfft, self.D), dtype=np.float32)
            #  a number of useful views on the input buffer
            self.x_p = self.fft_in_buffer[self.zf:self.zf+self.n_state,:]  # State buffer
            self.fresh_samples = self.fft_in_buffer[self.zf+self.n_state:self.zf+self.n_state+self.hop,:]
            self.old_samples = self.fft_in_buffer[self.zf+self.hop:self.zf+self.hop+self.n_state,:]

            self.y_p = np.zeros((self.zb, self.D), dtype=np.float32)  # prev reconstructed samples
            self.X = np.zeros((self.nbin, self.D), dtype=np.complex64)       # current frame in STFT domain
            self.out = np.zeros((self.hop,self.D), dtype=np.float32)


    def reset(self):
        """
        Reset state variables. Necesary after changing or setting the filter or zero padding.
        """
        self.num_frames = 0
        self.nbin = self.nfft // 2 + 1
        self.freq = np.linspace(0,self.fs/2,self.nbin)

        if self.D==1:
            self.fft_in_buffer[:] = 0.
            self.X[:] = 0.
            self.y_p[:] = 0.
        else:
            self.fft_in_buffer[:,:] = 0.
            self.X[:,:] = 0.
            self.y_p[:,:] = 0.

        self.dft = DFT(nfft=self.nfft,fs=self.fs,num_sig=self.D,
            analysis_window=self.analysis_window,
            synthesis_window=self.synthesis_window,
            transform=self.transform)

    def zero_pad_front(self, zf):
        """
        Set zero-padding at beginning of frame.
        """
        self.zf = zf
        self.nfft = self.N+self.zb+self.zf
        if self.analysis_window is not None:
            self.analysis_window = np.concatenate((np.zeros(zf), self.analysis_window))
        if self.synthesis_window is not None:
            self.synthesis_window = np.concatenate((np.zeros(zf), self.synthesis_window))

    def zero_pad_back(self, zb):
        """
        Set zero-padding at end of frame.
        """
        self.zb = zb
        self.nfft = self.N+self.zb+self.zf
        if self.analysis_window is not None:
            self.analysis_window = np.concatenate((self.analysis_window, np.zeros(zb)))
        if self.synthesis_window is not None:
            self.synthesis_window = np.concatenate((self.synthesis_window, np.zeros(zb)))

    def set_filter(self, coeff, zb=None, zf=None, freq=False):
        """
        Set time-domain filter with appropriate zero-padding.
        Frequency spectrum of the filter is computed and set for the object. 
        There is also a check for sufficient zero-padding.
        Parameters
        -----------
        coeff : numpy array 
            Filter in time domain.
        zb : int
            Amount of zero-padding added to back/end of frame.
        zf : int
            Amount of zero-padding added to front/beginning of frame.
        """
        # apply zero-padding
        if zb is not None:
            self.zero_pad_back(zb)
        if zf is not None:
            self.zero_pad_front(zf)  
        self.reset()      
        if not freq:
            # compute filter magnitude and phase spectrum
            self.H = np.complex64(np.fft.rfft(coeff, self.nfft, axis=0))
            # check for sufficient zero-padding
            if self.nfft < (self.N+len(coeff)-1):
                raise ValueError('Insufficient zero-padding for chosen number of samples per frame (L) and filter length (h). Require zero-padding such that new length is at least (L+h-1).')
        else:
            if len(coeff)!=self.nbin:
                raise ValueError('Invalid length for frequency domain coefficients.')
            self.H = coeff

        # We need to reallocate buffers after changing zero padding
        self.make_buffers()


    def analysis(self, x_n):
        """
        Transform new samples to STFT domain for analysis.
        Parameters
        -----------
        x_n : numpy array
            [self.hop] new samples.
        Returns
        -----------
        self.X : numpy array 
            Frequency spectrum of given frame.
        """

        # check for valid input - already done by self.dft
        # if x_n.shape[0]!=self.hop:
        #     raise ValueError('Invalid input dimensions.')
        # if self.D > 1 and x_n.shape[1]!=self.D:
        #     raise ValueError('Invalid input dimensions.')

        if x_n.ndim == 1:
            self.fresh_samples[:] = x_n[:]
        else:
            self.fresh_samples[:,:] = x_n[:,:]

        # apply DFT to current frame
        self.X[:] = self.dft.analysis(self.fft_in_buffer)
        self.x_p[:] = self.old_samples

        # self.num_frames += 1

    def process(self):
        """
        Apply filtering in STFT domain.
        Returns
        -----------
        self.X : numpy array 
            Frequency spectrum of given frame.
        """
        if self.H is None:
            warnings.warn("No filter given to the STFT object.")
        else:
            np.multiply(self.X, self.H, self.X)


    def synthesis(self):
        """
        Transform to time domain and reconstruct output with overlap-and-add.
        Returns
        -----------
        out: numpy array
            Reconstructed array of samples of length [self.hop]
        """
        # apply IDFT to current frame
        self.dft.synthesis(self.X)

        # reconstruct output
        if self.D==1:
            self.out[:] = self.dft.x[0:self.hop]

            if self.zb > 0:
                self.out[:self.zb] += self.y_p
                # update state variables
                self.y_p[:] = self.dft.x[-self.zb:]
        else:
            self.out = self.dft.x[0:self.hop,:]

            if self.zb > 0:
                self.out[:self.zb,:] += self.y_p[:,:]
                # update state variables
                self.y_p[:,:] = self.dft.x[-self.zb:,:]

        return self.out


    def get_prev_samples(self):
        """
        Get reconstructed previous samples.
        """
        return self.y_p
Ejemplo n.º 6
0
CIRCLES_NUM = int(input("How many circles?"))
IMAGE_DIRECTOR = f'D:\\'
GIFS_DIR = f'D:\\'
GIF_FPS = 50
order = CIRCLES_NUM // 2

for image in os.listdir(IMAGE_DIRECTOR):
    IMAGE_DIR = os.path.join(IMAGE_DIRECTOR, image)
    GIF_DIR = GIFS_DIR + "\\" + os.path.splitext(image)[0] + ".gif"
    imageData = Data(IMAGE_DIR)
    imageData.center()
    imageData.dataFigure()

    expSeries = ExponentSeries(imageData, order)
    DFT(imageData, expSeries)

    # imageData.plotData()
    # imageData.plotDFT()
    # imageData.plotDifferenceDFT()

    visual = Visualizer(imageData.getXTableDFT(),
                        imageData.getYTableDFT(),
                        expSeries.getExpCoef(), order,
                        imageData.getGrid(),
                        imageData.getFigLim())

    anim = visual.visualize()
    # visual.plotAnimation()
    anim.save(GIF_DIR, writer=LoopingPillowWriter(fps=GIF_FPS))
Ejemplo n.º 7
0
def __main__():
    results = None
    try:
        results = parseArgs()
    except BaseException as e:
        print(
            "ERROR\tIncorrect input syntax: Please check arguments and try again"
        )
        return

    mode = results.mode
    image = results.image

    # run tests
    DFT.test()

    if mode == 1:
        # read the image
        im_raw = plt.imread(image).astype(float)

        # pad the image to desired size
        old_shape = im_raw.shape
        new_shape = desiredSize(old_shape[0]), desiredSize(old_shape[1])
        im = np.zeros(new_shape)
        im[:old_shape[0], :old_shape[1]] = im_raw

        # perform fft 2d
        fft_im = DFT.fast_two_dimension(im)

        # display
        fig, ax = plt.subplots(1, 2)
        ax[0].imshow(im[:old_shape[0], :old_shape[1]], plt.cm.gray)
        ax[0].set_title('original')
        ax[1].imshow(np.abs(fft_im), norm=colors.LogNorm())
        ax[1].set_title('fft 2d with lognorm')
        fig.suptitle('Mode 1')
        plt.show()

    elif mode == 2:
        # define a percentage keep fraction
        keep_ratio = 0.08

        # read the image
        im_raw = plt.imread(image).astype(float)

        # pad the image to desired size
        old_shape = im_raw.shape
        new_shape = desiredSize(old_shape[0]), desiredSize(old_shape[1])
        im = np.zeros(new_shape)
        im[:old_shape[0], :old_shape[1]] = im_raw

        # perform fft 2d and remove high frequency values
        fft_im = DFT.fast_two_dimension(im)
        rows, columns = fft_im.shape
        print(
            "Fraction of pixels used {} and the number is ({}, {}) out of ({}, {})"
            .format(keep_ratio, int(keep_ratio * rows),
                    int(keep_ratio * columns), rows, columns))

        fft_im[int(rows * keep_ratio):int(rows * (1 - keep_ratio))] = 0
        fft_im[:,
               int(columns * keep_ratio):int(columns * (1 - keep_ratio))] = 0

        # perform ifft 2d to denoise the image
        denoised = DFT.fast_two_dimension_inverse(fft_im).real

        # display
        fig, ax = plt.subplots(1, 2)
        ax[0].imshow(im[:old_shape[0], :old_shape[1]], plt.cm.gray)
        ax[0].set_title('original')
        ax[1].imshow(denoised[:old_shape[0], :old_shape[1]], plt.cm.gray)
        ax[1].set_title('denoised')
        fig.suptitle('Mode 2')
        plt.show()
    elif mode == 3:
        # read the image
        im_raw = plt.imread(image).astype(float)

        # pad the image to desired size
        old_shape = im_raw.shape
        new_shape = desiredSize(old_shape[0]), desiredSize(old_shape[1])
        im = np.zeros(new_shape)
        im[:old_shape[0], :old_shape[1]] = im_raw
        originalCount = old_shape[0] * old_shape[1]

        # define compression levels
        compression = [0, 14, 30, 50, 70, 95]

        # write down abs of fft
        im_fft = DFT.fast_two_dimension(im)

        # render
        fig, ax = plt.subplots(2, 3)
        for i in range(2):
            for j in range(3):
                compression_level = compression[i * 3 + j]
                im_compressed = compress_image(im_fft, compression_level,
                                               originalCount)
                ax[i, j].imshow(
                    np.real(im_compressed)[:old_shape[0], :old_shape[1]],
                    plt.cm.gray)
                ax[i, j].set_title('{}% compression'.format(compression_level))

        fig.suptitle('Mode 3')
        plt.show()
    elif mode == 4:
        # define sample runs
        runs = 10

        # run plots
        fig, ax = plt.subplots()

        ax.set_xlabel('problem size')
        ax.set_ylabel('runtime in seconds')
        ax.set_title('Line plot with error bars')

        for algo_index, algo in enumerate(
            [DFT.slow_two_dimension, DFT.fast_two_dimension]):
            print("starting measurement for {}".format(algo.__name__))
            x = []
            y = []

            problem_size = 2**4
            while problem_size <= 2**12:
                print("doing problem size of {}".format(problem_size))
                a = np.random.rand(int(math.sqrt(problem_size)),
                                   int(math.sqrt(problem_size)))
                x.append(problem_size)

                stats_data = []
                for i in range(runs):
                    print("run {} ...".format(i + 1))
                    start_time = time.time()
                    algo(a)
                    delta = time.time() - start_time
                    stats_data.append(delta)

                mean = statistics.mean(stats_data)
                sd = statistics.stdev(stats_data)

                print("for problem size of {} over {} runs: mean {}, stdev {}".
                      format(problem_size, runs, mean, sd))

                y.append(mean)

                # ensure square and power of 2 problems sizes
                problem_size *= 4

            color = 'r--' if algo_index == 0 else 'g'
            plt.errorbar(x, y, yerr=sd, fmt=color)
        plt.show()
    else:
        print("ERROR\tMode {} is not recofgnized".format(mode))
        return