Beispiel #1
0
    def createImage(self):
        """ Creates a new image by separating out the cyan, magenta, or yellow
            component, depending on the mask color specified in the constructor.
            The amount of the component found in each pixel of the image is used
            to determine how much of a user-selected ink is used for each pixel
            in the new image for the label widget.
        """
        self.newImage = newImage = self.originalImage.copy()

        # Create CMY components for the ink being used.
        cyanInk = float(255 - QColor(self.paintColor).red()) / 255.0
        magentaInk = float(255 - QColor(self.paintColor).green()) / 255.0
        yellowInk = float(255 - QColor(self.paintColor).blue()) / 255.0

        convert = self.convertMap[self.maskColor]

        for y in range(newImage.height()):
            for x in range(newImage.width()):
                p = self.originalImage.pixel(x, y)

                # Separate the source pixel into its cyan component.
                if self.inverted:
                    amount = convert(p)
                else:
                    amount = 255 - convert(p)

                newColor = QColor(
                    255 - min(int(amount * cyanInk), 255),
                    255 - min(int(amount * magentaInk), 255),
                    255 - min(int(amount * yellowInk), 255))

                newImage.setPixel(x, y, newColor.rgb())

        self.imageLabel.setPixmap(QPixmap.fromImage(newImage))
Beispiel #2
0
    def render(self, rend=True):
        if (rend):
            if (self.modeBtn.isChecked()):
                self.qsst.srctext = self.textEdit.toPlainText()
                self.qsst.loadVars()
            self.qsst.convertQss()
            self.setStyleSheet(self.qsst.qss)
        else:
            self.setStyleSheet('')

        for var, btn in self.dict.items():
            if ("rgb" in btn.text()):
                t = btn.text().strip(r" rgba()")
                c = t.split(',')
                if (len(c) > 3):
                    a = c[3]
                else:
                    a = 255
                color = QColor(r, g, b, a)
            else:
                color = QColor(btn.text())
            s = ''
            if (qGray(color.rgb()) < 100):
                s += "color:white;"
            btn.setStyleSheet(s + "background:" + btn.text())
Beispiel #3
0
    def createImage(self):
        """ Creates a new image by separating out the cyan, magenta, or yellow
            component, depending on the mask color specified in the constructor.
            The amount of the component found in each pixel of the image is used
            to determine how much of a user-selected ink is used for each pixel
            in the new image for the label widget.
        """
        self.newImage = newImage = self.originalImage.copy()

        # Create CMY components for the ink being used.
        cyanInk = float(255 - QColor(self.paintColor).red()) / 255.0
        magentaInk = float(255 - QColor(self.paintColor).green()) / 255.0
        yellowInk = float(255 - QColor(self.paintColor).blue()) / 255.0

        convert = self.convertMap[self.maskColor]

        for y in range(newImage.height()):
            for x in range(newImage.width()):
                p = self.originalImage.pixel(x, y)

                # Separate the source pixel into its cyan component.
                if self.inverted:
                    amount = convert(p)
                else:
                    amount = 255 - convert(p)

                newColor = QColor(
                    255 - min(int(amount * cyanInk), 255),
                    255 - min(int(amount * magentaInk), 255),
                    255 - min(int(amount * yellowInk), 255))

                newImage.setPixel(x, y, newColor.rgb())

        self.imageLabel.setPixmap(QPixmap.fromImage(newImage))
Beispiel #4
0
    def loadColorPanel(self):
        self.qsst.srctext = self.editor.text()
        self.qsst.loadVars()
        # item = self.colorGridLayout.itemAt(0)
        # while (item != None):
        #     self.colorGridLayout.removeItem(item)
        #     # self.colorGridLayout.removeWidget(item.widget())
        #     # item.widget().setParent(None)#这三行没有作用
        #     sip.delete(item.widget())  # 虽然控件删除了,但是grid的行数列数没减少,但是不影响使用
        #     sip.delete(item)
        #     item = self.colorGridLayout.itemAt(0)
        # self.colorGridLayout.update()  # 不起作用

        # a,b=list(self.clrBtnDict.keys()),list(self.qsst.varDict.keys());a.sort();b.sort()
        if sorted(list(self.clrBtnDict.keys())) != sorted(
                list(self.qsst.varDict.keys())):
            while self.colorPanelLayout.count() > 0:
                self.colorPanelLayout.removeItem(
                    self.colorPanelLayout.itemAt(0))
            self.clrBtnDict = {}
            for varName, clrStr in self.qsst.varDict.items():
                contianerWidget = QWidget()
                contianerWidget.setMinimumSize(QSize(185, 25))
                label = QLabel(varName, contianerWidget)
                btn = QPushButton(clrStr, contianerWidget)
                if sys.platform.startswith("win"):
                    font1 = QFont("Arial", 10, QFont.Medium)
                    font2 = QFont("sans-serif", 9, QFont.Medium)
                    label.setFont(font1)
                    btn.setFont(font2)
                self.clrBtnDict[varName] = btn
                # label.setFixedWidth(80)
                # btn.setFixedWidth(100)
                label.move(5, 5)
                btn.move(100, 5)
                self.colorPanelLayout.addWidget(contianerWidget)
                self.colorPanelLayout.setSpacing(5)
                btn.clicked.connect(lambda x, var=varName: self.chclr(var))

        for varName, btn in self.clrBtnDict.items():
            clrStr = self.qsst.varDict[varName]
            btn.setText(clrStr)
            if "rgb" in clrStr:
                t = clrStr.strip(r" rgba()")
                c = t.split(',')
                if len(c) > 3:
                    lable = c[3]
                else:
                    lable = 255
                color = QColor(c[0], c[1], c[2], lable)
            else:
                color = QColor(clrStr)
            s = ''
            if qGray(color.rgb()) < 100:
                s += "color:white;"
            else:
                s += "color:black;"

            btn.setStyleSheet(s + "background:" + btn.text())
Beispiel #5
0
    def change_color(self, value):
        invert = QColor(255, 255, 255)
        invert.setRgb(invert.rgb() - self.color.rgb())
        self.ui.lineEdit.setStyleSheet(
            "QWidget { background-color: %s; color: %s}" %
            (self.color.name(), invert.name()))

        name = self.ui.listWidget.currentItem().text()
        info = self.settings.getClassFromName(name)
        rgb = self.color.getRgb()
        info['color'] = [rgb[0], rgb[1], rgb[2]]
 def __init__(self, parent):
     super(HueSliderWidget, self).__init__(parent)
     self.setFixedSize(parent.width(), parent.height())
     self.value = 0
     size = 100
     self.colorImage = QtGui.QImage(1, size, QtGui.QImage.Format_RGB32)
     c = QColor()
     for y in range(0, size):
         k = y / float(size)
         c.setHsvF(k, 1.0, 1.0)
         self.colorImage.setPixel(0, y, c.rgb())
     self.setCursor(Qt.PointingHandCursor)
 def __init__(self, parent):
     super(AlphaSliderWidget, self).__init__(parent)
     self.setFixedSize(parent.width(), parent.height())
     self.setCursor(Qt.PointingHandCursor)
     self.value = 0
     size = 100
     self.colorImage = QtGui.QImage(size, 1, QtGui.QImage.Format_RGB32)
     c = QColor()
     for x in range(0, size):
         k = x / float(size)
         c.setHsvF(1.0, 0.0, k)
         self.colorImage.setPixel(x, 0, c.rgb())
def generateHSVImage(w, h, hue, img=None):
    if not img:
        img = QtGui.QImage(w, h, QtGui.QImage.Format_RGB32)
    du = 1.0 / w
    dv = 1.0 / h
    c = QColor()
    for y in range(0, h):
        for x in range(0, w):
            s = du * x
            v = 1.0 - dv * y
            c.setHsvF(hue, s, v)
            img.setPixel(x, y, c.rgb())
    return img
 def bright_button_clicked(self):
     constant = self.spinner_brightness.value()
     qimage = self.imported_image.pixmap().toImage()
     for x in range(0 , qimage.width()):
         for y in  range(0 , qimage.height()):
             current_pixel =  qimage.pixel(x,y)
             cur_color = QColor(current_pixel)
             red = self.adjust_to_limit(cur_color.red() + constant)
             green = self.adjust_to_limit(cur_color.green() + constant)
             blue = self.adjust_to_limit(cur_color.blue() + constant)
             value = QColor(red,green,blue)
             qimage.setPixel(x,y,value.rgb())
     new_pixmap = QPixmap.fromImage(qimage)
     self.modified_image.setPixmap(new_pixmap)
Beispiel #10
0
    def createImage(self):
        """ Creates an image by combining the contents of the three screens
            to present a page preview.
            The image associated with each screen is separated into cyan,
            magenta, and yellow components. We add up the values for each
            component from the three screen images, and subtract the totals
            from the maximum value for each corresponding primary color.
        """
        newImage = self.scaledImage.copy()

        image1 = self.cyanWidget.image()
        image2 = self.magentaWidget.image()
        image3 = self.yellowWidget.image()
        darkness = 255 - self.brightness

        for y in range(newImage.height()):
            for x in range(newImage.width()):
                # Create three screens, using the quantities of the source CMY
                # components to determine how much of each of the inks are to
                # be put on each screen.
                p1 = image1.pixel(x, y)
                cyan1 = float(255 - qRed(p1))
                magenta1 = float(255 - qGreen(p1))
                yellow1 = float(255 - qBlue(p1))

                p2 = image2.pixel(x, y)
                cyan2 = float(255 - qRed(p2))
                magenta2 = float(255 - qGreen(p2))
                yellow2 = float(255 - qBlue(p2))

                p3 = image3.pixel(x, y)
                cyan3 = float(255 - qRed(p3))
                magenta3 = float(255 - qGreen(p3))
                yellow3 = float(255 - qBlue(p3))

                newColor = QColor(
                    max(255 - int(cyan1 + cyan2 + cyan3) - darkness, 0),
                    max(255 - int(magenta1 + magenta2 + magenta3) - darkness,
                        0),
                    max(255 - int(yellow1 + yellow2 + yellow3) - darkness, 0),
                )

                newImage.setPixel(x, y, newColor.rgb())

        self.finalWidget.setPixmap(QPixmap.fromImage(newImage))
