Pin-Jiun / ComputerVision

0 stars 0 forks source link

8-Retouch-filter #8

Open Pin-Jiun opened 1 year ago

Pin-Jiun commented 1 year ago

最後我們將前面的的成果,在函數中加入一些可變動的參數 這樣可調整性就會變得非常高,以後我們想要生成什麼樣的濾鏡,只要調一調參數就可以囉!

def japanese_style_filter(img):
    print("1. 調亮光線 (調整光線)")
    print("2. 加強飽和度 (調整飽和度)")
    img = modify_lightness_saturation(img, lightness=0, saturation=50) # 單位: +- %
    show_img(img)

    print("3. 將照片調成冷色調")
    img = modify_color_temperature(img, cold_rate=20) # 看你要+多冷 
    show_img(img)

    print("4. 增添顆粒感")
    img = gaussian_noise(img, mean=0, sigma=0.05) # mean 平均, sigma 標準差
    show_img(img)

    print("5. 降低對比")
    img = modify_contrast_and_brightness(img, brightness=20 , contrast=-35) # -255 ~ 255
    show_img(img)

    print("6. 降低高光")
    img = reduce_highlights(img, light_threshold=255) # 光源的 threshold 以上會被做降光處理
    show_img(img)

    return img
import cv2
import numpy as np
import matplotlib.pyplot as plt
import glob
from IPython.display import clear_output
import math

def show_img(img):
    plt.figure(figsize=(15,15)) 
    image_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    plt.imshow(image_rgb)
    plt.show()

def modify_lightness_saturation(img, lightness=0, saturation=300):

    origin_img = img

    # 圖像歸一化,且轉換為浮點型
    fImg = img.astype(np.float32)
    fImg = fImg / 255.0

    # 顏色空間轉換 BGR -> HLS
    hlsImg = cv2.cvtColor(fImg, cv2.COLOR_BGR2HLS)
    hlsCopy = np.copy(hlsImg)

#     lightness = 0 # lightness 調整為  "1 +/- 幾 %"
#     saturation = 300 # saturation 調整為 "1 +/- 幾 %"

    # 亮度調整
    hlsCopy[:, :, 1] = (1 + lightness / 100.0) * hlsCopy[:, :, 1]
    hlsCopy[:, :, 1][hlsCopy[:, :, 1] > 1] = 1  # 應該要介於 0~1,計算出來超過1 = 1

    # 飽和度調整
    hlsCopy[:, :, 2] = (1 + saturation / 100.0) * hlsCopy[:, :, 2]
    hlsCopy[:, :, 2][hlsCopy[:, :, 2] > 1] = 1  # 應該要介於 0~1,計算出來超過1 = 1

    # 顏色空間反轉換 HLS -> BGR 
    result_img = cv2.cvtColor(hlsCopy, cv2.COLOR_HLS2BGR)
    result_img = ((result_img * 255).astype(np.uint8))

    return result_img

def modify_color_temperature(img, cold_rate=20):

    # ---------------- 冷色調 ---------------- #  

#     height = img.shape[0]
#     width = img.shape[1]
#     dst = np.zeros(img.shape, img.dtype)

    # 1.計算三個通道的平均值,並依照平均值調整色調
    imgB = img[:, :, 0] 
    imgG = img[:, :, 1]
    imgR = img[:, :, 2] 

    # 調整色調請調整這邊~~ 
    # 白平衡 -> 三個值變化相同
    # 冷色調(增加b分量) -> 除了b之外都增加
    # 暖色調(增加r分量) -> 除了r之外都增加
    bAve = cv2.mean(imgB)[0] 
    gAve = cv2.mean(imgG)[0] + cold_rate
    rAve = cv2.mean(imgR)[0] + cold_rate
    aveGray = (int)(bAve + gAve + rAve) / 3

    # 2. 計算各通道增益係數,並使用此係數計算結果
    bCoef = aveGray / bAve
    gCoef = aveGray / gAve
    rCoef = aveGray / rAve
    imgB = np.floor((imgB * bCoef))  # 向下取整
    imgG = np.floor((imgG * gCoef))
    imgR = np.floor((imgR * rCoef))

    # 將原文第3部分的演算法做修改版,加快速度
    imgb = imgB
    imgb[imgb > 255] = 255

    imgg = imgG
    imgg[imgg > 255] = 255

    imgr = imgR
    imgr[imgr > 255] = 255

    cold_rgb = np.dstack((imgb, imgg, imgr)).astype(np.uint8) 

    return cold_rgb

