みなさんこんにちは!
前回、Pythonで線画を作ってみるという記事を書きました。
やってみたら面白かったので、それを応用して、水墨画風にしてみようと思います。
どこまで水墨画に近付けるか分かりませんが、やってみましょう
環境構築などは前回の記事を参照してください
要件
- 線は太め
- モノクロ
- 濃淡で表現する
- ちょっとぼかす
ぱっと思いつくのはこのくらいなので、この要件で進めてみます。
追加したコード
ぼかし、コントラスト、ハイライトを使って、水墨画っぽくしてます。
これが正解かは分かりませんが、色々と調整した結果、ここに落ち着きました。
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
コード全体
前回のコードも残してます。
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()
実行結果
さあ、結果はどうなったでしょうか。
生成された画像はこちらです!
ちょっとそれっぽく出来ているのではないでしょうか。
前回との比較
せっかくなので、比較してみます。
前回(線画)
今回(水墨画)
もう少し調整しても良さそうですが、個人的には満足です!
まとめ
前回に引き続き、Pythonで画像を生成してみました。
カメラの起動、画像データの取得と処理など、比較的簡単な実装で実現できました。
これをさらに応用すると、ボディカメラやドライブレコーダーと連携して動き回るだけで、様々な画像の学習ができそうですね。
他にも便利なライブラリがたくさんあるので、色々と使ってみて、スキルアップやサービスへの応用に役立てたいと思います