def warp_images(self, imgs, center_coor, deg_per_pixel=0.1, is_luminance_correction=True):
        """
        warp a image stack into visual degree coordinate system

        parameters
        ----------
        imgs : ndarray
            should be 2d or 3d, if 3d, axis will be considered as frame x rows x width
        center_coor : list or tuple of two floats
            the visual degree coordinates of the center of the image (altitude, azimuth)
        deg_per_pixel : float or list/tuple of two floats
            size of original pixel in visual degrees, (altitude, azimuth), if float, assume
            sizes in both dimension are the same
        is_luminance_correction : bool
            if True, wrapped images will have mean intensity equal 0, and values will be
            scaled up to reach minimum equal -1. or maximum equal 1.

        returns
        -------
        imgs_wrapped : 3d array, np.float32
            wrapped images, each frame should have exact same size of down sampled monitor
            resolution. the region on the monitor not covered by the image will have value
            of np.nan. value range [-1., 1.]
        coord_alt_wrapped : 2d array, np.float32
            the altitude coordinates of all pixels in the wrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_wrapped'.
        coord_azi_wrapped : 2d array, np.float32
            the azimuth coordinates of all pixels in the wrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_wrapped'.
        imgs_dewrapped : 3d array, dtype same as imgs
            unwrapped images, same dimension as input image stack. the region of original
            image that was not got displayed (outside of the monitor) will have value of
            np.nan. value range [-1., 1.]
        coord_alt_dewrapped : 2d array, np.float32
            the altitude coordinates of all pixels in the dewrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_dewrapped'.
        coord_azi_dewrapped : 2d array, np.float32
            the azimuth coordinates of all pixels in the dewrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_dewrapped'.
        """

        try:
            deg_per_pixel_alt = abs(float(deg_per_pixel[0]))
            deg_per_pixel_azi = abs(float(deg_per_pixel[1]))
        except TypeError:
            deg_per_pixel_alt = deg_per_pixel_azi = deg_per_pixel

        if len(imgs.shape) == 2:
            imgs_raw = np.array([imgs])
        elif len(imgs.shape) == 3:
            imgs_raw = imgs
        else:
            raise ValueError('input "imgs" should be 2d or 3d array.')

        # generate raw image pixel coordinates in visual degrees
        alt_start = center_coor[0] + (imgs_raw.shape[1] / 2) * deg_per_pixel_alt
        alt_axis = alt_start - np.arange(imgs_raw.shape[1]) * deg_per_pixel_alt
        azi_start = center_coor[1] - (imgs_raw.shape[2] / 2) * deg_per_pixel_azi
        azi_axis = np.arange(imgs_raw.shape[2]) * deg_per_pixel_azi + azi_start
        # img_coord_azi, img_coord_alt = np.meshgrid(azi_axis, alt_axis)

        # initialize output array
        imgs_wrapped = np.zeros((imgs_raw.shape[0],
                                 self.deg_coord_x.shape[0],
                                 self.deg_coord_x.shape[1]), dtype=np.float32)
        imgs_wrapped[:] = np.nan

        # for cropping imgs_raw
        x_min = x_max = y_max = y_min = None

        # for testing
        # img_count = np.zeros((imgs_raw.shape[1], imgs_raw.shape[2]), dtype=np.uint32)

        # loop through every display (wrapped) pixel
        for ii in range(self.deg_coord_x.shape[0]):
            for jj in range(self.deg_coord_x.shape[1]):

                # the wrapped coordinate of current display pixel [alt, azi]
                coord_w = [self.deg_coord_y[ii, jj], self.deg_coord_x[ii, jj]]

                # if the wrapped coordinates of current display pixel is covered
                # by the raw image
                if alt_axis[0] >= coord_w[0] >= alt_axis[-1] and \
                                        azi_axis[0] <= coord_w[1] <= azi_axis[-1]:

                    # get raw pixels arround the wrapped coordinates of current display pixel
                    u = (alt_axis[0] - coord_w[0]) / deg_per_pixel_alt
                    l = (coord_w[1] - azi_axis[0]) / deg_per_pixel_azi

                    # for testing:
                    # img_count[int(u), int(l)] += 1

                    if (u == round(u) and l == round(l)):  # right hit on one raw pixel
                        imgs_wrapped[:, ii, jj] = imgs_raw[:, int(u), int(l)]

                        # for cropping
                        if x_min is None:
                            x_min = x_max = l
                            y_min = y_max = u
                        else:
                            x_min = min(x_min, l)
                            x_max = max(x_max, l)
                            y_min = min(y_min, u)
                            y_max = max(y_max, u)

                    else:
                        u = int(u)
                        b = u + 1
                        l = int(l)
                        r = l + 1
                        w_ul = 1. / ia.distance(coord_w, [alt_axis[u], azi_axis[l]])
                        w_bl = 1. / ia.distance(coord_w, [alt_axis[b], azi_axis[l]])
                        w_ur = 1. / ia.distance(coord_w, [alt_axis[u], azi_axis[r]])
                        w_br = 1. / ia.distance(coord_w, [alt_axis[b], azi_axis[r]])

                        w_sum = w_ul + w_bl + w_ur + w_br

                        imgs_wrapped[:, ii, jj] = (imgs_raw[:, u, l] * w_ul +
                                                   imgs_raw[:, b, l] * w_bl +
                                                   imgs_raw[:, u, r] * w_ur +
                                                   imgs_raw[:, b, r] * w_br) / w_sum

                        # for cropping
                        if x_min is None:
                            x_min = l
                            x_max = l + 1
                            y_min = u
                            y_max = u + 1
                        else:
                            x_min = min(x_min, l)
                            x_max = max(x_max, l + 1)
                            y_min = min(y_min, u)
                            y_max = max(y_max, u + 1)

        # for testing
        # plt.imshow(img_count, interpolation='bicubic')
        # plt.colorbar()
        # plt.show()

        if is_luminance_correction:
            for frame_ind in range(imgs_wrapped.shape[0]):
                curr_frame = imgs_wrapped[frame_ind]
                curr_mean = np.nanmean(curr_frame.flat)
                curr_frame = curr_frame - curr_mean
                curr_amp = np.max([np.nanmax(curr_frame.flat), abs(np.nanmin(curr_frame.flat))])
                curr_frame = curr_frame / curr_amp
                imgs_wrapped[frame_ind] = curr_frame

        # crop image
        alt_range = np.logical_and(np.arange(imgs_raw.shape[1]) >= y_min,
                                   np.arange(imgs_raw.shape[1]) <= y_max)
        azi_range = np.logical_and(np.arange(imgs_raw.shape[2]) >= x_min,
                                   np.arange(imgs_raw.shape[2]) <= x_max)

        # print imgs_raw.shape
        # print imgs_raw.shape
        # print alt_range.shape
        # print azi_range.shape
        # print np.sum(alt_range)
        # print np.sum(azi_range)

        imgs_dewrapped = imgs_raw[:, alt_range, :]
        imgs_dewrapped = imgs_dewrapped[:, :, azi_range]

        # get degree coordinats of dewrapped images
        deg_coord_alt_ax_dewrapped = alt_axis[alt_range]
        deg_coord_azi_ax_dewrapped = azi_axis[azi_range]
        deg_coord_azi_dewrapped, deg_coord_alt_dewrapped = np.meshgrid(deg_coord_azi_ax_dewrapped,
                                                                       deg_coord_alt_ax_dewrapped)
        deg_coord_alt_dewrapped = deg_coord_alt_dewrapped.astype(np.float32)
        deg_coord_azi_dewrapped = deg_coord_azi_dewrapped.astype(np.float32)

        return imgs_wrapped, self.deg_coord_y, self.deg_coord_x, imgs_dewrapped, deg_coord_alt_dewrapped, \
               deg_coord_azi_dewrapped
 def test_distance(self):
     assert (ia.distance(3., 4.) == 1.)
     assert (ia.distance([5., 8.], [9., 11.]) == 5.)
