Files
Stomach_Cancer_Pytorch/Image_Process/image_enhancement.py

309 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import cv2
import numpy as np
import torch
from PIL import Image
import torchvision
import functools
import inspect
# 套用裝飾器到現有函數
def unsharp_mask(image, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0):
"""使用OpenCV實現的Unsharp Mask銳化處理
參數:
image: PIL.Image對象(RGB格式)
kernel_size: 高斯模糊的核大小,必須是奇數
sigma: 高斯模糊的標準差
amount: 銳化程度,值越大效果越強
threshold: 邊緣檢測閾值,僅在邊緣處進行銳化
返回:
銳化後的PIL.Image對象
"""
# 轉換PIL圖像為numpy數組
numpy_img = np.array(image, dtype=np.uint8)
# 對原圖進行高斯模糊
blurred = cv2.GaussianBlur(numpy_img, kernel_size, sigma)
# 計算銳化後的圖像
sharpened = cv2.addWeighted(numpy_img, 1 + amount, blurred, -amount, 0)
# 如果設置了threshold只在邊緣處應用銳化
if threshold > 0:
low_contrast_mask = np.absolute(numpy_img - blurred) < threshold
np.copyto(sharpened, numpy_img, where=low_contrast_mask)
# 確保像素值在有效範圍內
sharpened = np.clip(sharpened, 0, 255).astype(np.uint8)
# 轉回PIL圖像
return Image.fromarray(sharpened)
def histogram_equalization(image):
"""GPU加速的一般直方圖等化
參數:
image: PIL.Image對象(RGB格式)
返回:
直方圖等化後的PIL.Image對象
"""
# 轉換為numpy數組並轉為PyTorch張量
numpy_img = np.array(image)
tensor_img = torch.from_numpy(numpy_img).float().to('cuda')
# 分離通道並進行直方圖等化
result = torch.zeros_like(tensor_img)
for i in range(3): # 對RGB三個通道分別處理
channel = tensor_img[..., i]
# 計算直方圖
hist = torch.histc(channel, bins=256, min=0, max=255)
# 計算累積分布函數(CDF)
cdf = torch.cumsum(hist, dim=0)
cdf_normalized = ((cdf - cdf.min()) * 255) / (cdf.max() - cdf.min())
# 應用直方圖等化
result[..., i] = cdf_normalized[channel.long()]
# 轉回CPU和numpy數組
result = torch.clamp(result, 0, 255).byte()
result_np = result.cpu().numpy()
return Image.fromarray(result_np)
def Contrast_Limited_Adaptive_Histogram_Equalization(image, clip_limit=3.0, tile_size=(8, 8)):
"""使用OpenCV實現的對比度限制自適應直方圖均衡化(CLAHE)
參數:
image: PIL.Image對象(RGB格式)
clip_limit: 剪切限制,用於限制對比度增強的程度,較大的值會產生更強的對比度
tile_size: 圖像分塊大小的元組(height, width),較小的值會產生更局部的增強效果
返回:
CLAHE處理後的PIL.Image對象
"""
# 將PIL圖像轉換為OpenCV格式BGR
numpy_img = np.array(image)
bgr_img = cv2.cvtColor(numpy_img, cv2.COLOR_RGB2BGR)
# 轉換到LAB色彩空間
lab_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2LAB)
# 創建CLAHE對象
clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_size)
# 分離LAB通道
l, a, b = cv2.split(lab_img)
# 對L通道應用CLAHE
l_clahe = clahe.apply(l)
# 合併處理後的L通道與原始的a和b通道
lab_output = cv2.merge([l_clahe, a, b])
# 將LAB轉回BGR然後轉換為RGB
bgr_output = cv2.cvtColor(lab_output, cv2.COLOR_LAB2BGR)
rgb_output = cv2.cvtColor(bgr_output, cv2.COLOR_BGR2RGB)
# 轉換為PIL圖像並返回
return Image.fromarray(rgb_output)
def adaptive_histogram_equalization_without_limit(image, tile_size=(8, 8)):
"""使用OpenCV實現的自適應直方圖均衡化(AHE)
參數:
image: PIL.Image對象(RGB格式)
tile_size: 圖像分塊大小的元組(height, width),較小的值會產生更局部的增強效果
返回:
AHE處理後的PIL.Image對象
"""
# 將PIL圖像轉換為OpenCV格式BGR
numpy_img = np.array(image)
bgr_img = cv2.cvtColor(numpy_img, cv2.COLOR_RGB2BGR)
# 轉換到LAB色彩空間
lab_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2LAB)
# 分離LAB通道
l, a, b = cv2.split(lab_img)
# 創建AHE對象不設置clip limit
clahe = cv2.createCLAHE(clipLimit=None, tileGridSize=tile_size)
# 對L通道應用AHE
l_ahe = clahe.apply(l)
# 合併處理後的L通道與原始的a和b通道
lab_output = cv2.merge([l_ahe, a, b])
# 將LAB轉回BGR然後轉換為RGB
bgr_output = cv2.cvtColor(lab_output, cv2.COLOR_LAB2BGR)
rgb_output = cv2.cvtColor(bgr_output, cv2.COLOR_BGR2RGB)
# 轉換為PIL圖像並返回
return Image.fromarray(rgb_output)
def laplacian_sharpen(image):
"""
GPU加速的拉普拉斯銳化處理函數
參數:
image: PIL.Image對象(RGB格式)
返回:
銳化後的PIL.Image對象
"""
# 轉換為numpy數組並轉為PyTorch張量
numpy_img = np.array(image)
tensor_img = torch.from_numpy(numpy_img).float().to('cuda')
# 創建拉普拉斯算子
laplacian_kernel = torch.tensor([
[0, 1, 0],
[1, -4, 1],
[0, 1, 0]
], dtype=torch.float32, device='cuda').unsqueeze(0).unsqueeze(0)
# 對每個通道進行處理
result = torch.zeros_like(tensor_img)
for i in range(3): # RGB三個通道
channel = tensor_img[..., i]
# 添加批次和通道維度
channel = channel.unsqueeze(0).unsqueeze(0)
# 應用拉普拉斯算子
laplacian = torch.nn.functional.conv2d(channel, laplacian_kernel, padding=1)
# 移除批次和通道維度
laplacian = laplacian.squeeze()
# 銳化處理:原圖 - 拉普拉斯
result[..., i] = channel.squeeze() - laplacian
# 確保像素值在合理範圍內
result = torch.clamp(result, 0, 255).byte()
# 轉回CPU和numpy數組
result_np = result.cpu().numpy()
return Image.fromarray(result_np)
def adjust_hsv(image, v_adjustment=0):
"""調整圖像的HSV色彩空間中的H和V通道
參數:
image: PIL.Image對象(RGB格式)
v_adjustment: V通道的調整值範圍建議在[-255, 255]之間
返回:
HSV調整後的PIL.Image對象
"""
# 將PIL圖像轉換為OpenCV格式BGR
numpy_img = np.array(image)
bgr_img = cv2.cvtColor(numpy_img, cv2.COLOR_RGB2BGR)
# 轉換到HSV色彩空間
hsv_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2HSV)
# 調整V通道
hsv_img[..., 2] = np.clip(hsv_img[..., 2] + v_adjustment, 0, 255)
# 將HSV轉回BGR然後轉換為RGB
bgr_output = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR)
rgb_output = cv2.cvtColor(bgr_output, cv2.COLOR_BGR2RGB)
# 轉換為PIL圖像並返回
return Image.fromarray(rgb_output)
def gamma_correction(image, gamma=1.0):
"""對圖像進行伽馬校正
參數:
image: PIL.Image對象(RGB格式)
gamma: 伽馬值gamma > 1 時圖像變暗gamma < 1 時圖像變亮gamma = 1 時保持不變
返回:
伽馬校正後的PIL.Image對象
"""
# 將PIL圖像轉換為numpy數組
numpy_img = np.array(image)
# 將像素值歸一化到[0, 1]範圍
normalized = numpy_img.astype(float) / 255.0
# 應用伽馬校正
corrected = np.power(normalized, gamma)
# 將值縮放回[0, 255]範圍
output = np.clip(corrected * 255.0, 0, 255).astype(np.uint8)
# 轉換回PIL圖像並返回
return Image.fromarray(output)
def Hight_Light(image, Threshold):
image = np.array(image)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# 使用閾值檢測高光點(白色液滴)
_, thresh = cv2.threshold(gray, Threshold, 255, cv2.THRESH_BINARY)
# 使用形態學操作(膨脹)來擴大遮罩區域
kernel = np.ones((5, 5), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations=1)
# 使用 inpaint 修復高光點
image_inpaint = cv2.inpaint(image, dilated, 3, cv2.INPAINT_TELEA)
return Image.fromarray(image_inpaint)
def median_filter(image: Image.Image, kernel_size: int = 3):
"""
中值濾波Median Filter實現
參數:
image: PIL.Image對象(RGB格式)
kernel_size: 濾波核大小,必須是奇數
返回:
濾波後的PIL.Image對象
"""
# 確保kernel_size是奇數
if kernel_size % 2 == 0:
kernel_size += 1
# 轉換PIL圖像為numpy數組
numpy_img = np.array(image, dtype=np.uint8)
# 對每個通道應用中值濾波
result = np.zeros_like(numpy_img)
for i in range(3): # 對RGB三個通道分別處理
result[:, :, i] = cv2.medianBlur(numpy_img[:, :, i], kernel_size)
# 確保像素值在有效範圍內
result = np.clip(result, 0, 255).astype(np.uint8)
# 轉回PIL圖像
return Image.fromarray(result)
def mean_filter(image: Image.Image, kernel_size: int = 3):
"""
均質濾波Mean Filter實現
參數:
image: PIL.Image對象(RGB格式)
kernel_size: 濾波核大小,必須是奇數
返回:
濾波後的PIL.Image對象
"""
# 確保kernel_size是奇數
if kernel_size % 2 == 0:
kernel_size += 1
# 轉換PIL圖像為numpy數組
numpy_img = np.array(image, dtype=np.uint8)
# 創建均質濾波核所有元素都是1/(kernel_size*kernel_size)
kernel = np.ones((kernel_size, kernel_size), np.float32) / (kernel_size * kernel_size)
# 對每個通道應用均質濾波
result = np.zeros_like(numpy_img)
for i in range(3): # 對RGB三個通道分別處理
result[:, :, i] = cv2.filter2D(numpy_img[:, :, i], -1, kernel)
# 確保像素值在有效範圍內
result = np.clip(result, 0, 255).astype(np.uint8)
# 轉回PIL圖像
return Image.fromarray(result)