Beispiel #11
0
    def createImage(self):
        """ Creates an image by combining the contents of the three screens
            to present a page preview.
            The image associated with each screen is separated into cyan,
            magenta, and yellow components. We add up the values for each
            component from the three screen images, and subtract the totals
            from the maximum value for each corresponding primary color.
        """
        newImage = self.scaledImage.copy()

        image1 = self.cyanWidget.image()
        image2 = self.magentaWidget.image()
        image3 = self.yellowWidget.image()
        darkness = 255 - self.brightness

        for y in range(newImage.height()):
            for x in range(newImage.width()):
                # Create three screens, using the quantities of the source CMY
                # components to determine how much of each of the inks are to
                # be put on each screen.
                p1 = image1.pixel(x, y)
                cyan1 = float(255 - qRed(p1))
                magenta1 = float(255 - qGreen(p1))
                yellow1 = float(255 - qBlue(p1))

                p2 = image2.pixel(x, y)
                cyan2 = float(255 - qRed(p2))
                magenta2 = float(255 - qGreen(p2))
                yellow2 = float(255 - qBlue(p2))

                p3 = image3.pixel(x, y)
                cyan3 = float(255 - qRed(p3))
                magenta3 = float(255 - qGreen(p3))
                yellow3 = float(255 - qBlue(p3))

                newColor = QColor(
                    max(255 - int(cyan1 + cyan2 + cyan3) - darkness, 0),
                    max(255 - int(magenta1 + magenta2 + magenta3) - darkness, 0),
                    max(255 - int(yellow1 + yellow2 + yellow3) - darkness, 0))

                newImage.setPixel(x, y, newColor.rgb())

        self.finalWidget.setPixmap(QPixmap.fromImage(newImage))
Beispiel #12
0
    def apply_effect(self, effect, kwargs):

        if self.progressbar:
            self.progressbar.setFormat(self.hack_title.get(effect.__name__, '%p%'))

        if effect.__name__ != floodfill.__name__:
            for i in range(self.image.width()):
                for j in range(self.image.height()):
                    pixel = self.image.pixel(i, j)
                    r, g, b, a = QColor(pixel).getRgb()
                    r, g, b = effect(r, g, b, **kwargs)
                    new_pixel = QColor(r, g, b)
                    self.image.setPixel(QPoint(i, j), new_pixel.rgb())

                # if self.progressbar:
                #     self.progressbar.setValue(i)

                self.sig_step.emit(i)
                if (i+1) % 100 == 0 or i+1 == self.image.width():
                    print('line: %s/%s' % (i+1, self.image.width()))

        else:
            self.image = floodfill(self.image, signal=self.sig_step)
Beispiel #13
0
def create_palette(window_color: QColor, highlight_color: QColor) -> QPalette:
    """
    根据窗口样式window_color 和 高亮(选中)颜色创建窗口风格的palette
    :param window_color: 目标窗口样式
    :param highlight_color: 目标高亮样式
    :return: QPalette
    """

    # 根据HSV样式模型,获取该颜色的 hue色调 sat饱和度 和value明度(最后一个是透明度)
    hue, sat, window_value, _ = window_color.getHsv()

    color_from_value = lambda value: QColor.fromHsv(hue, sat,
                                                    bound(0, value, 255))

    is_light = window_value > 128
    base_value = window_value + 48 if is_light else window_value - 24

    light_text_value = min(255, window_value + 160)
    dark_text_value = max(0, window_value - 160)

    # 根据界面的元素设置字体颜色以便以后可以看清字体
    light_text_color = QColor(light_text_value, light_text_value,
                              light_text_value)
    dark_text_color = QColor(dark_text_value, dark_text_value, dark_text_value)
    light_disabled_text_color = QColor(light_text_value, light_text_value,
                                       light_text_value)
    dark_disabled_text_color = QColor(dark_text_value, dark_text_value,
                                      dark_text_value)

    palette = QPalette(color_from_value(window_value))
    palette.setColor(QPalette.Base, color_from_value(base_value))
    palette.setColor(QPalette.AlternateBase, color_from_value(base_value - 10))
    palette.setColor(QPalette.WindowText,
                     dark_text_color if is_light else light_text_color)
    palette.setColor(QPalette.ButtonText,
                     dark_text_color if is_light else light_text_color)
    palette.setColor(QPalette.Text,
                     dark_text_color if is_light else light_text_color)
    palette.setColor(QPalette.Light, color_from_value(window_value + 55))
    palette.setColor(QPalette.Dark, color_from_value(window_value - 55))
    palette.setColor(QPalette.Mid, color_from_value(window_value - 27))
    palette.setColor(QPalette.Midlight, color_from_value(window_value + 27))

    # 按组设置颜色
    palette.setColor(
        QPalette.Disabled, QPalette.WindowText,
        dark_disabled_text_color if is_light else light_disabled_text_color)
    palette.setColor(
        QPalette.Disabled, QPalette.ButtonText,
        dark_disabled_text_color if is_light else light_disabled_text_color)
    palette.setColor(
        QPalette.Disabled, QPalette.Text,
        dark_disabled_text_color if is_light else light_disabled_text_color)

    # 高亮的颜色是否偏黑
    from PyQt5.Qt import qGray
    highlight_is_dark = qGray(highlight_color.rgb()) < 120
    palette.setColor(QPalette.Highlight, highlight_color)
    palette.setColor(QPalette.HighlightedText,
                     Qt.white if highlight_is_dark else Qt.black)

    return palette