def gaussian_noise(img, mean=0, sigma=0.1):

    # int -> float (標準化)
    img = img / 255.0
    # 隨機生成高斯 noise (float + float)
    noise = np.random.normal(mean, sigma, img.shape)
    # noise + 原圖
    gaussian_out = img + noise
    # 所有值必須介於 0~1 之間,超過1 = 1,小於0 = 0
    gaussian_out = np.clip(gaussian_out, 0, 1)

    # 原圖: float -> int (0~1 -> 0~255)
    gaussian_out = np.uint8(gaussian_out*255)
    # noise: float -> int (0~1 -> 0~255)
    noise = np.uint8(noise*255)

    return gaussian_out

def modify_contrast_and_brightness(img, brightness=0 , contrast=-100):
    # 上面做法的問題:有做到對比增強,白的的確更白了。
    # 但沒有實現「黑的更黑」的效果

    B = brightness / 255.0
    c = contrast / 255.0 
    k = math.tan((45 + 44 * c) / 180 * math.pi)

    img = (img - 127.5 * (1 - B)) * k + 127.5 * (1 + B)

    # 所有值必須介於 0~255 之間,超過255 = 255,小於 0 = 0
    img = np.clip(img, 0, 255).astype(np.uint8)

    return img

def reduce_highlights(img, light_threshold=200):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 先轉成灰階處理
    ret, thresh = cv2.threshold(img_gray, light_threshold, 255, 0)  # 利用 threshold 過濾出高光的部分,目前設定高於 200 即為高光
    contours, hierarchy  = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    highlight_mask = np.zeros(img.shape, dtype=np.uint8) 

#     print(len(contours))

    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour) 
        highlight_mask[y:y+h, x:x+w] = 255 

#     print("Highlight part: ")
#     show_img(highlight_mask)

    # alpha,beta 共同決定高光消除後的模糊程度
    # alpha: 亮度的缩放因子,默認是 0.2, 範圍[0, 2], 值越大,亮度越低
    # beta:  亮度缩放後加上的参数,默認是 0.4, 範圍[0, 2],值越大,亮度越低
    result = cv2.illuminationChange(img, highlight_mask, alpha=0.2, beta=0.2) 
#     show_img(result)

    return result

def japanese_style_filter(img):
    print("1. 調亮光線 (調整光線)")
    print("2. 加強飽和度 (調整飽和度)")
    img = modify_lightness_saturation(img, lightness=0, saturation=50) # 單位: +- %
    show_img(img)

    print("3. 將照片調成冷色調")
    img = modify_color_temperature(img, cold_rate=20)
    show_img(img)

    print("4. 增添顆粒感")
    img = gaussian_noise(img, mean=0, sigma=0.05)
    show_img(img)

    print("5. 降低對比")
    img = modify_contrast_and_brightness(img, brightness=20 , contrast=-35) # -255 ~ 255
    show_img(img)

    print("6. 降低高光")
    img = reduce_highlights(img, light_threshold=255)
    show_img(img)

    return img
from google.colab import files
uploaded = files.upload()

print(list(uploaded.keys())[0])

file_name = list(uploaded.keys())[0]
origin_img = cv2.imread(file_name)
print("origin picture:")
show_img(origin_img)

result_img = japanese_style_filter(origin_img)
print("result picture:")
show_img(result_img)

https://www.wongwonggoods.com/all-posts/python/python_opencv/opencv-japanese-filter/