画像解析で検証、SILKYPIXは必要なのか?

カテゴリー:  Tech タグ:  raw image development software

Image

RICOH GR IIIx HDFを購入してから、画像フォーマットをJPEGでなくRAW形式で運用し ています。RAW画像を現像するために、市川ソフトラボラトリー1SILKPIX Developer Studio Pro11を使っていますが、 使い続ける価値があるかどうか気になっていました。

理由は、SILKYPIXはRAW現像の時間がかかる上に、プレビュー動作が非常に重たいからです。 特にプレビューの動作の問題は深刻で、しばらく使っているとフリーズしてしまうことも多く、 SILKYPIXのMac版はWindowsよりバージョンが一つ古いこともあり、 macOSの最適化の点で技術力に問題があるか、もしかするとバグがあるのかもと疑い たくなります。

macOSがRAWファイルをサポートしているので、今では多くのアプリでRAWファイルを 扱えます。特にPixelmator ProなどはmacOSに最適化されているため、RAW現像も非常 に高速です。

そのため、「SILKYPIXを使い続ける意味があるのか」と考えてしまうわけです。

今回はPython で画像を比較するツールを書いて、次の3つの画像を比較し データでその品質を検証してました。

比較は、以下の3つです。

  • Image1: Mac版のSILKYPIXで現像したJpeg File。調整は何も行っていない。
  • Image2: Pixelmator Proで現像したJpeg File。調整は何も行っていない。
  • Image3: GR IIIxで撮影時にJpegで保管したもの。ただし、Image Controlでネガフィルム調を指定

画像解析でJPEGファイルを比較

解析に使用したプログラムは、記事の最後に掲載しておきます。

検証に使用した画像は、ちょっと西日が紅葉に指している公園の風景です。暗い木が 茂っている部分と西日が差している紅葉部分で明度の差が激しく難しい画像だと思い ます。

結果は次のようになりました。

比較結果

詳細データです。

 python three-image-comparison.py

Image 1 Analysis:
Size: (4000, 6000, 3)
Mean Brightness: 85.267
Standard Deviation: 72.58
Mean Saturation: 113.675
Contrast: 255
File Size(KB): 19070.3955078125

Image 2 Analysis:
Size: (4000, 6000, 3)
Mean Brightness: 66.147
Standard Deviation: 73.611
Mean Saturation: 135.691
Contrast: 255
File Size(KB): 29992.3681640625

Image 3 Analysis:
Size: (4000, 6000, 3)
Mean Brightness: 93.122
Standard Deviation: 74.255
Mean Saturation: 85.623
Contrast: 255
File Size(KB): 13395.0634765625

Comparison Results:
SSIM 1-2: 0.68
SSIM 1-3: 0.847
SSIM 2-3: 0.737
Histogram Correlation 1-2: 0.3822719180861183
Histogram Correlation 1-3: 0.7985840630919663
Histogram Correlation 2-3: 0.13442670111231494
Size: (4000, 6000, 3)
Bit Depth 1: uint8
Bit Depth 2: uint8
Bit Depth 3: uint8

画像比較結果

データからわかる各画像の特性は、次の通りです。

  • SILKYPIXの画像
    • 中間的な明るさで落ち着いたトーン
    • 適度に彩度が高く、鮮やかさと自然さを両立
    • 明るさが安定しており、均一な仕上がり
  • Pixelmator Proの画像
    • 最も暗めの仕上がり。陰影が強調されている
    • 最も彩度が高く、鮮やかさが重視されている
    • トーンの変化がダイナミックで、劇的な印象
  • GR IIIxのJpeg画像(ネガフィルム調)
    • 最も明るい仕上がりで、軽やかで柔らかいトーン
    • 最も彩度が低めで落ち着いたナチュラルな色彩。
    • 明るさの変化が適度で、自然なグラデーション

比較結果では、次のような結果となっている。

  • SSIM(構造的類似性指数)からは、SILKYPIXとPixelmator Proは全体の構造がかな りことなり、明るさと彩度が大きく違う。GR IIIxのJpegはどちかというとSILKYPIXに近いが、彩度が控えめ。
  • ヒストグラム相関から、SILKYPIXとPixelmator Proは色分布が大きく異なってい る。GR IIIxのJpeg と比較するとSILKYPIXは類似性があり、Pixelmator Proは大きく違っている。

画像比較結果からのアプリの評価

画像の比較からだけ見ると次のような結論になります。

  • SILKYPIXは鮮やかな彩度とバランスのよい明るさで、自然なトーンと適度な色彩の鮮やかさが求められる ポートレートや風景写真などに向いている。バランスがよく汎用的が高い。
  • Pixelmator Proは、鮮やかな色彩とダイナミックなトーンで、広告やアート作品が向いている。やや暗めで撮影時と大きく印象が違っているため、劇的な表現になるがテーマを選んでしまう可能性が高い。素材により暗すぎる点が問題。
  • GR IIIxのJpeg画像はネガフィルム調を使っていることが大きいが、明るく柔らか いトーンで日常写真など落ち着いた印象がよい。

この画像だけで言うと、やはりSILKYPIXはそれなりによいし、数値でも確認できた。 逆にPixelmator Proはグラフィックにはよいが、写真には少しわざとらしさが出てし まう印象を持った。

ただし、両ソフトとも何も調整していないので、自動調整などの機能をそれぞれ持っ ているので、調整を入れると大きく違いが出る可能性もある。

意外だったのが、GR IIIx自体のJpeg、しかもImage Controlのネガフィルム調が個人 的に気に入ったこと。明るく軽やかで味がある表現となっている。

これであれば、RAW + JPEGで撮影して、問題なければGR IIIxのJPEGを使い、調整が必要ならば SILKYPIXで追い込んで現像というのよさそう。

