ChatGPTにプログラムを作らせた

ChatGPTにPythonでプログラムを作ってもらいました。
画像ファイルを読み込んで、トリミングと縮小を一度にできるプログラムです。
緑の四角で囲んだ範囲を1200×628に縮小して出力します。
WordPress専用の画像を作るツールです。

使い方

  • 画像ファイルを選択する
  • +,-キーで四角の枠を拡大、縮小する
  • 矢印キーで四角の枠を切り抜く位置に移動する
  • sキーで四角の枠内を切り抜き画像を保存する。選択したファイル名+_trm.pngで同一フォルダーに保存
  • Escキーで終了する

ChatGPTへの指示内容

下記の仕様のプログラムをpythonで作ってください。

### 機能 -ここから-
 【概要】
このプログラムは、クリップボード又は指定されたファイルから画像を取り込み、マウスやキーボード操作で選択した領域をトリミングし、
必要に応じてリサイズしたうえで保存する機能を提供する。

【機能】

1.画像の取り込み:
	- クリップボードに画像データがあれば、それを取り込む。
	- クリップボードにデータがない、または画像データでなければ、ファイル選択ダイアログから画像を選択する。
	- 取り込んだ画像を初期表示する際にトリミングする四角形を画像の中心に合わせて表示すること。四角形の横のサイズは表示サイズの1/2とする。
	  縦横比率はパラメータ(四角形比率)で指定された比率とする。

2.操作方法:
    - マウス左クリック: 四角形の選択範囲をクリックした位置を中心に再配置する。
    - '+'キー: 四角形の幅と高さを1ドットずつ拡大する。
    - '-'キー: 四角形の幅と高さを1ドットずつ縮小する。
    	[注意]拡縮時に中心点がずれない、即ち四方向に等しく拡縮するように注意すること。
    - 矢印キー: 四角形を1ドット単位で移動します。
      - 左矢印キー: 左方向に移動。
      - 右矢印キー: 右方向に移動。
      - 上矢印キー: 上方向に移動。
      - 下矢印キー: 下方向に移動。
	[注意]四角形を拡縮、移動する際に1回のキー入力で1ドットずつ変化するように注意すること。四角形の縦横比率を変えないこと。画像の外にはみ出さないこと。
		 
3. トリミングとリサイズ:
    - 取り込んだ画像が、パラメータ画面表示最大値を超える場合は、縦横比率比率を変えずに縮小する。
    - 出力画像の幅が指定された最大値(デフォルト: 1200ピクセル)を超える場合、縦横比を保持したまま縮小する。
	- 出力画像は 入力ファイル名に"_trmと"追加した名前で保存する。
	
4. パラメータ設定:
    - 四角形比率: 幅、高さ。
    - 画面表示最大値: 幅(2500)、高さ(1400)。
    - 矢印キーの移動量: 1ドット。
    - 四角形サイズ変更量: ドット。
    - 出力画像の最大幅: デフォルト値: 1200)
    
    
 【注意事項】
 	- 画像処理にはopencvを使う。
 	- 画像ファイルの接待パスには日本語が含まれる。エラーにならないようにすること。

### 機能 -ここまで-

### 手順 -ここから-

1.機能に矛盾や抜けがないかチェックし、あればそれを指摘しそれ以降の作業は行わない。
2.機能を日本語の仕様書として出力する。
3.スクリプトとして出力する。
4.スクリプトが機能を満たしているか確認すること。
5.スクリプトに適切な名前を付けること。
### 手順 -ここまで-

====================================  後から追加した機能   ====================================

次のスクリプトに機能を追加してください。
既存の機能が変わらないように十分に注意してください。

### 機能 -ここから-
現在は、指定したファイルから画像を入力していますが、
クリップボードに画像データがあれば、それを取り込む。
クリップボードにデータがない、または画像データでなければ、現状通りファイル選択ダイアログから画像を選択する。
クリップボードから取り込んだ場合は、デスクトップ上に、clipboard.pngで出力する。

### 機能 -ここまで-

