def plot(self):
        seq = self.getData('input')['seq']
        fig = plt.figure(figsize=(7, 10))
        f11, f12, f13 = fig.add_subplot(611), fig.add_subplot(
            612), fig.add_subplot(613)
        f2 = [fig.add_subplot(614), fig.add_subplot(615), fig.add_subplot(616)]
        t0, time_range = 0, [0, np.inf]
        for iB in range(1, len(seq.block_events)):
            block = seq.get_block(iB)
            is_valid = time_range[0] <= t0 <= time_range[1]
            if is_valid:
                if block is not None:
                    if 'adc' in block:
                        adc = block['adc']
                        t = adc.delay + [
                            (x * adc.dwell)
                            for x in range(0, int(adc.num_samples))
                        ]
                        f11.plot((t0 + t), np.zeros(len(t)))
                    if 'rf' in block:
                        rf = block['rf']
                        t = rf.t
                        f12.plot(np.squeeze(t0 + t), abs(rf.signal))
                        f13.plot(np.squeeze(t0 + t), np.angle(rf.signal))
                    grad_channels = ['gx', 'gy', 'gz']
                    for x in range(0, len(grad_channels)):
                        if grad_channels[x] in block:
                            grad = block[grad_channels[x]]
                            if grad.type == 'grad':
                                t = grad.t
                                waveform = 1e-3 * grad.waveform
                            else:
                                t = np.cumsum([
                                    0, grad.rise_time, grad.flat_time,
                                    grad.fall_time
                                ])
                                waveform = [
                                    1e-3 * grad.amplitude * x
                                    for x in [0, 1, 1, 0]
                                ]
                            f2[x].plot(np.squeeze(t0 + t), waveform)
            t0 += core.calcduration.calcduration(block)

        f11.set_ylabel('adc')
        f12.set_ylabel('rf mag hz')
        f13.set_ylabel('rf phase rad')
        [f2[x].set_ylabel(grad_channels[x]) for x in range(3)]

        # Save the plot temporarily as a PNG file to be displayed by the DisplayBox Widget
        plt.savefig('plot_temp.png')
        img = QtGui.QImage()
        img.load('plot_temp.png')
        self.setAttr('Sequence Plot', val=img)
        os.remove('plot_temp.png')
Beispiel #2
0
    def compute(self):

        import numpy as np
        edgeval = self.getVal('edge')

        # make a copy for changes
        if self.getVal('LeftRight'):
            outright = self.getData('inleft')
            outleft = self.getData('inright')
        else:
            outleft = self.getData('inleft')
            outright = self.getData('inright')

        if self.getVal('Transition') == 0:  # Toggle
            out = outleft
        elif self.getVal('Transition') == 1:  # Fade
            cr = 0.01 * float(self.getVal('edge'))
            cl = 1. - cr
            out = cl * outleft.astype(np.float) + cr * outright.astype(
                np.float)
        elif self.getVal('Transition') == 2:  # Horizontal
            out = np.append(outleft[:edgeval, :, :],
                            outright[edgeval:, :, :],
                            axis=0)
        elif self.getVal('Transition') == 3:  # Vertical
            out = np.append(outleft[:, :edgeval, :],
                            outright[:, edgeval:, :],
                            axis=1)
        elif self.getVal('Transition') == 4:  # Color
            out = np.copy(outleft)
            if self.getVal('edge') <= 1 or self.getVal('edge') == 5:
                out[:, :, 2] = outright[:, :, 2]  # Red
            if self.getVal('edge') >= 1 and self.getVal('edge') <= 3:
                out[:, :, 1] = outright[:, :, 1]  # Green
            if self.getVal('edge') >= 3:
                out[:, :, 0] = outright[:, :, 0]  # Blue

        image1 = out.astype(np.uint8)

        h, w = out.shape[:2]
        format_ = QtGui.QImage.Format_RGB32

        image = QtGui.QImage(image1.data, w, h, format_)
        image.ndarray = image1
        if image.isNull():
            self.log.warn("Image Viewer: cannot load image")

        self.setAttr('Viewport:', val=image)
        self.setData('out', image1)

        return 0
Beispiel #3
0
    def about(self):
        # Display
        image = QtGui.QImage(LOGO_PATH)
        dispbox = DisplayBox('')
        dispbox.set_pixmap(QtGui.QPixmap.fromImage(image))
        dispbox.set_scale(0.157)
        dispbox.set_interp(True)

        # Text
        tab = '&nbsp;&nbsp;&nbsp;&nbsp;'
        txt = '<center><font size=4><b>Graphical Programming Interface (GPI)</b></font><br><b><a href=http://gpilab.com>gpilab.com</a></b><br><br>' +\
              'Nicholas Zwart<br>Barrow Neurological Institute<br>Phoenix, Arizona' +\
              '<br><br>' +\
              tab + 'Release: '+ str(VERSION) + ' (' + str(RELEASE_DATE) +')' +\
              '<p>'+\
              'GPI is a graphical development environment designed for rapid prototyping '+\
              'of numeric algorithms.'+\
              '</p>'+\
              '<p>'+\
              'GPI development is sponsored by Philips Healthcare.'+\
              '</p></center>'
        txtbox = TextBox('')
        txtbox.set_val(txt)
        txtbox.set_wordwrap(True)
        txtbox.set_openExternalLinks(True)

        # set layout
        wdgvbox = QtGui.QVBoxLayout()
        wdgvbox.addWidget(dispbox)
        wdgvbox.addWidget(txtbox)
        wdgvbox.setStretch(0, 2)

        # set master widget
        self.aboutWdg = QtGui.QWidget()
        self.aboutWdg.setLayout(wdgvbox)
        # self.aboutWdg.setSizePolicy(QtGui.QSizePolicy.Minimum, \
        #   QtGui.QSizePolicy.Preferred)
        # self.aboutWdg.setMaximumWidth(420)
        self.aboutWdg.show()
        self.aboutWdg.raise_()
        log.debug(str(dispbox.sizeHint()))