Beispiel #14
0
class Tileset(Object):
    ##
    # Constructor.
    #
    # @param name        the name of the tileset
    # @param tileWidth   the width of the tiles in the tileset
    # @param tileHeight  the height of the tiles in the tileset
    # @param tileSpacing the spacing between the tiles in the tileset image
    # @param margin      the margin around the tiles in the tileset image
    ##
    def __init__(self, name, tileWidth, tileHeight, tileSpacing = 0, margin = 0):
        super().__init__(Object.TilesetType)

        self.mName = name
        self.mTileWidth = tileWidth
        self.mTileHeight = tileHeight
        self.mTileSpacing = tileSpacing
        self.mMargin = margin
        self.mImageWidth = 0
        self.mImageHeight = 0
        self.mColumnCount = 0
        self.mTerrainDistancesDirty = False

        self.mTileOffset = QPoint()
        self.mFileName = QString()
        self.mTiles = QList()
        self.mTransparentColor = QColor()
        self.mImageSource = QString()
        self.mTerrainTypes = QList()
        self.mWeakPointer = None

    ##
    # Destructor.
    ##
    def __del__(self):
        self.mTiles.clear()
        self.mTerrainTypes.clear()

    def create(name, tileWidth, tileHeight, tileSpacing = 0, margin = 0):
        tileset = Tileset(name, tileWidth, tileHeight, tileSpacing, margin)
        tileset.mWeakPointer = tileset
        return tileset
    
    def __iter__(self):
        return self.mTiles.__iter__()
        
    ##
    # Returns the name of this tileset.
    ##
    def name(self):
        return self.mName

    ##
    # Sets the name of this tileset.
    ##
    def setName(self, name):
        self.mName = name

    ##
    # Returns the file name of this tileset. When the tileset isn't an
    # external tileset, the file name is empty.
    ##
    def fileName(self):
        return self.mFileName

    ##
    # Sets the filename of this tileset.
    ##
    def setFileName(self, fileName):
        self.mFileName = fileName

    ##
    # Returns whether this tileset is external.
    ##
    def isExternal(self):
        return self.mFileName!=''

    ##
    # Returns the maximum width of the tiles in this tileset.
    ##
    def tileWidth(self):
        return self.mTileWidth

    ##
    # Returns the maximum height of the tiles in this tileset.
    ##
    def tileHeight(self):
        return self.mTileHeight

    ##
    # Returns the maximum size of the tiles in this tileset.
    ##
    def tileSize(self):
        return QSize(self.mTileWidth, self.mTileHeight)

    ##
    # Returns the spacing between the tiles in the tileset image.
    ##
    def tileSpacing(self):
        return self.mTileSpacing

    ##
    # Returns the margin around the tiles in the tileset image.
    ##
    def margin(self):
        return self.mMargin

    ##
    # Returns the offset that is applied when drawing the tiles in this
    # tileset.
    ##
    def tileOffset(self):
        return self.mTileOffset

    ##
    # @see tileOffset
    ##
    def setTileOffset(self, offset):
        self.mTileOffset = offset

    ##
    # Returns a const reference to the list of tiles in this tileset.
    ##
    def tiles(self):
        return QList(self.mTiles)

    ##
    # Returns the tile for the given tile ID.
    # The tile ID is local to this tileset, which means the IDs are in range
    # [0, tileCount() - 1].
    ##
    def tileAt(self, id):
        if id < self.mTiles.size():
            return self.mTiles.at(id)
        return None

    ##
    # Returns the number of tiles in this tileset.
    ##
    def tileCount(self):
        return self.mTiles.size()

    ##
    # Returns the number of tile columns in the tileset image.
    ##
    def columnCount(self):
        return self.mColumnCount

    ##
    # Returns the width of the tileset image.
    ##
    def imageWidth(self):
        return self.mImageWidth

    ##
    # Returns the height of the tileset image.
    ##
    def imageHeight(self):
        return self.mImageHeight

    ##
    # Returns the transparent color, or an invalid color if no transparent
    # color is used.
    ##
    def transparentColor(self):
        return QColor(self.mTransparentColor)

    ##
    # Sets the transparent color. Pixels with this color will be masked out
    # when loadFromImage() is called.
    ##
    def setTransparentColor(self, c):
        self.mTransparentColor = c

    ##
    # Load this tileset from the given tileset \a image. This will replace
    # existing tile images in this tileset with new ones. If the new image
    # contains more tiles than exist in the tileset new tiles will be
    # appended, if there are fewer tiles the excess images will be blanked.
    #
    # The tile width and height of this tileset must be higher than 0.
    #
    # @param image    the image to load the tiles from
    # @param fileName the file name of the image, which will be remembered
    #                 as the image source of this tileset.
    # @return <code>true</code> if loading was successful, otherwise
    #         returns <code>false</code>
    ##
    def loadFromImage(self, *args):
        l = len(args)
        if l==2:
            image, fileName = args

            tileSize = self.tileSize()
            margin = self.margin()
            spacing = self.tileSpacing()
    
            if (image.isNull()):
                return False
            stopWidth = image.width() - tileSize.width()
            stopHeight = image.height() - tileSize.height()
            oldTilesetSize = self.tileCount()
            tileNum = 0
            for y in range(margin, stopHeight+1, tileSize.height() + spacing):
                for x in range(margin, stopWidth+1, tileSize.width() + spacing):
                    tileImage = image.copy(x, y, tileSize.width(), tileSize.height())
                    tilePixmap = QPixmap.fromImage(tileImage)
                    if (self.mTransparentColor.isValid()):
                        mask = tileImage.createMaskFromColor(self.mTransparentColor.rgb())
                        tilePixmap.setMask(QBitmap.fromImage(mask))

                    if (tileNum < oldTilesetSize):
                        self.mTiles.at(tileNum).setImage(tilePixmap)
                    else:
                        self.mTiles.append(Tile(tilePixmap, tileNum, self))

                    tileNum += 1

            # Blank out any remaining tiles to avoid confusion
            while (tileNum < oldTilesetSize):
                tilePixmap = QPixmap(tileSize)
                tilePixmap.fill()
                self.mTiles.at(tileNum).setImage(tilePixmap)
                tileNum += 1

            self.mImageWidth = image.width()
            self.mImageHeight = image.height()
            self.mColumnCount = self.columnCountForWidth(self.mImageWidth)
            self.mImageSource = fileName
            return True
        elif l==1:
            ##
            # Convenience override that loads the image using the QImage constructor.
            ##
            fileName = args[0]
            return self.loadFromImage(QImage(fileName), fileName)

    ##
    # This checks if there is a similar tileset in the given list.
    # It is needed for replacing this tileset by its similar copy.
    ##
    def findSimilarTileset(self, tilesets):
        for candidate in tilesets:
            if (candidate.tileCount() != self.tileCount()):
                continue
            if (candidate.imageSource() != self.imageSource()):
                continue
            if (candidate.tileSize() != self.tileSize()):
                continue
            if (candidate.tileSpacing() != self.tileSpacing()):
                continue
            if (candidate.margin() != self.margin()):
                continue
            if (candidate.tileOffset() != self.tileOffset()):
                continue

            # For an image collection tileset, check the image sources
            if (self.imageSource()==''):
                if (not sameTileImages(self, candidate)):
                    continue

            return candidate
            
        return None

    ##
    # Returns the file name of the external image that contains the tiles in
    # this tileset. Is an empty string when this tileset doesn't have a
    # tileset image.
    ##
    def imageSource(self):
        return self.mImageSource

    ##
    # Returns the column count that this tileset would have if the tileset
    # image would have the given \a width. This takes into account the tile
    # size, margin and spacing.
    ##
    def columnCountForWidth(self, width):
        return int((width - self.mMargin + self.mTileSpacing) / (self.mTileWidth + self.mTileSpacing))

    ##
    # Returns a const reference to the list of terrains in this tileset.
    ##
    def terrains(self):
        return QList(self.mTerrainTypes)

    ##
    # Returns the number of terrain types in this tileset.
    ##
    def terrainCount(self):
        return self.mTerrainTypes.size()

    ##
    # Returns the terrain type at the given \a index.
    ##
    def terrain(self, index):
        if index >= 0:
            _x = self.mTerrainTypes[index]
        else:
            _x = None
        return _x

    ##
    # Adds a new terrain type.
    #
    # @param name      the name of the terrain
    # @param imageTile the id of the tile that represents the terrain visually
    # @return the created Terrain instance
    ##
    def addTerrain(self, name, imageTileId):
        terrain = Terrain(self.terrainCount(), self, name, imageTileId)
        self.insertTerrain(self.terrainCount(), terrain)
        return terrain

    ##
    # Adds the \a terrain type at the given \a index.
    #
    # The terrain should already have this tileset associated with it.
    ##
    def insertTerrain(self, index, terrain):
        self.mTerrainTypes.insert(index, terrain)
        # Reassign terrain IDs
        for terrainId in range(index, self.mTerrainTypes.size()):
            self.mTerrainTypes.at(terrainId).mId = terrainId
        # Adjust tile terrain references
        for tile in self.mTiles:
            for corner in range(4):
                terrainId = tile.cornerTerrainId(corner)
                if (terrainId >= index):
                    tile.setCornerTerrainId(corner, terrainId + 1)

        self.mTerrainDistancesDirty = True

    ##
    # Removes the terrain type at the given \a index and returns it. The
    # caller becomes responsible for the lifetime of the terrain type.
    #
    # This will cause the terrain ids of subsequent terrains to shift up to
    # fill the space and the terrain information of all tiles in this tileset
    # will be updated accordingly.
    ##
    def takeTerrainAt(self, index):
        terrain = self.mTerrainTypes.takeAt(index)
        # Reassign terrain IDs
        for terrainId in range(index, self.mTerrainTypes.size()):
            self.mTerrainTypes.at(terrainId).mId = terrainId

        # Clear and adjust tile terrain references
        for tile in self.mTiles:
            for corner in range(4):
                terrainId = tile.cornerTerrainId(corner)
                if (terrainId == index):
                    tile.setCornerTerrainId(corner, 0xFF)
                elif (terrainId > index):
                    tile.setCornerTerrainId(corner, terrainId - 1)

        self.mTerrainDistancesDirty = True
        return terrain

    ##
    # Returns the transition penalty(/distance) between 2 terrains. -1 if no
    # transition is possible.
    ##
    def terrainTransitionPenalty(self, terrainType0, terrainType1):
        if (self.mTerrainDistancesDirty):
            self.recalculateTerrainDistances()
            self.mTerrainDistancesDirty = False

        if terrainType0 == 255:
            terrainType0 = -1
        if terrainType1 == 255:
            terrainType1 = -1

        # Do some magic, since we don't have a transition array for no-terrain
        if (terrainType0 == -1 and terrainType1 == -1):
            return 0
        if (terrainType0 == -1):
            return self.mTerrainTypes.at(terrainType1).transitionDistance(terrainType0)
        return self.mTerrainTypes.at(terrainType0).transitionDistance(terrainType1)

    ##
    # Adds a new tile to the end of the tileset.
    ##
    def addTile(self, image, source=QString()):
        newTile = Tile(image, source, self.tileCount(), self)
        self.mTiles.append(newTile)
        if (self.mTileHeight < image.height()):
            self.mTileHeight = image.height()
        if (self.mTileWidth < image.width()):
            self.mTileWidth = image.width()
        return newTile

    def insertTiles(self, index, tiles):
        count = tiles.count()
        for i in range(count):
            self.mTiles.insert(index + i, tiles.at(i))
        # Adjust the tile IDs of the remaining tiles
        for i in range(index + count, self.mTiles.size()):
            self.mTiles.at(i).mId += count
        self.updateTileSize()

    def removeTiles(self, index, count):
        first = self.mTiles.begin() + index
        last = first + count
        last = self.mTiles.erase(first, last)
        # Adjust the tile IDs of the remaining tiles
        for last in self.mTiles:
            last.mId -= count
        self.updateTileSize()

    ##
    # Sets the \a image to be used for the tile with the given \a id.
    ##
    def setTileImage(self, id, image, source = QString()):
        # This operation is not supposed to be used on tilesets that are based
        # on a single image
        tile = self.tileAt(id)
        if (not tile):
            return
        previousImageSize = tile.image().size()
        newImageSize = image.size()
        tile.setImage(image)
        tile.setImageSource(source)
        if (previousImageSize != newImageSize):
            # Update our max. tile size
            if (previousImageSize.height() == self.mTileHeight or
                    previousImageSize.width() == self.mTileWidth):
                # This used to be the max image; we have to recompute
                self.updateTileSize()
            else:
                # Check if we have a new maximum
                if (self.mTileHeight < newImageSize.height()):
                    self.mTileHeight = newImageSize.height()
                if (self.mTileWidth < newImageSize.width()):
                    self.mTileWidth = newImageSize.width()

    ##
    # Used by the Tile class when its terrain information changes.
    ##
    def markTerrainDistancesDirty(self):
        self.mTerrainDistancesDirty = True

    ##
    # Sets tile size to the maximum size.
    ##
    def updateTileSize(self):
        maxWidth = 0
        maxHeight = 0
        for tile in self.mTiles:
            size = tile.size()
            if (maxWidth < size.width()):
                maxWidth = size.width()
            if (maxHeight < size.height()):
                maxHeight = size.height()

        self.mTileWidth = maxWidth
        self.mTileHeight = maxHeight

    ##
    # Calculates the transition distance matrix for all terrain types.
    ##
    def recalculateTerrainDistances(self):
        # some fancy macros which can search for a value in each byte of a word simultaneously
        def hasZeroByte(dword):
            return (dword - 0x01010101) & ~dword & 0x80808080

        def hasByteEqualTo(dword, value):
            return hasZeroByte(dword ^ int(~0/255 * value))

        # Terrain distances are the number of transitions required before one terrain may meet another
        # Terrains that have no transition path have a distance of -1
        for i in range(self.terrainCount()):
            type = self.terrain(i)
            distance = QVector()
            for _x in range(self.terrainCount() + 1):
                distance.append(-1)
            # Check all tiles for transitions to other terrain types
            for j in range(self.tileCount()):
                t = self.tileAt(j)
                if (not hasByteEqualTo(t.terrain(), i)):
                    continue
                # This tile has transitions, add the transitions as neightbours (distance 1)
                tl = t.cornerTerrainId(0)
                tr = t.cornerTerrainId(1)
                bl = t.cornerTerrainId(2)
                br = t.cornerTerrainId(3)
                # Terrain on diagonally opposite corners are not actually a neighbour
                if (tl == i or br == i):
                    distance[tr + 1] = 1
                    distance[bl + 1] = 1

                if (tr == i or bl == i):
                    distance[tl + 1] = 1
                    distance[br + 1] = 1

                # terrain has at least one tile of its own type
                distance[i + 1] = 0

            type.setTransitionDistances(distance)

        # Calculate indirect transition distances
        bNewConnections = False
        # Repeat while we are still making new connections (could take a
        # number of iterations for distant terrain types to connect)
        while bNewConnections:
            bNewConnections = False
            # For each combination of terrain types
            for i in range(self.terrainCount()):
                t0 = self.terrain(i)
                for j in range(self.terrainCount()):
                    if (i == j):
                        continue
                    t1 = self.terrain(j)
                    # Scan through each terrain type, and see if we have any in common
                    for t in range(-1, self.terrainCount()):
                        d0 = t0.transitionDistance(t)
                        d1 = t1.transitionDistance(t)
                        if (d0 == -1 or d1 == -1):
                            continue
                        # We have cound a common connection
                        d = t0.transitionDistance(j)
                        # If the new path is shorter, record the new distance
                        if (d == -1 or d0 + d1 < d):
                            d = d0 + d1
                            t0.setTransitionDistance(j, d)
                            t1.setTransitionDistance(i, d)
                            # We're making progress, flag for another iteration...
                            bNewConnections = True

    def sharedPointer(self):
        return self.mWeakPointer
