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

bgibtngc  于 2023-05-07  发布在  Python
关注(0)|答案(2)|浏览(259)

我想使用qt在python中裁剪一部分屏幕截图。我使用PIL抓取屏幕,并将其转换回QImage到QPixmap,用于我的QLabel我的代码适用于方形宽度和高度。我无法将PIL图像转换为QImage。
load_image_from_pil变量如果为False,则从IMAGE_PATH加载图像,否则抓取屏幕
任何帮助感激

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_()
hmae6n7t

hmae6n7t1#

我相信最简单的方法是将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))

这样可以跳过许多容易出错的步骤,这总是很好的。

hxzsmxv2

hxzsmxv22#

我使用了@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_()

相关问题