Beispiel #4
0
    def compute(self):

        from matplotlib import cm

        # make a copy for changes
        data = self.getData('in').copy()

        # get extra dimension parameters and modify data
        dimfunc = self.getVal('Extra Dimension')
        dimval = self.getVal('Slice/Tile Dimension')
        if data.ndim == 3 and dimfunc < 2:
            if dimfunc == 0:  # slice data
                slval = self.getVal('Slice') - 1
                if dimval == 0:
                    data = data[slval, ...]
                elif dimval == 1:
                    data = data[:, slval, :]
                else:
                    data = data[..., slval]
            else:  # tile data
                ncol = self.getVal('# Columns')
                nrow = self.getVal('# Rows')

                # add some blank tiles
                data = np.rollaxis(data, dimval)
                N, xres, yres = data.shape
                N_new = ncol * nrow
                pad_vals = ((0, N_new - N), (0, 0), (0, 0))
                data = np.pad(data, pad_vals, mode='constant')

                # from http://stackoverflow.com/a/13990648/333308
                data = np.reshape(data, (nrow, ncol, xres, yres))
                data = np.swapaxes(data, 1, 2)
                data = np.reshape(data, (nrow * xres, ncol * yres))

        # Read in parameters, make a little floor:ceiling adjustment
        gamma = self.getVal('Gamma')
        lval = self.getAttr('L W F C:', 'val')
        cval = self.getVal('Complex Display')

        if 'Complex Display' in self.widgetEvents():
            if cval == 4:
                self.setAttr('Color Map',
                             buttons=self.complex_cmaps,
                             collapsed=self.getAttr('Color Map', 'collapsed'),
                             val=0)
            # elif self.getAttr('Color Map', 'buttons') != self.real_cmaps:
            # there is no "get_buttons" method, so for now this will reset the
            # colormap whenever "Complex Display" is changed
            # this could/will be added in a future framework update
            else:
                self.setAttr('Color Map',
                             buttons=self.real_cmaps,
                             collapsed=self.getAttr('Color Map', 'collapsed'),
                             val=0)

        cmap = self.getVal('Color Map')
        sval = self.getVal('Scalar Display')
        zval = self.getVal('Zero Ref')
        fval = self.getVal('Fix Range')
        rmin = self.getVal('Range Min')
        rmax = self.getVal('Range Max')

        flor = 0.01 * lval['floor']
        ceil = 0.01 * lval['ceiling']
        if ceil == flor:
            if ceil == 1.:
                flor = 0.999
            else:
                ceil += 0.001

        # SHOW COMPLEX DATA
        if np.iscomplexobj(data) and cval == 4:
            mag = np.abs(data)
            phase = np.angle(data, deg=True)

            # normalize the mag
            data_min = 0.
            if fval:
                data_max = rmax
            else:
                data_max = mag.max()
                self.setAttr('Range Max', val=data_max)
            data_range = data_max - data_min
            dmask = np.ones(data.shape)
            new_min = data_range * flor + data_min
            new_max = data_range * ceil + data_min
            mag = np.clip(mag, new_min, new_max)

            if new_max > new_min:
                if (
                        gamma == 1
                ):  # Put in check for gamma=1, the common use case, just to save time
                    mag = (mag - new_min) / (new_max - new_min)
                else:
                    mag = pow((mag - new_min) / (new_max - new_min), gamma)
            else:
                mag = np.ones(mag.shape)

            # ADD BORDERS
            edgpix = self.getVal('Edge Pixels')
            blkpix = self.getVal('Black Pixels')
            if (edgpix + blkpix) > 0:
                # new image will be h2 x w2
                # frame defines edge pixels to paint with phase table
                h, w = mag.shape
                h2 = h + 2 * (edgpix + blkpix)
                w2 = w + 2 * (edgpix + blkpix)
                mag2 = np.zeros((h2, w2))
                phase2 = np.zeros((h2, w2))
                frame = np.zeros((h2, w2)) == 1
                frame[0:edgpix, :] = frame[h2 - edgpix:h2, :] = True
                frame[:, 0:edgpix] = frame[:, w2 - edgpix:w2] = True

                mag2[edgpix + blkpix:edgpix + blkpix + h,
                     edgpix + blkpix:edgpix + blkpix + w] = mag
                mag2[frame] = 1

                phase2[edgpix + blkpix:edgpix + blkpix + h,
                       edgpix + blkpix:edgpix + blkpix + w] = phase
                xloc = np.tile(np.linspace(-1., 1., w2), (h2, 1))
                yloc = np.transpose(np.tile(np.linspace(1., -1., h2), (w2, 1)))
                phase2[frame] = np.degrees(np.arctan2(yloc[frame],
                                                      xloc[frame]))

                mag = mag2
                phase = phase2

            # now colorize!
            if cmap == 0:  # HSV
                phase_cmap = cm.hsv
            elif cmap == 1:  # HSL
                try:
                    import seaborn as sns
                except:
                    self.log.warn(
                        "Seaborn (required for HSL map) not available! Falling back on HSV."
                    )
                    phase_cmap = cm.hsv
                else:  # from http://stackoverflow.com/a/34557535/333308
                    import matplotlib.colors as col
                    hlsmap = col.ListedColormap(sns.color_palette("hls", 256))
                    phase_cmap = hlsmap
            elif cmap == 2:  #HUSL
                try:
                    import seaborn as sns
                except:
                    self.log.warn(
                        "Seaborn (required for HUSL map) not available! Falling back on HSV."
                    )
                    phase_cmap = cm.hsv
                else:  # from http://stackoverflow.com/a/34557535/333308
                    import matplotlib.colors as col
                    huslmap = col.ListedColormap(sns.color_palette(
                        "husl", 256))
                    phase_cmap = huslmap
            elif cmap == 3:  # coolwarm
                phase_cmap = cm.coolwarm

            mag_norm = mag
            phase_norm = (phase + 180) / 360
            # phase shift to match old look better
            if cmap != 3:
                phase_norm = (phase_norm - 1 / 3) % 1
            colorized = 255 * cm.gray(mag_norm) * phase_cmap(phase_norm)
            red = colorized[..., 0]
            green = colorized[..., 1]
            blue = colorized[..., 2]
            alpha = colorized[..., 3]

        # DISPLAY SCALAR DATA
        elif dimfunc != 2:

            if np.iscomplexobj(data):
                if cval == 0:  # Real
                    data = np.real(data)
                elif cval == 1:  # Imag
                    data = np.imag(data)
                elif cval == 2:  # Mag
                    data = np.abs(data)
                elif cval == 3:  # Phase
                    data = np.angle(data, deg=True)

            if sval == 1:  # Mag
                data = np.abs(data)
            elif sval == 2:  # Sign
                sign = np.sign(data)
                data = np.abs(data)

            # normalize the data
            if fval:
                data_min = rmin
                data_max = rmax
            else:
                data_min = data.min()
                data_max = data.max()

            if sval != 2:
                if zval == 1:
                    data_min = 0.
                elif zval == 2:
                    data_max = max(abs(data_min), abs(data_max))
                    data_min = -data_max
                elif zval == 3:
                    data_max = 0.
                data_range = data_max - data_min
                self.setAttr('Range Min', val=data_min)
                self.setAttr('Range Max', val=data_max)
            else:
                data_min = 0.
                data_max = max(abs(data_min), abs(data_max))
                data_range = data_max
                self.setAttr('Range Min', val=-data_range)
                self.setAttr('Range Max', val=data_range)

            dmask = np.ones(data.shape)
            new_min = data_range * flor + data_min
            new_max = data_range * ceil + data_min
            data = np.minimum(np.maximum(data, new_min * dmask),
                              new_max * dmask)

            if new_max > new_min:
                if (
                        gamma == 1
                ):  # Put in check for gamma=1, the common use case, just to save time
                    data = 255. * (data - new_min) / (new_max - new_min)
                else:
                    data = 255. * pow(
                        (data - new_min) / (new_max - new_min), gamma)
            else:
                data = 255. * np.ones(data.shape)

            if sval != 2:  #Not Signed Data (Pass or Mag)
                # Show based on a color map
                if cmap == 0:  # Grayscale
                    red = green = blue = np.uint8(data)
                    alpha = 255. * np.ones(blue.shape)
                else:
                    rd = np.zeros(data.shape)
                    gn = np.zeros(data.shape)
                    be = np.zeros(data.shape)
                    zmask = np.zeros(data.shape)
                    fmask = np.ones(data.shape)

                    if cmap == 1:  # IceFire
                        hue = 4. * (data / 256.)
                        hindex0 = hue < 1.
                        hindex1 = np.logical_and(hue >= 1., hue < 2.)
                        hindex2 = np.logical_and(hue >= 2., hue < 3.)
                        hindex3 = np.logical_and(hue >= 3., hue < 4.)

                        be[hindex0] = hue[hindex0]
                        gn[hindex0] = zmask[hindex0]
                        rd[hindex0] = zmask[hindex0]

                        gn[hindex1] = (hue - 1.)[hindex1]
                        rd[hindex1] = (hue - 1.)[hindex1]
                        be[hindex1] = fmask[hindex1]

                        gn[hindex2] = fmask[hindex2]
                        rd[hindex2] = fmask[hindex2]
                        be[hindex2] = (3. - hue)[hindex2]

                        rd[hindex3] = fmask[hindex3]
                        gn[hindex3] = (4. - hue)[hindex3]
                        be[hindex3] = zmask[hindex3]

                    elif cmap == 2:  # Fire
                        hue = 4. * (data / 256.)
                        hindex0 = hue < 1.
                        hindex1 = np.logical_and(hue >= 1., hue < 2.)
                        hindex2 = np.logical_and(hue >= 2., hue < 3.)
                        hindex3 = np.logical_and(hue >= 3., hue < 4.)

                        be[hindex0] = hue[hindex0]
                        rd[hindex0] = zmask[hindex0]
                        gn[hindex0] = zmask[hindex0]

                        be[hindex1] = (2. - hue)[hindex1]
                        rd[hindex1] = (hue - 1.)[hindex1]
                        gn[hindex1] = zmask[hindex1]

                        rd[hindex2] = fmask[hindex2]
                        gn[hindex2] = (hue - 2.)[hindex2]
                        be[hindex2] = zmask[hindex2]

                        rd[hindex3] = fmask[hindex3]
                        gn[hindex3] = fmask[hindex3]
                        be[hindex3] = (hue - 3.)[hindex3]

                    elif cmap == 3:  # Hot
                        hue = 3. * (data / 256.)
                        hindex0 = hue < 1.
                        hindex1 = np.logical_and(hue >= 1., hue < 2.)
                        hindex2 = np.logical_and(hue >= 2., hue < 3.)

                        rd[hindex0] = hue[hindex0]
                        be[hindex0] = zmask[hindex0]
                        gn[hindex0] = zmask[hindex0]

                        gn[hindex1] = (hue - 1.)[hindex1]
                        rd[hindex1] = fmask[hindex1]
                        be[hindex1] = zmask[hindex1]

                        rd[hindex2] = fmask[hindex2]
                        gn[hindex2] = fmask[hindex2]
                        be[hindex2] = (hue - 2.)[hindex2]

                    if cmap == 4:  # Hot2, from ASIST (http://asist.umin.jp/index-e.htm)
                        rindex0 = data < 20.0
                        rindex1 = np.logical_and(data >= 20.0, data <= 100.0)
                        rindex2 = np.logical_and(data > 100.0, data < 128.0)
                        rindex3 = np.logical_and(data >= 128.0, data <= 191.0)
                        rindex4 = data > 191.0
                        rd[rindex0] = data[rindex0] * 4.0
                        rd[rindex1] = 80.0 - (data[rindex1] - 20.0)
                        rd[rindex3] = (data[rindex3] - 128.0) * 4.0
                        rd[rindex4] = data[rindex4] * 0.0 + 255.0
                        rd = rd / 255.0

                        gindex0 = data < 45.0
                        gindex1 = np.logical_and(data >= 45.0, data <= 130.0)
                        gindex2 = np.logical_and(data > 130.0, data < 192.0)
                        gindex3 = data >= 192.0
                        gn[gindex1] = (data[gindex1] - 45.0) * 3.0
                        gn[gindex2] = data[gindex2] * 0.0 + 255.0
                        gn[gindex3] = 252.0 - (data[gindex3] - 192.0) * 4.0
                        gn = gn / 255.0

                        bindex0 = (data < 1.0)
                        bindex1 = np.logical_and(data >= 1.0, data < 86.0)
                        bindex2 = np.logical_and(data >= 86.0, data <= 137.0)
                        bindex3 = data > 137.0
                        be[bindex1] = (data[bindex1] - 1.0) * 3.0
                        be[bindex2] = 255.0 - (data[bindex2] - 86.0) * 5.0
                        be = be / 255.0

                    elif cmap == 5:  # BGR
                        hue = 4. * (data / 256.)
                        hindex0 = hue < 1.
                        hindex1 = np.logical_and(hue >= 1., hue < 2.)
                        hindex2 = np.logical_and(hue >= 2., hue < 3.)
                        hindex3 = np.logical_and(hue >= 3., hue < 4.)

                        be[hindex0] = hue[hindex0]
                        gn[hindex0] = zmask[hindex0]
                        rd[hindex0] = zmask[hindex0]

                        gn[hindex1] = (hue - 1.)[hindex1]
                        rd[hindex1] = zmask[hindex1]
                        be[hindex1] = fmask[hindex1]

                        gn[hindex2] = fmask[hindex2]
                        rd[hindex2] = (hue - 2.)[hindex2]
                        be[hindex2] = (3. - hue)[hindex2]

                        rd[hindex3] = fmask[hindex3]
                        gn[hindex3] = (4. - hue)[hindex3]
                        be[hindex3] = zmask[hindex3]

                    blue = np.uint8(255. * rd)
                    red = np.uint8(255. * be)
                    green = np.uint8(255. * gn)
                    alpha = np.uint8(255. * np.ones(blue.shape))

            else:  #Signed data, positive numbers green, negative numbers magenta
                red = np.zeros(data.shape)
                green = np.zeros(data.shape)
                blue = np.zeros(data.shape)
                red[sign <= 0] = data[sign <= 0]
                blue[sign <= 0] = data[sign <= 0]
                green[sign >= 0] = data[sign >= 0]

                red = red.astype(np.uint8)
                green = green.astype(np.uint8)
                blue = blue.astype(np.uint8)
                alpha = np.uint8(data)

        # DISPLAY RGB image
        else:

            if data.shape[-1] > 3:
                red = data[:, :, 0].astype(np.uint8)
                green = data[:, :, 1].astype(np.uint8)
                blue = data[:, :, 2].astype(np.uint8)
                if (data.ndim == 3 and data.shape[-1] == 4):
                    alpha = data[:, :, 3].astype(np.uint8)
                else:
                    alpha = 255. * np.ones(blue.shape)
            else:
                self.log.warn("input veclen of " + str(data.shape[-1]) +
                              " is incompatible")
                return 1

        h, w = red.shape[:2]
        image1 = np.zeros((h, w, 4), dtype=np.uint8)
        image1[:, :, 0] = red
        image1[:, :, 1] = green
        image1[:, :, 2] = blue
        image1[:, :, 3] = alpha
        format_ = QtGui.QImage.Format_RGB32

        image = QtGui.QImage(image1.data, w, h, format_)

        #send the RGB values to the output port
        imageTru = np.zeros((h, w, 4), dtype=np.uint8)
        imageTru[:, :, 0] = red
        imageTru[:, :, 1] = green
        imageTru[:, :, 2] = blue
        imageTru[:, :, 3] = alpha
        image.ndarray = imageTru
        if image.isNull():
            self.log.warn("Image Viewer: cannot load image")

        self.setAttr('Viewport:', val=image)
        self.setData('out', imageTru)

        return 0