分析に使用したプログラム

やっつけ仕事で作ったので、入力ファイル名とかベタ書きしてしまっています。

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from skimage.metrics import structural_similarity as ssim
import cv2
import os


def compare_three_images(image1_path, image2_path, image3_path, output_path=None):
    """
    Compare three images and analyze them using various metrics

    Parameters:
    image1_path (str): Path to first image
    image2_path (str): Path to second image
    image3_path (str): Path to third image
    output_path (str): Path to save comparison results (optional)

    Returns:
    dict: Comparison metrics
    """
    # Load images
    img1 = cv2.imread(image1_path, cv2.IMREAD_UNCHANGED)
    img2 = cv2.imread(image2_path, cv2.IMREAD_UNCHANGED)
    img3 = cv2.imread(image3_path, cv2.IMREAD_UNCHANGED)

    if img1 is None or img2 is None or img3 is None:
        raise ValueError("Failed to load one or more images")

    # Normalize to 8-bit if necessary for visualization
    def normalize_to_8bit(img):
        if img.dtype != np.uint8:
            return cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
        return img

    img1_8bit = normalize_to_8bit(img1)
    img2_8bit = normalize_to_8bit(img2)
    img3_8bit = normalize_to_8bit(img3)

    # Convert to grayscale for SSIM
    gray1 = cv2.cvtColor(img1_8bit, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2_8bit, cv2.COLOR_BGR2GRAY)
    gray3 = cv2.cvtColor(img3_8bit, cv2.COLOR_BGR2GRAY)

    # Calculate SSIM between each pair
    ssim_1_2 = ssim(gray1, gray2)
    ssim_1_3 = ssim(gray1, gray3)
    ssim_2_3 = ssim(gray2, gray3)

    # Compare histograms between each pair
    def calculate_hist_correlation(img1, img2):
        hist1 = cv2.calcHist([img1], [0], None, [256], [0, 256])
        hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256])
        return cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)

    hist_corr_1_2 = calculate_hist_correlation(img1_8bit, img2_8bit)
    hist_corr_1_3 = calculate_hist_correlation(img1_8bit, img3_8bit)
    hist_corr_2_3 = calculate_hist_correlation(img2_8bit, img3_8bit)

    # Visualization
    plt.figure(figsize=(15, 10))

    # Images
    plt.subplot(231)
    plt.imshow(cv2.cvtColor(img1_8bit, cv2.COLOR_BGR2RGB))
    plt.title("Image 1")
    plt.axis("off")

    plt.subplot(232)
    plt.imshow(cv2.cvtColor(img2_8bit, cv2.COLOR_BGR2RGB))
    plt.title("Image 2")
    plt.axis("off")

    plt.subplot(233)
    plt.imshow(cv2.cvtColor(img3_8bit, cv2.COLOR_BGR2RGB))
    plt.title("Image 3")
    plt.axis("off")

    # Histograms
    plt.subplot(234)
    plt.hist(img1_8bit.ravel(), 256, [0, 256])
    plt.title("Histogram - Image 1")

    plt.subplot(235)
    plt.hist(img2_8bit.ravel(), 256, [0, 256])
    plt.title("Histogram - Image 2")

    plt.subplot(236)
    plt.hist(img3_8bit.ravel(), 256, [0, 256])
    plt.title("Histogram - Image 3")

    if output_path:
        plt.savefig(output_path)

    plt.close()

    return {
        "SSIM 1-2": ssim_1_2,
        "SSIM 1-3": ssim_1_3,
        "SSIM 2-3": ssim_2_3,
        "Histogram Correlation 1-2": hist_corr_1_2,
        "Histogram Correlation 1-3": hist_corr_1_3,
        "Histogram Correlation 2-3": hist_corr_2_3,
        "Size": img1.shape,
        "Bit Depth 1": str(img1.dtype),
        "Bit Depth 2": str(img2.dtype),
        "Bit Depth 3": str(img3.dtype),
    }


def analyze_image(image_path):
    """
    1枚の画像の詳細な分析を行います

    Parameters:
    image_path (str): 画像のパス

    Returns:
    dict: 画像の分析結果
    """
    img = cv2.imread(image_path)
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    return {
        "Size": img.shape,
        "Mean Brightness": np.mean(img),
        "Standard Deviation": np.std(img),
        "Mean Saturation": np.mean(hsv[:, :, 1]),
        "Contrast": np.max(img) - np.min(img),
        "File Size(KB)": os.path.getsize(image_path) / 1024,  # KB単位
    }


def format_results(results_dict):
    """
    Format the results dictionary for better readability
    """
    formatted = {}
    for key, value in results_dict.items():
        if isinstance(value, (np.float64, np.float32)):
            formatted[key] = float(round(value, 3))
        elif isinstance(value, np.uint8):
            formatted[key] = int(value)
        else:
            formatted[key] = value
    return formatted


if __name__ == "__main__":
    # Compare three images
    results = compare_three_images(
        "image1.jpg", "image2.jpg", "image3.jpg", "comparison_result.png"
    )

    # Analyze each image
    images = ["image1.jpg", "image2.jpg", "image3.jpg"]
    for i, image_path in enumerate(images, 1):
        analysis = analyze_image(image_path)
        print(f"\nImage {i} Analysis:")
        for key, value in format_results(analysis).items():
            print(f"{key}: {value}")

    print("\nComparison Results:")
    for key, value in format_results(results).items():
        print(f"{key}: {value}")

  1. Windowsユーザーだったころ市川ラボラトリーの「デイジーアート」という画 像編集ソフトを愛用してたなぁ。今では別の会社から販売してて「教育機関向け」になっているが・・・ 

コメント

Comments powered by Disqus