import sys
import os
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import cv2
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QFileDialog, QLineEdit, QComboBox, QSlider)
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import Qt
from pypinyin import lazy_pinyin
class ImageProcessor:
def __init__(self):
self.name_text = ""
self.font_size = 10
self.density_level = 5
self.font_path = None
def set_name(self, name, use_pinyin=False):
"""设置名字,可以选择使用拼音"""
if use_pinyin:
# 转换为拼音
self.name_text = ''.join(lazy_pinyin(name))
else:
self.name_text = name
def process_image(self, input_image_path, output_image_path):
"""主处理流程"""
# 1. 加载原始图像
original_img = Image.open(input_image_path).convert('L') # 转换为灰度图
# 2. 检测人脸并获取人脸区域
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
np_img = np.array(original_img)
faces = face_cascade.detectMultiScale(np_img, 1.1, 4)
# 3. 创建文字图像
text_img = self.create_text_image(original_img, faces)
# 4. 保存结果
text_img.save(output_image_path)
return text_img
def create_text_image(self, img, faces):
"""创建文字图像"""
# 创建空白图像
text_img = Image.new('L', img.size, color=255)
draw = ImageDraw.Draw(text_img)
# 加载字体
try:
font = ImageFont.truetype(self.font_path, self.font_size)
except:
print("Warning: Could not load specified font. Using default font instead.")
font = ImageFont.load_default()
# 获取人脸区域
face_regions = []
for (x, y, w, h) in faces:
face_regions.append((x, y, x + w, y + h))
# 遍历图像的每个像素块
block_size = max(self.font_size // 2, 5)
for y in range(0, img.height, block_size):
for x in range(0, img.width, block_size):
# 获取亮度
brightness = img.getpixel((x, y))
# 计算文字密度 (0-10)
density = int((1 - brightness / 255) * self.density_level)
density = max(0, min(10, density))
# 判断当前块是否在人脸区域内
in_face = False
for (fx, fy, fx_end, fy_end) in face_regions:
if fx <= x <= fx_end and fy <= y <= fy_end:
in_face = True
break
# 根据密度和区域决定是否绘制文字
if density > 0:
repeat_count = density
for _ in range(repeat_count):
offset_x = x + np.random.randint(0, block_size)
offset_y = y + np.random.randint(0, block_size)
# 随机选择文字
if len(self.name_text) > 0:
char = self.name_text[np.random.randint(0, len(self.name_text))]
else:
char = "无"
# 绘制文字
draw.text((offset_x, offset_y), char, font=font, fill=0)
return text_img
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.processor = ImageProcessor()
self.processor.font_path = r"C:\Windows\Fonts\SimHei.ttf" # 黑体字体路径
self.initUI()
def initUI(self):
self.setWindowTitle('人名头像图像生成器')
self.setGeometry(100, 100, 800, 600)
# 主窗口布局
main_widget = QWidget()
self.setCentralWidget(main_widget)
main_layout = QVBoxLayout(main_widget)
# 上部布局 - 控制面板
control_layout = QHBoxLayout()
# 文件上传区域
upload_widget = QWidget()
upload_layout = QVBoxLayout(upload_widget)
self.upload_btn = QPushButton('上传照片')
self.upload_btn.clicked.connect(self.upload_image)
self.input_text = QLineEdit()
self.input_text.setPlaceholderText('请输入您的名字或拼音')
self.font_size_slider = QSlider(Qt.Horizontal)
self.font_size_slider.setRange(5, 20)
self.font_size_slider.setValue(10)
self.font_size_slider.valueChanged.connect(self.update_size)
# 新增字体大小控制按钮
self.font_size_plus = QPushButton('+', self)
self.font_size_plus.clicked.connect(self.increase_font_size)
self.font_size_minus = QPushButton('-', self)
self.font_size_minus.clicked.connect(self.decrease_font_size)
self.density_slider = QSlider(Qt.Horizontal)
self.density_slider.setRange(1, 10)
self.density_slider.setValue(5)
self.density_slider.valueChanged.connect(self.update_density)
# 新增密度控制按钮
self.density_plus = QPushButton('+', self)
self.density_plus.clicked.connect(self.increase_density)
self.density_minus = QPushButton('-', self)
self.density_minus.clicked.connect(self.decrease_density)
self.use_pinyin = QComboBox()
self.use_pinyin.addItems(["使用汉字", "使用拼音"])
upload_layout.addWidget(QLabel('照片上传'))
upload_layout.addWidget(self.upload_btn)
upload_layout.addWidget(QLabel('名字/拼音'))
upload_layout.addWidget(self.input_text)
upload_layout.addWidget(QLabel('使用拼音'))
upload_layout.addWidget(self.use_pinyin)
# 布局字体大小控制区域
font_size_group = QHBoxLayout()
font_size_group.addWidget(QLabel('字体大小'))
font_size_group.addWidget(self.font_size_minus)
font_size_group.addWidget(self.font_size_slider)
font_size_group.addWidget(self.font_size_plus)
upload_layout.addLayout(font_size_group)
# 布局文字密度控制区域
density_group = QHBoxLayout()
density_group.addWidget(QLabel('文字密度'))
density_group.addWidget(self.density_minus)
density_group.addWidget(self.density_slider)
density_group.addWidget(self.density_plus)
upload_layout.addLayout(density_group)
# 预览区域
preview_widget = QWidget()
preview_layout = QVBoxLayout(preview_widget)
self.preview_label = QLabel('预览区域')
self.preview_label.setAlignment(Qt.AlignCenter)
self.preview_label.setFixedSize(256, 256)
self.preview_label.setStyleSheet("border: 1px solid #cccccc;")
preview_layout.addWidget(self.preview_label)
control_layout.addWidget(upload_widget)
control_layout.addWidget(preview_widget)
# 下部布局 - 结果区域
result_layout = QHBoxLayout()
self.original_label = QLabel('原始图像')
self.original_label.setAlignment(Qt.AlignCenter)
self.original_label.setFixedSize(300, 300)
self.original_label.setStyleSheet("border: 1px solid #cccccc;")
self.result_label = QLabel('生成结果')
self.result_label.setAlignment(Qt.AlignCenter)
self.result_label.setFixedSize(300, 300)
self.result_label.setStyleSheet("border: 1px solid #cccccc;")
self.save_btn = QPushButton('保存结果')
self.save_btn.clicked.connect(self.save_result)
result_layout.addWidget(self.original_label)
result_layout.addWidget(self.result_label)
result_layout.addWidget(self.save_btn)
# 添加到主布局
main_layout.addLayout(control_layout)
main_layout.addLayout(result_layout)
# 初始化变量
self.original_image_path = None
def upload_image(self):
"""上传照片并处理"""
filename, _ = QFileDialog.getOpenFileName(self, '选择照片', '.', '图像文件 (*.jpg *.png *.jpeg)')
if filename:
# 显示原始图像
pixmap = QPixmap(filename)
self.original_label.setPixmap(pixmap.scaled(300, 300, Qt.KeepAspectRatio))
# 保存原始图像路径
self.original_image_path = filename
# 更新预览
self.update_preview()
def update_preview(self):
"""更新预览"""
if self.original_image_path:
# 获取当前设置的名字
name = self.input_text.text()
use_pinyin = self.use_pinyin.currentIndex() == 1
# 设置处理器参数
self.processor.set_name(name, use_pinyin)
self.processor.font_size = self.font_size_slider.value()
self.processor.density_level = self.density_slider.value()
# 处理图像
temp_path = "temp_result.png"
result_img = self.processor.process_image(self.original_image_path, temp_path)
if result_img:
# 转换为QPixmap并显示
qimg = QImage(result_img.tobytes(), result_img.width, result_img.height,
result_img.width, QImage.Format_Grayscale8)
pixmap = QPixmap.fromImage(qimg)
self.result_label.setPixmap(pixmap.scaled(300, 300, Qt.KeepAspectRatio))
def save_result(self):
"""保存结果图像"""
if self.original_image_path:
# 处理图像
output_path, _ = QFileDialog.getSaveFileName(self, '保存结果', 'result.png', '图像文件 (*.png)')
if output_path:
self.processor.process_image(self.original_image_path, output_path)
print(f"图像已保存到 {output_path}")
def update_size(self):
"""更新字体大小"""
if self.original_image_path:
self.update_preview()
def update_density(self):
"""更新文字密度"""
if self.original_image_path:
self.update_preview()
def increase_font_size(self):
"""增大字体大小"""
current_value = self.font_size_slider.value()
if current_value < self.font_size_slider.maximum():
self.font_size_slider.setValue(current_value + 1)
self.update_preview()
def decrease_font_size(self):
"""减小字体大小"""
current_value = self.font_size_slider.value()
if current_value > self.font_size_slider.minimum():
self.font_size_slider.setValue(current_value - 1)
self.update_preview()
def increase_density(self):
"""增大文字密度"""
current_value = self.density_slider.value()
if current_value < self.density_slider.maximum():
self.density_slider.setValue(current_value + 1)
self.update_preview()
def decrease_density(self):
"""减小文字密度"""
current_value = self.density_slider.value()
if current_value > self.density_slider.minimum():
self.density_slider.setValue(current_value - 1)
self.update_preview()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())对人脸的识别不够细腻,希望增加更多细节,对于字体方面希望可以随机选择多种字体,并且可以进行角度旋转让效果更好