python 生成AI

PythonとOpenCVのコードをChatGPTで自動生成する

この記事では、ChatGPTを使ってpythonのコードを作成する事例を紹介します。

https://openai.com/chatgpt/

ChatGPTでコード生成するもの

今回は以下のPythonとOpenCVを使った写真の傾きを補正する射影変換のコードを再現することを目的にします。

https://kozakanalaboratory.com/python-opencv1/

ChatGPTへの指示文

上記記事にて、pythonで実現したいことの要求仕様を定義していました。要求仕様としては8つなので、これらをプロンプトとしてChatGPTに送信します。また、上記記事のコードにはmatplotlibは使用していないためその条件のコードが生成できるかを確認するために、matplotlibは使わないことをプロンプト文に追記しています。

以下を実行可能なpythonのコードを教えてください。matplotlibは使わないでください。

・ユーザーのパスの指定を元に、パス先に保存された画像を取得する

・補正の基準となる頂点の入力を受け付ける

・入力された頂点座標をもとに、画像を射影変換する

・補正後の画像の出力先のパス指定を受け付ける

・指定先に補正後の画像を保存する

・画像のパス指定(補正する画像と補正後の画像)はコードでの指定ではなく、任意で選択したい

・頂点座標の入力は実際の画像を見ながら指定できるようにしたい(頂点同士は直線で繋ぐこと)

・指定した頂点や補正する部分がわかるようにしたい

ChatGPTの実行結果

プロンプト文によるChatGPTで生成されたpythonコードは以下です。およそ20秒くらいで生成されました。早い!

import cv2
import numpy as np
from tkinter import filedialog, Tk

# ファイル選択ダイアログを表示するための関数
def choose_file(title="Choose an image"):
    root = Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename(title=title)
    return file_path

# 射影変換を行うための関数
def perform_perspective_transform(input_image, src_points, output_size):
    # 射影変換の行列を取得
    dst_points = np.float32([
        [0, 0],
        [output_size[0] - 1, 0],
        [output_size[0] - 1, output_size[1] - 1],
        [0, output_size[1] - 1]
    ])
    
    matrix = cv2.getPerspectiveTransform(src_points, dst_points)
    
    # 画像の射影変換を実行
    transformed_image = cv2.warpPerspective(input_image, matrix, output_size)
    return transformed_image

# 頂点を選択するための関数
def select_points(event, x, y, flags, param):
    global points, image
    
    if event == cv2.EVENT_LBUTTONDOWN:
        if len(points) < 4:
            points.append([x, y])
            cv2.circle(image, (x, y), 5, (0, 255, 0), -1)
            if len(points) > 1:
                cv2.line(image, tuple(points[-2]), tuple(points[-1]), (0, 255, 0), 2)
            cv2.imshow("Select points", image)

# メイン処理
if __name__ == "__main__":
    # 画像のパスを選択
    input_image_path = choose_file("Select the image to correct")
    image = cv2.imread(input_image_path)
    
    # 頂点の選択
    points = []
    cv2.imshow("Select points", image)
    cv2.setMouseCallback("Select points", select_points)
    
    while len(points) < 4:
        cv2.waitKey(1)
    
    # 選択した頂点を基に射影変換
    src_points = np.float32(points)
    output_size = (image.shape[1], image.shape[0])  # 元の画像と同じサイズに補正
    
    transformed_image = perform_perspective_transform(image, src_points, output_size)
    
    # 変換後の画像の保存先を選択
    output_image_path = filedialog.asksaveasfilename(defaultextension=".jpg", filetypes=[("JPEG files", "*.jpg"), ("PNG files", "*.png")], title="Save the corrected image")
    
    if output_image_path:
        cv2.imwrite(output_image_path, transformed_image)
        print(f"Image saved to {output_image_path}")
    
    cv2.destroyAllWindows()

以下のような解説も出力してくれました。

コードの説明

1. 画像選択: choose_file()関数を使い、ユーザーが補正したい画像をファイルダイアログで選択します。

