跳至主要内容

T4_0414

主要是分兩個部分:

  1. 通過不同的圖片分析模型去分析圖片 分析完圖片來產生需要修正的地方 使用不同的模型來進行修復
  1. 通過ollama來架設LLAMA來分析圖片 產生出對應的修圖建議 使用不同的模型來進行修復

  2. 自己訓練模型的話,可能花的成本會很高 然後就是訓練出來的不好 現在就是慢慢研究看看 花的時間太多的

#"背景原本是模糊或單色
#在低解析度下看起來沒問題,但上采樣放大時,AI 模型會嘗試「補出細節」,於是「亂補紋理」,造成怪異線條或重複紋理。
#使用 Real-ESRGAN 模型重建細節時過度補償
#realesr-general-x4v3.pth 是一個通用模型,但遇到簡單背景(白牆、純色牆),它會強行「生成細節」→ 導致拉絲感、像素條紋。
#Tile 切圖邊緣不連貫造成拼接痕跡
#若 tile=0 代表整張圖處理,若記憶體不足被強制裁切,也可能導致邊緣拼接失誤。

import os
import cv2
import numpy as np
from PIL import Image, ImageEnhance
import torch
from basicsr.archs.srvgg_arch import SRVGGNetCompact
from realesrgan import RealESRGANer
from gfpgan import GFPGANer

class ImageProcessor:
def __init__(self):
model_path = "C:/restore/Real-ESRGAN-0.3.0/weights/realesr-general-x4v3.pth"
self.upscale = 4
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

try:
model = SRVGGNetCompact(
num_in_ch=3,# 輸入通道數
num_out_ch=3, # 輸出通道數
num_feat=64, # 特徵維度
num_conv=32,# 捲積層數
upscale=self.upscale,
act_type='prelu'
)
self.upsampler = RealESRGANer(
scale=self.upscale,
model_path=model_path,
model=model,
tile=0,# 不切圖(避免拼接痕)
tile_pad=10,
pre_pad=0,
half=False,# 是否使用 FP16(若 GPU 記憶體吃緊可開啟)
device=self.device
)
print(f"Real-ESRGAN 載入成功: {model_path}")
except Exception as e:
print(f"Real-ESRGAN 載入錯誤: {e}")
self.upsampler = None

try:
gfpgan_model_path = "C:/restore/Real-ESRGAN-0.3.0/weights/GFPGANv1.4.pth"
self.gfpganer = GFPGANer(
model_path=gfpgan_model_path,
upscale=self.upscale,
arch='clean',
channel_multiplier=2,
bg_upsampler=self.upsampler
)
print(f"GFPGAN 載入成功: {gfpgan_model_path}")
except Exception as e:
print(f"GFPGAN 載入錯誤: {e}")
self.gfpganer = None

def full_restore(self, img_path):
"""整合增強、去噪、放大與臉部修復的完整流程"""
try:
# 開啟圖片並轉為 RGB 格式
img = Image.open(img_path).convert("RGB")
# 增強亮度與對比
img = ImageEnhance.Brightness(img).enhance(1.1)
img = ImageEnhance.Contrast(img).enhance(1.3)

# 去噪處理(OpenCV 需要 numpy 陣列)
img_np = np.array(img)
img_denoised = cv2.fastNlMeansDenoisingColored(img_np, None, 10, 10, 7, 21)

# 放大處理
if self.upsampler:
upscaled, _ = self.upsampler.enhance(img_denoised, outscale=self.upscale)
else:
upscaled = img_denoised

# 臉部修復處理
if self.gfpganer:
_, _, restored_img = self.gfpganer.enhance(upscaled, has_aligned=False, only_center_face=False, paste_back=True)
return restored_img
else:
return upscaled

except Exception as e:
print(f"圖片修復錯誤: {e}")
return None

# 批次處理資料夾內所有圖片
def process_folder(self, input_folder, output_folder):
if not os.path.exists(output_folder):
os.makedirs(output_folder)

for filename in os.listdir(input_folder):
if not filename.lower().endswith(('.jpg', '.jpeg', '.png')):
continue

input_path = os.path.join(input_folder, filename)
try:
print(f"處理中: {filename}")
result = self.full_restore(input_path)
if result is not None:
output_path = os.path.join(output_folder, f"final_{filename}")
if isinstance(result, np.ndarray):
cv2.imwrite(output_path, cv2.cvtColor(result, cv2.COLOR_RGB2BGR))
elif isinstance(result, Image.Image):
result.save(output_path)
print(f"{filename} 處理完成")
except Exception as e:
print(f"{filename} 處理失敗: {e}")

if __name__ == "__main__":
input_folder = "C:/restore/Real-ESRGAN-0.3.0/inputs"
output_folder = "C:/restore/output"
processor = ImageProcessor()
processor.process_folder(input_folder, output_folder)

