LoginSignup
6
2

みなさんこんにちは!

前回、Pythonで線画を作ってみるという記事を書きました。

やってみたら面白かったので、それを応用して、水墨画風にしてみようと思います。

どこまで水墨画に近付けるか分かりませんが、やってみましょう:muscle:

環境構築などは前回の記事を参照してください:bow:

要件

  • 線は太め
  • モノクロ
  • 濃淡で表現する
  • ちょっとぼかす

ぱっと思いつくのはこのくらいなので、この要件で進めてみます。

追加したコード

ぼかし、コントラスト、ハイライトを使って、水墨画っぽくしてます。
これが正解かは分かりませんが、色々と調整した結果、ここに落ち着きました。

def ink_painting_effect(img):
    # グレースケールに変換
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # bilateralFilterを適用してぼかしを強化
    filtered = cv2.bilateralFilter(gray, 9, 200, 75)

    # CLAHEを適用してコントラストを強化
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(5, 5))
    contrast_enhanced = clahe.apply(filtered)

    # ハイライトを強調
    alpha = 1.3 # コントラスト
    beta = 40   # 明るさ
    highlighted = cv2.addWeighted(contrast_enhanced, alpha, np.zeros_like(contrast_enhanced), 0, beta)

    # エッジ検出
    edges = cv2.adaptiveThreshold(highlighted, 255,
                                  cv2.ADAPTIVE_THRESH_MEAN_C,
                                  cv2.THRESH_BINARY, 15, 7)

    # マスクを使用して元の画像とエッジを組み合わせる
    ink_painting = cv2.bitwise_and(highlighted, highlighted, mask=edges)

    return ink_painting

コード全体

前回のコードも残してます。

sample.py
import cv2
import numpy as np

def line_drawing_image(img):
    # 画像のコントラストを調整
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.equalizeHist(gray)

    # ガウシアンブラーを適用
    gray_blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    
    # エッジ検出で線画を生成
    edges = cv2.adaptiveThreshold(gray_blurred, 255,
                                  cv2.ADAPTIVE_THRESH_MEAN_C,
                                  cv2.THRESH_BINARY, 11, 7)
    
    return edges

def ink_painting_effect(img):
    # グレースケールに変換
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # バイラテラルフィルタを適用してぼかしを強化
    filtered = cv2.bilateralFilter(gray, 9, 200, 75)

    # CLAHEを適用してコントラストを強化
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(5, 5))
    contrast_enhanced = clahe.apply(filtered)

    # ハイライトを強調
    alpha = 1.3 # コントラスト
    beta = 40   # 明るさ
    highlighted = cv2.addWeighted(contrast_enhanced, alpha, np.zeros_like(contrast_enhanced), 0, beta)

    # エッジ検出(閾値を調整)
    edges = cv2.adaptiveThreshold(highlighted, 255,
                                  cv2.ADAPTIVE_THRESH_MEAN_C,
                                  cv2.THRESH_BINARY, 15, 7)

    # マスクを使用して元の画像とエッジを組み合わせる
    ink_painting = cv2.bitwise_and(highlighted, highlighted, mask=edges)

    return ink_painting

cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("カメラが開けません。")
    exit()

frame_count = 0
saved_images = 0

# カメラがオープンしている間はループ
while saved_images < 4:
    # フレームをキャプチャする
    ret, frame = cap.read()
    if not ret:
        print("フレームの取得に失敗しました。")
        break

    # 線画風の画像を生成
    # line_drawing = line_drawing_image(frame)
    # 水墨画風の画像を生成
    line_drawing = ink_painting_effect(frame)

    # 生成した画像を表示する
    cv2.imshow('Line Drawing Camera', line_drawing)

    # 10フレームごとに画像を保存
    if frame_count % 10 == 0:
        cv2.imwrite(f'line_drawing_{frame_count}.jpg', line_drawing)
        print(f'line_drawing_{frame_count}.jpg を保存しました。')
        saved_images += 1

    frame_count += 1

    # 'q'が押されたらループを抜ける
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# カメラをリリースしてウィンドウを閉じる
cap.release()
cv2.destroyAllWindows()

実行結果

さあ、結果はどうなったでしょうか。
生成された画像はこちらです!
test2.jpg
ちょっとそれっぽく出来ているのではないでしょうか。

前回との比較

せっかくなので、比較してみます。

前回(線画)

test.jpg

今回(水墨画)

test2.jpg

もう少し調整しても良さそうですが、個人的には満足です!

まとめ

前回に引き続き、Pythonで画像を生成してみました。
カメラの起動、画像データの取得と処理など、比較的簡単な実装で実現できました。

これをさらに応用すると、ボディカメラやドライブレコーダーと連携して動き回るだけで、様々な画像の学習ができそうですね。

他にも便利なライブラリがたくさんあるので、色々と使ってみて、スキルアップやサービスへの応用に役立てたいと思います:grinning:

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2