[AI][Python]OpenCV圖片特校-馬賽克處理

文、意如

續上一篇:[AI][Python]OpenCV進行臉部偵測(取得臉部座標位置)

 

py07.py

import cv2  # 匯入 OpenCV 函式庫,用於影像處理

# 讀取彩色圖片(BGR格式)
img = cv2.imread('media/img3.jpg')  # 注意:需確認圖片路徑正確

# 顯示原圖的形狀(高度, 寬度, 色彩通道數)
print("img.shape=", img.shape)  # 例如:img.shape= (339, 755, 3)

# 顯示原始圖片視窗
cv2.imshow('Original Image', img)

# 指定臉部位置與大小(手動設定,未使用自動臉部偵測)
x, y, w, h = 272, 52, 143, 143  # (左上角座標x, y) + 寬度、高度

# 擷取臉部區域的圖像資料,取用 [y座標範圍, x座標範圍]
face = img[y:y+h, x:x+w]

# ========= 開始進行馬賽克處理 =========

# 設定馬賽克像素大小(值越大,模糊程度越高)
mosaic_size = 10

# 將臉部圖像縮小成 mosaic_size 的比例(例如變成 14x14 像素)
# INTER_LINEAR:較平滑的縮小方式
small = cv2.resize(face, (w // mosaic_size, h // mosaic_size), interpolation=cv2.INTER_LINEAR)

# 將剛剛縮小後的圖,再放大回原本大小
# INTER_NEAREST:放大時保留像素邊界(看起來更像馬賽克)
mosaic_face = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)

# 將處理後的馬賽克臉部,覆蓋回原圖的臉部位置
img[y:y+h, x:x+w] = mosaic_face

# ========= 馬賽克處理完成 =========

# 顯示處理後的圖片視窗
cv2.imshow("Mosaic Face", img)

# 等待任意鍵按下後,關閉所有 OpenCV 視窗
cv2.waitKey(0)
cv2.destroyAllWindows()
補充說明:
語法說明
cv2.imread()讀取圖片,第 2 個參數預設為 1(彩色)
img[y:y+h, x:x+w]取出圖像的區域(臉的矩形範圍)
cv2.resize()調整影像大小,這裡先縮小再放大產生像素化效果
INTER_LINEAR插值方式,適合縮小
INTER_NEAREST插值方式,適合放大馬賽克效果
cv2.imshow()顯示圖片視窗
cv2.waitKey(0)等待任意鍵按下
cv2.destroyAllWindows()關閉所有視窗
進階應用:

✅ 自動偵測多張人臉 → 對每一張臉都打馬賽克
✅ 為每張人臉加上綠色框線與提示文字
✅ 將結果圖片儲存為 output.jpg

功能描述
detectMultiScale()自動偵測圖片中的所有人臉
cv2.rectangle()繪製臉部框線
cv2.putText()加上提示文字
cv2.imwrite()將處理後的圖片儲存到本地

 

py08.py

import cv2  # 匯入 OpenCV 函式庫(用於影像處理與電腦視覺)

# 載入 OpenCV 內建的人臉特徵分類器 XML(包含各種臉部特徵)
case_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(case_path)

# 讀取一張圖片(以 BGR 彩色模式)
img = cv2.imread('media/img4.jpg')  # 可替換為你的圖片路徑
# 將彩色圖片轉成灰階(偵測速度更快)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 使用分類器偵測臉部
faces = face_cascade.detectMultiScale(
    gray,              # 傳入灰階圖像
    scaleFactor=1.1,   # 每次影像縮小的比例(>1,數字越小檢測越仔細但越慢)
    minNeighbors=5,    # 最小鄰近數,數字越大越嚴格(建議 3~6)
    minSize=(30, 30)   # 臉部的最小尺寸(小於這個尺寸的不會被偵測)
)

# 印出偵測到幾張人臉
print(f"共偵測到 {len(faces)} 張人臉")

# 遍歷每一張臉,進行處理
for i, (x, y, w, h) in enumerate(faces):
    # 繪製綠色的矩形框,框住臉部
    # (x, y):左上角座標,(x+w, y+h):右下角座標,(0, 255, 0):綠色,2:線條粗細
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 從原圖中擷取臉部區域(y:高度, x:寬度)
    face = img[y:y + h, x:x + w]

    # ----------- 進行「馬賽克處理」 -------------
    mosaic_size = 10  # 馬賽克的強度(越大越模糊)
    # 將臉部縮小
    small = cv2.resize(face, (w // mosaic_size, h // mosaic_size), interpolation=cv2.INTER_LINEAR)
    # 再放大回原尺寸(會變成像素狀)
    mosaic_face = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)
    # 將原本臉部區域替換為馬賽克後的區塊
    img[y:y + h, x:x + w] = mosaic_face

    # ----------- 顯示臉部的提示文字 -------------
    text = f"Face {i + 1}"  # 顯示:Face 1、Face 2…
    font = cv2.FONT_HERSHEY_SIMPLEX  # 使用內建英文字型
    font_scale = 0.6  # 文字大小
    thickness = 2     # 文字線條粗細
    color = (200, 200, 200)  # 文字顏色(灰白)

    # 計算文字位置:臉部上方,避免太靠上
    text_size, _ = cv2.getTextSize(text, font, font_scale, thickness)
    text_x = x
    text_y = y - 10 if y - 10 > 20 else y + 20
    # 加入提示文字
    cv2.putText(img, text, (text_x, text_y), font, font_scale, color, thickness)

# ----------- 在右下角加上總人臉數 -------------
face_count_text = f"Detected {len(faces)} face(s)"
text_size, _ = cv2.getTextSize(face_count_text, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2)
text_x = img.shape[1] - text_size[0] - 10  # 右邊留 10px 邊界
text_y = img.shape[0] - 10                 # 底部留 10px 邊界
cv2.putText(img, face_count_text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)

# ----------- 儲存處理後的圖片 -------------
cv2.imwrite("output.jpg", img)  # 將結果儲存為檔案
print("圖片已儲存為 output.jpg")

# ----------- 顯示處理後的圖片視窗 -------------
cv2.imshow("Face Mosaic", img)  # 視窗名稱 + 圖片內容
cv2.waitKey(0)                  # 等待任意鍵結束
cv2.destroyAllWindows()         # 關閉所有 OpenCV 視窗
讓使用者自行選擇圖片

py09.py

import cv2  # 匯入 OpenCV 函式庫(用於影像處理與電腦視覺)
from tkinter import Tk
from tkinter.filedialog import askopenfilename

# 關閉預設的 Tkinter 視窗
Tk().withdraw()

# 彈出檔案選擇對話框
file_path = askopenfilename(title="請選擇圖片", filetypes=[("Image files", "*.jpg *.png *.jpeg *.bmp")])

# 判斷是否有選擇檔案
if not file_path:
    print("未選擇圖片,程式結束。")
    exit()

# 讀取使用者選擇的圖片,後續圖像處理就可以繼續使用 img
img = cv2.imread(file_path)
if img is None:
    print("圖片讀取失敗")
    exit()

# 載入 OpenCV 內建的人臉特徵分類器 XML(包含各種臉部特徵)
case_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(case_path)

# 將彩色圖片轉成灰階(偵測速度更快)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 使用分類器偵測臉部
faces = face_cascade.detectMultiScale(
    gray,              # 傳入灰階圖像
    scaleFactor=1.1,   # 每次影像縮小的比例(>1,數字越小檢測越仔細但越慢)
    minNeighbors=5,    # 最小鄰近數,數字越大越嚴格(建議 3~6)
    minSize=(30, 30)   # 臉部的最小尺寸(小於這個尺寸的不會被偵測)
)

# 印出偵測到幾張人臉
print(f"共偵測到 {len(faces)} 張人臉")

# 遍歷每一張臉,進行處理
for i, (x, y, w, h) in enumerate(faces):
    # 繪製綠色的矩形框,框住臉部
    # (x, y):左上角座標,(x+w, y+h):右下角座標,(0, 255, 0):綠色,2:線條粗細
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 從原圖中擷取臉部區域(y:高度, x:寬度)
    face = img[y:y + h, x:x + w]

    # ----------- 進行「馬賽克處理」 -------------
    mosaic_size = 10  # 馬賽克的強度(越大越模糊)
    # 將臉部縮小
    small = cv2.resize(face, (w // mosaic_size, h // mosaic_size), interpolation=cv2.INTER_LINEAR)
    # 再放大回原尺寸(會變成像素狀)
    mosaic_face = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)
    # 將原本臉部區域替換為馬賽克後的區塊
    img[y:y + h, x:x + w] = mosaic_face

    # ----------- 顯示臉部的提示文字 -------------
    text = f"Face {i + 1}"  # 顯示:Face 1、Face 2…
    font = cv2.FONT_HERSHEY_SIMPLEX  # 使用內建英文字型
    font_scale = 0.6  # 文字大小
    thickness = 2     # 文字線條粗細
    color = (0, 0, 0)  # 文字顏色(灰白)

    # 計算文字位置:臉部上方,避免太靠上
    text_size, _ = cv2.getTextSize(text, font, font_scale, thickness)
    text_x = x
    text_y = y - 10 if y - 10 > 20 else y + 20
    # 加入提示文字
    cv2.putText(img, text, (text_x, text_y), font, font_scale, color, thickness)

# ----------- 在右下角加上總人臉數 -------------
face_count_text = f"Detected {len(faces)} face(s)"
text_size, _ = cv2.getTextSize(face_count_text, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2)
text_x = img.shape[1] - text_size[0] - 10  # 右邊留 10px 邊界
text_y = img.shape[0] - 10                 # 底部留 10px 邊界
cv2.putText(img, face_count_text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)

# ----------- 儲存處理後的圖片 -------------
cv2.imwrite("output.jpg", img)  # 將結果儲存為檔案
print("圖片已儲存為 output.jpg")

#調整顯示圖片的尺寸
max_width = 800
if img.shape[1] > max_width:
    scale = max_width / img.shape[1]
    resized_img = cv2.resize(img, (int(img.shape[1] * scale), int(img.shape[0] * scale)))
else:
    resized_img = img

# ----------- 顯示處理後的圖片視窗 -------------
cv2.imshow("Face Mosaic", resized_img)  # 視窗名稱 + 圖片內容
cv2.waitKey(0)                  # 等待任意鍵結束
cv2.destroyAllWindows()         # 關閉所有 OpenCV 視窗
讓使用者進行選擇圖片

py10.py

import cv2
import tkinter as tk
from tkinter import filedialog
import numpy as np

def select_image():
    # 使用者選圖
    filepath = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg *.png *.jpeg")])
    if not filepath:
        print("沒有選擇圖片")
        return

    # 安全讀取圖片(防止中文/空白路徑失敗)
    with open(filepath, 'rb') as f:
        img_array = np.asarray(bytearray(f.read()), dtype=np.uint8)
        img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)

    if img is None:
        print("圖片讀取失敗")
        return

    # 圖片縮小(避免過大閃退)
    max_width = 800
    scale = max_width / img.shape[1]
    img = cv2.resize(img, (int(img.shape[1]*scale), int(img.shape[0]*scale)))

    # 載入人臉偵測模型
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

    # 灰階轉換提升效能
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 偵測人臉
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    for (x, y, w, h) in faces:
        # 取出臉部區域
        face_roi = img[y:y+h, x:x+w]
        # 打馬賽克:縮小再放大
        mosaic = cv2.resize(face_roi, (16, 16), interpolation=cv2.INTER_LINEAR)
        mosaic = cv2.resize(mosaic, (w, h), interpolation=cv2.INTER_NEAREST)
        img[y:y+h, x:x+w] = mosaic

        # 畫出綠色框線
        cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)

        # 上方加灰色提示框 + 文字
        label = "face"
        (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
        cv2.rectangle(img, (x, y-25), (x + tw + 10, y), (128, 128, 128), -1)
        cv2.putText(img, label, (x + 5, y - 7), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)

    # 顯示總數
    count_text = f"{len(faces)} faces"
    (ctw, cth), _ = cv2.getTextSize(count_text, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2)
    cx = img.shape[1] - ctw - 10
    cy = img.shape[0] - 10
    cv2.putText(img, count_text, (cx, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

    # 儲存圖片
    cv2.imwrite("output.jpg", img)
    print("已儲存為 output.jpg")

    # 顯示圖片
    cv2.imshow("馬賽克人臉", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# GUI 主畫面
root = tk.Tk()
root.title("人臉馬賽克工具")
root.geometry("300x100")

btn = tk.Button(root, text="選擇圖片並處理", command=select_image, font=("Arial", 14))
btn.pack(expand=True)

root.mainloop()

 

 

Yiru@Studio - 關於我 - 意如