指定輸入資料夾input_folder與輸出資料夾output_folder路徑。

初始化 ImageProcessor 類別。 載入 Real-ESRGAN, GFPGAN 模型

自動批次處理你指定的輸入資料夾 input_folder 裡的所有圖片

  1. 讀取每一張圖片
  2. 呼叫 full_restore(img_path) 進行完整修復流程
  3. 儲存結果至 output_folder 資料夾中

修復前: pexels-photo-31448633

修復後: final_pexels-photo-31448633

剩下的圖片: https://docs.google.com/document/d/1HU_Q2t3VQWCJtrZxIQmASSQ_xL7nhnH7SQHkIsnxYVM/edit?usp=sharing


其中一種方法: 較為便利,但產生的修圖建議充滿不確定性內容

來源不確定性內容建議做法
🔍 LLaVA 輸出結果分析會根據圖片壓縮或失真而有所偏誤(尤其是背景簡單或臉部模糊時)T使用原始高畫質圖輸入模型,並盡量避免 JPEG 壓縮過重
🤖 模型穩定性建議數值有時可能跳動(同張圖輸入多次建議不一致)多次分析取平均值或投票機制
🧠 Prompt 精準度若 prompt 太籠統可能導致輸出太模糊已使用的 prompt_2 結構良好,若要自動修圖建議進一步調整為 JSON 結構
📐 圖片構圖感知模型對主體判斷會受背景干擾(特別是在灰階圖)可在圖片上人工標註主體區域輔助分析(LLaVA v1.6 支援 box hint)
ollama run llava
import requests
import base64

# 圖片轉 base64
def encode_image(image_path):
with open(image_path, "rb") as img_file:
return base64.b64encode(img_file.read()).decode('utf-8')

# 圖片與提示文字
image_path = "C:\\restore\\Real-ESRGAN-0.3.0\\inputs\\00017_gray.png"
prompt = """
你是一位專業攝影後製專家,請針對我上傳的圖片提供詳細的修圖建議。請從以下幾個面向逐一說明:

1. **曝光(Exposure)**:是否過曝或曝光不足?建議的修正方式。
2. **對比(Contrast)**:是否需要增強或減少對比?建議值與原因。
3. **白平衡(White Balance)**:色溫是否正確?是否偏黃或偏藍?建議的調整方向。
4. **亮度與陰影(Brightness & Shadows)**:整體亮度是否均衡?陰影區域是否太暗或過曝?
5. **飽和度(Saturation)**:顏色是否過於鮮豔或黯淡?是否建議做局部或整體調整?
6. **清晰度與銳利度(Sharpness)**:影像是否模糊?需要加強細節嗎?
7. **構圖(Composition)**:主體位置是否理想?裁切或重構的建議?
8. **背景處理(Background)**:背景是否雜亂?建議進行模糊、去背或替換?
9. **整體風格建議(Optional)**:適合的濾鏡風格或視覺風格方向(如復古、清新、明亮、電影感等)。

請用條列式回答,每一項都包含分析與建議的調整方式,並建議如何進行修正(例如增加亮度、降低高光或調整色調)。
"""

prompt_2 = """
你是一位專業的攝影後製專家,請針對我提供的圖片,依據整體視覺效果進行修圖分析與建議。

請就以下面向提供具體分析與調整建議,**每項標題中請加上建議的數值**,例如:
- 曝光(建議 +10%)
- 白平衡(建議 5500K)
- 飽和度(建議 -15%)

請按照以下格式進行回覆:

1. **曝光(建議 ±%)**:目前整體是否偏暗或過曝?請提供建議的曝光值增減百分比。
2. **對比(建議 ±%)**:對比度是否適中?建議的增減比例為何?
3. **白平衡(建議色溫 K 值)**:畫面是否偏黃或偏藍?建議調整的色溫數值(如 5500K)為何?
4. **亮度與陰影(建議亮度 ±%、陰影 ±%)**:畫面是否有過暗或過亮區域?應該加強或減弱多少?
5. **飽和度(建議 ±%)**:色彩是否過於黯淡或過於飽和?建議的整體或局部調整幅度。
6. **清晰度與銳利度(建議 ±%)**:影像是否模糊?是否需要增加邊緣或細節的清晰度?
7. **構圖(建議裁切比例或視覺中心移動方向)**:主體構圖是否理想?如需裁切,請說明裁切建議(如裁去上方 10%)。
8. **背景處理(建議模糊強度、去背、替換等)**:背景是否雜亂或干擾主體?是否建議進行模糊、去背或替換?
9. **整體風格建議(建議濾鏡類型或視覺風格)**:根據畫面氛圍,建議適合的濾鏡風格(如:清新、復古、電影感等),並簡述原因。

請用條列式回覆,每點請先**總結觀察情況**,再提供**具體的建議調整方向與數值**。


"""