※ChatGPTへの指示のポイント
 1.「機能に矛盾や抜けがないかチェック」させたこと
   出力ファイル名が決まらないと漏れをチェックしてくれました。
 2.プログラムを作る前に仕様書を作らせたこと
   ChatGPTに言葉で内容を確認させると、出力の品質が向上します。
 3.細かな調整が必要となる
   実際には、ファイルの絶対パスに日本語が含まれると動作せず、何度か修正が発生しました。

ChatGPTが出力したプログラム

import cv2
import numpy as np
from tkinter import filedialog, Tk
import os
from PIL import ImageGrab, Image

# パラメータ設定
RECT_RATIO = (1200, 628)  # 四角形比率 (幅:高さ)
DISPLAY_MAX_SIZE = (2500, 1400)  # 画面表示最大値 (幅, 高さ)
MAX_OUTPUT_WIDTH = 1200  # 出力画像の最大幅
MOVE_STEP = 10  # 矢印キーの移動量
RESIZE_STEP = 10  # 四角形サイズ変更量

class ImageCropper:
    def __init__(self, image, filename):
        self.image = image
        self.filename = filename
        self.display_image, self.scale = self.resize_image_for_display(image)
        self.rect = self.initialize_rect()
        self.clone = self.display_image.copy()

    def resize_image_for_display(self, img):
        """表示用に画像を縮小する(画面表示最大値を超えない)"""
        h, w = img.shape[:2]
        scale = min(DISPLAY_MAX_SIZE[1] / h, DISPLAY_MAX_SIZE[0] / w, 1)
        return cv2.resize(img, (int(w * scale), int(h * scale))), scale

    def initialize_rect(self):
        """トリミングする四角形を画像中心に初期化"""
        h, w = self.display_image.shape[:2]
        rw = w // 2
        rh = int(rw / RECT_RATIO[0] * RECT_RATIO[1])
        return [(w // 2 - rw // 2, h // 2 - rh // 2), (w // 2 + rw // 2, h // 2 + rh // 2)]

    def adjust_rect(self):
        """四角形が画像内に収まるよう調整"""
        h, w = self.display_image.shape[:2]
        self.rect[0] = (max(self.rect[0][0], 0), max(self.rect[0][1], 0))
        self.rect[1] = (min(self.rect[1][0], w), min(self.rect[1][1], h))

    def draw_rect(self):
        """四角形を描画"""
        self.clone = self.display_image.copy()
        cv2.rectangle(self.clone, self.rect[0], self.rect[1], (0, 255, 0), 2)

    def move_rect(self, dx, dy):
        """四角形を移動"""
        self.rect[0] = (self.rect[0][0] + dx, self.rect[0][1] + dy)
        self.rect[1] = (self.rect[1][0] + dx, self.rect[1][1] + dy)
        self.adjust_rect()

    def resize_rect(self, delta):
        """四角形をリサイズ"""
        cx = (self.rect[0][0] + self.rect[1][0]) // 2
        cy = (self.rect[0][1] + self.rect[1][1]) // 2
        rw = (self.rect[1][0] - self.rect[0][0]) // 2 + delta
        rh = int(rw / RECT_RATIO[0] * RECT_RATIO[1])
        self.rect = [(cx - rw, cy - rh), (cx + rw, cy + rh)]
        self.adjust_rect()

    def crop_and_save(self):
        """トリミングして保存"""
        x1, y1 = self.rect[0]
        x2, y2 = self.rect[1]
        crop = self.image[int(y1 / self.scale):int(y2 / self.scale), int(x1 / self.scale):int(x2 / self.scale)]
        h, w = crop.shape[:2]
        if w > MAX_OUTPUT_WIDTH:
            scale = MAX_OUTPUT_WIDTH / w
            crop = cv2.resize(crop, (MAX_OUTPUT_WIDTH, int(h * scale)))
        save_path = os.path.splitext(self.filename)[0] + "_trm.png"

        # 保存処理(日本語パス対応)
        success, encoded_image = cv2.imencode('.png', crop)
        if success:
            encoded_image.tofile(save_path)
            print(f"Saved: {save_path}")
        else:
            print("Failed to save the image.")

    def show(self):
        """画像を表示して操作を待機"""
        while True:
            self.draw_rect()
            cv2.imshow("Image Cropper", self.clone)
            key = cv2.waitKeyEx(1)
            if key == 27:  # ESCで終了
                break
            elif key == ord('s'):  # sキーで保存
                self.crop_and_save()
            elif key == ord('+'):  # +キーで拡大
                self.resize_rect(RESIZE_STEP)
            elif key == ord('-'):  # -キーで縮小
                self.resize_rect(-RESIZE_STEP)
            elif key == 0x250000:  # 左矢印キー
                self.move_rect(-MOVE_STEP, 0)
            elif key == 0x270000:  # 右矢印キー
                self.move_rect(MOVE_STEP, 0)
            elif key == 0x260000:  # 上矢印キー
                self.move_rect(0, -MOVE_STEP)
            elif key == 0x280000:  # 下矢印キー
                self.move_rect(0, MOVE_STEP)
        cv2.destroyAllWindows()

def get_image_from_clipboard():
    """クリップボードから画像を取得"""
    clipboard_image = ImageGrab.grabclipboard()
    if isinstance(clipboard_image, Image.Image):
        img_np = np.array(clipboard_image)
        img = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
        desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
        save_path = os.path.join(desktop_path, "clipboard.png")
        cv2.imwrite(save_path, img)
        return img, save_path
    return None, None

def get_image_from_file():
    """ファイル選択から画像を取得"""
    Tk().withdraw()
    filepath = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp")])
    if filepath and os.path.exists(filepath):
        return cv2.imdecode(np.fromfile(filepath, dtype=np.uint8), cv2.IMREAD_COLOR), filepath
    return None, None

def main():
    img, path = get_image_from_clipboard()
    if img is None:
        img, path = get_image_from_file()
    if img is None:
        print("画像が選択されませんでした。")
        return
    cropper = ImageCropper(img, path)
    cropper.show()

if __name__ == "__main__":
    main()

"""
【概要】
このプログラムは、指定された画像ファイルを読み込み、マウスやキーボード操作で選択した領域をトリミングし、必要に応じてリサイズした境界保存する機能を提供します。

【機能】
画像の取り込み:

ファイル選択ダイアログを使用して画像ファイルを指定する。
クリップボードから画像を取り込む機能はありません。
読み込む画像ファイルのパスには日本語を含めてもエラーなく処理できる。
操作方法:

矢印キー:四角形を10ドット単位で移動します。
左矢印キー: 左方向に移動します。
右矢印キー: 右方向に移動します。
上矢印キー: 上方向に移動します。
下矢印キー: 下方向に移動します。
'+'キー: 四角形の幅と高さを10ドットずつ拡大します。
'-'キー: 四角形の幅と高いさを10ドットずつ縮小します。
's'キー: 現在のトリミング範囲で画像を保存。
'Esc'キー: プログラムを終了します。
トリミングとリサイズ:

指定された比率(横1200:縦628)でトリミングする。
出力画像の幅が指定された最大値(デフォルト: 1200ピクセル)を超える場合、縦横比を保持したまま縮小する。
出力画像は、入力ファイル名に「_trm」を追加した名前で保存します。
パラメータ設定:

四角形比率:横1200、縦628。
画面表示最大値:幅(2500)、高さ(1400)。
矢印キーの移動量: 10ドット。
四角形サイズ変更量: 10ドット。
出力画像の最大幅: わが値: 1200。
【注意事項】
矢印キーの動作:

矢印キーを正しく動作させるため、cv2.waitKeyExを利用しています。
特殊キーのコードに対応するため、以下のキーコードを用いて処理しています。
左矢印:0x250000
上矢印:0x260000
右矢印:0x270000
矢印:0x280000
ファイルパスの日本語対応:

cv2.imdecodeをnp.fromfile使用して、日本語を含むファイルパスでも画像を正しく読み込めるよう対応しています。
【使用方法】
プログラムを実行すると、ファイル選択ダイアログが表示されるので画像ファイルを指定します。
矢印キーや'+'/'-'キーで四角形の位置やサイズを調整します。
's'キーを押してトリミングした画像を保存。
'Esc'キーでプログラムを終了します。

"""

関連記事

関連記事が見つかりませんでした。