PYQT5 实现亚克力磨砂效果的QLabel

前言
Windows10 在 UWP 应用中支持亚克力画刷,可以在部件的底部绘制亚克力效果的背景图。下面我们使用 QLabel 来模拟这个磨砂过程。

实现方法
MSDN 文档中介绍了亚克力材料的配方,包括:高斯模糊、亮度混合、色调混合和噪声纹理。

在这里插入图片描述

高斯模糊
我们先来实现高斯模糊的效果,使用 scipy 可以很轻松的实现这个过程:

# coding:utf-8
import numpy as np
from PIL import Image
from PyQt5.QtGui import QPixmap
from scipy.ndimage.filters import gaussian_filter


def gaussianBlur(imagePath: str, blurRadius=18, brightFactor=1, blurPicSize: tuple = None) -> np.ndarray:
    """ 对图片进行高斯模糊处理

Parameters
----------
imagePath: str
    图片路径

blurRadius: int
    模糊半径

brightFactor:float
    亮度缩放因子

blurPicSize: tuple
    高斯模糊前将图片缩放到指定大小,可以加快模糊速度

Returns
-------
image: `~np.ndarray` of shape `(w, h, c)`
    高斯模糊后的图像
"""
if not imagePath.startswith(':'):
    image = Image.open(imagePath)
else:
    image = Image.fromqpixmap(QPixmap(imagePath))

if blurPicSize:
    # 调整图片尺寸,减小计算量,还能增加额外的模糊
    w, h = image.size
    ratio = min(blurPicSize[0] / w, blurPicSize[1] / h)
    w_, h_ = w * ratio, h * ratio

    if w_ < w:
        image = image.resize((int(w_), int(h_)), Image.ANTIALIAS)

image = np.array(image)

# 处理图像是灰度图的情况
if len(image.shape) == 2:
    image = np.stack([image, image, image], axis=-1)

# 对每一个颜色通道分别磨砂
for i in range(3):
    image[:, :, i] = gaussian_filter(
        image[:, :, i], blurRadius) * brightFactor

return image

亚克力纹理
接下来在 QLabel 上面绘制出亮度混合、色调混合和噪声纹理,一般色调混合使用的颜色是图像的主题色,可以用 colorthief 库提取:

class AcrylicTextureLabel(QLabel):
    """ 亚克力纹理标签 """

def __init__(self, tintColor: QColor, luminosityColor: QColor, noiseOpacity=0.03, parent=None):
    """
    Parameters
    ----------
    tintColor: QColor
        RGB 主色调

    luminosityColor: QColor
        亮度层颜色

    noiseOpacity: float
        噪声层透明度

    parent:
        父级窗口
    """
    super().__init__(parent=parent)
    self.tintColor = QColor(tintColor)
    self.luminosityColor = QColor(luminosityColor)
    self.noiseOpacity = noiseOpacity
    self.noiseImage = QImage('resource/noise.png')
    self.setAttribute(Qt.WA_TranslucentBackground)

def setTintColor(self, color: QColor):
    """ 设置主色调 """
    self.tintColor = color
    self.update()

def paintEvent(self, e):
    """ 绘制亚克力纹理 """
    acrylicTexture = QImage(64, 64, QImage.Format_ARGB32_Premultiplied)

    # 绘制亮度层
    acrylicTexture.fill(self.luminosityColor)

    # 绘制主色调
    painter = QPainter(acrylicTexture)
    painter.fillRect(acrylicTexture.rect(), self.tintColor)

    # 绘制噪声
    painter.setOpacity(self.noiseOpacity)
    painter.drawImage(acrylicTexture.rect(), self.noiseImage)

    acrylicBrush = QBrush(acrylicTexture)
    painter = QPainter(self)
    painter.fillRect(self.rect(), acrylicBrush)

用到的噪声图像如下图所示:

在这里插入图片描述

亚克力标签
最后在 QLabel 上叠加磨砂图像和亚克力纹理,可以通过 Image.toqpixmap() 将 Image 转换为 QPixmap:

class AcrylicLabel(QLabel):
    """ 亚克力标签 """

def __init__(self, blurRadius: int, tintColor: QColor, luminosityColor=QColor(255, 255, 255, 0),
             maxBlurSize: tuple = None, parent=None):
    """
    Parameters
    ----------
    blurRadius: int
        磨砂半径

    tintColor: QColor
        主色调

    luminosityColor: QColor
        亮度层颜色

    maxBlurSize: tuple
        最大磨砂尺寸,越小磨砂速度越快

    parent:
        父级窗口
    """
    super().__init__(parent=parent)
    self.imagePath = ''
    self.blurPixmap = QPixmap()
    self.blurRadius = blurRadius
    self.maxBlurSize = maxBlurSize
    self.acrylicTextureLabel = AcrylicTextureLabel(
        tintColor, luminosityColor, parent=self)

def setImage(self, imagePath: str):
    """ 设置图片 """
    if imagePath == self.imagePath:
        return

    self.imagePath = imagePath
    image = Image.fromarray(gaussianBlur(
        imagePath, self.blurRadius, 0.85, self.maxBlurSize))
    self.blurPixmap = image.toqpixmap()  # type:QPixmap
    self.setPixmap(self.blurPixmap)
    self.adjustSize()

def setTintColor(self, color: QColor):
    """ 设置主色调 """
    self.acrylicTextureLabel.setTintColor(color)

def resizeEvent(self, e):
    super().resizeEvent(e)
    self.acrylicTextureLabel.resize(self.size())
    self.setPixmap(self.blurPixmap.scaled(
        self.size(), Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation))

测试
下面是测试用的埃罗芒阿老师:

在这里插入图片描述

代码如下:

# coding:utf-8
import sys

from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication

from acrylic import AcrylicLabel


app = QApplication(sys.argv)
w = AcrylicLabel(20, QColor(105, 114, 168, 102))
w.setImage('resource/ClariS_ヒトリゴト (アニメ盤).jpg')
w.show()
app.exec_()

结果如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值