python - drop - matplotlib and pyqt
¿Cómo imprimo un mapa de colores en una escena usando pyqt? (4)
TL; DR: solo necesita leer la sección "Actualizar".
¿Cómo se
numpy.random.random((256, 256))
como un mapa de colores para una escena qt?
Ese es el resumen del resumen.
Actualizar:
Lo siguiente me da el mapa de colores que quiero guardar en el archivo.
scaled_image = Image.fromarray(np.uint8(self.image*255))
plt.savefig("/home/test.png")
self.image
es una matriz numpy de 256x256, todos sus valores oscilan entre -1 y 1.
¿Cómo puedo hacer que esta imagen salga a una escena en Qt? Puedes usar self.image = numpy.random.random((256, 256))
para tener un punto de partida similar a mí. ¿Cómo obtienes tu matriz numpy 2D de valores aleatorios en la escena pyqt como un mapa de colores?
Actualización 24/02/1016
Tan cerca. Esto parece funcionar, pero la escala ha sido invertida. El azul ahora está caliente y el rojo está frío. ¿Cómo puedo cambiar esto para que se vea como la imagen de arriba?
scene = QGraphicsScene(self)
scaled_image = Image.fromarray(np.uint8(self.image*255))
gcf().canvas.draw() # IMPORTANT!
stringBuffer = gcf().canvas.buffer_rgba() # IMPORTANT!
l, b, w, h = gcf().bbox.bounds
qImage = QtGui.QImage(stringBuffer,
w,
h,
QtGui.QImage.Format_ARGB32)
pixmap = QtGui.QPixmap.fromImage(qImage)
pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
scene.addItem(pixmapItem)
self.graphicsView.setScene(scene)
Lo que he probado 23/02/2016
Lo siguiente me deja una pantalla en blanco.
scene = QGraphicsScene(self)
scaled_image = Image.fromarray(np.uint8(self.image*255))
pixMap = QPixmap(scaled_image)
scene.addPixmap(pixMap)
self.graphicsView.setScene(scene)
Lo siguiente me da una escala de grises de salida a la escena Qt. ¿Por qué no está en color?
scene = QGraphicsScene(self)
scaled_image = Image.fromarray(np.uint8(self.image*255))
imgQ = ImageQt(scaled_image)
pixMap = QtGui.QPixmap.fromImage(imgQ)
scene.addPixmap(pixMap)
self.graphicsView.setScene(scene)
here hice ingeniería inversa de soluciones a problemas de mapa de colores y exhibí una imagen here .
Siguiendo los consejos de una solución publicada, primero intenté crear un QGraphicsPixmapItem
y luego agregar el elemento a la escena. Los documentos oficiales eran un poco confusos, por lo que finalmente obtuve lo que necesitaba de los documentos mucho más crujientes . Lamentablemente obtengo la misma escala de grises que arriba. Código abajo:
scene = QGraphicsScene(self)
scaled_image = Image.fromarray(np.uint8(self.image*255))
imgQ = ImageQt(scaled_image)
pixMap = QtGui.QPixmap.fromImage(imgQ)
pixMapItem = QtGui.QGraphicsPixmapItem(pixMap)
scene.addItem(pixMapItem)
self.graphicsView.setScene(scene)
Otras cosas que he probado (mayores):
self.image
es una matriz numpy 2D, todos sus valores oscilan entre -1 y 1.
Escalo de la siguiente manera y obtengo una imagen en escala de grises. Sin embargo, quiero un mapa de colores:
scene = QGraphicsScene(self)
scaled_image = (self.image + 1) * (255 / 2)
scene.addPixmap(QPixmap.fromImage(qimage2ndarray.array2qimage(scaled_image)))
self.graphicsView.setScene(scene)
#min(self.image) = -0.64462
#max(self.image) = 1.0
Si hubiera hecho lo siguiente, habría obtenido el mapa de colores que quiero, como en la imagen de abajo de una aplicación web que he desarrollado anteriormente.
>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> imgplot = ax.imshow(self.image)
¿Cómo agrego un mapa de colores a la escena qt, en lugar de tener una escala de grises?
Así que esto funcionó ... pero me siento tan sucio haciéndolo así:
scene = QGraphicsScene(self)
scaled_image = Image.fromarray(np.uint8(self.image*255))
plt.savefig(".../Downloads/itworks.png")
pixMap = QPixmap(".../Downloads/itworks.png")
scene.addPixmap(pixMap)
self.graphicsView.setScene(scene)
¿Realmente tiene que haber una dependencia en guardar la imagen en un archivo y luego volver a cargarla como un QPixmap para que esto funcione ...? ¿No es esta una respuesta en cinta muy poco profética a lo que creo que es una demanda bastante estándar de pyqt? Me preocupa tener que guardar la imagen en un archivo cada vez que se producirá un cuello de botella a medida que me escala y, además, me molesta porque tendré que administrar el sistema de archivos.
numpy.random.random((256, 256))
la recompensa abierta a cualquier persona que pueda proporcionar un medio de salida numpy.random.random((256, 256))
a una escena qt sin un paso intermedio de guardado en archivo.
Mientras tanto, esta solución de cinta adhesiva funciona:
Actualización: para referencia, esto es lo que terminé haciendo que funcionó perfectamente usando el código de rbaleksandar e imposeren . Gracias a todos!
scene = self.QScene(self)
scaled_image = Image.fromarray(255-np.uint8(self.image*255))
plt.imshow(scaled_image, interpolation = "nearest")
gcf().canvas.draw() # IMPORTANT!
stringBuffer = gcf().canvas.buffer_rgba() # IMPORTANT!
l, b, w, h = gcf().bbox.bounds
qImage = QtGui.QImage(stringBuffer,
w,
h,
QtGui.QImage.Format_ARGB32)
pixmap = QtGui.QPixmap.fromImage(qImage)
pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
scene.addItem(pixmapItem)
self.graphicsView.setScene(scene)
Debe continuar por la ruta de presentación de muestras de Matplotlib (probablemente también junto con la personalización de mapas de colores ) utilizando el backend PyQt4 de matplotlib .
He usado estas herramientas mpl-PyQt4 antes y, aunque puede parecer engorroso al principio, es lo que estás buscando (uso de herramientas nativas, sin traducción técnica / puente) y más extensible. Dichas propiedades se muestran en el ejemplo haciendo una animación junto con la disposición de parcelas QLayout
Ya tienes código que casi funciona. Obtienes la imagen usando:
scaled_image = Image.fromarray(np.uint8(self.image*255))
Para invertir solo necesita restar sus datos actuales a 255.
scaled_image = Image.fromarray(255-np.uint8(self.image*255))
Aquí asumo que su código actual funciona correctamente y solo tiene valores invertidos. Pero si sus datos son realmente de -1 a 1, entonces el código actual limitará la mitad de los resultados a cero (porque el valor mínimo para uint8 es cero). El código apropiado para los valores de -1 a 1 debe modificarse un poco:
scaled_image = Image.fromarray(255 - (self.image + 1)*127.5)
PS: puedes invertir colores sin ningún tipo de cálculo usando diferentes ''jet_r''
( ''jet_r''
por ejemplo). Pero asegúrese de que sus valores estén adecuadamente escalados
QPixmap
admite valores de color superiores a 255 y múltiples formatos de imagen . Si eso no fuera cierto, todos los íconos en Qt habrían sido grises (obviamente no es el caso).
Puede generar su mapa de colores de la forma que desee (antes (utilizando OpenCV y numpy) o después de convertirlo en un QImage
(usar Qt)), convertirlo en un QPixmap
y usar adjúntelo a su QGraphicsPixmapItem
(no use QPixmap
como un parte de QGraphicScene
directamente)QGraphicsScene
.
EDITAR: He leído mal la documentación. En realidad, puede usar QPixmap
directamente en un QGraphicScene usando addPixmap()
. Lo siento por eso. Como una disculpa aquí hay un código para ti. :PAG
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class ImageView(QGraphicsView):
def __init__(self, pixmap=None, parent=None):
''''''
QGraphicsView shows the image
''''''
super(ImageView, self).__init__(parent)
self.pixmap = pixmap
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
layout = QVBoxLayout(self)
pic = QPixmap(''/home/-----/Pictures/7 Cat Sins - Wrath.jpg'')
grview = ImageView(pic, self)
layout.addWidget(grview)
self.setFixedSize(pic.size())
scene = QGraphicsScene(self)
scene.addPixmap(pic)
grview.setScene(scene)
self.show()
def main():
app = QApplication(sys.argv)
w = Widget()
return sys.exit(app.exec_())
if __name__ == ''__main__'':
main()
Produce el siguiente resultado:
Fuente de la imagen: busque 7 Cat Sins - Wrath en Google;)
Básicamente, crea un visor de imágenes, crea el gráfico de escena, agrega un mapa de píxeles al gráfico de escenas, configura la escena del espectador de imágenes a ese gráfico y muestra el mapa de píxeles en la pantalla con ese visor.
EDIT2: Bueno, entonces parece que tuvo problemas con la integración real de matplotlib
. Aquí es cómo lo haces (tomado de here con un pequeño cambio para gcf().canvas.buffer_rgba()
):
import numpy as np
from matplotlib import use
use(''AGG'')
from matplotlib.pylab import *
from PySide import QtCore,QtGui
# Following are used for the generation of the image but you have your own imports so you don''t need them
from matplotlib.transforms import Bbox
from matplotlib.path import Path
from matplotlib.patches import Rectangle
# Generation of the figure (you can skip all that and use your stuff)
rect = Rectangle((-1, -1), 2, 2, facecolor="#aaaaaa")
gca().add_patch(rect)
bbox = Bbox.from_bounds(-1, -1, 2, 2)
for i in range(12):
vertices = (np.random.random((4, 2)) - 0.5) * 6.0
vertices = np.ma.masked_array(vertices, [[False, False], [True, True], [False, False], [False, False]])
path = Path(vertices)
if path.intersects_bbox(bbox):
color = ''r''
else:
color = ''b''
plot(vertices[:,0], vertices[:,1], color=color)
# The conversion and display of the plot
app = QtGui.QApplication(sys.argv)
gcf().canvas.draw() # IMPORTANT!
stringBuffer = gcf().canvas.buffer_rgba() # IMPORTANT!
l, b, w, h = gcf().bbox.bounds
qImage = QtGui.QImage(stringBuffer,
w,
h,
QtGui.QImage.Format_ARGB32)
scene = QtGui.QGraphicsScene()
view = QtGui.QGraphicsView(scene)
pixmap = QtGui.QPixmap.fromImage(qImage)
pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
scene.addItem(pixmapItem)
view.show()
app.exec_()
EDITAR 3: Para su problema de mapa de colores invertido, consulte aquí (documentación) y aquí (SO) .
PD: en lugar de usar una biblioteca adicional como qimage2ndarray
para convertir imágenes OpenCV a QImage
s, le aconsejo que lo haga por su cuenta para ver qué se necesita hacer exactamente. Estas bibliotecas están limpias si tiene mucha experiencia con el material y solo necesita ahorrar algo de tiempo. Al lado de esa razón, aléjate de ellos.