Exemplo n.º 3
0
    def warp_images(self, imgs, center_coor, deg_per_pixel=0.1, is_luminance_correction=True):
        """
        warp a image stack into visual degree coordinate system

        parameters
        ----------
        imgs : ndarray
            should be 2d or 3d, if 3d, axis will be considered as frame x rows x width
        center_coor : list or tuple of two floats
            the visual degree coordinates of the center of the image (altitude, azimuth)
        deg_per_pixel : float or list/tuple of two floats
            size of original pixel in visual degrees, (altitude, azimuth), if float, assume
            sizes in both dimension are the same
        is_luminance_correction : bool
            if True, wrapped images will have mean intensity equal 0, and values will be
            scaled up to reach minimum equal -1. or maximum equal 1.

        returns
        -------
        imgs_wrapped : 3d array, np.float32
            wrapped images, each frame should have exact same size of down sampled monitor
            resolution. the region on the monitor not covered by the image will have value
            of np.nan. value range [-1., 1.]
        coord_alt_wrapped : 2d array, np.float32
            the altitude coordinates of all pixels in the wrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_wrapped'.
        coord_azi_wrapped : 2d array, np.float32
            the azimuth coordinates of all pixels in the wrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_wrapped'.
        imgs_dewrapped : 3d array, dtype same as imgs
            unwrapped images, same dimension as input image stack. the region of original
            image that was not got displayed (outside of the monitor) will have value of
            np.nan. value range [-1., 1.]
        coord_alt_dewrapped : 2d array, np.float32
            the altitude coordinates of all pixels in the dewrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_dewrapped'.
        coord_azi_dewrapped : 2d array, np.float32
            the azimuth coordinates of all pixels in the dewrapped images in visual degrees.
            should have the same shape as each frame in 'imgs_dewrapped'.
        """

        try:
            deg_per_pixel_alt = abs(float(deg_per_pixel[0]))
            deg_per_pixel_azi = abs(float(deg_per_pixel[1]))
        except TypeError:
            deg_per_pixel_alt = deg_per_pixel_azi = deg_per_pixel

        if len(imgs.shape) == 2:
            imgs_raw = np.array([imgs])
        elif len(imgs.shape) == 3:
            imgs_raw = imgs
        else:
            raise ValueError('input "imgs" should be 2d or 3d array.')

        # generate raw image pixel coordinates in visual degrees
        alt_start = center_coor[0] + (imgs_raw.shape[1] / 2) * deg_per_pixel_alt
        alt_axis = alt_start - np.arange(imgs_raw.shape[1]) * deg_per_pixel_alt
        azi_start = center_coor[1] - (imgs_raw.shape[2] / 2) * deg_per_pixel_azi
        azi_axis = np.arange(imgs_raw.shape[2]) * deg_per_pixel_azi + azi_start
        # img_coord_azi, img_coord_alt = np.meshgrid(azi_axis, alt_axis)

        # initialize output array
        imgs_wrapped = np.zeros((imgs_raw.shape[0],
                                 self.deg_coord_x.shape[0],
                                 self.deg_coord_x.shape[1]), dtype=np.float32)
        imgs_wrapped[:] = np.nan

        # for cropping imgs_raw
        x_min = None;
        x_max = None;
        y_min = None;
        y_max = None

        # for testing
        # img_count = np.zeros((imgs_raw.shape[1], imgs_raw.shape[2]), dtype=np.uint32)

        # loop through every display (wrapped) pixel
        for ii in range(self.deg_coord_x.shape[0]):
            for jj in range(self.deg_coord_x.shape[1]):

                # the wrapped coordinate of current display pixel [alt, azi]
                coord_w = [self.deg_coord_y[ii, jj], self.deg_coord_x[ii, jj]]

                # if the wrapped coordinates of current display pixel is covered
                # by the raw image
                if alt_axis[0] >= coord_w[0] >= alt_axis[-1] and \
                                        azi_axis[0] <= coord_w[1] <= azi_axis[-1]:

                    # get raw pixels arround the wrapped coordinates of current display pixel
                    u = (alt_axis[0] - coord_w[0]) / deg_per_pixel_alt
                    l = (coord_w[1] - azi_axis[0]) / deg_per_pixel_azi

                    # for testing:
                    # img_count[int(u), int(l)] += 1

                    if (u == round(u) and l == round(l)):  # right hit on one raw pixel
                        imgs_wrapped[:, ii, jj] = imgs_raw[:, int(u), int(l)]

                        # for cropping
                        if x_min is None:
                            x_min = x_max = l
                            y_min = y_max = u
                        else:
                            x_min = min(x_min, l)
                            x_max = max(x_max, l)
                            y_min = min(y_min, u)
                            y_max = max(y_max, u)

                    else:
                        u = int(u);
                        b = u + 1;
                        l = int(l);
                        r = l + 1
                        w_ul = 1. / ia.distance(coord_w, [alt_axis[u], azi_axis[l]])
                        w_bl = 1. / ia.distance(coord_w, [alt_axis[b], azi_axis[l]])
                        w_ur = 1. / ia.distance(coord_w, [alt_axis[u], azi_axis[r]])
                        w_br = 1. / ia.distance(coord_w, [alt_axis[b], azi_axis[r]])

                        w_sum = w_ul + w_bl + w_ur + w_br

                        imgs_wrapped[:, ii, jj] = (imgs_raw[:, u, l] * w_ul +
                                                   imgs_raw[:, b, l] * w_bl +
                                                   imgs_raw[:, u, r] * w_ur +
                                                   imgs_raw[:, b, r] * w_br) / w_sum

                        # for cropping
                        if x_min is None:
                            x_min = l;
                            x_max = l + 1;
                            y_min = u;
                            y_max = u + 1
                        else:
                            x_min = min(x_min, l);
                            x_max = max(x_max, l + 1)
                            y_min = min(y_min, u);
                            y_max = max(y_max, u + 1)

        # for testing
        # plt.imshow(img_count, interpolation='bicubic')
        # plt.colorbar()
        # plt.show()

        if is_luminance_correction:
            for frame_ind in range(imgs_wrapped.shape[0]):
                curr_frame = imgs_wrapped[frame_ind]
                curr_mean = np.nanmean(curr_frame.flat)
                curr_frame = curr_frame - curr_mean
                curr_amp = np.max([np.nanmax(curr_frame.flat), abs(np.nanmin(curr_frame.flat))])
                curr_frame = curr_frame / curr_amp
                imgs_wrapped[frame_ind] = curr_frame

        # crop image
        alt_range = np.logical_and(np.arange(imgs_raw.shape[1]) >= y_min,
                                   np.arange(imgs_raw.shape[1]) <= y_max)
        azi_range = np.logical_and(np.arange(imgs_raw.shape[2]) >= x_min,
                                   np.arange(imgs_raw.shape[2]) <= x_max)

        # print imgs_raw.shape
        # print imgs_raw.shape
        # print alt_range.shape
        # print azi_range.shape
        # print np.sum(alt_range)
        # print np.sum(azi_range)

        imgs_dewrapped = imgs_raw[:, alt_range, :]
        imgs_dewrapped = imgs_dewrapped[:, :, azi_range]

        # get degree coordinats of dewrapped images
        deg_coord_alt_ax_dewrapped = alt_axis[alt_range]
        deg_coord_azi_ax_dewrapped = azi_axis[azi_range]
        deg_coord_azi_dewrapped, deg_coord_alt_dewrapped = np.meshgrid(deg_coord_azi_ax_dewrapped,
                                                                       deg_coord_alt_ax_dewrapped)
        deg_coord_alt_dewrapped = deg_coord_alt_dewrapped.astype(np.float32)
        deg_coord_azi_dewrapped = deg_coord_azi_dewrapped.astype(np.float32)

        return imgs_wrapped, self.deg_coord_y, self.deg_coord_x, imgs_dewrapped, deg_coord_alt_dewrapped, \
               deg_coord_azi_dewrapped