【问题标题】:Draw line: retrieve the covered pixels画线:检索覆盖的像素
【发布时间】:2016-11-21 14:48:21
【问题描述】:

我想在一个小部件上画一条线:

from PyQt4 import QtGui, QtCore

class LineLabel(QtGui.QLabel):

    def __init__(self,parent=None):
        super(LineLabel,self).__init__(parent)
        self.setMinimumSize(100,100)
        self.setMaximumSize(100,100)

    def paintEvent(self,e):
        painter=QtGui.QPainter(self)
        pen = QtGui.QPen()
        pen.setWidth(5)
        painter.setPen(pen)
        painter.drawLine(10,10,90,90)
        painter.end()

def test():
    form = QtGui.QWidget()
    label = LineLabel(form)
    form.show()
    return form

import sys
app = QtGui.QApplication(sys.argv)
window =test()
sys.exit(app.exec_())

获取线所覆盖的像素列表的最佳方法是什么?

来自 cmets 的更新:

  • 我不需要直接知道起点和终点之间的像素,而是所有那些变为黑色的像素(因为线条有一定宽度,所以像素更多)。
  • 我的总体目标是快速了解小部件上的哪些像素是黑色的。迭代图像的像素并查询颜色比从存储颜色的列表中读取颜色值要慢得多:对我来说,100 万像素的图像需要 1.9 秒,而 100 万条目的列表需要 0.23 秒.因此,每次更改小部件上的图像后,我必须更新该列表,例如画一条线。
  • 在 QGraphicsScene 中引用 QGraphicsItem 的答案也很有帮助。

【问题讨论】:

  • 这个答案可能对你有帮助:stackoverflow.com/a/12362480/2531279
  • 确实是同一个问题。对 QImage.scanLine 的引用有所帮助,但答案仍然不能令人满意,因为迭代像素真的很慢。与答案相比,将迭代的区域限制在图像的可能部分(由线的起点和终点定义)使其更快。

标签: pyqt pyqt4


【解决方案1】:

您可以使用线性方程在直线中找到您想要的点。我认为没有提到画线。

from PyQt4 import QtGui
from PyQt4.QtGui import QColor, QPaintEvent

m_nInitialX = 0.0
m_nInitialY = 0.0


# my line abstraction
class MyLine:
    x1, y1, x2, y2 = .0, .0, .0, .0
    width = .0
    px, py = (.0, .0)
    draw_point = False

    def __init__(self, x1, y1, x2, y2, width):
        self.x1, self.y1, self.x2, self.y2 = (x1, y1, x2, y2)
        self.width = width

    def is_in_line(self, x, y):
        # mark a position in the line
        m = (self.y2 - self.y1) / (self.x2 - self.x1)
        print(m*(x-self.x1)-(y-self.y1))
        if abs((m*(x-self.x1) - (y-self.y1))) <= self.width/2:
            self.draw_point = True
            return True
        else:
            return False

    def add_red_point(self, x, y):
        self.px, self.py = (x, y)

    def draw(self, widget):
        painter = QtGui.QPainter(widget)
        pen = QtGui.QPen()
        pen.setWidth(self.width)
        painter.setPen(pen)
        painter.drawLine(self.x1, self.y1, self.y2, self.y2)

        if self.draw_point:
            pen.setColor(QColor(255, 0, 0))
            painter.setPen(pen)
            painter.drawPoint(self.px, self.py)
        painter.end()


line = MyLine(10, 10, 90, 90, width=10)  # <-- my line abstraction


class LineLabel(QtGui.QLabel):

    def __init__(self, parent=None):
        super(LineLabel, self).__init__(parent)
        self.setMinimumSize(100, 100)
        self.setMaximumSize(100, 100)

    # always redraw when needed
    def paintEvent(self, e):
        print("draw!")
        line.draw(self)

    def mousePressEvent(self, event):
        # mark clicked position in line
        m_nInitialX = event.pos().x()
        m_nInitialY = event.pos().y()
        if line.is_in_line(m_nInitialX, m_nInitialY):
            line.add_red_point(m_nInitialX, m_nInitialY)
            self.repaint()


def test():
    form = QtGui.QWidget()
    label = LineLabel(form)
    form.show()
    return form

import sys

app = QtGui.QApplication(sys.argv)
window = test()
sys.exit(app.exec_())

【讨论】:

  • 我希望 PyQt 提供一个解决方案。在我的示例中,该线具有一定的宽度,因此仅在该线的两个端点之间进行插值(例如使用 Bresenham 算法)并不是完整的解决方案。在更一般的问题中(示例中未描述),线可能不是实线而是虚线,或者不是直线而是更复杂的形状。我认为 PyQt 应该知道线条覆盖了哪些像素,因为它必须告诉图形驱动程序使这些像素变黑。
  • 明白你的意思。但是,当您想对绘制的图形进行任何更改时,通常的方法是重新绘制整个画布。这就是为什么我们通常为了重绘的目的而保留原语的抽象。
  • 顺便说一句。我找到了另一个可能对您有帮助的问题的答案stackoverflow.com/questions/13368947/…
  • 在该线程中,程序将像素存储在列表中并绘制它们。这是相反的方式,可能很容易。我通常要做的是将图像像素的记录保存在列表中以供以后阅读;绘制线时必须更新此列表。我刚刚检查过从列表中读取一个像素几乎比从图像中读取像素快十倍。最糟糕的解决方案是遍历可能是线条一部分的图像像素并读取它们的值;当然,这很耗时。
  • 我不知道你想做什么。但那是一个“位图”解决方案,但您始终可以使用参数解决方案,就像游戏一样。跟踪原始参数。并通过原语进行重绘,正如我首先所说的那样,这是最有效的方法。过去可以读取显存,但今天已不实用。抱歉,如果我无法提供帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 2013-01-27
  • 1970-01-01
相关资源
最近更新 更多