如何在 python 中用 pil 图像数据填充 QImage

问题描述 投票:0回答:2

我想使用 qt 在 python 中裁剪一部分屏幕截图。 我使用 PIL 抓取屏幕并将其转换回 QImage 到 QPixmap 用于我的 QLabel 我的代码适用于方形宽度和高度。我无法将 PIL 图像转换为 QImage。

load_image_from_pil 变量从 IMAGE_PATH 加载图像,如果它是 False,否则它会抓取屏幕

感谢任何帮助

import sys
import cv2
import numpy as np
from PIL import ImageGrab, Image
from PySide2.QtCore import QSize, Qt, QRect
from PySide2.QtGui import QImage,QColor,QPixmap
from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton,QLabel


#True = from screen using pil image grab
#False = from path
load_image_from_pil=True

IMAGE_PATH=r"C:\Users\kosta\Pictures\Art_inspiration1.png"

#####    EXPECTED FUNCTIONALITY   #######
#crop a screenshot of the screen to x,y=0,0 with width=100 ,height=100

def NumpyArray_to_qimage(np_arr,x,y,w,h):
    #make qimage from numpy
    qimage = QImage(np_arr.data, w, h, 3 * w, QImage.Format_RGB888) 
    return qimage

def PIL_to_NumpyArray(pil_img):
    return np.array(pil_img)
def PIL_to_qimage(pil_img, x,y,w,h):
    #convert pil to numpy array
    np_arr = PIL_to_NumpyArray(pil_img)


    qimage = NumpyArray_to_qimage(np_arr,x,y,w,h)
    return qimage


# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # global x,y,w,h
        x,y,w,h=0,0,100,300

        self.setWindowTitle("My App1")

        self.label = QLabel("label")
        self.label.setGeometry(QRect(x,y,w,h))

        qimage=None
        # qimage = QImage(im_np.data, w, h, 3 * w, QImage.Format_RGB32) 
        if load_image_from_pil:
            print("screenshot and cropping image")
            #screenshot whole screen
            grab_image = ImageGrab.grab()
            
            # crop portion of image
            image_arr = np.array(grab_image)
            
            cropped_image= image_arr[x:x+w,y:y+h]

            # cropped_image = Image.fromarray(np.uint8(cropped_image)).convert('RGB')
            # cropped_image = Image.fromarray(image_arr.astype('uint8'), 'RGB')
            cropped_image = Image.fromarray(cropped_image)

            cv2.imshow('Live', image_arr[y:y+h,x:x+w])


            # image_arr = np.array(grab_image)
            # image_arr = image_arr[x:x+w,y:y+h]
            # image = Image.fromarray(image_arr)
            
            qimage = PIL_to_qimage(cropped_image,x,y,w,h)
        else:
            print("loading image from file")
            qimage = QImage(IMAGE_PATH)
        
        pixmap = QPixmap.fromImage(qimage)
        print(qimage)
        self.label.setPixmap(pixmap)   
        # Set the central widget of the Window.
        self.setCentralWidget(self.label)
        self.resize(self.label.width(), self.label.height())

app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec_()
python numpy python-imaging-library pyside2 qimage
2个回答
1
投票

我相信获得所需内容的最简单方法是按如下方式替换

PIL_to_qimage
函数(如 this answer 中所建议):

def PIL_to_qimage(pil_img):
    temp = pil_img.convert('RGBA')
    return QImage(
        temp.tobytes('raw', "RGBA"),
        temp.size[0],
        temp.size[1],
        QImage.Format.Format_RGBA8888
    )

话虽如此,您的代码中似乎有很多关于索引的混淆。对于裁剪 PIL 图像,研究

Image.crop
方法可能会很有趣,如下所示:

cropped_image = grab_image.crop((x, y, x+w, y+h))

这让您可以跳过一些容易出错的步骤,这总是很好。


0
投票

我采用了@musicamante 的解决方案,该解决方案建议使用

QScreen.grabWindow
进行屏幕截图,使用 QPixmap.copy(QRect) 进行裁剪,并删除不需要的 PIL 库。

这里是任何遇到相同问题或想要测试它的人的完整工作代码。

import sys
import cv2
import numpy as np
from PIL import ImageGrab, Image
from PySide2.QtCore import QSize, Qt, QRect
from PySide2.QtGui import QImage,QColor,QPixmap,QScreen
from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton,QLabel

import PySide2
#True = from screen using pil image grab
#False = from path
load_image_from_pil=True

IMAGE_PATH=r"C:\Users\kosta\Pictures\Art_inspiration1.png"

#####    EXPECTED FUNCTIONALITY   #######
#crop a screenshot of the screen to x,y=0,0 with width=100 ,height=100

def NumpyArray_to_qimage(np_arr,x,y,w,h):
    #make qimage from numpy
    qimage = QImage(np_arr.data, w, h, 3 * w, QImage.Format_RGB888) 
    return qimage

def PIL_to_NumpyArray(pil_img):
    return np.array(pil_img)
def PIL_to_qimage(pil_img, x,y,w,h):
    #convert pil to numpy array
    np_arr = PIL_to_NumpyArray(pil_img)


    qimage = NumpyArray_to_qimage(np_arr,x,y,w,h)
    return qimage


# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # global x,y,w,h
        x,y,w,h=0,0,800,780

        self.setWindowTitle("My App1")

        self.label = QLabel("label")
        self.label.setGeometry(QRect(x,y,w,h))

        qimage=None
        pixmap=None
        # qimage = QImage(im_np.data, w, h, 3 * w, QImage.Format_RGB32) 
        if load_image_from_pil:
            print("screenshot and cropping image")
            # screenshot whole screen
            screen = QApplication.primaryScreen()
            winid = QApplication.desktop().winId()
            grab_image = screen.grabWindow(winid)

            # grab_image is a Qpixmap now
            
            
            #### crop portion of image ####
            # convert grab_image to QImage in order to crop by QImage.copy(QRect)
            # grab_image = grab_image.toImage().copy(x,y,w,h)
            rect = QRect(x,y,w,h)
            cropped_image = grab_image.copy(rect)
            
            # return qimage
            pixmap=cropped_image
        else:
            print("loading image from file")
            qimage = QImage(IMAGE_PATH)
        
        # pixmap = QPixmap.fromImage(qimage)
        # print(qimage)
        self.label.setPixmap(pixmap)   
        # Set the central widget of the Window.
        self.setCentralWidget(self.label)
        self.resize(self.label.width(), self.label.height())

app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec_()
© www.soinside.com 2019 - 2024. All rights reserved.