# 編碼圖片
image_b64 = encode_image(image_path)

# 發送到 Ollama 本機伺服器
response = requests.post(
'http://localhost:11434/api/generate',
json={
"model": "llava",
"prompt": prompt_2,
"images": [image_b64],
"stream": False # 設為 True 可逐步串流接收結果
}
)

# 輸出回答
print(response.json()['response'])

範例圖片: 00017_gray 輸出結果: image


pytorch_test | 小筆記 | 資料、模型、訓練流程全面優化

目前在進行測試 但測試出來的不太對勁 總是有點模糊 訓練出來的效果有點不太好 可能會需要來優化模型 資料集是從kaggle上抓下來的

from torch.utils.data import Dataset, DataLoader
from PIL import Image
import torchvision.transforms as T
import torch.nn as nn
import torch
import os
from glob import glob
import matplotlib.pyplot as plt
from torch.optim.lr_scheduler import ReduceLROnPlateau

# Dataset 與 DataLoader
class DeblurDataset(Dataset):
def __init__(self, blur_paths, sharp_paths):
self.blur_paths = blur_paths
self.sharp_paths = sharp_paths
self.transform = T.Compose([
T.Resize((256, 256)),
T.ToTensor()
])
def __len__(self):
return len(self.blur_paths)
def __getitem__(self, index):
blur_img = Image.open(self.blur_paths[index]).convert('RGB')
sharp_img = Image.open(self.sharp_paths[index]).convert('RGB')
return self.transform(blur_img), self.transform(sharp_img)

# 模型範例(簡單的 CNN)
class DeblurCNN(nn.Module):
def __init__(self):
super().__init__()
# self.net = nn.Sequential(
# nn.Conv2d(3, 64, kernel_size = 3, padding = 1),
# nn.ReLU(),
# nn.Conv2d(64, 3, kernel_size = 3, padding = 1),
# )
self.encoder = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3, padding=1), # input channels=3, output=64
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
)
self.middle = nn.Sequential(
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
)
self.decoder = nn.Sequential(
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(64, 3, kernel_size=3, padding=1), # output to RGB
)
def forward(self, x):
# return self.net(x)
x = self.encoder(x)
x = self.middle(x)
x = self.decoder(x)
return x

if __name__ == '__main__':
# os.makedirs('blurred', exist_ok=True)

# 假設圖片路徑如下
blur_dir = "blurred"
sharp_dir = "sharp"

# 取得所有圖片路徑,確保順序一致
blur_paths = sorted(glob(os.path.join(blur_dir, "*.jpg")))
sharp_paths = sorted(glob(os.path.join(sharp_dir, "*.jpg")))

# 初始化 Dataset
dataset = DeblurDataset(blur_paths, sharp_paths)

# 創建 DataLoader
dataloader = DataLoader(dataset, batch_size=8, shuffle=True, num_workers=2)

model = DeblurCNN().cpu()
loss_fn = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=3, verbose=True)

losses = []

for epoch in range(5):
epoch_loss = 0.0
model.train() # 加這行更好
for blur, sharp in dataloader:
blur, sharp = blur.cpu(), sharp.cpu()
output = model(blur)
loss = loss_fn(output, sharp)

optimizer.zero_grad()
loss.backward()
optimizer.step()

epoch_loss += loss.item()

avg_loss = epoch_loss / len(dataloader)
losses.append(avg_loss)
print(f'Epoch {epoch + 1}, Loss: {avg_loss:.6f}')
# print(f'learning rate: {optimizer.param_groups[0]['lr']:.6e}')
scheduler.step(avg_loss)

# 畫出 loss 圖
plt.figure()
plt.plot(losses, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Over Epochs')
plt.legend()
plt.grid(True)

# 保存圖片
plt.savefig('loss_curve_4.png') # 圖片會存在你的工作目錄中
plt.show()
# 儲存模型
torch.save(model.state_dict(), 'deblurred_model_4.pth')

# 載入模型
# model = DeblurringCNN().cpu()
# model.load_state_dict(torch.load('deblurring_model.pth'))

input 效果不太行 output_MIMO_UNet

loss_curve_4


下次加強建議:

在處理圖片前可能需要預先處理過(Preprocessing) 像是針對人臉的部分 在使用模型前,先檢查是否有人臉存在 若是有,將人臉框起來進行圖片處理 結束後,再將人臉組合回背景

Column 1Column 2Column 3
TextTextText
成員模組分支名稱開發位置
Amy前端 (React)feature/amy-uifrontend/
Bob後端 (Spring Boot)feature/bob-apibackend/
CarlAI 模型 / APIfeature/carl-aiai-server/