Beispiel #15
0
    def fill_zatravka(self, x_zatravka, y_zatravka):
        stack = [[x_zatravka, y_zatravka]]
        fill_color = self.colormain
        line_color = QColor(0, 0, 0)
        line_color = line_color.rgb()
        while (len(stack)):
            QApplication.processEvents()
            x, y = stack.pop()
            self.image.setPixel(x, y, fill_color)
            temp_x = x

            while (self.image.pixelColor(x, y).rgb() != line_color):
                self.image.setPixel(x, y, fill_color)
                x += 1
            x_prav = x - 1

            x = temp_x
            while (self.image.pixelColor(x, y).rgb() != line_color):
                self.image.setPixel(x, y, fill_color)
                x -= 1

            self.repaint()

            x_lev = x + 1

            #++++++++++++++++++++++++++
            x = x_lev
            y += 1
            while (x <= x_prav):
                flag = False
                while (self.image.pixelColor(x, y).rgb() != line_color
                       and self.image.pixelColor(x, y).rgb() != fill_color
                       and x <= x_prav):
                    if flag == False:
                        flag = True
                    x += 1

                if flag == True:
                    if (self.image.pixelColor(x, y).rgb() != line_color
                            and self.image.pixelColor(x, y).rgb() != fill_color
                            and x == x_prav):
                        stack.append([x, y])
                    else:
                        stack.append([x - 1, y])
                    flag = False

                x_vhod = x
                while (self.image.pixelColor(x, y).rgb() != line_color
                       and self.image.pixelColor(x, y).rgb() != fill_color
                       and x < x_prav):
                    x += 1

                if x == x_vhod:
                    x += 1
            x = x_lev
            y -= 2
            #Second part
            while (x <= x_prav):
                flag = False
                while (self.image.pixelColor(x, y).rgb() != line_color
                       and self.image.pixelColor(x, y).rgb() != fill_color
                       and x <= x_prav):
                    if flag == False:
                        flag = True
                    x += 1

                if flag == True:
                    if (self.image.pixelColor(x, y).rgb() != line_color
                            and self.image.pixelColor(x, y).rgb() != fill_color
                            and x == x_prav):
                        stack.append([x, y])
                    else:
                        stack.append([x - 1, y])
                    flag = False

                x_vhod = x
                while (self.image.pixelColor(x, y).rgb() != line_color
                       and self.image.pixelColor(x, y).rgb() != fill_color
                       and x < x_prav):
                    x += 1

                if x == x_vhod:
                    x += 1
Beispiel #16
0
    def loadColorPanel(self):
        self.qsst.srctext = self.editor.text()
        if not self.qsst.loadVars():
            return
        # item = self.colorGridLayout.itemAt(0)
        # while (item != None):
        #     self.colorGridLayout.removeItem(item)
        #     # self.colorGridLayout.removeWidget(item.widget())
        #     # item.widget().setParent(None)#这三行没有作用
        #     sip.delete(item.widget())  # 虽然控件删除了,但是grid的行数列数没减少,但是不影响使用
        #     sip.delete(item)
        #     item = self.colorGridLayout.itemAt(0)
        # self.colorGridLayout.update()  # 不起作用

        # a,b=list(self.clrBtnDict.keys()),list(self.qsst.varDict.keys());a.sort();b.sort()
        if sorted(list(self.clrBtnDict.keys())) != sorted(
                list(self.qsst.varDict.keys())):
            while self.colorPanelLayout.count() > 0:
                self.colorPanelLayout.removeItem(
                    self.colorPanelLayout.itemAt(0))
            self.clrBtnDict = {}
            labels = {}
            widLabel = 0
            widBtn = 0
            for varName, clrStr in self.qsst.varDict.items():
                label = QLabel(varName)  # , contianerWidget)
                btn = QPushButton(clrStr)  # , contianerWidget)
                if sys.platform.startswith("win"):
                    font1 = QFont("Arial", 10, QFont.Medium)
                    font2 = QFont("sans-serif", 9, QFont.Medium)
                    label.setFont(font1)
                    btn.setFont(font2)
                self.clrBtnDict[varName] = btn
                labels[varName] = label
                label.adjustSize()
                widLabel = label.width(
                ) if label.width() > widLabel else widLabel
                btn.adjustSize()
                widBtn = btn.width() if btn.width() > widBtn else widBtn
                # label.move(5, 5)
                # btn.move(100, 5)
                btn.clicked.connect(lambda x, var=varName: self.chclr(var))
            for name, btn in self.clrBtnDict.items():
                contianerWidget = QWidget()
                lay = QHBoxLayout()
                labels[name].setFixedWidth(widLabel)
                btn.setFixedWidth(widBtn)
                lay.addWidget(labels[name])
                lay.addWidget(btn)
                contianerWidget.setLayout(lay)
                # contianerWidget.setMinimumSize(QSize(185, 25))
                self.colorPanelLayout.addWidget(contianerWidget)

        for varName, btn in self.clrBtnDict.items():
            clrStr = self.qsst.varDict[varName]
            btn.setText(clrStr)
            if "rgb" in clrStr:
                t = clrStr.strip(r" rgba()")
                c = t.split(',')
                if len(c) > 3:
                    lable = c[3]
                else:
                    lable = 255
                try:
                    color = QColor(int(c[0]), int(c[1]), int(c[2]), lable)
                except Exception:
                    continue
            else:
                try:
                    color = QColor(clrStr)
                except Exception:
                    continue
            s = ''
            if qGray(color.rgb()) < 100:
                s += "color:white;"
            else:
                s += "color:black;"

            btn.setStyleSheet(s + "background:" + btn.text())
