Tuple[float, bool]: """ FFTを使用してピンボケを検出 Args: image: 入力画像(グレースケール) Returns: score: ボケの度合いを示すスコア(低いほどボケている) "> Tuple[float, bool]: """ FFTを使用してピンボケを検出 Args: image: 入力画像(グレースケール) Returns: score: ボケの度合いを示すスコア(低いほどボケている) "> Tuple[float, bool]: """ FFTを使用してピンボケを検出 Args: image: 入力画像(グレースケール) Returns: score: ボケの度合いを示すスコア(低いほどボケている) ">
import sys
import cv2             # opencv-python
import numpy as np
from scipy.ndimage import variance
from typing import Tuple

class BlurDetector:
    def __init__(self):
        self.laplacian_threshold = 100  # ラプラシアンによるブレ検出の閾値
        self.fft_threshold = 10  # FFTによるボケ検出の閾値

    def detect_motion_blur(self, image: np.ndarray) -> Tuple[float, bool]:
        """
        ラプラシアン変換を使用して動きブレを検出
        Args:
            image: 入力画像(グレースケール)
        Returns:
            score: ブレの度合いを示すスコア(低いほどブレている)
            is_blurred: ブレているかどうかのブール値
        """
        # ラプラシアン変換で輪郭を強調
        laplacian = cv2.Laplacian(image, cv2.CV_64F)
        # 分散を計算
        score = variance(laplacian)
        is_blurred = score < self.laplacian_threshold
        return score, is_blurred

    def detect_focus_blur(self, image: np.ndarray) -> Tuple[float, bool]:
        """
        FFTを使用してピンボケを検出
        Args:
            image: 入力画像(グレースケール)
        Returns:
            score: ボケの度合いを示すスコア(低いほどボケている)
            is_blurred: ボケているかどうかのブール値
        """
        # 画像をフーリエ変換
        f_transform = np.fft.fft2(image)
        f_shift = np.fft.fftshift(f_transform)
        # パワースペクトルを計算
        magnitude_spectrum = 20 * np.log(np.abs(f_shift))
        # 高周波成分の平均を計算
        rows, cols = image.shape
        center_row, center_col = rows // 2, cols // 2
        mask = np.zeros_like(magnitude_spectrum)
        mask[center_row-30:center_row+30, center_col-30:center_col+30] = 1
        high_freq_mean = np.mean(magnitude_spectrum * (1 - mask))
        score = high_freq_mean
        is_blurred = score < self.fft_threshold
        return score, is_blurred

    def analyze_image(self, image_path: str) -> dict:
        """
        画像を分析してブレとボケの両方を検出
        Args:
            image_path: 画像ファイルのパス
        Returns:
            dict: 分析結果を含む辞書
        """
        # 画像を読み込んでグレースケールに変換
        image = cv2.imread(image_path)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        # モーションブレとピンボケを検出
        motion_score, has_motion_blur = self.detect_motion_blur(gray)
        focus_score, has_focus_blur = self.detect_focus_blur(gray)
        return {
            "motion_blur": {
                "score": motion_score,
                "detected": has_motion_blur
            },
            "focus_blur": {
                "score": focus_score,
                "detected": has_focus_blur
            }
        }

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python detect_blur.py <image_file>")
        sys.exit(1)

    image_file = sys.argv[1]
    detector = BlurDetector()
    result = detector.analyze_image(image_file)
    print(result)

IMG_1961.jpeg

python detect_blur.py C:\Users\XXX\Pictures\Tz5-smqGODc_ZPXk.jpg {'motion_blur': {'score': 97.60005976340015, 'detected': True}, 'focus_blur': {'score': 137.49029206799617, 'detected': False}}