はじめに
画像処理100本ノックとは画像処理を初めてやる人や経験者でも技術力向上のための問題集です。
今回は「Gasyori100knock-1」のサイトにある問題を、今話題の生成AI達がどの程度解けるのかを見てどの生成AIが使い勝手がいいか比べて行こうと思う。
使っていく生成AIは
- ChatGPT3.5
- Gemini
- Claude2
*注意:すべて無料版を使用
Q1チャンネル入れ替え
使用画像
*以下は生成AIの出力結果のみを提示する。
ChatGPT
Pythonで画像を読み込んでRGBをBGRの順に入れ替えるには、OpenCVライブラリを使用するのが一般的です。以下に、その方法を示します。
import cv2
# 画像を読み込む
image = cv2.imread('input_image.jpg')
# RGBをBGRに変換する
bgr_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
# 変換された画像を保存する
cv2.imwrite('output_image.jpg', bgr_image)
これで、input_image.jpg というファイル名の画像を読み込み、RGBをBGRの順に変換して output_image.jpg として保存します。
出力結果
Gemini
Pythonで画像を読み込み、RGBをBGRに変換するには、主に以下の2つの方法があります。
1. OpenCVを使う
OpenCVは、画像処理やコンピュータビジョンに特化したライブラリです。OpenCVを使うと、画像の読み込み、書き込み、様々な画像処理を簡単に行うことができます。
import cv2
# 画像を読み込む
image = cv2.imread('image.jpg')
# RGBからBGRに変換する
bgr_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
# BGR画像を保存する
cv2.imwrite('bgr_image.jpg', bgr_image)
コードは注意してご使用ください。
出力結果
- NumPyを使う
NumPyは、数値計算に特化したライブラリです。NumPyを使うと、画像データを多次元配列として扱い、RGBとBGRの変換を行うことができます。
import numpy as np
# 画像を読み込む
image = cv2.imread('image.jpg')
# RGBデータをBGRに変換する
bgr_image = image[:, :, ::-1]
# BGR画像を保存する
cv2.imwrite('bgr_image.jpg', bgr_image)
コードは注意してご使用ください。
補足
OpenCVとNumPy以外にも、Pillowなどのライブラリを使ってRGBとBGRの変換を行うことができます。
画像を読み込む形式によっては、デフォルトでRGBではなくBGRの形式で読み込まれる場合があります。その場合は、変換が必要ありません。
変換後の画像を保存する際は、形式に注意する必要があります。例えば、BMP形式で保存する場合は、BGRの形式で保存する必要があります。
上記以外にも、様々な方法でRGBとBGRの変換を行うことができます。ご自身の目的に合った方法を選択してください。
出力結果
Claude2
Pythonで画像のRGBをBGRに変換する方法は以下のとおりです。
import cv2
# 画像を読み込む
image = cv2.imread('image.jpg')
# RGBをBGRに変換
bgr_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
# 変換後の画像を表示
cv2.imshow('BGR Image', bgr_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
上記のコードでは、以下の手順を踏んでいます。
cv2.imread()関数を使って、image.jpgという名前の画像ファイルを読み込みます。
cv2.cvtColor()関数を使って、読み込んだ画像をRGBからBGRに変換します。cv2.COLOR_RGB2BGRは、OpenCVの定数で、RGBからBGRに変換することを指定しています。
変換後の画像をcv2.imshow()関数を使って表示します。'BGR Image'はウィンドウのタイトルです。
cv2.waitKey(0)は、ユーザーがキーを押すまで待機します。
cv2.destroyAllWindows()は、表示されているウィンドウを閉じます。
注意点として、OpenCVは画像をBGRの順序で読み込むため、RGBからBGRに変換する必要があります。また、cv2.imread()関数にファイルパスを正しく指定する必要があります。
公式解答
import cv2
# function: BGR -> RGB
def BGR2RGB(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# RGB > BGR
img[:, :, 0] = r
img[:, :, 1] = g
img[:, :, 2] = b
return img
# Read image
img = cv2.imread("imori.jpg")
# BGR -> RGB
img = BGR2RGB(img)
# Save result
cv2.imwrite("out.jpg", img)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
出力結果
Q29アフィン変換(拡大縮小)
また、(2) (1)の条件に加えて、x方向に+30、y方向に-30だけ平行移動を同時に実現せよ。
ChatGPT3.5
次に、平行移動を追加してリサイズと平行移動を同時に実現します。これにはアフィン変換行列の最後の列に平行移動の情報を追加する必要があります。ここではx方向に+30、y方向に-30だけ平行移動を行うとします。
import cv2
import numpy as np
# 画像読み込み
image = cv2.imread('input_image.jpg')
# オリジナル画像の高さと幅を取得
height, width = image.shape[:2]
# アフィン変換行列を作成
# x方向に1.3倍、y方向に0.8倍にリサイズ
# x方向に+30、y方向に-30だけ平行移動
transform_matrix = np.float32([[1.3, 0, 30], [0, 0.8, -30]])
# アフィン変換を適用してリサイズと平行移動を同時に実現
transformed_image = cv2.warpAffine(image, transform_matrix, (int(width * 1.3) + 30, int(height * 0.8) - 30))
# 変換後の画像を保存
/* Your code... */
cv2.imwrite('transformed_image.jpg', transformed_image) ``` このコードでは、リサイズと平行移動を同時に行うためにアフィン変換行列に変換情報を追加しました。そして、OpenCVの`warpAffine`関数を使って変換を適用し、`transformed_image.jpg`というファイル名で保存しています。
出力結果
Gemini
## Pythonでアフィン変換を用いて画像を(1.3倍, 0.8倍)にリサイズし、x方向に+30、y方向に-30だけ平行移動する方法
以下のコードは、Pythonでアフィン変換を用いて画像を(1.3倍, 0.8倍)にリサイズし、x方向に+30、y方向に-30だけ平行移動する方法です。
import cv2
import numpy as np
# 画像を読み込む
image = cv2.imread('image.jpg')
# アフィン変換行列を作成する
# 1.3倍x0.8倍に拡大し、(0, 0)を画像の中心にする
M = np.array([[1.3, 0, 30], [0, 0.8, -30], [0, 0, 1]], dtype=np.float32)
# アフィン変換を行う
resized_image = cv2.warpAffine(image, M, (image.shape[1] * 13 // 10, image.shape[0] * 8 // 10))
# リサイズ後の画像を保存する
cv2.imwrite('resized_image.jpg', resized_image)
**説明**
このコードは、前述のコードを以下のように変更しています。
* アフィン変換行列 `M` に、平行移動量 `(30, -30)` を追加しています。
**補足**
* このコードは、OpenCV 4.0以降で使用できます。
* アフィン変換以外にも、回転や傾きの操作など、様々な操作を行うことができます。
* 詳しくは、OpenCVの公式ドキュメントを参照してください。
OpenCV: Geometric Transformations of Images(https://docs.opencv.org/4.x/da/d6e/tutorial_py_geometric_transformations.html)
上記以外にも、様々な方法で画像をリサイズ and 平行移動することができます。ご自身の目的に合った方法を選択してください。
出力結果
Claude2
アフィン変換を使って、x方向に1.3倍、y方向に0.8倍にリサイズし、さらにx方向に+30、y方向に-30だけ平行移動するPythonコードは以下のようになります。
import cv2
import numpy as np
# 画像を読み込む
img = cv2.imread('image.jpg')
# アフィン変換の変換行列を定義
rows, cols = img.shape[:2]
scale_x = 1.3
scale_y = 0.8
shift_x = 30
shift_y = -30
transform_matrix = np.array([[scale_x, 0, shift_x],
[0, scale_y, shift_y]])
# アフィン変換を適用
resized_img = cv2.warpAffine(img, transform_matrix, (int(cols*scale_x+shift_x), int(rows*scale_y+shift_y)))
# 変換後の画像を表示
cv2.imshow('Resized and Shifted Image', resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
変更点は以下の2点です。
1. 変換行列`transform_matrix`の定義部分で、`shift_x`と`shift_y`を追加し、平行移動量を指定しています。
2. `cv2.warpAffine()`関数の第3引数で、出力画像のサイズを計算する際に、平行移動量`shift_x`と`shift_y`を加算しています。
このコードを実行すると、元の画像がx方向に1.3倍、y方向に0.8倍にリサイズされ、さらにx方向に+30、y方向に-30だけ平行移動した画像が表示されます。
アフィン変換の変換行列は以下のように構成されています。
[scale_x, 0, shift_x]
[0, scale_y, shift_y]
この行列を用いることで、拡大縮小と平行移動を同時に実現できます。
公式解答
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Affine
def affine(img, a, b, c, d, tx, ty):
H, W, C = img.shape
# temporary image
img = np.zeros((H+2, W+2, C), dtype=np.float32)
img[1:H+1, 1:W+1] = _img
# get new image shape
H_new = np.round(H * d).astype(np.int)
W_new = np.round(W * a).astype(np.int)
out = np.zeros((H_new+1, W_new+1, C), dtype=np.float32)
# get position of new image
x_new = np.tile(np.arange(W_new), (H_new, 1))
y_new = np.arange(H_new).repeat(W_new).reshape(H_new, -1)
# get position of original image by affine
adbc = a * d - b * c
x = np.round((d * x_new - b * y_new) / adbc).astype(np.int) - tx + 1
y = np.round((-c * x_new + a * y_new) / adbc).astype(np.int) - ty + 1
x = np.minimum(np.maximum(x, 0), W+1).astype(np.int)
y = np.minimum(np.maximum(y, 0), H+1).astype(np.int)
# assgin pixcel to new image
out[y_new, x_new] = img[y, x]
out = out[:H_new, :W_new]
out = out.astype(np.uint8)
return out
# Read image
_img = cv2.imread("imori.jpg").astype(np.float32)
# Affine
out = affine(_img, a=1.3, b=0, c=0, d=0.8, tx=30, ty=-30)
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
出力結果
結果
簡単な問題と少し難しい問題を解かせてみた。簡単な問題は三者とも正解したが少し難しい問題に関しては似たような出力結果だが平行移動がうまく実装されなかった。しかしChatGPTに関しては一番簡単な方法で解いてくれる。解説もプログラム内での説明のみ。Geminiはやり方が複数あるときは複数提示してくれる。説明はプログラム内でも説明を書きGeminiでの返答内でも説明の欄を設けてくれる。Claude2はプログラム内での説明はなしで返答での説明。Geminiと同じで説明の欄を設けそこで一行ずつ説明している。Claude2は画像をその場で出力するだけで画像を保存するコードは提示しなかった。
ツールごとの違い
ここまでは一から作ってもらったが、Q29のプログラムの途中を渡しその後のプログラムを作ってほしいとした結果、ChatGPTのみが正しいコードを示した。 このことからChatGPTの文章理解能力が高いと考えられる。文章を理解する能力が高いからこそ途中で行き詰ってしまったプログラムでも作り上げることができる。 しかしGeminiとclaude2は文章を理解する能力が高くないので丸投げするのではなくエラー文を提示して少しずつプログラムを改善していくことが現実的だと考えた。 Geminiは唯一解答の最後に絶対「このコードはあくまで一例です」と付け足される。そのためGeminiだけはモラルの数値がこの中では高く設定されていると考えられる。 Claude2は特に二つと大きく違うことはなかった。ただ自分の意見に対して強気な姿勢をもって対応してくる。
まとめ
どの生成AIも正しいコードを示してくれた。その中でもChatGPTは無課金でも文章の理解能力に長けていてほか二つよりも優秀だと感じたがプログラムのエラーを提示すればどのAIも改善案を出してくれる。正しい使い方をすればプログラミングで詰まってしまったりしたときの手助けをしてくれる優秀なAIだと思う。あくまで手助けでありAIの解答を丸写ししては勉強にならないし間違いに気づくことができないためすべてを鵜呑みにすることはしないようにしてください。
コメント
無料版を使用している部分がとてもいいと思いました
正しい使い方をすればどの生成AIも優秀だなと感じました。また生成AIについてわかりやすくまとめられていて見やすかったです。
各生成AIの違いと特徴が非常にわかりやすくまとめられていてとても参考になる。
無料版での比較な為、生成AI初心者にもとっつきやすい内容であると感じた。
AIにも作った会社や人によって機能や利点、欠点は変わってくるので今回のこの実験はAIツールを使う人達にとって自分はどれが一番便利だと感じたか、また、使い分けもすることができると思うのでとても参考になりました。
AIは、「理解できる命令」をより詳細に与えることが特に大事だと思いました。
また、それぞれの生成AIは言語理解などの性能が違うため、適材適所で使うようにすることが重要だと思いました。
比較対象が無料版の生成AIであることが、これから利用を検討している人にとって非常に有益だと感じました。無料版を比較している記事はあまり見かけないので、とても参考になって良いと思います。