Beispiel #17
0
class STGWindow(QtWidgets.QMainWindow):
    def __init__(self, parent_settings, parent=None, callback=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.ui = SettingsWindow.Ui_MainWindow()
        self.ui.setupUi(self)

        self.color = QColor()

        self.parent_settings = parent_settings
        self.settings = Settings('config/settings.json')
        self.settings.load_json()

        self.ui.pushButton_2.clicked.connect(self.close)
        self.ui.pushButton.clicked.connect(self.apply)
        self.ui.pushButton_3.clicked.connect(self.ok)
        self.ui.pushButton_4.clicked.connect(self.rollback)
        self.ui.pushButton_5.clicked.connect(self.select_color)
        self.ui.pushButton_6.clicked.connect(self.apply_all)

        self.ui.checkBox.stateChanged.connect(self.change_enabled)
        self.ui.spinBox.valueChanged.connect(self.change_border_size)
        self.ui.spinBox_2.valueChanged.connect(self.change_text_size)
        self.ui.doubleSpinBox.valueChanged.connect(self.change_confidence)
        self.ui.lineEdit.textChanged.connect(self.change_color)

        self.ui.listWidget.itemClicked.connect(self.list_select)
        for dct in self.settings.CLASSES:
            self.ui.listWidget.insertItem(0, dct['name'])

        self.ui.listWidget.setCurrentRow(0)
        self.list_select(self.ui.listWidget.currentItem())

    def apply_all(self):
        rgb = self.color.getRgb()
        for info in self.settings.CLASSES:
            info['color'] = [rgb[0], rgb[1], rgb[2]]
            info['confidence'] = self.ui.doubleSpinBox.value()
            info['border_size'] = self.ui.spinBox.value()
            info['text_size'] = self.ui.spinBox_2.value()
            info['enabled'] = self.ui.checkBox.isChecked()

    def change_color(self, value):
        invert = QColor(255, 255, 255)
        invert.setRgb(invert.rgb() - self.color.rgb())
        self.ui.lineEdit.setStyleSheet(
            "QWidget { background-color: %s; color: %s}" %
            (self.color.name(), invert.name()))

        name = self.ui.listWidget.currentItem().text()
        info = self.settings.getClassFromName(name)
        rgb = self.color.getRgb()
        info['color'] = [rgb[0], rgb[1], rgb[2]]

    def select_color(self):
        self.color = QColorDialog.getColor()
        self.ui.lineEdit.setText(self.color.name())

    def change_confidence(self, value):
        name = self.ui.listWidget.currentItem().text()
        info = self.settings.getClassFromName(name)
        info['confidence'] = value

    def change_border_size(self, value):
        name = self.ui.listWidget.currentItem().text()
        info = self.settings.getClassFromName(name)
        info['border_size'] = value

    def change_text_size(self, value):
        name = self.ui.listWidget.currentItem().text()
        info = self.settings.getClassFromName(name)
        info['text_size'] = value

    def change_enabled(self):
        name = self.ui.listWidget.currentItem().text()
        info = self.settings.getClassFromName(name)
        info['enabled'] = self.ui.checkBox.isChecked()

    def rollback(self):
        self.settings.default()
        self.list_select(self.ui.listWidget.currentItem())

    def ok(self):
        self.apply()
        self.close()

    def apply(self):
        self.settings.save_json()
        self.parent_settings.load_json()

    def list_select(self, item):
        info = self.settings.getClassFromName(item.text())
        self.ui.checkBox.setChecked(info['enabled'])
        self.ui.spinBox.setValue(info['border_size'])
        self.ui.spinBox_2.setValue(info['text_size'])
        self.ui.doubleSpinBox.setValue(info['confidence'])

        self.color = QColor(info['color'][0], info['color'][1],
                            info['color'][2])
        self.ui.lineEdit.setText(self.color.name())
Beispiel #18
0
class ImageLayer(Layer):
    ##
    # Constructor.
    ##
    def __init__(self, name, x, y, width, height):
        super().__init__(Layer.ImageLayerType, name, x, y, width, height)

        self.mImage = QPixmap()
        self.mTransparentColor = QColor()
        self.mImageSource = QString()

    ##
    # Destructor.
    ##
    def __del__(self):
        pass

    def usedTilesets(self):
        return QSet()

    def referencesTileset(self, arg1):
        return False

    def replaceReferencesToTileset(self, arg1, arg2):
        pass

    def canMergeWith(self, arg1):
        return False

    def mergedWith(self, arg1):
        return None

    ##
    # Returns the transparent color, or an invalid color if no transparent
    # color is used.
    ##
    def transparentColor(self):
        return QColor(self.mTransparentColor)

    ##
    # Sets the transparent color. Pixels with this color will be masked out
    # when loadFromImage() is called.
    ##
    def setTransparentColor(self, c):
        self.mTransparentColor = c

    ##
    #  Sets image source file name
    ##
    def setSource(self, source):
        self.mImageSource = source

    ##
    # Returns the file name of the layer image.
    ##
    def imageSource(self):
        return self.mImageSource

    ##
    # Returns the image of this layer.
    ##
    def image(self):
        return QPixmap(self.mImage)

    ##
    # Sets the image of this layer.
    ##
    def setImage(self, image):
        self.mImage = image

    ##
    # Resets layer image.
    ##
    def resetImage(self):
        self.mImage = QPixmap()
        self.mImageSource = ''

    ##
    # Load this layer from the given \a image. This will replace the existing
    # image. The \a fileName becomes the new imageSource, regardless of
    # whether the image could be loaded.
    #
    # @param image    the image to load the layer from
    # @param fileName the file name of the image, which will be remembered
    #                 as the image source of this layer.
    # @return <code>true</code> if loading was successful, otherwise
    #         returns <code>false</code>
    ##
    def loadFromImage(self, image, fileName):
        self.mImageSource = fileName
        if (image.isNull()):
            self.mImage = QPixmap()
            return False

        self.mImage = QPixmap.fromImage(image)
        if (self.mTransparentColor.isValid()):
            mask = image.createMaskFromColor(self.mTransparentColor.rgb())
            self.mImage.setMask(QBitmap.fromImage(mask))

        return True

    ##
    # Returns True if no image source has been set.
    ##
    def isEmpty(self):
        return self.mImage.isNull()

    def clone(self):
        return self.initializeClone(ImageLayer(self.mName, self.mX, self.mY, self.mWidth, self.mHeight))

    def initializeClone(self, clone):
        super().initializeClone(clone)
        clone.mImageSource = self.mImageSource
        clone.mTransparentColor = self.mTransparentColor
        clone.mImage = self.mImage
        return clone
 def get_vector(color: QColor) -> tuple:
     rgb = color.rgb()
     return qRed(rgb), qGreen(rgb), qBlue(rgb)
Beispiel #20
0
class ImageLayer(Layer):
    ##
    # Constructor.
    ##
    def __init__(self, name, x, y, width, height):
        super().__init__(Layer.ImageLayerType, name, x, y, width, height)

        self.mImage = QPixmap()
        self.mTransparentColor = QColor()
        self.mImageSource = QString()

    ##
    # Destructor.
    ##
    def __del__(self):
        pass

    def usedTilesets(self):
        return QSet()

    def referencesTileset(self, arg1):
        return False

    def replaceReferencesToTileset(self, arg1, arg2):
        pass

    def canMergeWith(self, arg1):
        return False

    def mergedWith(self, arg1):
        return None

    ##
    # Returns the transparent color, or an invalid color if no transparent
    # color is used.
    ##
    def transparentColor(self):
        return QColor(self.mTransparentColor)

    ##
    # Sets the transparent color. Pixels with this color will be masked out
    # when loadFromImage() is called.
    ##
    def setTransparentColor(self, c):
        self.mTransparentColor = c

    ##
    #  Sets image source file name
    ##
    def setSource(self, source):
        self.mImageSource = source

    ##
    # Returns the file name of the layer image.
    ##
    def imageSource(self):
        return self.mImageSource

    ##
    # Returns the image of this layer.
    ##
    def image(self):
        return QPixmap(self.mImage)

    ##
    # Sets the image of this layer.
    ##
    def setImage(self, image):
        self.mImage = image

    ##
    # Resets layer image.
    ##
    def resetImage(self):
        self.mImage = QPixmap()
        self.mImageSource = ''

    ##
    # Load this layer from the given \a image. This will replace the existing
    # image. The \a fileName becomes the new imageSource, regardless of
    # whether the image could be loaded.
    #
    # @param image    the image to load the layer from
    # @param fileName the file name of the image, which will be remembered
    #                 as the image source of this layer.
    # @return <code>true</code> if loading was successful, otherwise
    #         returns <code>false</code>
    ##
    def loadFromImage(self, image, fileName):
        self.mImageSource = fileName
        if (image.isNull()):
            self.mImage = QPixmap()
            return False

        self.mImage = QPixmap.fromImage(image)
        if (self.mTransparentColor.isValid()):
            mask = image.createMaskFromColor(self.mTransparentColor.rgb())
            self.mImage.setMask(QBitmap.fromImage(mask))

        return True

    ##
    # Returns True if no image source has been set.
    ##
    def isEmpty(self):
        return self.mImage.isNull()

    def clone(self):
        return self.initializeClone(
            ImageLayer(self.mName, self.mX, self.mY, self.mWidth,
                       self.mHeight))

    def initializeClone(self, clone):
        super().initializeClone(clone)
        clone.mImageSource = self.mImageSource
        clone.mTransparentColor = self.mTransparentColor
        clone.mImage = self.mImage
        return clone
Beispiel #21
0
 def setColor(self, color: QColor):
     # RGB channels are used for widget color bar display
     self.color = QColor(color.rgb())
     # Alpha channel will be used as the new widget value
     self.value = color.alpha()
     self.update()
Beispiel #22
0
Datei: app.py Projekt: ipapi/ipap
def grayscale_colortable():
    table = []
    for i in range(0, 256):
        color = QColor(i, i, i)
        table.append(color.rgb())
    return table
Beispiel #23
0
class Setting:
    settingDefault = {
        'X': 1320,
        'Y': 850,
        'W': 600,
        'H': 300,
        'TP': 0.5,
        'CL': QColor(Qt.darkCyan).rgb(),
        'FM': 'hh:mm'
    }
    settingMinMax = {
        'X': [0, 9999],
        'Y': [0, 9999],
        'W': [0, 9999],
        'H': [0, 9999],
        'TP': [0.0, 1.0],
        'CL': [QColor(0, 0, 0).rgb(),
               QColor(255, 255, 255).rgb()],
        'FM': ['hh:mm:ss', 'hh:mm']
    }

    def SettingSave(self):
        try:
            with open('setting.json', 'w', encoding='utf8') as file:
                setting = dict()
                setting['X'] = self.X
                setting['Y'] = self.Y
                setting['W'] = self.W
                setting['H'] = self.H
                setting['TP'] = self.TP
                setting['CL'] = self.CL
                setting['FM'] = self.FM
                json.dump(setting, file)
        except Exception as identifier:
            print(('setting.json save error!', identifier))
            pass

    def SettingLoadOne(self, setting, name, continued):
        if continued:
            if name not in setting or type(setting[name]) != type(
                    self.settingDefault[name]
            ) or setting[name] < self.settingMinMax[name][0] or setting[
                    name] > self.settingMinMax[name][1]:
                print('%s load bad!' % name)
                return self.settingDefault[name]
            else:
                return setting[name]
        else:
            if name not in setting or type(setting[name]) != type(
                    self.settingDefault[name]
            ) or setting[name] not in self.settingMinMax[name]:
                print('%s load bad!' % name)
                return self.settingDefault[name]
            else:
                return setting[name]

    def SettingLoad(self):
        try:
            with open('setting.json', 'r', encoding='utf8') as file:
                setting = json.loads(file.read())
                self.X = self.SettingLoadOne(setting, 'X', True)
                self.Y = self.SettingLoadOne(setting, 'Y', True)
                self.W = self.SettingLoadOne(setting, 'W', True)
                self.H = self.SettingLoadOne(setting, 'H', True)
                self.TP = self.SettingLoadOne(setting, 'TP', True)
                self.CL = self.SettingLoadOne(setting, 'CL', True)
                self.FM = self.SettingLoadOne(setting, 'FM', False)
        except Exception as identifier:
            print(('setting.json load error!', identifier))
            self.X = self.settingDefault['X']
            self.Y = self.settingDefault['Y']
            self.W = self.settingDefault['W']
            self.H = self.settingDefault['H']
            self.TP = self.settingDefault['TP']
            self.CL = self.settingDefault['CL']
            self.FM = self.settingDefault['FM']

    def SettingDialog(self, ApplyChange):
        from PyQt5.QtWidgets import (QDialog, QSpinBox, QComboBox,
                                     QDialogButtonBox, QFormLayout,
                                     QColorDialog, QPushButton, QSizePolicy)

        dialog = self.dialog = QDialog()
        dialog.setWindowTitle('设置')
        if hasattr(sys, "_MEIPASS"):
            dialog.setWindowIcon(QIcon(sys._MEIPASS + r'/Icon.ico'))
        else:
            dialog.setWindowIcon(QIcon(r'./Icon.ico'))

        boxX = QSpinBox(dialog)
        boxX.setRange(-100000, 100000)
        boxX.setValue(self.X)
        boxY = QSpinBox(dialog)
        boxY.setRange(-100000, 100000)
        boxY.setValue(self.Y)
        boxW = QSpinBox(dialog)
        boxW.setRange(0, 100000)
        boxW.setValue(self.W)
        boxH = QSpinBox(dialog)
        boxH.setRange(0, 100000)
        boxH.setValue(self.H)

        boxTP = QSpinBox(dialog)
        boxTP.setRange(0, 100)
        boxTP.setValue(self.TP * 100)

        self.buttonColorVal = QColor(self.CL)
        self.buttonColor = QPushButton(parent=dialog)
        self.buttonColor.setStyleSheet('QWidget {background-color:%s}' %
                                       self.buttonColorVal.name())

        def ChangeCol():
            qcd = QColorDialog(dialog)
            qcd.setWindowTitle('颜色选择')
            qcd.setCurrentColor(self.buttonColorVal)
            if qcd.exec() == QDialog.Accepted:
                self.buttonColorVal = qcd.selectedColor()
                self.buttonColor.setStyleSheet(
                    'QWidget {background-color:%s}' %
                    self.buttonColorVal.name())

        self.buttonColor.clicked.connect(ChangeCol)

        boxFM = QComboBox(dialog)
        boxFM.addItems(self.settingMinMax['FM'])
        boxFM.setCurrentIndex(boxFM.findText(self.FM))

        def Apply():
            self.X = boxX.value()
            self.Y = boxY.value()
            self.W = boxW.value()
            self.H = boxH.value()
            self.TP = boxTP.value() / 100.0
            self.CL = self.buttonColorVal.rgb()
            self.FM = boxFM.currentText()
            ApplyChange()
            self.SettingSave()

        buttonBox = QDialogButtonBox(
            QDialogButtonBox.Apply | QDialogButtonBox.Ok
            | QDialogButtonBox.Cancel, Qt.Horizontal, dialog)
        buttonBox.button(QDialogButtonBox.Apply).setText("应用")
        buttonBox.button(QDialogButtonBox.Ok).setText("确定")
        buttonBox.button(QDialogButtonBox.Cancel).setText("取消")
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.button(QDialogButtonBox.Apply).clicked.connect(Apply)

        form = QFormLayout(dialog)
        form.addRow(QLabel("设置:"))
        form.addRow("坐标X:", boxX)
        form.addRow("坐标Y:", boxY)
        form.addRow("大小W:", boxW)
        form.addRow("大小H:", boxH)
        form.addRow("透明度:", boxTP)
        form.addRow("颜色:", self.buttonColor)
        form.addRow("格式:", boxFM)
        form.addRow(buttonBox)

        dialog.setFixedSize(dialog.sizeHint())

        if dialog.exec() == QDialog.Accepted:
            Apply()
Beispiel #24
0
class AppWindow(QMainWindow):
    def __init__(self):
        super(AppWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.img_area.setScaledContents(False)
        self.ui.img_area.setStyleSheet('border: 1px solid red')
        self.add_tool_bar()
        self.bind_actions()
        self.init_vars()

    def init_vars(self):
        self.open_mode = OPEN_MODE.OPEN_FILE
        self.opened_files = []
        self.cur_img = None
        self.panel_pic = None  # 用来在上面绘制矩阵等形状
        self.origin_img = None  # 保留原始大小的图片
        self.labelimg = None
        self.scale = 1
        self.cur_rect_list = []
        self.cur_label_list = []
        self.histroty = []
        self.fill_color = QColor('green')
        self.pixel_range = [-5, 5]
        self.state = STATE.NORMAL
        self.start_point = None
        self.end_point = None
        self.polygon_points = None
        self.ellipse_points = None
        self.modified = False
        self.saved = False

        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.DEBUG)
        handler = logging.StreamHandler()
        handler.setLevel(logging.DEBUG)
        formatter = logging.Formatter('%(levelname)s %(funcName)s %(message)s')
        handler.setFormatter(formatter)
        self.logger.addHandler(handler)

    def refresh_vars(self):
        self.cur_img = None
        self.panel_pic = None  # 用来在上面绘制矩阵等形状
        self.origin_img = None  # 保留原始大小的图片
        self.labelimg = None
        self.scale = 1
        self.cur_rect_list = []
        self.cur_label_list = []
        self.histroty = []
        self.state = STATE.NORMAL
        self.ui.actionRectangle.setChecked(False)
        self.ui.actionPolygon.setChecked(False)
        self.ui.actionEllipse.setChecked(False)
        self.start_point = None
        self.end_point = None
        self.polygon_points = None
        self.ellipse_points = None
        self.modified = False
        self.saved = False

    def bind_actions(self):
        self.ui.actionOpen_File.triggered.connect(self.open_file)
        self.ui.actionOpen_Dir.triggered.connect(self.open_dir)
        self.ui.file_list.itemClicked.connect(self.file_list_item_changed)
        self.ui.actionZoom_In.triggered.connect(self.zoom_in_pic)
        self.ui.actionZoom_Out.triggered.connect(self.zoom_out_pic)
        self.ui.img_area.mouse_pressed.connect(self.mouse_pressed)
        self.ui.img_area.mouse_move.connect(self.mouse_move)
        self.ui.img_area.mouse_release.connect(self.mouse_release)
        self.ui.actionfill_color.triggered.connect(self.set_fill_color)
        self.ui.actionSet_Pixel_Range.triggered.connect(self.set_pixel_range)
        self.ui.actionUndo.triggered.connect(self.undo)
        self.ui.actionSave.triggered.connect(self.save)
        self.ui.actionPolygon.triggered.connect(self.create_polygon)
        self.ui.actionRectangle.triggered.connect(self.create_rectangle)
        self.ui.actionEllipse.triggered.connect(self.create_ellipse)

    def save(self):
        name = str(self.selected_filename.absolute())
        items = name.split('.')
        output_filename = '.'.join(items[:-1]) + '.npy'
        np.save(output_filename, self.labelimg)
        self.saved = True
        self.modified = False

    def undo(self, checked):
        if self.state == STATE.DRAW_POLYGON and self.polygon_points is not None and self.polygon_points[
                'finish'] is False:
            if len(self.polygon_points['points']) == 1:
                self.polygon_points = None
            elif len(self.polygon_points['points']) > 1:
                self.polygon_points['points'].pop(-1)
                self.draw_lines(self.polygon_points['points'], False)
                if self.labelimg is not None:
                    pic = self.draw_points()
                    self.show_pic(file_name=None, content=pic)
                else:
                    self.show_pic(file_name=None, content=self.panel_pic)
        else:
            if len(self.histroty) == 0:
                return
            x, y = self.histroty.pop(-1)
            self.labelimg[x, y] = 0
            pic = self.draw_points()
            self.show_pic(file_name=None, content=pic)
            self.modified = True

    def set_fill_color(self, checked):
        color = QColorDialog.getColor()
        if color.isValid():
            self.fill_color = color

    def set_pixel_range(self, checked):
        dialog = PixelRangeDialog()
        if dialog.exec_():
            v1, v2 = dialog.get_result()
            self.pixel_range = [v1, v2]
            self.logger.debug(self.pixel_range)

    def create_polygon(self, checked):
        if checked:
            self.state = STATE.DRAW_POLYGON
            self.ui.actionEllipse.setChecked(False)
            self.ui.actionRectangle.setChecked(False)
        else:
            self.state = STATE.NORMAL

    def create_rectangle(self, checked):
        if checked:
            self.state = STATE.DRAW_RECTANGLE
            self.ui.actionEllipse.setChecked(False)
            self.ui.actionPolygon.setChecked(False)
        else:
            self.state = STATE.NORMAL

    def create_ellipse(self, checked):
        if checked:
            self.state = STATE.DRAW_ELLIPSE
            self.ui.actionPolygon.setChecked(False)
            self.ui.actionRectangle.setChecked(False)
        else:
            self.state = STATE.NORMAL

    def pos_in_img_area(self, pos: PyQt5.QtCore.QPoint):
        if self.cur_img is None:
            return False, None
        width = self.ui.img_area.width()
        height = self.ui.img_area.height()
        img_height, img_width, _ = self.cur_img.shape
        w = (width - img_width) // 2
        h = (height - img_height) // 2
        x_valid = w <= pos.x() <= w + img_width
        y_valid = h <= pos.y() <= h + img_height
        valid = x_valid and y_valid
        if valid:
            return True, (pos.x() - w, pos.y() - h)
        else:
            return False, None

    def mouse_pressed(self, ev: QMouseEvent):
        if self.state == STATE.NORMAL:
            return
        if ev.button() == Qt.LeftButton:
            pos = ev.pos()
            valid, relative_pos = self.pos_in_img_area(pos)
            self.logger.debug(valid)
            if valid:
                self.logger.debug(relative_pos)
                point = (int(relative_pos[0] / self.scale),
                         int(relative_pos[1] / self.scale))
                if self.state == STATE.DRAW_RECTANGLE:
                    self.start_point = point
                    self.end_point = None
                    self.logger.debug(self.start_point)
                elif self.state == STATE.DRAW_POLYGON:
                    if self.polygon_points is None or self.polygon_points[
                            'finish'] is True:
                        self.polygon_points = {
                            'finish': False,
                            'points': [point]
                        }
                    else:
                        p1 = np.array([
                            self.polygon_points['points'][0][0] * self.scale,
                            self.polygon_points['points'][0][1] * self.scale
                        ])
                        p2 = np.array(
                            [point[0] * self.scale, point[1] * self.scale])
                        dis = np.linalg.norm(p1 - p2, 2)
                        if dis < 10:
                            self.polygon_points['finish'] = True
                            self.draw_lines(self.polygon_points['points'],
                                            True)
                        else:
                            self.polygon_points['points'].append(point)
                            self.draw_lines(self.polygon_points['points'],
                                            False)
                        if self.labelimg is not None:
                            pic = self.draw_points()
                            self.show_pic(file_name=None, content=pic)
                        else:
                            self.show_pic(file_name=None,
                                          content=self.panel_pic)
                elif self.state == STATE.DRAW_ELLIPSE:
                    if self.ellipse_points is None:
                        self.ellipse_points = {'points': [point], 'info': None}
                    elif len(self.ellipse_points['points']) == 1:
                        self.ellipse_points['points'].append(point)
                        self.draw_lines(self.ellipse_points['points'], False)
                        if self.labelimg is not None:
                            pic = self.draw_points()
                            self.show_pic(file_name=None, content=pic)
                        else:
                            self.show_pic(file_name=None,
                                          content=self.panel_pic)
                    elif len(self.ellipse_points['points']) == 2:
                        self.ellipse_points['points'].append(point)
                        self.ellipse_points['info'] = self.draw_ellipse(
                            self.ellipse_points['points'])
                        if self.labelimg is not None:
                            pic = self.draw_points()
                            self.show_pic(file_name=None, content=pic)
                        else:
                            self.show_pic(file_name=None,
                                          content=self.panel_pic)
                    else:
                        self.ellipse_points = {'points': [point], 'info': None}
                else:
                    raise NotImplementedError()
        elif ev.button() == Qt.RightButton:
            pass

    def mouse_move(self, ev: QMouseEvent):
        if self.state == STATE.NORMAL:
            return
        pos = ev.pos()
        valid, relative_pos = self.pos_in_img_area(pos)
        if valid:
            relative_pos = (int(relative_pos[0] / self.scale),
                            int(relative_pos[1] / self.scale))
            if self.state == STATE.DRAW_RECTANGLE:
                self.draw_rect(self.start_point, relative_pos)
                if self.labelimg is not None:
                    pic = self.draw_points()
                    self.show_pic(file_name=None, content=pic)
                else:
                    self.show_pic(file_name=None, content=self.panel_pic)
            elif self.state == STATE.DRAW_POLYGON:
                pass
            elif self.state == STATE.DRAW_ELLIPSE:
                pass
            else:
                raise NotImplementedError()

    def draw_ellipse(self, points):
        color_r, color_g, color_b = self.fill_color.red(
        ), self.fill_color.green(), self.fill_color.blue()
        points = list(
            map(
                lambda item:
                (int(item[0] * self.scale), int(item[1] * self.scale)),
                points))
        p1 = np.array(points[0])
        p2 = np.array(points[1])
        if p1[0] > p2[0]:
            p1, p2 = p2, p1
        p3 = np.array(points[2])
        center = tuple((p1 + p2) // 2)
        r1 = int(np.linalg.norm(p1 - p2, 2) / 2)
        a = p2[1] - p1[1]
        b = p1[0] - p2[0]
        c = p2[0] * p1[1] - p1[0] * p2[1]
        r2 = int(np.abs(a * p3[0] + b * p3[1] + c) / np.sqrt(a**2 + b**2))
        if r1 > r2:
            theta = -1 * (np.arctan(a / b) * 180) / np.pi
            self.panel_pic = cv.ellipse(self.cur_img.copy(), center, (r1, r2),
                                        theta, 0, 360,
                                        (color_r, color_g, color_b), 1)
            return ((int(center[0] / self.scale), int(center[1] / self.scale)),
                    (int(r1 / self.scale), int(r2 / self.scale)), theta)
        else:
            theta = (np.arctan(a / b) * 180) / np.pi
            if theta > 0:
                theta = 90 - theta
            else:
                theta = -90 - theta
            self.panel_pic = cv.ellipse(self.cur_img.copy(), center, (r2, r1),
                                        theta, 0, 360,
                                        (color_r, color_g, color_b), 1)
            return ((int(center[0] / self.scale), int(center[1] / self.scale)),
                    (int(r2 / self.scale), int(r1 / self.scale)), theta)

    def draw_lines(self, points, end=False):
        b, g, r = self.fill_color.blue(), self.fill_color.green(
        ), self.fill_color.red()
        temp_img = self.cur_img.copy()
        points = list(
            map(
                lambda item:
                (int(item[0] * self.scale), int(item[1] * self.scale)),
                points))
        for i in range(len(points) - 1):
            temp_img = cv.line(temp_img, points[i], points[i + 1], (r, g, b),
                               1)
        if end:
            temp_img = cv.line(temp_img, points[-1], points[0], (r, g, b), 1)
        self.panel_pic = temp_img

    def draw_rect(self, start_point, end_point):
        b, g, r = self.fill_color.blue(), self.fill_color.green(
        ), self.fill_color.red()
        self.fill_color.rgb()
        start_point = (int(start_point[0] * self.scale),
                       int(start_point[1] * self.scale))
        end_point = (int(end_point[0] * self.scale),
                     int(end_point[1] * self.scale))
        self.panel_pic = cv.rectangle(self.cur_img.copy(), start_point,
                                      end_point, (r, g, b), 1)

    def draw_points(self):
        if self.labelimg is None:
            return
        b, g, r = self.fill_color.blue(), self.fill_color.green(
        ), self.fill_color.red()
        x, y = np.where(self.labelimg == 1)
        temp = self.panel_pic.copy()
        for i in range(x.shape[0]):
            cv.circle(temp, (int(y[i] * self.scale), int(x[i] * self.scale)),
                      1, (r, g, b), 1)
        return temp

    def mouse_release(self, ev: QMouseEvent):
        if self.state == STATE.NORMAL:
            return
        if ev.button() == Qt.LeftButton:
            if self.state == STATE.DRAW_RECTANGLE:
                pos = ev.pos()
                valid, relative_pos = self.pos_in_img_area(pos)
                self.logger.debug(valid)
                if valid:
                    self.logger.debug(relative_pos)
                    self.end_point = (int(relative_pos[0] / self.scale),
                                      int(relative_pos[1] / self.scale))
        elif ev.button() == Qt.RightButton:
            if self.state == STATE.NORMAL:
                return
            if self.state == STATE.DRAW_RECTANGLE:
                if self.start_point is None or self.end_point is None:
                    return
                pos = ev.pos()
                valid, relative_pos = self.pos_in_img_area(pos)
                if valid:
                    click_pos = (int(relative_pos[0] / self.scale),
                                 int(relative_pos[1] / self.scale))
                    min_x, max_x = min(self.start_point[0],
                                       self.end_point[0]), max(
                                           self.start_point[0],
                                           self.end_point[0])
                    min_y, max_y = min(self.start_point[1],
                                       self.end_point[1]), max(
                                           self.start_point[1],
                                           self.end_point[1])
                    self.logger.debug(click_pos)
                    if min_x <= click_pos[0] <= max_x and min_y <= click_pos[
                            1] <= max_y:
                        pixel_value = self.origin_img[click_pos[1],
                                                      click_pos[0], 0]
                        low, high = pixel_value + \
                            self.pixel_range[0], pixel_value + \
                            self.pixel_range[1]
                        selected_area = self.origin_img[min_y:max_y + 1,
                                                        min_x:max_x + 1, 0]
                        x, y = np.where(
                            (selected_area >= low) * (selected_area <= high))
                        x = x + min_y
                        y = y + min_x
                        self.labelimg[x, y] = 1
                        pic = self.draw_points()
                        self.show_pic(file_name=None, content=pic)
                        self.histroty.append((x, y))
                        self.modified = True
            elif self.state == STATE.DRAW_POLYGON:
                if self.polygon_points is None or self.polygon_points[
                        'finish'] is False:
                    return
                pos = ev.pos()
                valid, relative_pos = self.pos_in_img_area(pos)
                if valid:
                    click_pos = (int(relative_pos[0] / self.scale),
                                 int(relative_pos[1] / self.scale))
                    self.logger.debug(click_pos)
                    x_pos = np.array(
                        [item[0] for item in self.polygon_points['points']])
                    y_pos = np.array(
                        [item[1] for item in self.polygon_points['points']])
                    min_x, max_x = x_pos.min(), x_pos.max()
                    min_y, max_y = y_pos.min(), y_pos.max()
                    p = np.array(self.polygon_points['points']).reshape(
                        [1, len(self.polygon_points['points']), 2])
                    p[0, :, 0] -= min_x
                    p[0, :, 1] -= min_y
                    mask = np.zeros([max_y - min_y + 1, max_x - min_x + 1],
                                    np.uint8)
                    mask = cv.fillPoly(mask, p, 1)
                    pixel_value = self.origin_img[click_pos[1], click_pos[0],
                                                  0]
                    low, high = pixel_value + \
                        self.pixel_range[0], pixel_value + self.pixel_range[1]
                    selected_img = self.origin_img[min_y:max_y + 1,
                                                   min_x:max_x + 1, 0]
                    x, y = np.where(
                        (selected_img >= low) * (selected_img <= high) * mask)
                    x = x + min_y
                    y = y + min_x
                    self.labelimg[x, y] = 1
                    pic = self.draw_points()
                    self.show_pic(file_name=None, content=pic)
                    self.histroty.append((x, y))
                    self.modified = True
            elif self.state == STATE.DRAW_ELLIPSE:
                if self.ellipse_points is None or len(
                        self.ellipse_points['points']
                ) < 3 or self.ellipse_points['info'] is None:
                    return
                pos = ev.pos()
                valid, relative_pos = self.pos_in_img_area(pos)
                if valid:
                    click_pos = (int(relative_pos[0] / self.scale),
                                 int(relative_pos[1] / self.scale))
                    self.logger.debug(click_pos)
                    center, r, theta = self.ellipse_points['info']
                    theta = int(np.around(theta))
                    p = cv.ellipse2Poly(center, r, theta, 0, 360, 1)
                    num_p = p.shape[0]
                    p = p.reshape((1, num_p, 2))
                    min_x, max_x = np.min(p[0, :, 0]), np.max(p[0, :, 0])
                    min_y, max_y = np.min(p[0, :, 1]), np.max(p[0, :, 1])
                    p[0, :, 0] -= min_x
                    p[0, :, 1] -= min_y
                    mask = np.zeros((max_y - min_y + 1, max_x - min_x + 1),
                                    np.uint8)
                    mask = cv.fillPoly(mask, p, 1)
                    pixel_value = self.origin_img[click_pos[1], click_pos[0],
                                                  0]
                    low, high = pixel_value + \
                        self.pixel_range[0], pixel_value + self.pixel_range[1]
                    selected_img = self.origin_img[min_y:max_y + 1,
                                                   min_x:max_x + 1, 0]
                    x, y = np.where(
                        (selected_img >= low) * (selected_img <= high) * mask)
                    x = x + min_y
                    y = y + min_x
                    self.labelimg[x, y] = 1
                    pic = self.draw_points()
                    self.show_pic(file_name=None, content=pic)
                    self.histroty.append((x, y))
                    self.modified = True
                    self.saved = False

    def zoom_in_pic(self, checked):
        self.zoom_pic(True)

    def zoom_out_pic(self, checked):
        self.zoom_pic(False)

    def zoom_pic(self, zoom_in):
        if self.cur_img is None:
            return
        if zoom_in:
            if self.scale >= 5:
                pass
            elif self.scale < 1:
                self.scale += 0.1
            else:
                self.scale += 1
        else:
            if self.scale == 0:
                pass
            elif self.scale <= 1:
                self.scale -= 0.1
            else:
                self.scale -= 1
        self.logger.debug(self.scale)
        height, width, _ = self.origin_img.shape
        self.cur_img = cv.resize(
            self.origin_img,
            (int(height * self.scale), int(width * self.scale)),
            cv.INTER_LINEAR)
        if self.state == STATE.DRAW_RECTANGLE:
            if self.start_point is not None and self.end_point is not None:
                self.draw_rect(self.start_point, self.end_point)
                if self.labelimg is not None:
                    pic = self.draw_points()
                    self.show_pic(content=pic)
                else:
                    self.show_pic(file_name=None, content=self.panel_pic)
        elif self.state == STATE.DRAW_POLYGON:
            if self.polygon_points is not None and self.polygon_points[
                    'finish'] is True:
                self.draw_lines(self.polygon_points['points'], True)
                if self.labelimg is not None:
                    pic = self.draw_points()
                    self.show_pic(content=pic)
                else:
                    self.show_pic(file_name=None, content=self.panel_pic)
        elif self.state == STATE.DRAW_ELLIPSE:
            if self.ellipse_points is not None and len(
                    self.ellipse_points['points']) == 3:
                self.draw_ellipse(self.ellipse_points['points'])
                if self.labelimg is not None:
                    pic = self.draw_points()
                    self.show_pic(content=pic)
                else:
                    self.show_pic(file_name=None, content=self.panel_pic)
        elif self.labelimg is not None:
            self.panel_pic = self.cur_img.copy()
            pic = self.draw_points()
            self.show_pic(file_name=None, content=pic)
        else:
            self.show_pic(file_name=None)

    def file_list_item_changed(self, item):
        if self.modified and not self.saved:
            res = QMessageBox.warning(
                self, 'warning', 'Changes not saved, do you want to save?',
                QMessageBox.Ok | QMessageBox.No, QMessageBox.Ok)
            if res == QMessageBox.Ok:
                self.save()
        base_pic_name = item.text()
        for index, filename in enumerate(self.opened_files):
            if filename.name == base_pic_name:
                selected_filename = filename
                break
        self.selected_filename = selected_filename
        self.refresh_vars()
        self.open(self.selected_filename)

    def add_tool_bar(self):
        self.toolbar = QToolBar()
        self.addToolBar(Qt.TopToolBarArea, self.toolbar)
        self.toolbar.addAction(self.ui.actionOpen_File)
        self.toolbar.addAction(self.ui.actionOpen_Dir)
        self.toolbar.addAction(self.ui.actionSave)
        self.toolbar.addAction(self.ui.actionZoom_In)
        self.toolbar.addAction(self.ui.actionZoom_Out)
        self.toolbar.addAction(self.ui.actionfill_color)
        self.toolbar.addAction(self.ui.actionSet_Pixel_Range)
        self.toolbar.addAction(self.ui.actionRectangle)
        self.toolbar.addAction(self.ui.actionEllipse)
        self.toolbar.addAction(self.ui.actionPolygon)
        self.toolbar.addAction(self.ui.actionUndo)

    def show_pic(self, file_name=None, content=None):
        if file_name is not None:
            file_name = str(file_name.absolute())
            img = cv.imdecode(np.fromfile(file_name, dtype=np.uint8), -1)
            assert img is not None
            if len(img.shape) == 2:
                img = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
            height, width, channel = img.shape
            self.cur_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
            self.origin_img = self.cur_img
            self.labelimg = np.zeros(self.origin_img.shape[:2], dtype=np.int)
            qimg = QImage(self.cur_img.data, width, height, width * channel,
                          QImage.Format_RGB888)
            self.ui.img_area.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)
            self.ui.img_area.setPixmap(QPixmap.fromImage(qimg))
            self.ui.img_area.adjustSize()
        elif content is not None:
            height, width, channel = content.shape
            qimg = QImage(content.data, width, height, width * channel,
                          QImage.Format_RGB888)
            self.ui.img_area.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)
            self.ui.img_area.setPixmap(QPixmap.fromImage(qimg))
            self.ui.img_area.adjustSize()
        else:
            height, width, channel = self.cur_img.shape
            qimg = QImage(self.cur_img.data, width, height, width * channel,
                          QImage.Format_RGB888)
            self.ui.img_area.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)
            self.ui.img_area.setPixmap(QPixmap.fromImage(qimg))
            self.ui.img_area.adjustSize()

    def open_file(self, checked):
        if self.modified and not self.saved:
            res = QMessageBox.warning(
                self, 'warning', 'Changes not saved, do you want to save?',
                QMessageBox.Ok | QMessageBox.No, QMessageBox.Ok)
            if res == QMessageBox.Ok:
                self.save()
        filename, filetype = QFileDialog.getOpenFileName(
            self, '选取文件', '.', 'PNG Files(*.png);;JPG Files(*.jpg)')
        if filename == '':
            return
        filename = Path(filename)
        self.open_mode = OPEN_MODE.OPEN_FILE
        self.opened_files = [filename]
        self.selected_filename = filename
        self.open(self.selected_filename)
        self.refresh_list()

    def open_dir(self, checked):
        if self.modified and not self.saved:
            res = QMessageBox.warning(
                self, 'warning', 'Changes not saved, do you want to save?',
                QMessageBox.Ok | QMessageBox.No, QMessageBox.Ok)
            if res == QMessageBox.Ok:
                self.save()
        opened_dir = QFileDialog.getExistingDirectory(self, '打开文件夹', '.')
        if opened_dir == '':
            return
        opened_dir = Path(opened_dir)
        self.open_mode = OPEN_MODE.OPEN_DIR
        self.opened_files = list(opened_dir.iterdir())
        self.opened_files = [
            item for item in self.opened_files if util.is_pic(item)
        ]
        if len(self.opened_files) == 0:
            QMessageBox.warning(self, 'warning', 'No image found')
        else:
            self.selected_filename = self.opened_files[0]
            self.open(self.selected_filename)
            self.refresh_list()

    def refresh_list(self):
        self.ui.file_list.clear()
        for file_name in self.opened_files:
            base_name = file_name.name
            self.ui.file_list.addItem(base_name)

    def open(self, filename: Path):
        self.setWindowTitle(filename.name)
        self.show_pic(file_name=filename)
        temp = str(filename).split('.')
        npy_filename = '.'.join(temp[:-1]) + '.npy'
        if os.path.exists(npy_filename):
            self.labelimg = np.load(npy_filename)
            self.panel_pic = self.cur_img.copy()
            pic = self.draw_points()
            self.show_pic(file_name=None, content=pic)