Last Updated on 2021-05-17 by Clay
最近一直把時間浪費在開發自己有興趣的工具(浪費得非常開心),導致不斷遇到一些關於影像處理的奇怪問題。
今天想要紀錄的,便是如何將兩張圖片合併 —— 我發現若是簡單地使用 PIL 當中的 composite() 函式會將第二張圖片蓋掉第一張圖片,無奈之下,我開始嘗試將第二張圖片的背景轉為透明。轉換成透明背景後圖片,合併的結果我覺得相當自然。
若是對 Python 當中 PIL 模組感興趣的話,可以參考他們的官方教學:
那麼,以下我便開始介紹怎麼將兩張圖片合併。
前置準備
如果是第一次使用 PIL,需要以以下指令安裝:
pip3 install pillow
由於我是使用自己寫的『繪圖板』來進行圖片的合併,相關的心得筆記可以參考我之前寫過的紀錄:
合併圖片的流程
首先,我有一張這樣的狗狗圖片:
然後,我有我的繪圖板程式:
我將程式碼儲存成 PaintLabel.py,為重寫 PyQt5 當中 QLabel 的程式。
# -*- coding: utf-8 -*- from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * class PLabel(QLabel): def __init__(self, centralwidget): super(PLabel, self).__init__(centralwidget) self.tracing_xy = [] self.lineHistory = [] self.pen = QPen(Qt.black, 10, Qt.SolidLine) def paintEvent(self, QPaintEvent): self.painter = QPainter() self.painter.begin(self) self.painter.setPen(self.pen) start_x_temp = 0 start_y_temp = 0 if self.lineHistory: for line_n in range(len(self.lineHistory)): for point_n in range(1, len(self.lineHistory[line_n])): start_x, start_y = self.lineHistory[line_n][point_n-1][0], self.lineHistory[line_n][point_n-1][1] end_x, end_y = self.lineHistory[line_n][point_n][0], self.lineHistory[line_n][point_n][1] self.painter.drawLine(start_x, start_y, end_x, end_y) for x, y in self.tracing_xy: if start_x_temp == 0 and start_y_temp == 0: self.painter.drawLine(self.start_xy[0][0], self.start_xy[0][1], x, y) else: self.painter.drawLine(start_x_temp, start_y_temp, x, y) start_x_temp = x start_y_temp = y self.painter.end() def mousePressEvent(self, QMouseEvent): self.start_xy = [(QMouseEvent.pos().x(), QMouseEvent.pos().y())] def mouseMoveEvent(self, QMouseEvent): self.tracing_xy.append((QMouseEvent.pos().x(), QMouseEvent.pos().y())) self.update() def mouseReleaseEvent(self, QMouseEvent): self.lineHistory.append(self.start_xy+self.tracing_xy) self.tracing_xy = []
相關的筆記可以在我之前寫的《Python 中使用 PyQt5 製作簡易繪圖板》當中看到。
然後我將兩張圖片疊在一起(上方的是繪圖板):
我可以任意畫畫。
然後,我們寫一個程式將兩張圖片儲存起來,程式碼也不長,加上剛才寫重寫 QLabel 的程式也才一百行左右而已。
# -*- coding: utf-8 -*- import sys from PyQt5 import QtWidgets from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import * from label_test import Ui_MainWindow from PIL import ImageQt, Image from PaintLabel import PLabel class MainWindow(QtWidgets.QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.statusbar.setVisible(False) self.paintBoard = PLabel(self.ui.centralwidget) self.paintBoard.setGeometry(QRect(self.ui.label.pos(), self.ui.label.size())) self.add = QShortcut(QKeySequence("Ctrl+S"), self) self.add.activated.connect(self.compositeEvent) def compositeEvent(self): image1 = ImageQt.fromqpixmap(self.ui.label.pixmap()) image2 = ImageQt.fromqimage(self.paintBoard.grab()) image1 = image1.convert('RGBA') image2 = image2.resize(image1.size) # Transparency newImage2 = [] for item in image2.getdata(): if item[:3] == (240, 240, 240): newImage2.append((240, 240, 240, 0)) else: newImage2.append(item) image2.putdata(newImage2) print(image1.mode, image1.size) print(image2.mode, image2.size) newImage = Image.alpha_composite(image1, image2) newImage.save('test.png') if __name__ == '__main__': app = QtWidgets.QApplication([]) window = MainWindow() window.show() sys.exit(app.exec_())
最重要的其實就是這一行:
newImage = Image.alpha_composite(image1, image2)
使用 alpha_composite() 函式就可以將我的兩張圖片合併在一起了。儲存檔案,就是我最上方的那張狗狗海盜圖。