Beispiel #5
0
    def __init__(self, image_path):

        # find the limiting desktop dimension (w or h)
        pm = QtGui.QPixmap.fromImage(QtGui.QImage(image_path))
        g = QtGui.QDesktopWidget().availableGeometry()
        w = g.width()
        h = g.height()
        r = float(pm.width()) / pm.height()  # aspect ratio
        if (w <= pm.width()):
            h = int(w / r)
        if (h <= pm.height()):
            w = int(h * r)

        # the splash is almost useless below 500pts
        if w < 500:
            w = 500

        # resize the image based on new width
        if (w != g.width()) or (h != g.height()):
            pm = pm.scaledToWidth(int(w * 0.8),
                                  mode=QtCore.Qt.SmoothTransformation)

        # scale subsequent parameters based on new image width
        iw = pm.width()
        ih = pm.height()

        super(Splash, self).__init__(pm)

        # use a timer instead of the EULA
        self._timer = QtCore.QTimer()
        self._timer.timeout.connect(self.terms_accepted.emit)
        self._timer.setSingleShot(True)
        if not INCLUDE_EULA:
            self._timer.start(2000)

        panel = QtGui.QWidget()
        pal = QtGui.QPalette(QtGui.QColor(255, 255, 255))  # white
        panel.setAutoFillBackground(True)
        panel.setPalette(pal)

        lic = '''
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        '''
        self.lic = QtGui.QTextEdit(lic)
        self.lic.setReadOnly(True)

        button_title = 'Agree'
        self.wdg1 = QtGui.QPushButton(button_title, self)
        self.wdg1.setCheckable(False)
        self.wdg1.setFixedSize(int(iw * 0.2), int(iw * 0.05))
        self.wdg1.clicked[bool].connect(self.accept)

        button_title = 'Quit'
        self.wdg2 = QtGui.QPushButton(button_title, self)
        self.wdg2.setCheckable(False)
        self.wdg2.setFixedSize(int(iw * 0.2), int(iw * 0.05))
        self.wdg2.clicked[bool].connect(self.reject)

        buf = 'Click Agree to start GPI or Quit to exit.'
        new_fw = iw * 0.45
        for fw_i in range(20, 0, -1):
            f = QtGui.QFont('gill sans', fw_i)
            fm = QtGui.QFontMetricsF(f)
            cfw = fm.width(buf)
            if cfw < new_fw:
                break
        f = QtGui.QFont('gill sans', fw_i)

        self.prompt = QtGui.QLabel(buf)
        self.prompt.setAlignment(QtCore.Qt.AlignCenter)
        self.prompt.setFont(f)

        wdgLayout = QtGui.QHBoxLayout()
        #wdgLayout.setContentsMargins(0, 0, 0, 0)  # no spaces around this item
        #wdgLayout.setSpacing(0)
        #wdgLayout.addSpacerItem(QtGui.QSpacerItem(iw/2,1,hPolicy=QtGui.QSizePolicy.Minimum))
        wdgLayout.addWidget(self.prompt)
        wdgLayout.addWidget(self.wdg1)
        #wdgLayout.addSpacerItem(QtGui.QSpacerItem(int(iw*0.01),1,hPolicy=QtGui.QSizePolicy.Minimum))
        wdgLayout.addWidget(self.wdg2)
        #wdgLayout.addSpacerItem(QtGui.QSpacerItem(1,1,hPolicy=QtGui.QSizePolicy.MinimumExpanding))

        # a small panel
        vbox_p = QtGui.QVBoxLayout()
        vbox_p.setContentsMargins(10, 10, 10, 10)
        vbox_p.setSpacing(10)
        vbox_p.addWidget(self.lic)
        vbox_p.addLayout(wdgLayout)
        panel.setLayout(vbox_p)

        # white space | panel
        vbox = QtGui.QVBoxLayout()
        #vbox.setContentsMargins(0, 0, 0, int(iw*0.02))  # no spaces around this item
        vbox.setContentsMargins(0, 0, 0, 0)  # no spaces around this item
        vbox.setSpacing(0)

        vbox.addSpacerItem(
            QtGui.QSpacerItem(iw, (1 - 0.28) * ih,
                              hPolicy=QtGui.QSizePolicy.Minimum,
                              vPolicy=QtGui.QSizePolicy.Minimum))

        #vbox.addWidget(self.lic)
        vbox.addWidget(panel)
        #vbox.addLayout(wdgLayout)

        if INCLUDE_EULA:
            self.setLayout(vbox)

        self._accept = False
    def compute(self):
        import numpy as np
        from scipy import linalg

        self.log.node("Virtual Channels node running compute()")
        twoD_or_threeD = 2

        # GETTING WIDGET INFO
        mtx_xy = self.getVal('mtx')
        trajectory = self.getVal('trajectory')
        image_ceiling = self.getVal('image ceiling')
        crop_left = self.getVal('crop left')
        crop_right = self.getVal('crop right')
        crop_top = self.getVal('crop top')
        crop_bottom = self.getVal('crop bottom')
        reset_compute_button = self.getVal('reset compute button each time')
        compute = self.getVal('compute')
        # number of virtual channels m
        m = self.getVal('virtual channels')
        numiter = self.getVal('SDC Iterations')

        # GETTING PORT INFO
        data = self.getData('data').astype(np.complex64, copy=False)
        noise = self.getData('noise')
        sensitivity_map_uncropped = self.getData('sensitivity map')
        param = self.getData('params_in')

        # set dimensions
        nr_points = data.shape[-1]
        nr_arms = data.shape[-2]
        nr_coils = data.shape[0]
        if data.ndim == 3:
            extra_dim1 = 1
            extra_dim2 = 1
            data.shape = [nr_coils, extra_dim2, extra_dim1, nr_arms, nr_points]
        elif data.ndim == 4:
            extra_dim1 = data.shape[-3]
            extra_dim2 = 1
            data.shape = [nr_coils, extra_dim2, extra_dim1, nr_arms, nr_points]
        elif data.ndim == 5:
            extra_dim1 = data.shape[-3]
            extra_dim2 = data.shape[-4]
        elif data.ndim > 5:
            self.log.warn("Not implemented yet")

        print("data shape: " + str(data.shape))

        if sensitivity_map_uncropped is None:
            # if cropping or image scaling sliders were changed then use the previously stored csm instead of calcluating a new one
            has_csm_been_calculated = self.getData('sum of square image')
            if ((has_csm_been_calculated is not None)
                    and (('crop left' in self.widgetEvents()) or
                         ('crop right' in self.widgetEvents()) or
                         ('crop top' in self.widgetEvents()) or
                         ('crop bottom' in self.widgetEvents()) or
                         ('image ceiling' in self.widgetEvents()))):
                csm = self.getData('masked and normalized sense map')
                image = self.getData('sum of square image').copy()
                if ((csm is None) or (image is None)):
                    self.log.warn("This should not happen.")
                    return 1
                csm_mtx = csm.shape[-1]
            else:
                # calculate auto-calibration B1 maps
                import triggeredGASSP.gridding.Kaiser2D_utils as kaiser2D
                UI_mask_floor = self.getVal('Mask Floor (% of max mag)')
                if (trajectory == 0):
                    # spiral or radial
                    coords = self.getData('coords').astype(np.float32,
                                                           copy=False)
                    if (coords is None):
                        self.log.warn(
                            "Either a sensitiviy map or coords to calculate one is required"
                        )
                        return 1

                    # parameters from UI
                    UI_width = self.getVal('Autocalibration Width (%)')
                    UI_taper = self.getVal('Autocalibration Taper (%)')
                    #UI_mask_floor = self.getVal('Mask Floor (% of max mag)')
                    UI_average_csm = self.getVal(
                        'Dynamic data - average all dynamics for csm')
                    csm_mtx = np.int(0.01 * UI_width * mtx_xy)

                    if coords.shape[-3] > 400:
                        is_GoldenAngle_data = True
                    else:
                        is_GoldenAngle_data = False
                    if param is not None:
                        if 'spDYN_GOLDANGLE_ON' in param:
                            if int(param['spDYN_GOLDANGLE_ON'][0]) == 1:
                                is_GoldenAngle_data = True
                            else:
                                is_GoldenAngle_data = False
                    print("is GoldenAngle: " + str(is_GoldenAngle_data))
                    if is_GoldenAngle_data:
                        nr_arms_cms = self.getVal(
                            '# golden angle dynamics for csm')
                    else:
                        nr_arms_cms = nr_arms
                    self.log.debug("nr_arms_cms: " + str(nr_arms_cms))
                    csm_data = data[..., 0:nr_arms_cms, :]

                    # oversampling: Oversample at the beginning and crop at the end
                    oversampling_ratio = 2.  #1.375
                    mtx = np.int(csm_mtx * oversampling_ratio)
                    if mtx % 2:
                        mtx += 1
                    if oversampling_ratio > 1:
                        mtx_min = np.int((mtx - csm_mtx) / 2)
                        mtx_max = mtx_min + csm_mtx
                    else:
                        mtx_min = 0
                        mtx_max = mtx

                    # average dynamics or cardiac phases for csm
                    if ((extra_dim1 > 1) and UI_average_csm):
                        csm_data = np.sum(csm_data, axis=2)
                        csm_data = np.sum(
                            csm_data, axis=1
                        )  # Modified by Dan Zhu, simply add extra_dim2 as well
                        extra_dim1_csm = 1
                        #csm_data.shape = [nr_coils, extra_dim2, extra_dim1_csm, nr_arms_cms, nr_points]
                        extra_dim2_csm = 1  # Modified by Dan Zhu, simply add extra_dim2 as well
                        csm_data.shape = [
                            nr_coils, extra_dim2_csm, extra_dim1_csm,
                            nr_arms_cms, nr_points
                        ]
                        # Modified by Dan Zhu, simply add extra_dim2 as well

                    else:
                        extra_dim1_csm = extra_dim1
                        extra_dim2_csm = extra_dim2

                    self.log.debug("csm_data shape: " + str(csm_data.shape))
                    self.log.debug("coords shape: " + str(coords.shape))

                    # coords dimensions: (add 1 dimension as they could have another dimension for golden angle dynamics
                    if coords.ndim == 3:
                        coords.shape = [1, nr_arms, nr_points, twoD_or_threeD]

                    # create low resolution csm
                    # cropping the data will make gridding and FFT much faster
                    magnitude_one_interleave = np.zeros(nr_points)
                    for x in range(nr_points):
                        magnitude_one_interleave[x] = np.sqrt(
                            coords[0, 0, x, 0]**2 + coords[0, 0, x, 1]**2)
                    self.log.debug(magnitude_one_interleave)
                    within_csm_width_radius = magnitude_one_interleave[:] < (
                        0.01 * UI_width * 0.5
                    )  # for BNI spirals should be 0.45 instead of 0.5
                    nr_points_csm_width = within_csm_width_radius.sum()

                    # now set the dimension lists
                    # Modified by Dan Zhu, simply add extra_dim2 as well
                    out_dims_grid = [
                        nr_coils, extra_dim2_csm, extra_dim1_csm, mtx,
                        nr_arms_cms, nr_points_csm_width
                    ]
                    out_dims_fft = [
                        nr_coils, extra_dim2_csm, extra_dim1_csm, mtx, mtx
                    ]

                    csm_data = csm_data[..., 0:nr_points_csm_width]
                    csm_coords = 1. / (0.01 * UI_width) * coords[
                        ..., 0:nr_arms_cms, 0:nr_points_csm_width, :]

                    self.log.debug("csm_data shape: " + str(csm_data.shape))
                    self.log.debug("csm_coords shape: " +
                                   str(csm_coords.shape))

                    # generate SDC based on number of arms and nr of points being used for csm
                    import gpi_core.gridding.sdc as sd
                    #csm_weights = sd.twod_sdcsp(csm_coords.squeeze().astype(np.float64), numiter, 0.01 * UI_taper, mtx)
                    cmtxdim = np.array([mtx, mtx], dtype=np.int64)
                    wates = np.ones((nr_arms_cms * nr_points_csm_width),
                                    dtype=np.float64)
                    coords_for_sdc = csm_coords.astype(np.float64)
                    coords_for_sdc.shape = [
                        nr_arms_cms * nr_points_csm_width, twoD_or_threeD
                    ]
                    csm_weights = sd.twod_sdc(coords_for_sdc, wates, cmtxdim,
                                              numiter, 0.01 * UI_taper)
                    csm_weights.shape = [1, nr_arms_cms, nr_points_csm_width]

                    # pre-calculate Kaiser-Bessel kernel
                    kernel_table_size = 800
                    kernel = kaiser2D.kaiserbessel_kernel(
                        kernel_table_size, oversampling_ratio)

                    # pre-calculate the rolloff for the spatial domain
                    roll = kaiser2D.rolloff2D(mtx, kernel)
                    # Grid
                    gridded_kspace = kaiser2D.grid2D(
                        csm_data, csm_coords, csm_weights.astype(np.float32),
                        kernel, out_dims_grid)
                    self.setData('debug', gridded_kspace)
                    # filter k-space - not needed anymore as SDC taper is used now.
                    ## win = kaiser2D.window2(gridded_kspace.shape[-2:], windowpct=UI_taper, widthpct=100)
                    ## gridded_kspace *= win
                    # FFT
                    image_domain = kaiser2D.fft2D(gridded_kspace,
                                                  dir=0,
                                                  out_dims_fft=out_dims_fft)
                    # rolloff
                    image_domain *= roll
                    # crop to original matrix size
                    csm = image_domain[..., mtx_min:mtx_max, mtx_min:mtx_max]
                else:
                    # Cartesian
                    csm_mtx = nr_arms
                    extra_dim2_csm = 1
                    extra_dim1_csm = 1
                    mtx_min = (nr_points - nr_arms) // 2
                    mtx_max = mtx_min + csm_mtx
                    out_dims_fft = [
                        nr_coils, extra_dim2_csm, extra_dim1_csm, nr_arms,
                        nr_points
                    ]
                    csm = kaiser2D.fft2D(data,
                                         dir=0,
                                         out_dims_fft=out_dims_fft)
                    csm = csm[..., mtx_min:mtx_max]
                # normalize by rms (better would be to use a whole body coil image
                csm_rms = np.sqrt(np.sum(np.abs(csm)**2, axis=0))
                csm = csm / csm_rms
                # zero out points that are below mask threshold
                thresh = 0.01 * UI_mask_floor * csm_rms.max()
                csm *= csm_rms > thresh
                # for ROI selection use csm_rms, which still has some contrast
                image = csm_rms
                image.shape = [csm_mtx, csm_mtx]
                image_sos = image.copy()
                self.setData('sum of square image', image_sos)
        else:
            csm = sensitivity_map_uncropped
            csm_mtx = csm.shape[-1]
            # create sum-of-squares of sensitivity map to allow selection of ROI
            image = np.copy(csm)
            image = np.sqrt(np.sum(np.abs(image)**2, axis=0))
            image.shape = [csm_mtx, csm_mtx]
        self.setData('masked and normalized sense map', csm)

        # display sum-of-squares of sensitivity map to allow selection of ROI
        data_max = image.max()
        data_min = image.min()

        image[:, crop_left - 1] = data_max
        image[:, crop_right - 1] = data_max
        image[crop_top - 1, :] = data_max
        image[crop_bottom - 1, :] = data_max

        data_range = data_max - data_min
        new_max = data_range * 0.01 * image_ceiling + data_min
        dmask = np.ones(image.shape)
        image = np.minimum(image, new_max * dmask)
        if new_max > data_min:
            image = 255. * (image - data_min) / (new_max - data_min)
        red = green = blue = np.uint8(image)
        alpha = 255. * np.ones(blue.shape)
        h, w = red.shape[:2]
        image1 = np.zeros((h, w, 4), dtype=np.uint8)
        image1[:, :, 0] = red
        image1[:, :, 1] = green
        image1[:, :, 2] = blue
        image1[:, :, 3] = alpha

        format_ = QtGui.QImage.Format_RGB32

        image2 = QtGui.QImage(image1.data, w, h, format_)
        image2.ndarry = image1
        self.setAttr('image', val=image2)

        # crop sensitivity map
        csm.shape = [nr_coils, csm_mtx, csm_mtx]
        sensitivity_map = csm[:, crop_top - 1:crop_bottom,
                              crop_left - 1:crop_right]
        #self.setData('debug', np.squeeze(sensitivity_map))

        # get sizes
        # number of channels n
        n = sensitivity_map.shape[-3]
        x_size = sensitivity_map.shape[-1]
        y_size = sensitivity_map.shape[-2]
        nr_pixels = x_size * y_size

        if compute:

            # noise covariance matrix Psi
            noise_cv_matrix = np.cov(noise)

            # Cholesky decomposition to determine T, where T Psi T_H = 1
            L = np.linalg.cholesky(noise_cv_matrix)
            T = np.linalg.inv(L)

            # decorrelated sensitivity map S_hat
            S_hat = np.zeros([nr_pixels, n], dtype=np.complex64)
            for x in range(x_size):
                for y in range(y_size):
                    index = y + x * y_size
                    S_hat[index, :] = np.dot(T, sensitivity_map[:, y, x])

            self.log.debug("after S_hat")

            # P = sum of S_hat S_hat_pseudo_inverse over all pixels
            P = np.zeros([n, n], dtype=np.complex64)
            S_hat_matrix = np.zeros([n, 1], dtype=np.complex64)
            for index in range(nr_pixels):
                # pseudo inverse of S_hat
                S_hat_matrix[:, 0] = S_hat[index, :]
                S_hat_pinv = np.linalg.pinv(S_hat_matrix)
                P = P + np.dot(S_hat_matrix, S_hat_pinv)
            self.log.debug("after S_hat_pinv")

            # singular value decomposition of P
            # if P is symmetric and positive definite, the SVD is P = U d U.H instead of P = U d V.H
            U, d, V = np.linalg.svd(P)
            self.log.debug("after svd")

            # the transformation matrix A is then given by A = C U.H T
            # C is diagonal matrix with 1 on the first m rows and 0 in the remaining
            # instead of using C, only assing mxn to A
            C = np.array(np.zeros([n, n]), dtype=np.float32)
            self.log.debug("after C")
            for x in range(m):
                C[x, x] = 1.
            A_square = np.dot(C, np.dot(U.T.conjugate(), T))
            A = A_square[0:m, :]
            self.log.debug("after A")

            # Compress the data
            if data.ndim == 5:
                out = np.zeros([m, extra_dim2, extra_dim1, nr_arms, nr_points],
                               dtype=data.dtype)
                for extra2 in range(extra_dim2):
                    for extra1 in range(extra_dim1):
                        for arm in range(nr_arms):
                            for point in range(nr_points):
                                out[:, extra2, extra1, arm, point] = np.dot(
                                    A, data[:, extra2, extra1, arm, point])

            # SETTING PORT INFO
            self.setData('compressed data', np.squeeze(out))
            self.setData('A', A)
            self.setData('noise covariance', noise_cv_matrix)

            # end of compute
            if reset_compute_button:
                self.setAttr('compute', val=False)

        return 0