首頁 > 軟體

Python+PyQT5實現手繪圖片生成器

2022-02-15 10:02:29

手繪圖片生成器可以將匯入的彩色圖片通過python分析光源、灰度等操作生成手繪圖片。

UI介面的整體部分程式碼塊,UI介面的設計比較簡單。效果在上面的圖片展示。

class HandImage(QWidget):
    def __init__(self):
        super(HandImage, self).__init__()
        self.init_ui()

    def init_ui(self):
        '''
        UI介面元件及佈局
        :return:
        '''
        self.setWindowTitle('手繪圖片生成器   公眾號:[Python 集中營]')
        self.setWindowIcon(QIcon('手繪圖示.ico'))

        self.setFixedWidth(500)

        self.sou_im_path = QLineEdit()
        self.sou_im_path.setReadOnly(True)

        self.sou_im_path_btn = QPushButton()
        self.sou_im_path_btn.setText('源圖片')
        self.sou_im_path_btn.clicked.connect(self.sou_im_path_btn_clk)

        self.dir_path = QLineEdit()
        self.dir_path.setReadOnly(True)

        self.dir_path_btn = QPushButton()
        self.dir_path_btn.setText('儲存')
        self.dir_path_btn.clicked.connect(self.dir_path_btn_clk)

        self.start_btn = QPushButton()
        self.start_btn.setText('開始繪製影象')
        self.start_btn.clicked.connect(self.start_btn_clk)

        grid = QGridLayout()
        grid.addWidget(self.sou_im_path, 0, 0, 1, 1)
        grid.addWidget(self.sou_im_path_btn, 0, 1, 1, 1)
        grid.addWidget(self.dir_path, 1, 0, 1, 1)
        grid.addWidget(self.dir_path_btn, 1, 1, 1, 1)
        grid.addWidget(self.start_btn, 2, 0, 1, 2)

        self.thread_ = WorkThread(self)
        self.thread_.finished.connect(self.finished)

        self.setLayout(grid)

    # UI介面上的槽函數

    def sou_im_path_btn_clk(self):
        '''
        選擇源圖片並設定路徑
        :return:
        '''
        im_path = QFileDialog.getOpenFileName(self, os.getcwd(), '開啟圖片', 'Image File(*.jpg);;Image File(*.png)')
        self.sou_im_path.setText(im_path[0])

    def dir_path_btn_clk(self):
        '''
        選擇儲存路徑並設定路徑
        :return:
        '''
        dir_path = QFileDialog.getExistingDirectory(self, os.getcwd(), '選擇路徑')
        self.dir_path.setText(dir_path)

    def start_btn_clk(self):
        '''
        開始按鈕繫結的槽函數
        :return:
        '''
        self.start_btn.setEnabled(False)
        self.thread_.start()

    def finished(self, finished):
        '''
        用於子執行緒傳遞完成訊號的槽函數
        :param finished: 訊號變數
        :return:
        '''
        if finished is True:
            self.start_btn.setEnabled(True)

其中繪圖用到的第三方庫只有兩個,主要的還是Pillow影象處理庫,還有就是numpy科學計算庫用於一些陣列計算等的操作。

將第三方的處理庫匯入到程式碼塊中

from PIL import Image  # 影象處理模組
import numpy as np  # 科學計算庫

# PyQt5介面製作及樣式、核心元件
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

# 應用基礎操作相關
import sys
import os

建立用於專門手繪影象的子執行緒類,將UI介面的處理邏輯和生成影象的處理邏輯分開不至於產生無響應的卡死狀態。