2. 頂点指定: select_points()関数を用いて、ユーザーが画像上で4つの頂点をマウスクリックで指定します。選択された頂点は画像上に表示されます。

3. 射影変換: perform_perspective_transform()関数で、指定された頂点を基に画像の射影変換を行います。

4. 保存先選択: filedialog.asksaveasfilename()を使用して、補正後の画像の保存先を指定し、その場所に変換後の画像を保存します。

これを実行した結果がこちら。射影変換はできていますが、基準点を取る際に表示される点や線が補正後の出力画像にも残ってしまっています。

指示文の追加

上記までの実行結果に対して、以下の指示文を追加(ChatGPTの出力結果に対して返信)しました。

変換後の画像にはマウスクリック時の円や直線は表示しないように修正してください。

その出力結果がこちら。

import cv2
import numpy as np
from tkinter import filedialog, Tk

# ファイル選択ダイアログを表示するための関数
def choose_file(title="Choose an image"):
    root = Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename(title=title)
    return file_path

# 射影変換を行うための関数
def perform_perspective_transform(input_image, src_points, output_size):
    # 射影変換の行列を取得
    dst_points = np.float32([
        [0, 0],
        [output_size[0] - 1, 0],
        [output_size[0] - 1, output_size[1] - 1],
        [0, output_size[1] - 1]
    ])
    
    matrix = cv2.getPerspectiveTransform(src_points, dst_points)
    
    # 画像の射影変換を実行
    transformed_image = cv2.warpPerspective(input_image, matrix, output_size)
    return transformed_image

# 頂点を選択するための関数
def select_points(event, x, y, flags, param):
    global points, display_image
    
    if event == cv2.EVENT_LBUTTONDOWN:
        if len(points) < 4:
            points.append([x, y])
            temp_image = display_image.copy()
            cv2.circle(temp_image, (x, y), 5, (0, 255, 0), -1)
            if len(points) > 1:
                cv2.line(temp_image, tuple(points[-2]), tuple(points[-1]), (0, 255, 0), 2)
            cv2.imshow("Select points", temp_image)

# メイン処理
if __name__ == "__main__":
    # 画像のパスを選択
    input_image_path = choose_file("Select the image to correct")
    original_image = cv2.imread(input_image_path)
    
    # 元の画像を表示するためにコピー
    display_image = original_image.copy()
    
    # 頂点の選択
    points = []
    cv2.imshow("Select points", display_image)
    cv2.setMouseCallback("Select points", select_points)
    
    while len(points) < 4:
        cv2.waitKey(1)
    
    # 選択した頂点を基に射影変換
    src_points = np.float32(points)
    output_size = (original_image.shape[1], original_image.shape[0])  # 元の画像と同じサイズに補正
    
    transformed_image = perform_perspective_transform(original_image, src_points, output_size)
    
    # 変換後の画像の保存先を選択
    output_image_path = filedialog.asksaveasfilename(defaultextension=".jpg", filetypes=[("JPEG files", "*.jpg"), ("PNG files", "*.png")], title="Save the corrected image")
    
    if output_image_path:
        cv2.imwrite(output_image_path, transformed_image)
        print(f"Image saved to {output_image_path}")
    
    cv2.destroyAllWindows()

基準点を取る際に表示される点や線が出力画像から消えました!途中の補正点の表示の仕方や、出力結果のアスペクト比など修正したい点はありますが、数十秒程度の2回のやり取りでここまでできるのはすごいです。

まとめ

要求仕様さえ決まっていれば、ChatGPTである程度完成されたコードが生成できそうです。
ただし、ChatGPTの出力結果は正しくない場合もあり、出力コードのチェックや実行して不具合がないことの確認は必須です。

以上より、最初のドラフトをChatGPTに生成してもらって、詳細を修正していく、という使い方が効率的だと思います。

要求仕様のクオリティがChatGPTの出力のクオリティに効いてきます。要求仕様がやはり大事!

所長
所長

-python, 生成AI