class WorkThread(QThread):
    finished = pyqtSignal(bool)

    def __init__(self, parent=None):
        super(WorkThread, self).__init__(parent)
        self.parent = parent
        self.working = True

    def __del__(self):
        self.working = False
        self.wait()

    def run(self):
        # 源圖片路徑
        sou_im_path = self.parent.sou_im_path.text().strip()
        # 儲存路徑
        dir_path = self.parent.dir_path.text().strip()
        if sou_im_path == '' or dir_path == '':
            self.finished.emit(True)
            return
        # 開啟需要進行轉的影象,並進行引數設定,取出來的引數主要影象的一些梯度值。最後進行陣列儲存。
        vals = np.asarray(Image.open(sou_im_path).convert('L')).astype('float')

        '''影象引數處理'''
        depth = 12.0  # 設定初始化深度
        gray_vals = np.gradient(vals)  # 提取影象灰度的梯度值
        gray_x, gray_y = gray_vals  # 單獨提取橫座標與縱座標的灰度值
        print('當前橫座標的灰度值:', gray_x)
        print('當前縱座標的灰度值:', gray_y)

        # 重新設定橫座標合縱座標的灰度值
        gray_x = gray_x * depth / 100.0
        gray_y = gray_y * depth / 100.0

        # 根據numpy.sqrt()函數計算橫座標和縱座標灰度值的平方根
        gray_sqrt = np.sqrt(gray_x ** 2 + gray_y ** 2 + 1.0)

        # 重新計算X軸、Y軸、Z軸的光源
        light_x = gray_x / gray_sqrt
        light_y = gray_y / gray_sqrt
        light_z = 1.0 / gray_sqrt

        # 計算光源的方位角度、俯視角度
        agnle_el = np.pi / 2.2  # 俯視角度
        agnle_az = np.pi / 4.  # 方位角度

        # 分別計算光源對X軸、Y軸、Z軸的影響
        dx = np.cos(agnle_el) * np.cos(agnle_az)  # 光源對x 軸的影響
        dy = np.cos(agnle_el) * np.sin(agnle_az)  # 光源對y 軸的影響
        dz = np.sin(agnle_el)  # 光源對z 軸的影響

        # 設定光源歸一化處理
        light = 255 * (dx * light_x + dy * light_y + dz * light_z)
        light = light.clip(0, 255)

        # 重新構建影象
        image = Image.fromarray(light.astype('uint8'))
        image.save(dir_path + '/手繪影象.jpg')
        self.finished.emit(True)
        print('手繪影象繪製完成!')

主要程式碼塊實現都在上面了,下面將展示完整的程式碼

完整程式碼

# -*- coding:utf-8 -*-
# @author Python 集中營
# @date 2022/2/10
# @file test2.py

# done

# 手繪圖片生成器:以雪容融為例一鍵生成...

# 手繪圖片生成器可以將匯入的彩色圖片通過python分析光源、灰度等操作生成手繪圖片。

# 其中繪圖用到的第三方庫只有兩個,主要的還是Pillow影象處理庫,還有就是numpy科學計算庫用於一些陣列計算等的操作。

# 將第三方的處理庫匯入到程式碼塊中
from PIL import Image  # 影象處理模組
import numpy as np  # 科學計算庫

# PyQt5介面製作及樣式、核心元件
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

# 應用基礎操作相關
import sys
import os

# 建立用於專門手繪影象的子執行緒類,將UI介面的處理邏輯和生成影象的處理邏輯分開不至於產生無響應的卡死狀態。
class WorkThread(QThread):
    finished = pyqtSignal(bool)

    def __init__(self, parent=None):
        super(WorkThread, self).__init__(parent)
        self.parent = parent
        self.working = True

    def __del__(self):
        self.working = False
        self.wait()

    def run(self):
        # 源圖片路徑
        sou_im_path = self.parent.sou_im_path.text().strip()
        # 儲存路徑
        dir_path = self.parent.dir_path.text().strip()
        if sou_im_path == '' or dir_path == '':
            self.finished.emit(True)
            return
        # 開啟需要進行轉的影象,並進行引數設定,取出來的引數主要影象的一些梯度值。最後進行陣列儲存。
        vals = np.asarray(Image.open(sou_im_path).convert('L')).astype('float')

        '''影象引數處理'''
        depth = 12.0  # 設定初始化深度
        gray_vals = np.gradient(vals)  # 提取影象灰度的梯度值
        gray_x, gray_y = gray_vals  # 單獨提取橫座標與縱座標的灰度值
        print('當前橫座標的灰度值:', gray_x)
        print('當前縱座標的灰度值:', gray_y)

        # 重新設定橫座標合縱座標的灰度值
        gray_x = gray_x * depth / 100.0
        gray_y = gray_y * depth / 100.0

        # 根據numpy.sqrt()函數計算橫座標和縱座標灰度值的平方根
        gray_sqrt = np.sqrt(gray_x ** 2 + gray_y ** 2 + 1.0)

        # 重新計算X軸、Y軸、Z軸的光源
        light_x = gray_x / gray_sqrt
        light_y = gray_y / gray_sqrt
        light_z = 1.0 / gray_sqrt

        # 計算光源的方位角度、俯視角度
        agnle_el = np.pi / 2.2  # 俯視角度
        agnle_az = np.pi / 4.  # 方位角度

        # 分別計算光源對X軸、Y軸、Z軸的影響
        dx = np.cos(agnle_el) * np.cos(agnle_az)  # 光源對x 軸的影響
        dy = np.cos(agnle_el) * np.sin(agnle_az)  # 光源對y 軸的影響
        dz = np.sin(agnle_el)  # 光源對z 軸的影響

        # 設定光源歸一化處理
        light = 255 * (dx * light_x + dy * light_y + dz * light_z)
        light = light.clip(0, 255)

        # 重新構建影象
        image = Image.fromarray(light.astype('uint8'))
        image.save(dir_path + '/手繪影象.jpg')
        self.finished.emit(True)
        print('手繪影象繪製完成!')


# UI介面的整體部分程式碼塊,UI介面的設計比較簡單。效果在下面的圖片展示。

class HandImage(QWidget):
    def __init__(self):
        super(HandImage, self).__init__()
        self.init_ui()

    def init_ui(self):
        '''
        UI介面元件及佈局
        :return:
        '''
        self.setWindowTitle('手繪圖片生成器   公眾號:[Python 集中營]')
        self.setWindowIcon(QIcon('手繪圖示.ico'))

        self.setFixedWidth(500)

        self.sou_im_path = QLineEdit()
        self.sou_im_path.setReadOnly(True)

        self.sou_im_path_btn = QPushButton()
        self.sou_im_path_btn.setText('源圖片')
        self.sou_im_path_btn.clicked.connect(self.sou_im_path_btn_clk)

        self.dir_path = QLineEdit()
        self.dir_path.setReadOnly(True)

        self.dir_path_btn = QPushButton()
        self.dir_path_btn.setText('儲存')
        self.dir_path_btn.clicked.connect(self.dir_path_btn_clk)

        self.start_btn = QPushButton()
        self.start_btn.setText('開始繪製影象')
        self.start_btn.clicked.connect(self.start_btn_clk)

        grid = QGridLayout()
        grid.addWidget(self.sou_im_path, 0, 0, 1, 1)
        grid.addWidget(self.sou_im_path_btn, 0, 1, 1, 1)
        grid.addWidget(self.dir_path, 1, 0, 1, 1)
        grid.addWidget(self.dir_path_btn, 1, 1, 1, 1)
        grid.addWidget(self.start_btn, 2, 0, 1, 2)

        self.thread_ = WorkThread(self)
        self.thread_.finished.connect(self.finished)

        self.setLayout(grid)

    # UI介面上的槽函數

    def sou_im_path_btn_clk(self):
        '''
        選擇源圖片並設定路徑
        :return:
        '''
        im_path = QFileDialog.getOpenFileName(self, os.getcwd(), '開啟圖片', 'Image File(*.jpg);;Image File(*.png)')
        self.sou_im_path.setText(im_path[0])

    def dir_path_btn_clk(self):
        '''
        選擇儲存路徑並設定路徑
        :return:
        '''
        dir_path = QFileDialog.getExistingDirectory(self, os.getcwd(), '選擇路徑')
        self.dir_path.setText(dir_path)

    def start_btn_clk(self):
        '''
        開始按鈕繫結的槽函數
        :return:
        '''
        self.start_btn.setEnabled(False)
        self.thread_.start()

    def finished(self, finished):
        '''
        用於子執行緒傳遞完成訊號的槽函數
        :param finished: 訊號變數
        :return:
        '''
        if finished is True:
            self.start_btn.setEnabled(True)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = HandImage()
    main.show()
    sys.exit(app.exec_())

以上就是Python+PyQT5實現手繪圖片生成器的詳細內容,更多關於Python PyQT5手繪圖片生成器的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com